2022-02-07 19:02:04 +03:00
|
|
|
const errors = require('@tryghost/errors');
|
2021-12-09 14:10:06 +03:00
|
|
|
const sinon = require('sinon');
|
2022-02-07 22:43:33 +03:00
|
|
|
const assert = require('assert');
|
2022-02-15 16:08:58 +03:00
|
|
|
const nock = require('nock');
|
2021-12-09 14:10:06 +03:00
|
|
|
|
2022-02-08 23:21:03 +03:00
|
|
|
// Helper services
|
|
|
|
const configUtils = require('./configUtils');
|
2022-05-30 10:03:27 +03:00
|
|
|
const WebhookMockReceiver = require('@tryghost/webhook-mock-receiver');
|
2023-01-13 14:45:58 +03:00
|
|
|
const EmailMockReceiver = require('@tryghost/email-mock-receiver');
|
2022-05-30 10:03:27 +03:00
|
|
|
const {snapshotManager} = require('@tryghost/express-test').snapshot;
|
2022-02-08 23:21:03 +03:00
|
|
|
|
2022-02-07 19:02:04 +03:00
|
|
|
let mocks = {};
|
2022-02-07 20:28:53 +03:00
|
|
|
let emailCount = 0;
|
2022-02-07 19:02:04 +03:00
|
|
|
|
2022-02-08 23:21:03 +03:00
|
|
|
// Mockable services
|
2021-12-09 14:10:06 +03:00
|
|
|
const mailService = require('../../core/server/services/mail/index');
|
2023-01-13 14:45:58 +03:00
|
|
|
const originalMailServiceSend = mailService.GhostMailer.prototype.send;
|
2022-02-08 23:21:03 +03:00
|
|
|
const labs = require('../../core/shared/labs');
|
2022-03-25 14:44:03 +03:00
|
|
|
const events = require('../../core/server/lib/common/events');
|
2022-12-01 15:43:49 +03:00
|
|
|
const settingsCache = require('../../core/shared/settings-cache');
|
2022-03-25 14:44:03 +03:00
|
|
|
|
2022-04-28 11:55:20 +03:00
|
|
|
let fakedLabsFlags = {};
|
|
|
|
const originalLabsIsSet = labs.isSet;
|
|
|
|
|
2022-03-25 14:44:03 +03:00
|
|
|
/**
|
|
|
|
* Stripe Mocks
|
|
|
|
*/
|
2021-12-09 14:10:06 +03:00
|
|
|
|
2022-03-10 13:55:22 +03:00
|
|
|
const disableStripe = async () => {
|
|
|
|
// This must be required _after_ startGhost has been called, because the models will
|
|
|
|
// not have been loaded otherwise. Consider moving the dependency injection of models
|
|
|
|
// into the init method of the Stripe service.
|
|
|
|
const stripeService = require('../../core/server/services/stripe');
|
|
|
|
await stripeService.disconnect();
|
|
|
|
};
|
|
|
|
|
2022-03-25 14:44:03 +03:00
|
|
|
const mockStripe = () => {
|
|
|
|
nock.disableNetConnect();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Email Mocks & Assertions
|
|
|
|
*/
|
|
|
|
|
2022-03-25 13:41:58 +03:00
|
|
|
/**
|
|
|
|
* @param {String|Object} response
|
|
|
|
*/
|
|
|
|
const mockMail = (response = 'Mail is disabled') => {
|
2023-01-13 14:45:58 +03:00
|
|
|
const mockMailReceiver = new EmailMockReceiver({
|
|
|
|
snapshotManager: snapshotManager,
|
|
|
|
sendResponse: response
|
|
|
|
});
|
|
|
|
|
|
|
|
mailService.GhostMailer.prototype.send = mockMailReceiver.send.bind(mockMailReceiver);
|
|
|
|
mocks.mail = sinon.spy(mailService.GhostMailer.prototype, 'send');
|
|
|
|
mocks.mockMailReceiver = mockMailReceiver;
|
2022-02-07 19:02:04 +03:00
|
|
|
|
2023-01-13 14:45:58 +03:00
|
|
|
return mockMailReceiver;
|
2022-02-07 19:02:04 +03:00
|
|
|
};
|
|
|
|
|
2022-05-26 06:11:41 +03:00
|
|
|
const mockWebhookRequests = () => {
|
2022-05-30 10:03:27 +03:00
|
|
|
mocks.webhookMockReceiver = new WebhookMockReceiver({snapshotManager});
|
2022-05-26 06:11:41 +03:00
|
|
|
|
|
|
|
return mocks.webhookMockReceiver;
|
|
|
|
};
|
|
|
|
|
2023-01-18 07:55:33 +03:00
|
|
|
/**
|
|
|
|
* @deprecated use emailMockReceiver.sentEmailCount(count) instead
|
|
|
|
* @param {Number} count number of emails sent
|
|
|
|
*/
|
2022-02-07 20:28:53 +03:00
|
|
|
const sentEmailCount = (count) => {
|
2022-02-07 19:02:04 +03:00
|
|
|
if (!mocks.mail) {
|
|
|
|
throw new errors.IncorrectUsageError({
|
|
|
|
message: 'Cannot assert on mail when mail has not been mocked'
|
|
|
|
});
|
|
|
|
}
|
2022-02-07 20:28:53 +03:00
|
|
|
|
2023-01-13 14:45:58 +03:00
|
|
|
mocks.mockMailReceiver.sentEmailCount(count);
|
2022-02-07 20:28:53 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
const sentEmail = (matchers) => {
|
|
|
|
if (!mocks.mail) {
|
|
|
|
throw new errors.IncorrectUsageError({
|
|
|
|
message: 'Cannot assert on mail when mail has not been mocked'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let spyCall = mocks.mail.getCall(emailCount);
|
|
|
|
|
2022-09-02 17:57:59 +03:00
|
|
|
assert.notEqual(spyCall, null, 'Expected at least ' + (emailCount + 1) + ' emails sent.');
|
|
|
|
|
2022-02-07 20:28:53 +03:00
|
|
|
// We increment here so that the messaging has an index of 1, whilst getting the call has an index of 0
|
|
|
|
emailCount += 1;
|
|
|
|
|
|
|
|
sinon.assert.called(mocks.mail);
|
|
|
|
|
|
|
|
Object.keys(matchers).forEach((key) => {
|
|
|
|
let value = matchers[key];
|
|
|
|
|
|
|
|
// We use assert, rather than sinon.assert.calledWith, as we end up with much better error messaging
|
|
|
|
assert.notEqual(spyCall.args[0][key], undefined, `Expected email to have property ${key}`);
|
2022-07-25 17:27:38 +03:00
|
|
|
|
|
|
|
if (value instanceof RegExp) {
|
|
|
|
assert.match(spyCall.args[0][key], value, `Expected Email ${emailCount} to have ${key} that matches ${value}, got ${spyCall.args[0][key]}`);
|
|
|
|
return;
|
|
|
|
}
|
2023-01-13 14:45:58 +03:00
|
|
|
|
2022-02-07 20:28:53 +03:00
|
|
|
assert.equal(spyCall.args[0][key], value, `Expected Email ${emailCount} to have ${key} of ${value}`);
|
|
|
|
});
|
2022-08-18 18:38:42 +03:00
|
|
|
|
|
|
|
return spyCall.args[0];
|
2021-12-09 14:10:06 +03:00
|
|
|
};
|
|
|
|
|
2022-03-25 14:44:03 +03:00
|
|
|
/**
|
|
|
|
* Events Mocks & Assertions
|
|
|
|
*/
|
|
|
|
|
|
|
|
const mockEvents = () => {
|
|
|
|
mocks.events = sinon.stub(events, 'emit');
|
|
|
|
};
|
|
|
|
|
|
|
|
const emittedEvent = (name) => {
|
|
|
|
sinon.assert.calledWith(mocks.events, name);
|
|
|
|
};
|
|
|
|
|
2022-12-01 15:43:49 +03:00
|
|
|
/**
|
|
|
|
* Settings Mocks
|
|
|
|
*/
|
|
|
|
|
|
|
|
let fakedSettings = {};
|
|
|
|
const originalSettingsGetter = settingsCache.get;
|
|
|
|
|
|
|
|
const fakeSettingsGetter = (setting) => {
|
|
|
|
if (fakedSettings.hasOwnProperty(setting)) {
|
|
|
|
return fakedSettings[setting];
|
|
|
|
}
|
|
|
|
|
|
|
|
return originalSettingsGetter(setting);
|
|
|
|
};
|
|
|
|
|
|
|
|
const mockSetting = (key, value) => {
|
|
|
|
if (!mocks.settings) {
|
|
|
|
mocks.settings = sinon.stub(settingsCache, 'get').callsFake(fakeSettingsGetter);
|
|
|
|
}
|
|
|
|
|
|
|
|
fakedSettings[key] = value;
|
|
|
|
};
|
|
|
|
|
2022-03-25 14:44:03 +03:00
|
|
|
/**
|
|
|
|
* Labs Mocks
|
|
|
|
*/
|
2022-04-28 11:55:20 +03:00
|
|
|
|
|
|
|
const fakeLabsIsSet = (flag) => {
|
|
|
|
if (fakedLabsFlags.hasOwnProperty(flag)) {
|
|
|
|
return fakedLabsFlags[flag];
|
|
|
|
}
|
|
|
|
|
|
|
|
return originalLabsIsSet(flag);
|
|
|
|
};
|
|
|
|
|
2022-03-25 14:44:03 +03:00
|
|
|
const mockLabsEnabled = (flag, alpha = true) => {
|
|
|
|
// We assume we should enable alpha experiments unless explicitly told not to!
|
|
|
|
if (!alpha) {
|
|
|
|
configUtils.set('enableDeveloperExperiments', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mocks.labs) {
|
2022-04-28 11:55:20 +03:00
|
|
|
mocks.labs = sinon.stub(labs, 'isSet').callsFake(fakeLabsIsSet);
|
2022-03-25 14:44:03 +03:00
|
|
|
}
|
|
|
|
|
2022-04-28 11:55:20 +03:00
|
|
|
fakedLabsFlags[flag] = true;
|
2022-03-25 14:44:03 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
const mockLabsDisabled = (flag, alpha = true) => {
|
|
|
|
// We assume we should enable alpha experiments unless explicitly told not to!
|
|
|
|
if (!alpha) {
|
|
|
|
configUtils.set('enableDeveloperExperiments', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mocks.labs) {
|
2022-04-28 11:55:20 +03:00
|
|
|
mocks.labs = sinon.stub(labs, 'isSet').callsFake(fakeLabsIsSet);
|
2022-03-25 14:44:03 +03:00
|
|
|
}
|
|
|
|
|
2022-04-28 11:55:20 +03:00
|
|
|
fakedLabsFlags[flag] = false;
|
2022-03-25 14:44:03 +03:00
|
|
|
};
|
|
|
|
|
2022-02-07 19:02:04 +03:00
|
|
|
const restore = () => {
|
2022-02-08 23:21:03 +03:00
|
|
|
configUtils.restore();
|
2022-02-07 19:02:04 +03:00
|
|
|
sinon.restore();
|
|
|
|
mocks = {};
|
2022-04-28 11:55:20 +03:00
|
|
|
fakedLabsFlags = {};
|
2022-12-01 15:43:49 +03:00
|
|
|
fakedSettings = {};
|
2022-02-07 20:28:53 +03:00
|
|
|
emailCount = 0;
|
2022-02-15 16:08:58 +03:00
|
|
|
nock.cleanAll();
|
|
|
|
nock.enableNetConnect();
|
2022-05-26 06:11:41 +03:00
|
|
|
|
|
|
|
if (mocks.webhookMockReceiver) {
|
|
|
|
mocks.webhookMockReceiver.reset();
|
|
|
|
}
|
2023-01-13 14:45:58 +03:00
|
|
|
|
|
|
|
mailService.GhostMailer.prototype.send = originalMailServiceSend;
|
2022-02-07 19:02:04 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = {
|
2022-03-25 14:44:03 +03:00
|
|
|
mockEvents,
|
2022-02-07 19:02:04 +03:00
|
|
|
mockMail,
|
2022-03-10 13:55:22 +03:00
|
|
|
disableStripe,
|
2022-02-15 16:08:58 +03:00
|
|
|
mockStripe,
|
2022-02-08 23:21:03 +03:00
|
|
|
mockLabsEnabled,
|
2022-02-10 15:03:47 +03:00
|
|
|
mockLabsDisabled,
|
2022-05-26 06:11:41 +03:00
|
|
|
mockWebhookRequests,
|
2022-12-01 15:43:49 +03:00
|
|
|
mockSetting,
|
2022-02-07 20:28:53 +03:00
|
|
|
restore,
|
|
|
|
assert: {
|
|
|
|
sentEmailCount,
|
2022-03-25 14:44:03 +03:00
|
|
|
sentEmail,
|
|
|
|
emittedEvent
|
2022-02-07 20:28:53 +03:00
|
|
|
}
|
2022-02-07 19:02:04 +03:00
|
|
|
};
|