Refactored webhook tests to use e2e framework

- webhooks are one of the remaining places where we need some sort of api version handling
- in order to fixup the tests for this, I wanted to first change them to use the e2e framework
This commit is contained in:
Hannah Wolfe 2022-05-06 12:17:32 +01:00
parent 7618f925e1
commit d3ea145c19
No known key found for this signature in database
GPG Key ID: AB586C3B5AE5C037
2 changed files with 218 additions and 131 deletions

View File

@ -0,0 +1,137 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Webhooks API Can create a webhook 1: [body] 1`] = `
Object {
"webhooks": Array [
Object {
"api_version": "canary",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
"event": "test.create",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"integration_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_triggered_at": null,
"last_triggered_error": null,
"last_triggered_status": null,
"name": "test",
"secret": "thisissecret",
"status": "available",
"target_url": "http://example.com/webhooks/test/extra/1",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
},
],
}
`;
exports[`Webhooks API Can create a webhook 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "414",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Webhooks API Can delete a webhook 1: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin",
"x-powered-by": "Express",
}
`;
exports[`Webhooks API Can edit a webhook 1: [body] 1`] = `
Object {
"webhooks": Array [
Object {
"api_version": "canary",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
"event": "subscriber.added",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"integration_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_triggered_at": null,
"last_triggered_error": null,
"last_triggered_status": null,
"name": "Edit Test",
"secret": "thisissecret",
"status": "available",
"target_url": "https://example.com/new-subscriber",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}/,
},
],
}
`;
exports[`Webhooks API Can edit a webhook 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "418",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Webhooks API Fails nicely when adding a duplicate webhook 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": null,
"context": "Target URL has already been used for this event.",
"details": null,
"help": null,
"id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"message": "Validation error, cannot save webhook.",
"property": null,
"type": "ValidationError",
},
],
}
`;
exports[`Webhooks API Fails nicely when adding a duplicate webhook 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "250",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Webhooks API Fails nicely when creating an orphaned webhook 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": null,
"context": "Validation failed for 'integration_id'. 'integration_id' value does not match any existing integration.",
"details": null,
"help": "Provide the 'integration_id' of an existing integration.",
"id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"message": "Validation error, cannot save webhook.",
"property": null,
"type": "ValidationError",
},
],
}
`;
exports[`Webhooks API Fails nicely when creating an orphaned webhook 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "359",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;

View File

@ -1,116 +1,91 @@
const should = require('should');
const supertest = require('supertest');
const testUtils = require('../../utils');
const config = require('../../../core/shared/config');
const localUtils = require('./utils');
const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
const {anyEtag, anyErrorId, anyObjectId, anyISODate} = matchers;
const API_VERSION = 'canary';
const webhookMatcher = {
id: anyObjectId,
integration_id: anyObjectId,
created_at: anyISODate,
updated_at: anyISODate
};
describe('Webhooks API', function () {
let request;
const API_VERSION = 'canary';
let agent;
let createdWebhookId;
let webhookData;
before(async function () {
await localUtils.startGhost();
request = supertest.agent(config.get('url'));
await localUtils.doAuth(request, 'integrations');
});
agent = await agentProvider.getAdminAPIAgent();
await fixtureManager.init('integrations');
await agent.loginAsOwner();
it('Can create a webhook', async function () {
const webhookData = {
// create a webhook linked to a real integration
webhookData = {
event: 'test.create',
target_url: 'http://example.com/webhooks/test/extra/1',
name: 'test',
secret: 'thisissecret',
api_version: API_VERSION,
integration_id: testUtils.DataGenerator.Content.integrations[0].id
integration_id: fixtureManager.get('integrations', 0).id
};
});
const res = await request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Origin', config.get('url'))
.send({webhooks: [webhookData]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201);
it('Can create a webhook', async function () {
const {body} = await agent.post('/webhooks/')
.body({webhooks: [webhookData]})
.expectStatus(201)
.matchHeaderSnapshot({
// Note: No location header as there is no read method for webhooks
etag: anyEtag
const jsonResponse = res.body;
})
.matchBodySnapshot({
webhooks: [webhookMatcher]
});
should.exist(jsonResponse.webhooks);
// Store an id for use in future tests. Not the best pattern but does keep the tests readable.
createdWebhookId = body.webhooks[0].id;
});
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
jsonResponse.webhooks[0].event.should.equal(webhookData.event);
jsonResponse.webhooks[0].target_url.should.equal(webhookData.target_url);
jsonResponse.webhooks[0].secret.should.equal(webhookData.secret);
jsonResponse.webhooks[0].name.should.equal(webhookData.name);
jsonResponse.webhooks[0].api_version.should.equal(webhookData.api_version);
jsonResponse.webhooks[0].integration_id.should.equal(webhookData.integration_id);
should.not.exist(res.headers.location);
await request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Origin', config.get('url'))
.send({webhooks: [webhookData]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(422);
it('Fails nicely when adding a duplicate webhook', async function () {
await agent.post('/webhooks/')
.body({webhooks: [webhookData]})
.expectStatus(422)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
});
});
it('Fails nicely when creating an orphaned webhook', async function () {
const webhookData = {
event: 'test.create',
target_url: 'http://example.com/webhooks/test/extra/10',
name: 'test',
secret: 'thisissecret',
api_version: API_VERSION,
integration_id: `fake-integration`
};
const res = await request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Origin', config.get('url'))
.send({webhooks: [webhookData]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(422);
const jsonResponse = res.body;
should.exist(jsonResponse.errors);
jsonResponse.errors[0].type.should.equal('ValidationError');
jsonResponse.errors[0].context.should.equal(`Validation failed for 'integration_id'. 'integration_id' value does not match any existing integration.`);
await agent
.post('/webhooks/')
.body({webhooks: [{
event: 'test.create',
target_url: 'http://example.com/webhooks/test/extra/10',
name: 'test',
secret: 'thisissecret',
api_version: API_VERSION,
integration_id: `fake-integration`
}]})
.expectStatus(422)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
});
});
it('Can edit a webhook', async function () {
let createdIntegration;
let createdWebhook;
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
.set('Origin', config.get('url'))
.send({
integrations: [{
name: 'Rubbish Integration Name'
}]
})
.expect(201);
[createdIntegration] = res.body.integrations;
const res2 = await request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Origin', config.get('url'))
.send({
webhooks: [{
name: 'Testing',
event: 'site.changed',
target_url: 'https://example.com/rebuild',
integration_id: createdIntegration.id
}]
})
.expect(201);
[createdWebhook] = res2.body.webhooks;
const res3 = await request.put(localUtils.API.getApiQuery(`webhooks/${createdWebhook.id}/`))
.set('Origin', config.get('url'))
.send({
await agent.put(`/webhooks/${createdWebhookId}/`)
.body({
webhooks: [{
name: 'Edit Test',
event: 'subscriber.added',
@ -118,47 +93,22 @@ describe('Webhooks API', function () {
integration_id: 'ignore_me'
}]
})
.expect(200)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private);
const [updatedWebhook] = res3.body.webhooks;
should.equal(updatedWebhook.id, createdWebhook.id);
should.equal(updatedWebhook.name, 'Edit Test');
should.equal(updatedWebhook.event, 'subscriber.added');
should.equal(updatedWebhook.target_url, 'https://example.com/new-subscriber');
should.equal(updatedWebhook.integration_id, createdIntegration.id);
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
webhooks: [webhookMatcher]
});
});
it('Can delete a webhook', async function () {
const newWebhook = {
event: 'test.create',
// a different target_url from above is needed to avoid an "already exists" error
target_url: 'http://example.com/webhooks/test/2',
integration_id: testUtils.DataGenerator.Content.integrations[0].id
};
// create the webhook that is to be deleted
const res = await request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Origin', config.get('url'))
.send({webhooks: [newWebhook]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201);
const jsonResponse = res.body;
should.exist(jsonResponse.webhooks);
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
jsonResponse.webhooks[0].event.should.equal(newWebhook.event);
jsonResponse.webhooks[0].target_url.should.equal(newWebhook.target_url);
// begin delete test
const res2 = await request.del(localUtils.API.getApiQuery('webhooks/' + jsonResponse.webhooks[0].id + '/'))
.set('Origin', config.get('url'))
.expect(204);
res2.body.should.be.empty();
await agent
.delete(`/webhooks/${createdWebhookId}/`)
.expectStatus(204)
.expectEmptyBody()
.matchHeaderSnapshot({
etag: anyEtag
});
});
});