0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-15 03:01:37 -05:00

Added loginAs[Role] to e2e framework with example

closes: https://github.com/TryGhost/Toolbox/issues/342
refs: 032a26f9f3
refs: 588c9d04e8

- Now that the old `users:no-owner` (now named 'users') is working correctly :)
- Was able to add loginAs[Role] methods for each staff role, so that it's possible to execute tests as that user and check permissions
- Refactored the email preview tests to use the new e2e framework and these methods, as an example
This commit is contained in:
Hannah Wolfe 2022-09-02 10:20:11 +01:00
parent 588c9d04e8
commit 642b6ff8ae
No known key found for this signature in database
GPG key ID: AB586C3B5AE5C037
3 changed files with 211 additions and 192 deletions

View file

@ -40,6 +40,36 @@ Object {
}
`;
exports[`Email Preview API As Contributor cannot send test email 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": null,
"context": null,
"details": null,
"ghostErrorCode": 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": "You do not have permission to sendTestEmail email_previews",
"property": null,
"type": "NoPermissionError",
},
],
}
`;
exports[`Email Preview API As Contributor cannot send test email 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": "248",
"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[`Email Preview API As Editor can send test email 1: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",

View file

@ -1,61 +1,43 @@
const should = require('should');
const supertest = require('supertest');
const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
const {anyEtag, anyErrorId} = matchers;
const assert = require('assert');
// @TODO: factor out these requires
const ObjectId = require('bson-objectid');
const testUtils = require('../../utils');
const localUtils = require('./utils');
const config = require('../../../core/shared/config');
const models = require('../../../core/server/models/index');
describe('Email Preview API', function () {
let request;
let agent;
before(async function () {
await localUtils.startGhost();
request = supertest.agent(config.get('url'));
await localUtils.doAuth(request, 'users:extra', 'newsletters', 'posts');
agent = await agentProvider.getAdminAPIAgent();
await fixtureManager.init('users', 'newsletters', 'posts');
await agent.loginAsOwner();
});
describe('Read', function () {
it('can\'t retrieve for non existent post', async function () {
const res = await request.get(localUtils.API.getApiQuery(`email_previews/posts/${ObjectId().toHexString()}/`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.errors);
testUtils.API.checkResponseValue(jsonResponse.errors[0], [
'message',
'context',
'type',
'details',
'property',
'help',
'code',
'id',
'ghostErrorCode'
]);
await agent.get('email_previews/posts/abcd1234abcd1234abcd1234/')
.expectStatus(404)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
});
});
it('can read post email preview with fields', async function () {
const res = await request
.get(localUtils.API.getApiQuery(`email_previews/posts/${testUtils.DataGenerator.Content.posts[0].id}/`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.email_previews);
localUtils.API.checkResponse(jsonResponse.email_previews[0], 'email_previews', null, null);
await agent
.get(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot();
});
it('can read post email preview with email card and replacements', async function () {
@ -67,32 +49,19 @@ describe('Email Preview API', function () {
html: '<p>This is the actual post content...</p>',
plaintext: 'This is the actual post content...',
status: 'draft',
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904'
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904',
published_at: new Date(0)
});
await models.Post.add(post, {context: {internal: true}});
const res = await request
.get(localUtils.API.getApiQuery(`email_previews/posts/${post.id}/`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.email_previews);
jsonResponse.email_previews[0].html.should.match(/Hey there {unknown}/);
jsonResponse.email_previews[0].html.should.match(/Welcome to your first Ghost email!/);
jsonResponse.email_previews[0].html.should.match(/This is the actual post content\.\.\./);
jsonResponse.email_previews[0].html.should.match(/Another email card with a similar replacement, see\?/);
jsonResponse.email_previews[0].plaintext.should.match(/Hey there {unknown}/);
jsonResponse.email_previews[0].plaintext.should.match(/Welcome to your first Ghost email!/);
jsonResponse.email_previews[0].plaintext.should.match(/This is the actual post content\.\.\./);
jsonResponse.email_previews[0].plaintext.should.match(/Another email card with a similar replacement, see\?/);
await agent
.get(`email_previews/posts/${post.id}/`)
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot();
});
it('has custom content transformations for email compatibility', async function () {
@ -104,35 +73,30 @@ describe('Email Preview API', function () {
html: '<p>This is the actual post content...</p>',
plaintext: 'This is the actual post content...',
status: 'draft',
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904'
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904',
published_at: new Date(0)
});
await models.Post.add(post, {context: {internal: true}});
const res = await request
.get(localUtils.API.getApiQuery(`email_previews/posts/${post.id}/`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.email_previews);
const [preview] = jsonResponse.email_previews;
preview.html.should.containEql('Testing links in email excerpt');
preview.html.should.match(/&#39;/);
preview.html.should.not.match(/&apos;/);
await agent
.get(`email_previews/posts/${post.id}/`)
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot()
.expect(({body}) => {
// Extra assert to ensure apostrophe is transformed
assert.doesNotMatch(body.email_previews[0].html, /Testing links in email excerpt and apostrophes &apos;/);
assert.match(body.email_previews[0].html, /Testing links in email excerpt and apostrophes &#39;/);
});
});
it('uses the posts newsletter', async function () {
it('uses the posts newsletter by default', async function () {
const defaultNewsletter = await models.Newsletter.getDefaultNewsletter();
defaultNewsletter.id.should.not.eql(testUtils.DataGenerator.Content.newsletters[0].id, 'Should use a non-default newsletter for this test');
const selectedNewsletter = fixtureManager.get('newsletters', 0);
defaultNewsletter.id.should.not.eql(selectedNewsletter.id, 'Should use a non-default newsletter for this test');
const post = testUtils.DataGenerator.forKnex.createPost({
id: ObjectId().toHexString(),
@ -143,31 +107,29 @@ describe('Email Preview API', function () {
plaintext: 'This is the actual post content...',
status: 'scheduled',
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904',
newsletter_id: testUtils.DataGenerator.Content.newsletters[0].id
newsletter_id: selectedNewsletter.id,
published_at: new Date(0)
});
await models.Post.add(post, {context: {internal: true}});
const res = await request
.get(localUtils.API.getApiQuery(`email_previews/posts/${post.id}/`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.email_previews);
const [preview] = jsonResponse.email_previews;
preview.html.should.containEql(testUtils.DataGenerator.Content.newsletters[0].name);
await agent
.get(`email_previews/posts/${post.id}/`)
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot()
.expect(({body}) => {
// Extra assert to ensure newsletter is correct
assert.doesNotMatch(body.email_previews[0].html, new RegExp(defaultNewsletter.get('name')));
assert.match(body.email_previews[0].html, new RegExp(selectedNewsletter.name));
});
});
it('uses the newsletter provided through ?newsletter=slug', async function () {
const defaultNewsletter = await models.Newsletter.getDefaultNewsletter();
const selectedNewsletter = testUtils.DataGenerator.Content.newsletters[0];
const selectedNewsletter = fixtureManager.get('newsletters', 0);
selectedNewsletter.id.should.not.eql(defaultNewsletter.id, 'Should use a non-default newsletter for this test');
@ -179,129 +141,122 @@ describe('Email Preview API', function () {
html: '<p>This is the actual post content...</p>',
plaintext: 'This is the actual post content...',
status: 'draft',
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904'
uuid: 'd52c42ae-2755-455c-80ec-70b2ec55c904',
published_at: new Date(0)
});
await models.Post.add(post, {context: {internal: true}});
const res = await request
.get(localUtils.API.getApiQuery(`email_previews/posts/${post.id}/?newsletter=${selectedNewsletter.slug}`))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.email_previews);
const [preview] = jsonResponse.email_previews;
preview.html.should.containEql(testUtils.DataGenerator.Content.newsletters[0].name);
await agent
.get(`email_previews/posts/${post.id}/?newsletter=${selectedNewsletter.slug}`)
.expectStatus(200)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot()
.expect(({body}) => {
// Extra assert to ensure newsletter is correct
assert.doesNotMatch(body.email_previews[0].html, new RegExp(defaultNewsletter.get('name')));
assert.match(body.email_previews[0].html, new RegExp(selectedNewsletter.name));
});
});
});
describe('As Owner', function () {
it('can send test email', async function () {
const url = localUtils.API.getApiQuery(`email_previews/posts/${testUtils.DataGenerator.Content.posts[0].id}/`);
await request
.post(url)
.set('Origin', config.get('url'))
.send({
await agent
.post(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.body({
emails: ['test@ghost.org']
})
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(204)
.expect((res) => {
res.body.should.be.empty();
});
.expectStatus(204)
.matchHeaderSnapshot({
etag: anyEtag
})
.expectEmptyBody();
});
});
describe('As Admin', function () {
before(async function () {
const user = await testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'admin+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[0].name
});
request.user = user;
await localUtils.doAuth(request);
await agent.loginAsAdmin();
});
it('can send test email', async function () {
const url = localUtils.API.getApiQuery(`email_previews/posts/${testUtils.DataGenerator.Content.posts[0].id}/`);
await request
.post(url)
.set('Origin', config.get('url'))
.send({
await agent
.post(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.body({
emails: ['test@ghost.org']
})
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(204)
.expect((res) => {
res.body.should.be.empty();
});
.expectStatus(204)
.matchHeaderSnapshot({
etag: anyEtag
})
.expectEmptyBody();
});
});
describe('As Editor', function () {
before(async function () {
const user = await testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({
email: 'test+editor@ghost.org'
}),
role: testUtils.DataGenerator.Content.roles[1].name
});
request.user = user;
await localUtils.doAuth(request);
await agent.loginAsEditor();
});
it('can send test email', async function () {
const url = localUtils.API.getApiQuery(`email_previews/posts/${testUtils.DataGenerator.Content.posts[0].id}/`);
await request
.post(url)
.set('Origin', config.get('url'))
.send({
await agent
.post(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.body({
emails: ['test@ghost.org']
})
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(204)
.expect((res) => {
res.body.should.be.empty();
});
.expectStatus(204)
.matchHeaderSnapshot({
etag: anyEtag
})
.expectEmptyBody();
});
});
describe('As Author', function () {
before(async function () {
const user = await testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({
email: 'test+author@ghost.org'
}),
role: testUtils.DataGenerator.Content.roles[2].name
});
request.user = user;
await localUtils.doAuth(request);
await agent.loginAsAuthor();
});
it('cannot send test email', async function () {
const url = localUtils.API.getApiQuery(`email_previews/posts/${testUtils.DataGenerator.Content.posts[0].id}/`);
await request
.post(url)
.set('Origin', config.get('url'))
.send({
await agent
.post(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.body({
emails: ['test@ghost.org']
})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403)
.expect((res) => {
res.body.should.be.an.Object().with.property('errors');
.expectStatus(403)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
});
});
});
describe('As Contributor', function () {
before(async function () {
await agent.loginAsContributor();
});
it('cannot send test email', async function () {
await agent
.post(`email_previews/posts/${fixtureManager.get('posts', 0).id}/`)
.body({
emails: ['test@ghost.org']
})
.expectStatus(403)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
});
});
});

View file

@ -2,9 +2,17 @@ const TestAgent = require('./test-agent');
const errors = require('@tryghost/errors');
const DataGenerator = require('../fixtures/data-generator');
const ownerUser = {
email: DataGenerator.Content.users[0].email,
password: DataGenerator.Content.users[0].password
const roleMap = {
owner: 0,
admin: 1,
editor: 2,
author: 3,
contributor: 7
};
const getRoleUserFromFixtures = (role) => {
const {email, password} = DataGenerator.Content.users[roleMap[role]];
return {email, password};
};
/**
@ -19,7 +27,13 @@ class AdminAPITestAgent extends TestAgent {
super(app, options);
}
async loginAs(email, password) {
async loginAs(email, password, role) {
if (role) {
let user = getRoleUserFromFixtures(role);
email = user.email;
password = user.password;
}
const res = await this.post('/session/')
.body({
grant_type: 'password',
@ -32,6 +46,10 @@ class AdminAPITestAgent extends TestAgent {
throw new errors.IncorrectUsageError({
message: 'Ghost is redirecting, do you have an instance already running on port 2369?'
});
} else if (res.statusCode === 404 && role) {
throw new errors.IncorrectUsageError({
message: `Unable to login as ${role} - user not found. Did you pass 'users' to fixtureManager.init() ?`
});
} else if (res.statusCode !== 200 && res.statusCode !== 201) {
throw new errors.IncorrectUsageError({
message: res.body.errors[0].message
@ -42,7 +60,23 @@ class AdminAPITestAgent extends TestAgent {
}
async loginAsOwner() {
await this.loginAs(ownerUser.email, ownerUser.password);
await this.loginAs(null, null, 'owner');
}
async loginAsAdmin() {
await this.loginAs(null, null, 'admin');
}
async loginAsEditor() {
await this.loginAs(null, null, 'editor');
}
async loginAsAuthor() {
await this.loginAs(null, null, 'author');
}
async loginAsContributor() {
await this.loginAs(null, null, 'contributor');
}
}