0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Added awaiting jobs and events by default to all tests (#16505)

no issue

This change waits for domain events and jobs before continuing with the
next test. This prevents issues where background tasks in tests are
executed when the next test is running and the configurations have
changed, causing random error logs and test failures.

It also includes a change in Stripe mocking in one E2E test to make use
of the new StripeMocker instead of custom mocking in each test (also to
reduce error logs).
This commit is contained in:
Simon Backx 2023-04-06 09:05:16 +02:00 committed by GitHub
parent 16c625a630
commit ba8f082d41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 101 deletions

View file

@ -1,71 +1,26 @@
const statsService = require('../../../../core/server/services/stats'); const statsService = require('../../../../core/server/services/stats');
const {agentProvider, fixtureManager, mockManager} = require('../../../utils/e2e-framework'); const {agentProvider, fixtureManager, mockManager} = require('../../../utils/e2e-framework');
const moment = require('moment');
require('should'); require('should');
const nock = require('nock'); const {stripeMocker} = require('../../../utils/e2e-framework-mock-manager');
const moment = require('moment');
let agent; let agent;
let counter = 0;
async function createMemberWithSubscription(interval, amount, currency, date) { async function createMemberWithSubscription(interval, amount, currency, date) {
counter += 1; const tier = await stripeMocker.createTier({
const fakePrice = {
id: 'price_' + counter,
product: '',
active: true,
nickname: 'Paid',
unit_amount: amount,
currency, currency,
type: 'recurring', monthly_price: amount,
recurring: { yearly_price: amount
interval });
} const price = await stripeMocker.getPriceForTier(tier.get('slug'), interval);
}; const fakeCustomer = stripeMocker.createCustomer({});
await stripeMocker.createSubscription({
const fakeSubscription = { customer: fakeCustomer,
id: 'sub_' + counter, price,
customer: 'cus_' + counter, start_date: moment(date).unix()
status: 'active', }, {
cancel_at_period_end: false, sendWebhook: false
metadata: {}, });
current_period_end: Date.now() / 1000 + 1000,
start_date: moment(date).unix(),
plan: fakePrice,
items: {
data: [{
price: fakePrice
}]
}
};
const fakeCustomer = {
id: 'cus_' + counter,
name: 'Test Member',
email: 'create-member-subscription-' + counter + '@email.com',
subscriptions: {
type: 'list',
data: [fakeSubscription]
}
};
nock('https://api.stripe.com')
.persist()
.get(/v1\/.*/)
.reply((uri) => {
const [match, resource] = uri.match(/\/?v1\/(\w+)\/?(\w+)/) || [null];
if (!match) {
return [500];
}
if (resource === 'customers') {
return [200, fakeCustomer];
}
if (resource === 'subscriptions') {
return [200, fakeSubscription];
}
});
const initialMember = { const initialMember = {
name: fakeCustomer.name, name: fakeCustomer.name,
@ -78,8 +33,6 @@ async function createMemberWithSubscription(interval, amount, currency, date) {
.post(`/members/`) .post(`/members/`)
.body({members: [initialMember]}) .body({members: [initialMember]})
.expectStatus(201); .expectStatus(201);
nock.cleanAll();
} }
describe('MRR Stats Service', function () { describe('MRR Stats Service', function () {
@ -87,15 +40,15 @@ describe('MRR Stats Service', function () {
agent = await agentProvider.getAdminAPIAgent(); agent = await agentProvider.getAdminAPIAgent();
await fixtureManager.init(); await fixtureManager.init();
await agent.loginAsOwner(); await agent.loginAsOwner();
mockManager.mockMail();
}); });
after(async function () { beforeEach(function () {
mockManager.restore(); mockManager.mockMail();
mockManager.mockStripe();
}); });
afterEach(function () { afterEach(function () {
nock.cleanAll(); mockManager.restore();
}); });
describe('getCurrentMrr', function () { describe('getCurrentMrr', function () {
@ -103,7 +56,7 @@ describe('MRR Stats Service', function () {
const result = await statsService.mrr.getCurrentMrr(); const result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'usd', currency: 'usd', // need to check capital usage here!
mrr: 0 mrr: 0
} }
]); ]);
@ -114,7 +67,7 @@ describe('MRR Stats Service', function () {
const result = await statsService.mrr.getCurrentMrr(); const result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
} }
]); ]);
@ -125,11 +78,11 @@ describe('MRR Stats Service', function () {
const result = await statsService.mrr.getCurrentMrr(); const result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 1 mrr: 1
} }
]); ]);
@ -140,11 +93,11 @@ describe('MRR Stats Service', function () {
const result = await statsService.mrr.getCurrentMrr(); const result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 2 mrr: 2
} }
]); ]);
@ -155,11 +108,11 @@ describe('MRR Stats Service', function () {
let result = await statsService.mrr.getCurrentMrr(); let result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 3 mrr: 3
} }
]); ]);
@ -169,11 +122,11 @@ describe('MRR Stats Service', function () {
result = await statsService.mrr.getCurrentMrr(); result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 3 mrr: 3
} }
]); ]);
@ -183,11 +136,11 @@ describe('MRR Stats Service', function () {
result = await statsService.mrr.getCurrentMrr(); result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 3 mrr: 3
} }
]); ]);
@ -197,11 +150,11 @@ describe('MRR Stats Service', function () {
result = await statsService.mrr.getCurrentMrr(); result = await statsService.mrr.getCurrentMrr();
result.should.eql([ result.should.eql([
{ {
currency: 'eur', currency: 'EUR',
mrr: 500 mrr: 500
}, },
{ {
currency: 'usd', currency: 'USD',
mrr: 4 mrr: 4
} }
]); ]);
@ -216,22 +169,22 @@ describe('MRR Stats Service', function () {
{ {
date: '2000-01-10', date: '2000-01-10',
delta: 500, delta: 500,
currency: 'eur' currency: 'EUR'
}, },
{ {
date: '2000-01-10', date: '2000-01-10',
delta: 1, delta: 1,
currency: 'usd' currency: 'USD'
}, },
{ {
date: '2000-01-11', date: '2000-01-11',
delta: 1, delta: 1,
currency: 'usd' currency: 'USD'
}, },
{ {
date: '2000-01-12', date: '2000-01-12',
delta: 2, delta: 2,
currency: 'usd' currency: 'USD'
} }
]); ]);
}); });

View file

@ -17,3 +17,21 @@ mochaHooks.beforeAll = async function () {
// Disable network in tests to prevent any accidental requests // Disable network in tests to prevent any accidental requests
mockManager.disableNetwork(); mockManager.disableNetwork();
}; };
const originalAfterEach = mochaHooks.afterEach;
mochaHooks.afterEach = async function () {
const domainEvents = require('@tryghost/domain-events');
const mentionsJobsService = require('../../core/server/services/mentions-jobs');
const jobsService = require('../../core/server/services/jobs');
await domainEvents.allSettled();
await mentionsJobsService.allSettled();
await jobsService.allSettled();
// Last time for events emitted during jobs
await domainEvents.allSettled();
if (originalAfterEach) {
await originalAfterEach();
}
};

View file

@ -19,6 +19,8 @@ class StripeMocker {
prices = []; prices = [];
products = []; products = [];
nockInterceptors = [];
constructor(data = {}) { constructor(data = {}) {
this.customers = data.customers ?? []; this.customers = data.customers ?? [];
this.subscriptions = data.subscriptions ?? []; this.subscriptions = data.subscriptions ?? [];
@ -80,6 +82,25 @@ class StripeMocker {
return this.#getData(this.prices, id)[1]; return this.#getData(this.prices, id)[1];
} }
/**
*
* @param {object} data
* @param {string} [data.name]
* @param {string} data.currency
* @param {number} data.monthly_price
* @param {number} data.yearly_price
* @returns
*/
async createTier({name, currency, monthly_price, yearly_price}) {
return await models.Product.add({
name: name ?? ('Tier ' + this.#generateRandomId()),
type: 'paid',
currency: currency.toUpperCase(),
monthly_price,
yearly_price
});
}
async createTrialSubscription({customer, price, ...overrides}) { async createTrialSubscription({customer, price, ...overrides}) {
return await this.createSubscription({ return await this.createSubscription({
customer, customer,
@ -113,7 +134,7 @@ class StripeMocker {
await DomainEvents.allSettled(); await DomainEvents.allSettled();
} }
async createSubscription({customer, price, ...overrides}) { async createSubscription({customer, price, ...overrides}, options = {sendWebhook: true}) {
const subscriptionId = `sub_${this.#generateRandomId()}`; const subscriptionId = `sub_${this.#generateRandomId()}`;
const subscription = { const subscription = {
@ -140,18 +161,20 @@ class StripeMocker {
customer.subscriptions.data.push(subscription); customer.subscriptions.data.push(subscription);
// Announce // Announce
await this.sendWebhook({ if (options.sendWebhook) {
type: 'checkout.session.completed', await this.sendWebhook({
data: { type: 'checkout.session.completed',
object: { data: {
mode: 'subscription', object: {
customer: customer.id, mode: 'subscription',
metadata: { customer: customer.id,
checkoutType: 'signup' metadata: {
checkoutType: 'signup'
}
} }
} }
} });
}); }
return subscription; return subscription;
} }
@ -266,10 +289,21 @@ class StripeMocker {
return [200, subscription]; return [200, subscription];
} }
remove() {
for (const interceptor of this.nockInterceptors) {
nock.removeInterceptor(interceptor);
}
this.nockInterceptors = [];
}
stub() { stub() {
nock('https://api.stripe.com') this.remove();
let interceptor = nock('https://api.stripe.com')
.persist() .persist()
.get(/v1\/.*/) .get(/v1\/.*/);
this.nockInterceptors.push(interceptor);
interceptor
.reply((uri) => { .reply((uri) => {
const [match, resource, id] = uri.match(/\/?v1\/(\w+)\/?(\w+)/) || [null]; const [match, resource, id] = uri.match(/\/?v1\/(\w+)\/?(\w+)/) || [null];
@ -308,9 +342,11 @@ class StripeMocker {
return [500]; return [500];
}); });
nock('https://api.stripe.com') interceptor = nock('https://api.stripe.com')
.persist() .persist()
.post(/v1\/.*/) .post(/v1\/.*/);
this.nockInterceptors.push(interceptor);
interceptor
.reply((uri, body) => { .reply((uri, body) => {
const [match, resource, id] = uri.match(/\/?v1\/(\w+)(?:\/?(\w+)){0,2}/) || [null]; const [match, resource, id] = uri.match(/\/?v1\/(\w+)(?:\/?(\w+)){0,2}/) || [null];
@ -345,9 +381,11 @@ class StripeMocker {
return [500]; return [500];
}); });
nock('https://api.stripe.com') interceptor = nock('https://api.stripe.com')
.persist() .persist()
.delete(/v1\/.*/) .delete(/v1\/.*/);
this.nockInterceptors.push(interceptor);
interceptor
.reply((uri) => { .reply((uri) => {
const [match, resource, id] = uri.match(/\/?v1\/(\w+)(?:\/?(\w+)){0,2}/) || [null]; const [match, resource, id] = uri.match(/\/?v1\/(\w+)(?:\/?(\w+)){0,2}/) || [null];