Fixed webhook modal title showing "New webhook" when editing a webhook

refs https://github.com/TryGhost/Ghost/issues/10137
- adjust modal title depending on `webhook.isNew` state
- add acceptance tests for modal creation
- add missing mirage webhook factory
- mock integrations/api-keys/webhooks in test env rather than development
This commit is contained in:
Kevin Ansfield 2018-11-12 16:31:47 +00:00
parent 032fba8f7b
commit c33edbac08
6 changed files with 99 additions and 37 deletions

View File

@ -1,30 +1,30 @@
<header class="modal-header" data-test-modal="webhook-form">
<h1>New webhook</h1>
<h1 data-test-text="title">{{if webhook.isNew "New" "Edit"}} webhook</h1>
</header>
<button class="close" href="" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}</button>
<div class="modal-body">
<fieldset>
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="name"}}
<label for="new-webhook-name" class="fw6">Name</label>
<label for="webhook-name" class="fw6">Name</label>
{{gh-text-input
value=(readonly webhook.name)
input=(action (mut webhook.name) value="target.value")
focus-out=(action "validate" "name" target=webhook)
id="new-webhook-name"
id="webhook-name"
name="name"
class="gh-input mt1"
placeholder="Webhook name..."
autofocus="autofocus"
autocapitalize="off"
autocorrect="off"
data-test-input="new-webhook-name"}}
{{gh-error-message errors=webhook.errors property="name" data-test-error="new-webhook-name"}}
data-test-input="webhook-name"}}
{{gh-error-message errors=webhook.errors property="name" data-test-error="webhook-name"}}
{{/gh-form-group}}
</fieldset>
<fieldset>
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="event"}}
<label for="new-webhook-event" class="fw6">Event</label>
<label for="webhook-event" class="fw6">Event</label>
<span class="gh-select">
{{one-way-select webhook.event
options=availableEvents
@ -35,49 +35,49 @@
includeBlank=true
prompt="Select an event"
update=(action "selectEvent")
id="new-webhook-event"
id="webhook-event"
name="event"
data-test-select="new-webhook-event"}}
data-test-select="webhook-event"}}
{{svg-jar "arrow-down-small"}}
</span>
{{gh-error-message errors=webhook.errors property="event" data-test-error="new-webhook-event"}}
{{gh-error-message errors=webhook.errors property="event" data-test-error="webhook-event"}}
{{/gh-form-group}}
</fieldset>
<fieldset>
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="targetUrl"}}
<label for="new-webhook-targetUrl" class="fw6">Target URL</label>
<label for="webhook-targetUrl" class="fw6">Target URL</label>
{{gh-text-input
value=(readonly webhook.targetUrl)
input=(action (mut webhook.targetUrl) value="target.value")
focus-out=(action "validate" "targetUrl" target=webhook)
id="new-webhook-targetUrl"
id="webhook-targetUrl"
name="targetUrl"
class="gh-input mt1"
placeholder="Webhook target URL..."
autofocus="autofocus"
autocapitalize="off"
autocorrect="off"
data-test-input="new-webhook-targetUrl"}}
{{gh-error-message errors=webhook.errors property="targetUrl" data-test-error="new-webhook-targetUrl"}}
data-test-input="webhook-targetUrl"}}
{{gh-error-message errors=webhook.errors property="targetUrl" data-test-error="webhook-targetUrl"}}
{{/gh-form-group}}
</fieldset>
{{#if config.enableDeveloperExperiments}}
<fieldset>
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="secret"}}
<label for="new-webhook-secret" class="fw6">Secret</label>
<label for="webhook-secret" class="fw6">Secret</label>
{{gh-text-input
value=(readonly webhook.secret)
oninput=(action (mut webhook.secret) value="target.value")
focus-out=(action "validate" "secret" target=webhook)
id="new-webhook-secret"
id="webhook-secret"
name="secret"
class="gh-input mt1"
placeholder="Webhook secret..."
autofocus="autofocus"
autocapitalize="off"
autocorrect="off"
data-test-input="new-webhook-secret"}}
{{gh-error-message errors=webhook.errors property="secret" data-test-error="new-webhook-secret"}}
data-test-input="webhook-secret"}}
{{gh-error-message errors=webhook.errors property="secret" data-test-error="webhook-secret"}}
{{/gh-form-group}}
</fieldset>
{{/if}}
@ -87,7 +87,7 @@
</div>
<div class="modal-footer">
<button {{action "closeModal"}} class="gh-btn" data-test-button="cancel-new-webhook">
<button {{action "closeModal"}} class="gh-btn" data-test-button="cancel-webhook">
<span>Cancel</span>
</button>
{{gh-task-button buttonText

View File

@ -172,28 +172,30 @@
</thead>
<tbody>
{{#each filteredWebhooks as |webhook|}}
<tr class="hide-child bt b--whitegrey f7">
<td class="pa2 pl3">{{webhook.name}}</td>
<td class="pa2 pl3">{{event-name webhook.event}}</td>
<td class="pa2 pl3">{{webhook.targetUrl}}</td>
<td class="pa2 pl3">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
<tr class="hide-child bt b--whitegrey f7" data-test-webhook-row="{{webhook.id}}">
<td class="pa2 pl3" data-test-text="name">{{webhook.name}}</td>
<td class="pa2 pl3" data-test-text="event">{{event-name webhook.event}}</td>
<td class="pa2 pl3" data-test-text="targetUrl">{{webhook.targetUrl}}</td>
<td class="pa2 pl3" data-test-text="last-triggered">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
<td class="w1 pa2 pl3 nowrap">
<div class="child flex items-center">
{{#link-to "settings.integration.webhooks.edit" integration webhook}}
{{#link-to "settings.integration.webhooks.edit" integration webhook data-test-link="edit-webhook"}}
{{svg-jar "pen" class="w6 h-auto fill-midgrey pa1 mr1"}}
{{/link-to}}
<button {{action "confirmWebhookDeletion" webhook}}>
<button {{action "confirmWebhookDeletion" webhook}} data-test-button="delete-webhook">
{{svg-jar "trash" class="w6 fill-red pa1"}}
</button>
</div>
</td>
</tr>
{{else}}
<tr class="bt b--whitegrey">
<tr class="bt b--whitegrey" data-test-webhooks-blank-slate>
<td colspan="5" class="pa5 pt15 pb15 tc midgrey f7">
<span class="db">No webhooks configured</span>
<span class="dib mt1">
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center"}}{{svg-jar "add" class="w3 h-auto fill-blue mr1"}} Add webhook{{/link-to}}
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center" data-test-link="add-webhook"}}
{{svg-jar "add" class="w3 h-auto fill-blue mr1"}} Add webhook
{{/link-to}}
</span>
</td>
</tr>
@ -203,8 +205,9 @@
<tfoot class="bt b--lightgrey">
<tr>
<td colspan="5" class="pa3 f7">
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center"}}{{svg-jar "add" class="w3
h-auto fill-blue mr1"}} Add webhook{{/link-to}}
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center" data-test-link="add-webhook"}}
{{svg-jar "add" class="w3h-auto fill-blue mr1"}} Add webhook
{{/link-to}}
</td>
</tr>
</tfoot>

View File

@ -25,9 +25,6 @@ export default function () {
// this.put('/posts/:id/', versionMismatchResponse);
// mockTags(this);
// this.loadFixtures('settings');
mockIntegrations(this);
mockApiKeys(this);
mockWebhooks(this);
// keep this line, it allows all other API requests to hit the real server
this.passthrough();
@ -45,8 +42,10 @@ export function testConfig() {
// this.timing = 400; // delay for each request, automatically set to 0 during testing
// this.logging = true;
mockApiKeys(this);
mockAuthentication(this);
mockConfiguration(this);
mockIntegrations(this);
mockInvites(this);
mockPosts(this);
mockRoles(this);
@ -57,6 +56,7 @@ export function testConfig() {
mockThemes(this);
mockUploads(this);
mockUsers(this);
mockWebhooks(this);
/* Notifications -------------------------------------------------------- */

View File

@ -7,11 +7,6 @@ export default function mockWebhooks(server) {
server.post('/webhooks/', function ({webhooks}) {
let attrs = this.normalizedRequestAttrs();
// TODO: should mirage be handling this?
attrs.integrationId = attrs.integration;
delete attrs.integration;
let errors = [];
if (!attrs.name) {

View File

@ -0,0 +1,18 @@
import moment from 'moment';
import {AVAILABLE_EVENTS} from 'ghost-admin/helpers/event-name';
import {Factory} from 'ember-cli-mirage';
export default Factory.extend({
name(i) { return `Integration ${i + 1}`;},
event(i) {
let event = AVAILABLE_EVENTS[i % 3];
return event.event;
},
target(i) { return `https://example.com/${i + 1}`; },
lastTriggeredAt: null,
createdAt() { return moment.utc().format(); },
createdBy: 1,
updatedAt() { return moment.utc().format(); },
updatedBy: 1
});

View File

@ -422,6 +422,52 @@ describe('Acceptance: Settings - Integrations', function () {
).to.equal('Test Integration');
});
it('can manage an integration\'s webhooks', async function () {
server.create('integration');
await visit('/settings/integrations/1');
expect(find('[data-test-webhooks-blank-slate]').length).to.equal(1);
// open new webhook modal
await click('[data-test-link="add-webhook"]');
expect(find('[data-test-modal="webhook-form"]').length).to.equal(1);
expect(find('[data-test-modal="webhook-form"] [data-test-text="title"]').text())
.to.have.string('New webhook');
// can cancel new webhook
await click('[data-test-button="cancel-webhook"]');
expect(find('[data-test-modal="webhook-form"]').length).to.equal(0);
// create new webhook
await click('[data-test-link="add-webhook"]');
await fillIn('[data-test-input="webhook-name"]', 'First webhook');
await fillIn('[data-test-select="webhook-event"]', 'site.changed');
await fillIn('[data-test-input="webhook-targetUrl"]', 'https://example.com/first-webhook');
await click('[data-test-button="save-webhook"]');
// modal closed and 1 webhook listed with correct details
expect(find('[data-test-modal="webhook-form"]').length).to.equal(0);
expect(find('[data-test-webhook-row]').length).to.equal(1);
let row = find('[data-test-webhook-row="1"]');
expect(row.find('[data-test-text="name"]').text())
.to.have.string('First webhook');
expect(row.find('[data-test-text="event"]').text())
.to.have.string('Site Changed (rebuild)');
expect(row.find('[data-test-text="targetUrl"]').text())
.to.have.string('https://example.com/first-webhook');
expect(row.find('[data-test-text="last-triggered"]').text())
.to.have.string('Not triggered');
// click edit webhook link
await click('[data-test-webhook-row="1"] [data-test-link="edit-webhook"]');
// modal appears and has correct title
expect(find('[data-test-modal="webhook-form"]').length).to.equal(1);
expect(find('[data-test-modal="webhook-form"] [data-test-text="title"]').text())
.to.have.string('Edit webhook');
});
// test to ensure the `value=description` passed to `gh-text-input` is `readonly`
it('doesn\'t show unsaved changes modal after placing focus on description field', async function () {
server.create('integration');