2023-02-13 17:29:01 +03:00
|
|
|
const {agentProvider, fixtureManager, mockManager, configUtils} = require('../../utils/e2e-framework');
|
|
|
|
const assert = require('assert');
|
|
|
|
const nock = require('nock');
|
|
|
|
const sinon = require('sinon');
|
|
|
|
const models = require('../../../core/server/models');
|
|
|
|
const moment = require('moment');
|
|
|
|
|
2023-02-15 09:43:40 +03:00
|
|
|
const milestoneEmailsService = require('../../../core/server/services/milestone-emails');
|
2023-02-13 17:29:01 +03:00
|
|
|
|
|
|
|
let agent;
|
|
|
|
let counter = 0;
|
|
|
|
let membersCounter = 0;
|
|
|
|
|
|
|
|
async function createMemberWithSubscription(interval, amount, currency, date) {
|
|
|
|
counter += 1;
|
|
|
|
membersCounter += 1;
|
|
|
|
|
|
|
|
const fakePrice = {
|
|
|
|
id: 'price_' + counter,
|
|
|
|
product: '',
|
|
|
|
active: true,
|
|
|
|
nickname: 'Paid',
|
|
|
|
unit_amount: amount,
|
|
|
|
currency,
|
|
|
|
type: 'recurring',
|
|
|
|
recurring: {
|
|
|
|
interval
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const fakeSubscription = {
|
|
|
|
id: 'sub_' + counter,
|
|
|
|
customer: 'cus_' + counter,
|
|
|
|
status: 'active',
|
|
|
|
cancel_at_period_end: 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, body) => {
|
|
|
|
const [match, resource, id] = uri.match(/\/?v1\/(\w+)\/?(\w+)/) || [null];
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
return [500];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resource === 'customers') {
|
|
|
|
return [200, fakeCustomer];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resource === 'subscriptions') {
|
|
|
|
return [200, fakeSubscription];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const initialMember = {
|
|
|
|
name: fakeCustomer.name,
|
|
|
|
email: fakeCustomer.email,
|
|
|
|
subscribed: true,
|
|
|
|
stripe_customer_id: fakeCustomer.id
|
|
|
|
};
|
|
|
|
|
|
|
|
await agent
|
|
|
|
.post(`/members/`)
|
|
|
|
.body({members: [initialMember]})
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
nock.cleanAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
async function createFreeMembers(amount, amountImported = 0) {
|
|
|
|
const members = [];
|
|
|
|
|
|
|
|
const newsletters = await agent.get(`/newsletters/`);
|
|
|
|
const newsletter = newsletters.body?.newsletters?.[0];
|
|
|
|
|
|
|
|
for (let index = 0; index < amount; index++) {
|
|
|
|
let membersAddRequest;
|
|
|
|
membersCounter += 1;
|
|
|
|
|
|
|
|
const member = {
|
|
|
|
name: 'Test Member',
|
|
|
|
email: 'free-member-' + membersCounter + '@email.com',
|
|
|
|
status: 'free',
|
|
|
|
uuid: `f6f91461-d7d8-4a3f-aa5d-8e582c40b99${membersCounter}`
|
|
|
|
};
|
|
|
|
|
|
|
|
if (amountImported > 0) {
|
|
|
|
member.subscribed = true;
|
|
|
|
member.newsletters = [newsletter];
|
|
|
|
|
|
|
|
const createMemberEvent = await agent
|
|
|
|
.post(`/members/`)
|
|
|
|
.body({members: [member]})
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
const id = createMemberEvent.body.members[0].id;
|
|
|
|
|
|
|
|
// Manually add the members_subscribe_event so we can test imported members
|
|
|
|
const editedEvent = await models.MemberSubscribeEvent.add({
|
|
|
|
newsletter_id: newsletter.id,
|
|
|
|
member_id: id,
|
|
|
|
subscribed: true,
|
|
|
|
source: index < amountImported ? 'import' : 'member'
|
|
|
|
});
|
|
|
|
|
|
|
|
membersAddRequest = Promise.all([createMemberEvent, editedEvent]);
|
|
|
|
} else {
|
|
|
|
membersAddRequest = await agent
|
|
|
|
.post(`/members/`)
|
|
|
|
.body({members: [member]})
|
|
|
|
.expectStatus(201);
|
|
|
|
}
|
|
|
|
|
|
|
|
members.push(membersAddRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
await Promise.all(members);
|
|
|
|
}
|
|
|
|
|
|
|
|
describe('Milestone Emails Service', function () {
|
|
|
|
const milestonesConfig = {
|
2023-02-15 09:43:40 +03:00
|
|
|
arr: [{currency: 'usd', values: [100, 150]}],
|
|
|
|
members: [10, 20, 30]
|
2023-02-13 17:29:01 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
before(async function () {
|
|
|
|
agent = await agentProvider.getAdminAPIAgent();
|
|
|
|
await fixtureManager.init('newsletters');
|
|
|
|
await agent.loginAsOwner();
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(async function () {
|
|
|
|
sinon.createSandbox();
|
|
|
|
// TODO: stub out stripe mode
|
|
|
|
// stripeModeStub = sinon.stub().returns(true);
|
|
|
|
// milestoneEmailsService.__set__('getStripeLiveEnabled', stripeModeStub);
|
|
|
|
configUtils.set('milestones', milestonesConfig);
|
|
|
|
mockManager.mockLabsEnabled('milestoneEmails');
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(async function () {
|
|
|
|
await configUtils.restore();
|
|
|
|
mockManager.restore();
|
|
|
|
sinon.restore();
|
|
|
|
});
|
|
|
|
|
2023-02-15 09:43:40 +03:00
|
|
|
it('Inits milestone service', async function () {
|
|
|
|
await milestoneEmailsService.init();
|
|
|
|
|
|
|
|
assert.ok(milestoneEmailsService.api);
|
|
|
|
});
|
|
|
|
|
2023-02-13 17:29:01 +03:00
|
|
|
it('Runs ARR and Members milestone jobs', async function () {
|
2023-02-15 09:43:40 +03:00
|
|
|
mockManager.mockSetting('stripe_connect_publishable_key', 'pk_live_89843uihsidfh98832uo8ri');
|
|
|
|
|
2023-02-13 17:29:01 +03:00
|
|
|
// No ARR and no members
|
|
|
|
const firstRun = await milestoneEmailsService.initAndRun();
|
|
|
|
assert(firstRun.members === undefined);
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(firstRun.arr === undefined);
|
2023-02-13 17:29:01 +03:00
|
|
|
|
|
|
|
await createFreeMembers(7);
|
|
|
|
await createMemberWithSubscription('year', 5000, 'usd', '2000-01-10');
|
|
|
|
await createMemberWithSubscription('month', 100, 'usd', '2000-01-10');
|
|
|
|
const secondRun = await milestoneEmailsService.initAndRun();
|
|
|
|
assert(secondRun.members === undefined);
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(secondRun.arr === undefined);
|
2023-02-13 17:29:01 +03:00
|
|
|
|
|
|
|
// Reached the first milestone for members
|
|
|
|
await createFreeMembers(1);
|
|
|
|
const thirdRun = await milestoneEmailsService.initAndRun();
|
|
|
|
assert(thirdRun.members.value === 10);
|
|
|
|
assert(thirdRun.members.emailSentAt !== undefined);
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(thirdRun.arr === undefined);
|
2023-02-13 17:29:01 +03:00
|
|
|
|
|
|
|
// Reached the first milestone for ARR
|
2023-02-15 09:43:40 +03:00
|
|
|
// but has already reached members milestone, so no new one
|
|
|
|
// will be created
|
2023-02-13 17:29:01 +03:00
|
|
|
await createMemberWithSubscription('month', 500, 'usd', '2000-01-10');
|
|
|
|
await createMemberWithSubscription('month', 500, 'eur', '2000-01-10');
|
|
|
|
const fourthRun = await milestoneEmailsService.initAndRun();
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(fourthRun.members === undefined);
|
|
|
|
assert(fourthRun.arr.value === 100);
|
|
|
|
assert(fourthRun.arr.emailSentAt !== undefined);
|
2023-02-13 17:29:01 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('Does not send emails for milestones when imported members present', async function () {
|
2023-02-15 09:43:40 +03:00
|
|
|
mockManager.mockSetting('stripe_publishable_key', 'pk_live_89843uihsidfh98832uo8ri');
|
|
|
|
mockManager.mockSetting('stripe_connect_publishable_key', 'pk_test_89843uihsidfh98832uo8ri');
|
|
|
|
|
2023-02-13 17:29:01 +03:00
|
|
|
await createFreeMembers(10, 1);
|
|
|
|
await createMemberWithSubscription('month', 1000, 'usd', '2023-01-10');
|
|
|
|
const result = await milestoneEmailsService.initAndRun();
|
|
|
|
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(result.members.value === 20);
|
2023-02-13 17:29:01 +03:00
|
|
|
assert(result.members.emailSentAt === null);
|
2023-02-15 09:43:40 +03:00
|
|
|
assert(result.arr.value === 150);
|
|
|
|
assert(result.arr.emailSentAt === null);
|
2023-02-13 17:29:01 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('Does not run when milestoneEmails labs flag is not set', async function () {
|
|
|
|
mockManager.mockLabsDisabled('milestoneEmails');
|
|
|
|
|
|
|
|
const result = await milestoneEmailsService.initAndRun();
|
|
|
|
assert(result === undefined);
|
|
|
|
});
|
|
|
|
|
2023-02-15 09:43:40 +03:00
|
|
|
it('Does not run ARR milestones when Stripe is not live enabled', async function () {
|
|
|
|
mockManager.mockSetting('stripe_publishable_key', 'pk_test_89843uihsidfh98832uo8ri');
|
|
|
|
mockManager.mockSetting('stripe_connect_publishable_key', 'pk_test_89843uihsidfh98832uo8ri');
|
|
|
|
await createFreeMembers(10);
|
2023-02-13 17:29:01 +03:00
|
|
|
|
2023-02-15 09:43:40 +03:00
|
|
|
const result = await milestoneEmailsService.initAndRun();
|
|
|
|
assert(result.members.value === 30);
|
|
|
|
assert(result.members.emailSentAt !== undefined);
|
|
|
|
assert(result.arr === undefined);
|
|
|
|
});
|
2023-02-13 17:29:01 +03:00
|
|
|
});
|