Ghost/ghost/core/test/e2e-api/members/send-magic-link.test.js
Simon Backx 913ad18b71
Added DomainEvents.allSettled utility method (#16075)
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.
2023-01-04 14:30:35 +01:00

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'
}
});
});
});