913ad18b71
no issue With the increased usage of DomainEvents, it gets harder to build reliable tests without having to resort to timeouts. This utility method allows us to wait for all events to be processed before continuing with the test. This change should speed up tests and make them more reliable. It only adds extra code when running tests and shouldn't impact production.
254 lines
8.5 KiB
JavaScript
254 lines
8.5 KiB
JavaScript
const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework');
|
|
const should = require('should');
|
|
const settingsCache = require('../../../core/shared/settings-cache');
|
|
const DomainEvents = require('@tryghost/domain-events');
|
|
const {anyErrorId} = matchers;
|
|
|
|
let membersAgent, membersService;
|
|
|
|
describe('sendMagicLink', function () {
|
|
before(async function () {
|
|
const agents = await agentProvider.getAgentsForMembers();
|
|
membersAgent = agents.membersAgent;
|
|
|
|
membersService = require('../../../core/server/services/members');
|
|
|
|
await fixtureManager.init('members');
|
|
});
|
|
|
|
beforeEach(function () {
|
|
mockManager.mockMail();
|
|
|
|
// Reset settings
|
|
settingsCache.set('members_signup_access', {value: 'all'});
|
|
});
|
|
|
|
afterEach(function () {
|
|
mockManager.restore();
|
|
});
|
|
|
|
it('Errors when passed multiple emails', async function () {
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email: 'one@test.com,two@test.com',
|
|
emailType: 'signup'
|
|
})
|
|
.expectStatus(400);
|
|
});
|
|
|
|
it('Throws an error when logging in to a email that does not exist', async function () {
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signin'
|
|
})
|
|
.expectStatus(400)
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId,
|
|
// Add this here because it is easy to be overlooked (we need a human readable error!)
|
|
// 'Please sign up first' should be included only when invite only is disabled.
|
|
message: 'No member exists with this e-mail address. Please sign up first.'
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Throws an error when logging in to a email that does not exist (invite only)', async function () {
|
|
settingsCache.set('members_signup_access', {value: 'invite'});
|
|
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signin'
|
|
})
|
|
.expectStatus(400)
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId,
|
|
// Add this here because it is easy to be overlooked (we need a human readable error!)
|
|
// 'Please sign up first' should NOT be included
|
|
message: 'No member exists with this e-mail address.'
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Throws an error when trying to sign up on an invite only site', async function () {
|
|
settingsCache.set('members_signup_access', {value: 'invite'});
|
|
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signup'
|
|
})
|
|
.expectStatus(400)
|
|
.matchBodySnapshot({
|
|
errors: [{
|
|
id: anyErrorId
|
|
}]
|
|
});
|
|
});
|
|
|
|
it('Creates a valid magic link with tokenData, and without urlHistory', async function () {
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signup'
|
|
})
|
|
.expectEmptyBody()
|
|
.expectStatus(201);
|
|
|
|
// Check email is sent
|
|
const mail = mockManager.assert.sentEmail({
|
|
to: email,
|
|
subject: /Complete your sign up to Ghost!/
|
|
});
|
|
|
|
// Get link from email
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
const parsed = new URL(url);
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
// Get data
|
|
const data = await membersService.api.getTokenDataFromMagicLinkToken(token);
|
|
|
|
should(data).match({
|
|
email,
|
|
attribution: {
|
|
id: null,
|
|
url: null,
|
|
type: null
|
|
}
|
|
});
|
|
});
|
|
|
|
it('Creates a valid magic link from custom signup with redirection', async function () {
|
|
const customSignupUrl = 'http://localhost:2368/custom-signup-form-page';
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
await membersAgent
|
|
.post('/api/send-magic-link')
|
|
.header('Referer', customSignupUrl)
|
|
.body({
|
|
email,
|
|
emailType: 'signup',
|
|
autoRedirect: true
|
|
})
|
|
.expectEmptyBody()
|
|
.expectStatus(201);
|
|
|
|
const mail = await mockManager.assert.sentEmail({
|
|
to: email,
|
|
subject: /Complete your sign up to Ghost!/
|
|
});
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
const parsed = new URL(url);
|
|
const redirect = parsed.searchParams.get('r');
|
|
should(redirect).equal(customSignupUrl);
|
|
});
|
|
|
|
it('Creates a valid magic link from custom signup with redirection disabled', async function () {
|
|
const customSignupUrl = 'http://localhost:2368/custom-signup-form-page';
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
await membersAgent
|
|
.post('/api/send-magic-link')
|
|
.header('Referer', customSignupUrl)
|
|
.body({
|
|
email,
|
|
emailType: 'signup',
|
|
autoRedirect: false
|
|
})
|
|
.expectEmptyBody()
|
|
.expectStatus(201);
|
|
|
|
const mail = await mockManager.assert.sentEmail({
|
|
to: email,
|
|
subject: /Complete your sign up to Ghost!/
|
|
});
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
const parsed = new URL(url);
|
|
const redirect = parsed.searchParams.get('r');
|
|
should(redirect).equal(null);
|
|
});
|
|
|
|
it('triggers email alert for free member signup', async function () {
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signup'
|
|
})
|
|
.expectEmptyBody()
|
|
.expectStatus(201);
|
|
|
|
// Check email is sent
|
|
const mail = mockManager.assert.sentEmail({
|
|
to: email,
|
|
subject: /Complete your sign up to Ghost!/
|
|
});
|
|
|
|
// Get link from email
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
const parsed = new URL(url);
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
// Get member data from token
|
|
const data = await membersService.api.getMemberDataFromMagicLinkToken(token);
|
|
|
|
// Wait for the dispatched events (because this happens async)
|
|
await DomainEvents.allSettled();
|
|
// Check member alert is sent to site owners
|
|
mockManager.assert.sentEmail({
|
|
to: 'jbloggs@example.com',
|
|
subject: /🥳 Free member signup: newly-created-user-magic-link-test@test.com/
|
|
});
|
|
|
|
// Check member data is returned
|
|
should(data).match({
|
|
email
|
|
});
|
|
});
|
|
|
|
it('Converts the urlHistory to the attribution and stores it in the token', async function () {
|
|
const email = 'newly-created-user-magic-link-test-2@test.com';
|
|
await membersAgent.post('/api/send-magic-link')
|
|
.body({
|
|
email,
|
|
emailType: 'signup',
|
|
urlHistory: [
|
|
{
|
|
path: '/test-path',
|
|
time: Date.now()
|
|
}
|
|
]
|
|
})
|
|
.expectEmptyBody()
|
|
.expectStatus(201);
|
|
|
|
// Check email is sent
|
|
const mail = mockManager.assert.sentEmail({
|
|
to: email,
|
|
subject: /Complete your sign up to Ghost!/
|
|
});
|
|
|
|
// Get link from email
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
const parsed = new URL(url);
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
// Get data
|
|
const data = await membersService.api.getTokenDataFromMagicLinkToken(token);
|
|
|
|
should(data).match({
|
|
email,
|
|
attribution: {
|
|
id: null,
|
|
url: '/test-path',
|
|
type: 'url'
|
|
}
|
|
});
|
|
});
|
|
});
|