Ghost/ghost/stats-service/test/lib/mrr.test.js

391 lines
12 KiB
JavaScript
Raw Normal View History

const MrrStatsService = require('../../lib/MrrStatsService');
const moment = require('moment');
const sinon = require('sinon');
const knex = require('knex').default;
require('should');
describe('MrrStatsService', function () {
describe('getHistory', function () {
/** @type {MrrStatsService} */
let mrrStatsService;
const today = '2000-01-10';
const tomorrow = '2000-01-11';
const yesterday = '2000-01-09';
const dayBeforeYesterday = '2000-01-08';
const twoDaysBeforeYesterday = '2000-01-07';
after(function () {
sinon.restore();
});
/** @type {import('knex').Knex} */
let db;
before(function () {
const todayDate = moment(today).toDate();
sinon.useFakeTimers(todayDate.getTime());
});
beforeEach(async function () {
db = knex({client: 'sqlite3', connection: {filename: ':memory:'}, useNullAsDefault: true});
mrrStatsService = new MrrStatsService({knex: db});
await db.schema.createTable('members_paid_subscription_events', function (table) {
table.string('currency');
table.string('mrr_delta');
table.date('created_at');
});
await db.schema.createTable('members_stripe_customers_subscriptions', function (table) {
table.string('plan_currency');
table.string('mrr');
});
});
afterEach(async function () {
await db.destroy();
});
it('Handles no data', async function () {
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(1);
// Note that currencies should always be sorted ascending, so EUR should be first.
results[0].should.eql({
date: today,
mrr: 0,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 0,
currency: 'usd'
}
]);
});
it('Always returns at least one value', async function () {
await db('members_stripe_customers_subscriptions').insert([{
plan_currency: 'usd',
mrr: 1
}, {
plan_currency: 'eur',
mrr: 2
}]);
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(2);
// Note that currencies should always be sorted ascending, so EUR should be first.
results[0].should.eql({
date: today,
mrr: 2,
currency: 'eur'
});
results[1].should.eql({
date: today,
mrr: 1,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 2,
currency: 'eur'
},
{
mrr: 1,
currency: 'usd'
}
]);
});
it('Does not substract delta of first event', async function () {
await db('members_stripe_customers_subscriptions').insert([{
plan_currency: 'usd',
mrr: 5
}]);
await db('members_paid_subscription_events').insert([{
created_at: today,
mrr_delta: 5,
currency: 'usd'
}]);
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(2);
results[0].should.eql({
date: yesterday,
mrr: 0,
currency: 'usd'
});
results[1].should.eql({
date: today,
mrr: 5,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 5,
currency: 'usd'
}
]);
});
it('Correctly calculates deltas', async function () {
await db('members_paid_subscription_events').insert([{
created_at: yesterday,
mrr_delta: 2,
currency: 'usd'
},
{
created_at: today,
mrr_delta: 5,
currency: 'usd'
}]);
await db('members_stripe_customers_subscriptions').insert([{
plan_currency: 'usd',
mrr: 2
}, {
plan_currency: 'usd',
mrr: 5
}]);
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(3);
results[0].should.eql({
date: dayBeforeYesterday,
mrr: 0,
currency: 'usd'
});
results[1].should.eql({
date: yesterday,
mrr: 2,
currency: 'usd'
});
results[2].should.eql({
date: today,
mrr: 7,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 7,
currency: 'usd'
}
]);
});
it('Correctly calculates deltas for multiple currencies', async function () {
await db('members_paid_subscription_events').insert([
{
created_at: yesterday,
mrr_delta: 200,
currency: 'eur'
},
{
created_at: yesterday,
mrr_delta: 2,
currency: 'usd'
},
{
created_at: today,
mrr_delta: 800,
currency: 'eur'
},
{
created_at: today,
mrr_delta: 5,
currency: 'usd'
}
]);
await db('members_stripe_customers_subscriptions').insert([{
plan_currency: 'eur',
mrr: 200
}, {
plan_currency: 'usd',
mrr: 2
}, {
plan_currency: 'eur',
mrr: 800
}, {
plan_currency: 'usd',
mrr: 5
}, {
plan_currency: 'eur',
mrr: 200
}]);
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(6);
results[0].should.eql({
date: dayBeforeYesterday,
mrr: 200,
currency: 'eur'
});
results[1].should.eql({
date: dayBeforeYesterday,
mrr: 0,
currency: 'usd'
});
results[2].should.eql({
date: yesterday,
mrr: 400,
currency: 'eur'
});
results[3].should.eql({
date: yesterday,
mrr: 2,
currency: 'usd'
});
results[4].should.eql({
date: today,
mrr: 1200,
currency: 'eur'
});
results[5].should.eql({
date: today,
mrr: 7,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 1200,
currency: 'eur'
},
{
mrr: 7,
currency: 'usd'
}
]);
});
it('Ignores invalid currencies in deltas', async function () {
await db('members_paid_subscription_events').insert({
created_at: today,
mrr_delta: 200,
currency: 'abc'
});
await db('members_stripe_customers_subscriptions').insert({
plan_currency: 'usd',
mrr: 7
});
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(1);
results[0].should.eql({
date: yesterday,
mrr: 7,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 7,
currency: 'usd'
}
]);
});
it('Ignores events in the future', async function () {
await db('members_paid_subscription_events').insert([
{
created_at: yesterday,
mrr_delta: 2,
currency: 'usd'
},
{
created_at: today,
mrr_delta: 5,
currency: 'usd'
},
{
created_at: tomorrow,
mrr_delta: 10,
currency: 'usd'
}
]);
await db('members_stripe_customers_subscriptions').insert({plan_currency: 'usd', mrr: 7});
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(3);
results[0].should.eql({
date: dayBeforeYesterday,
mrr: 0,
currency: 'usd'
});
results[1].should.eql({
date: yesterday,
mrr: 2,
currency: 'usd'
});
results[2].should.eql({
date: today,
mrr: 7,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 7,
currency: 'usd'
}
]);
});
it('Correctly handles negative total MRR', async function () {
await db('members_paid_subscription_events').insert([
{
created_at: dayBeforeYesterday,
mrr_delta: 2,
currency: 'usd'
},
{
created_at: yesterday,
mrr_delta: -1000,
currency: 'usd'
},
{
created_at: today,
mrr_delta: 1000,
currency: 'usd'
}
]);
await db('members_stripe_customers_subscriptions').insert({plan_currency: 'usd', mrr: 7});
const {data: results, meta} = await mrrStatsService.getHistory();
results.length.should.eql(4);
results[0].should.eql({
date: twoDaysBeforeYesterday,
mrr: 5,
currency: 'usd'
});
results[1].should.eql({
date: dayBeforeYesterday,
// We are mainly testing that this should not be 1000!
mrr: 7,
currency: 'usd'
});
results[2].should.eql({
date: yesterday,
// Should never be shown negative (in fact it is -993 here)
mrr: 0,
currency: 'usd'
});
results[3].should.eql({
date: today,
mrr: 7,
currency: 'usd'
});
meta.totals.should.eql([
{
mrr: 7,
currency: 'usd'
}
]);
});
});
});