mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 03:14:03 +03:00
b6519e0f1f
fixes GRO-34 fixes GRO-33 This is a revision of a previous commit, that broke the browser tests because changes in the data generator (requiring bookshelf had side effects). This adds a new way to run all tests with enforced numeric ObjectIDs. These numeric ids cause issues if they are used withing NQL filters. So they surface tiny bugs in our codebase. You can run tests using this option via: NUMERIC_IDS=1 yarn test:e2e Removed some defensive logic that could be explained by this discovered issue.
394 lines
15 KiB
JavaScript
394 lines
15 KiB
JavaScript
const _ = require('lodash');
|
|
const should = require('should');
|
|
const supertest = require('supertest');
|
|
const config = require('../../../core/shared/config');
|
|
const testUtils = require('../../utils');
|
|
const localUtils = require('./utils');
|
|
const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
|
|
const {anyEtag, anyErrorId, anyContentVersion} = matchers;
|
|
|
|
describe('Integrations API', function () {
|
|
let request;
|
|
|
|
before(async function () {
|
|
await localUtils.startGhost();
|
|
request = supertest.agent(config.get('url'));
|
|
await localUtils.doAuth(request, 'integrations');
|
|
});
|
|
|
|
const findBy = (prop, val) => object => object[prop] === val;
|
|
|
|
it('Can browse all integrations', async function () {
|
|
const res = await request.get(localUtils.API.getApiQuery(`integrations/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
should.equal(res.body.integrations.length, 6);
|
|
|
|
// there is no enforced order for integrations which makes order different on SQLite and MySQL
|
|
const zapierIntegration = _.find(res.body.integrations, {name: 'Zapier'}); // from migrations
|
|
should.exist(zapierIntegration);
|
|
|
|
const testIntegration = _.find(res.body.integrations, {name: 'Test Integration'}); // from fixtures
|
|
should.exist(testIntegration);
|
|
|
|
const exploreIntegration = _.find(res.body.integrations, {name: 'Test Core Integration'}); // from fixtures
|
|
should.exist(exploreIntegration);
|
|
|
|
const selfServeMigrationIntegration = _.find(res.body.integrations, {name: 'Self-Serve Migration Integration'}); // from fixtures
|
|
should.exist(selfServeMigrationIntegration);
|
|
});
|
|
|
|
it('Can not read internal integration', async function () {
|
|
await request.get(localUtils.API.getApiQuery(`integrations/${testUtils.DataGenerator.Content.integrations[1].id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(404);
|
|
});
|
|
|
|
it('Can successfully create a single integration with auto generated content and admin api key', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Dis-Integrate!!'
|
|
}]
|
|
})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(201);
|
|
|
|
should.equal(res.body.integrations.length, 1);
|
|
|
|
const [integration] = res.body.integrations;
|
|
should.equal(integration.name, 'Dis-Integrate!!');
|
|
|
|
should.equal(integration.api_keys.length, 2);
|
|
|
|
const contentApiKey = integration.api_keys.find(findBy('type', 'content'));
|
|
should.equal(contentApiKey.integration_id, integration.id);
|
|
|
|
const adminApiKey = integration.api_keys.find(findBy('type', 'admin'));
|
|
should.equal(adminApiKey.integration_id, integration.id);
|
|
should.exist(adminApiKey.secret);
|
|
|
|
// check Admin API key secret format
|
|
const [id, secret] = adminApiKey.secret.split(':');
|
|
should.exist(id);
|
|
should.equal(id, adminApiKey.id);
|
|
should.exist(secret);
|
|
secret.length.should.equal(64);
|
|
|
|
should.exist(res.headers.location);
|
|
res.headers.location.should.equal(`http://127.0.0.1:2369${localUtils.API.getApiQuery('integrations/')}${res.body.integrations[0].id}/`);
|
|
});
|
|
|
|
it('Can successfully create a single integration with a webhook', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Integratatron4000',
|
|
webhooks: [{
|
|
event: 'something',
|
|
target_url: 'http://example.com'
|
|
}]
|
|
}]
|
|
})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(201);
|
|
|
|
should.equal(res.body.integrations.length, 1);
|
|
|
|
const [integration] = res.body.integrations;
|
|
should.equal(integration.name, 'Integratatron4000');
|
|
|
|
should.equal(integration.webhooks.length, 1);
|
|
|
|
const webhook = integration.webhooks[0];
|
|
should.equal(webhook.integration_id, integration.id);
|
|
|
|
should.exist(res.headers.location);
|
|
res.headers.location.should.equal(`http://127.0.0.1:2369${localUtils.API.getApiQuery('integrations/')}${res.body.integrations[0].id}/`);
|
|
});
|
|
|
|
it('Can successfully get a created integration', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Interrogation Integration'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const [createdIntegration] = res.body.integrations;
|
|
|
|
const res2 = await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
should.equal(res2.body.integrations.length, 1);
|
|
|
|
const [integration] = res2.body.integrations;
|
|
|
|
should.equal(integration.id, createdIntegration.id);
|
|
should.equal(integration.name, createdIntegration.name);
|
|
should.equal(integration.slug, createdIntegration.slug);
|
|
should.equal(integration.description, createdIntegration.description);
|
|
should.equal(integration.icon_image, createdIntegration.icon_image);
|
|
});
|
|
|
|
it('Can successfully get *all* created integrations with api_keys', async function () {
|
|
await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Integrate with this!'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Winter-(is)-great'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const res = await request.get(localUtils.API.getApiQuery(`integrations/?include=api_keys&limit=all`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const body = res.body;
|
|
// This is the only page
|
|
should.equal(body.meta.pagination.page, 1);
|
|
should.equal(body.meta.pagination.pages, 1);
|
|
should.equal(body.meta.pagination.next, null);
|
|
should.equal(body.meta.pagination.prev, null);
|
|
|
|
body.integrations.forEach((integration) => {
|
|
should.exist(integration.api_keys);
|
|
if (integration.api_keys.length) {
|
|
integration.api_keys.forEach((apiKey) => {
|
|
should.exist(apiKey.secret);
|
|
|
|
if (apiKey.type === 'content') {
|
|
should.equal(apiKey.secret.split(':').length, 1, `${integration.name} api key secret should have correct key format without ":"`);
|
|
} else if (apiKey.type === 'admin') {
|
|
should.equal(apiKey.secret.split(':').length, 2, `${integration.name} api key secret should have correct key format with ":"`);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
it('Can successfully edit a created integration', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Rubbish Integration Name'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const [createdIntegration] = res.body.integrations;
|
|
|
|
await request.put(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Awesome Integration Name',
|
|
description: 'Finally got round to writing this...'
|
|
}]
|
|
})
|
|
.expect(200);
|
|
|
|
const res2 = await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const [updatedIntegration] = res2.body.integrations;
|
|
|
|
should.equal(updatedIntegration.id, createdIntegration.id);
|
|
should.equal(updatedIntegration.name, 'Awesome Integration Name');
|
|
should.equal(updatedIntegration.description, 'Finally got round to writing this...');
|
|
});
|
|
|
|
it('Can successfully refresh an integration api key', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/?include=api_keys'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Rubbish Integration Name'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const [createdIntegration] = res.body.integrations;
|
|
const apiKeys = createdIntegration.api_keys;
|
|
const adminApiKey = apiKeys.find(key => key.type === 'admin');
|
|
|
|
await request.post(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/api_key/${adminApiKey.id}/refresh`))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
id: createdIntegration.id
|
|
}]
|
|
})
|
|
.expect(200);
|
|
|
|
const res2 = await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/?include=api_keys`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const [updatedIntegration] = res2.body.integrations;
|
|
const updatedAdminApiKey = updatedIntegration.api_keys.find(key => key.type === 'admin');
|
|
should.equal(updatedIntegration.id, createdIntegration.id);
|
|
updatedAdminApiKey.secret.should.not.eql(adminApiKey.secret);
|
|
|
|
const res3 = await request.get(localUtils.API.getApiQuery(`actions/?filter=resource_id:'${adminApiKey.id}'&include=actor`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const actions = res3.body.actions;
|
|
const refreshedAction = actions.find((action) => {
|
|
return action.event === 'refreshed';
|
|
});
|
|
should.exist(refreshedAction);
|
|
});
|
|
|
|
it('Can successfully add and delete a created integrations webhooks', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Webhook-less Integration'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const [createdIntegration] = res.body.integrations;
|
|
|
|
await request.put(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
webhooks: [{
|
|
event: 'somestuff',
|
|
target_url: 'http://example.com'
|
|
}]
|
|
}]
|
|
})
|
|
.expect(200);
|
|
|
|
const res2 = await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/?include=webhooks`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const [updatedIntegration] = res2.body.integrations;
|
|
|
|
should.equal(updatedIntegration.webhooks.length, 1);
|
|
|
|
const webhook = updatedIntegration.webhooks[0];
|
|
should.equal(webhook.integration_id, updatedIntegration.id);
|
|
|
|
await request.put(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
webhooks: []
|
|
}]
|
|
})
|
|
.expect(200);
|
|
|
|
const res3 = await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/?include=webhooks`))
|
|
.set('Origin', config.get('url'))
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(200);
|
|
|
|
const [updatedIntegration2] = res3.body.integrations;
|
|
should.equal(updatedIntegration2.webhooks.length, 0);
|
|
});
|
|
|
|
it('Can successfully delete a created integration', async function () {
|
|
const res = await request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Short Lived Integration'
|
|
}]
|
|
})
|
|
.expect(201);
|
|
|
|
const [createdIntegration] = res.body.integrations;
|
|
|
|
await request.del(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect(204)
|
|
.expect((_res) => {
|
|
_res.body.should.be.empty();
|
|
});
|
|
|
|
await request.get(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.set('Origin', config.get('url'))
|
|
.expect(404);
|
|
|
|
const editRes = await request.put(localUtils.API.getApiQuery(`integrations/${createdIntegration.id}/`))
|
|
.send({
|
|
integrations: [createdIntegration]
|
|
})
|
|
.set('Origin', config.get('url'))
|
|
.expect(404);
|
|
|
|
editRes.body.errors[0].context.should.eql('Integration not found.');
|
|
});
|
|
|
|
describe('As Administrator', function () {
|
|
let agent;
|
|
|
|
before(async function () {
|
|
agent = await agentProvider.getAdminAPIAgent();
|
|
await fixtureManager.init('users', 'integrations');
|
|
await agent.loginAsContributor();
|
|
});
|
|
|
|
it('Can\'t see Self-Serve or any other integration', async function () {
|
|
await agent
|
|
.get('integrations')
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
})
|
|
.matchBodySnapshot({
|
|
errors: [
|
|
{
|
|
id: anyErrorId
|
|
}
|
|
]
|
|
})
|
|
.expectStatus(403);
|
|
});
|
|
});
|
|
});
|