overleaf/services/web/test/unit/src/Subscription/RecurlyEventHandlerTests.js
andrew rumble 032deaf05c Switch to mongodb-legacy
GitOrigin-RevId: 11e09528c153de6b7766d18c3c90d94962190371
2024-08-21 08:04:24 +00:00

383 lines
11 KiB
JavaScript

const SandboxedModule = require('sandboxed-module')
const { ObjectId } = require('mongodb-legacy')
const sinon = require('sinon')
const modulePath =
'../../../../app/src/Features/Subscription/RecurlyEventHandler'
describe('RecurlyEventHandler', function () {
beforeEach(function () {
this.userId = '123abc234bcd456cde567def'
this.planCode = 'collaborator-annual'
this.eventData = {
account: {
account_code: this.userId,
},
subscription: {
uuid: '8435ad98c1ce45da99b07f6a6a2e780f',
plan: {
plan_code: 'collaborator-annual',
},
quantity: 1,
state: 'active',
trial_started_at: new Date('2021-01-01 12:34:56'),
trial_ends_at: new Date('2021-01-08 12:34:56'),
current_period_started_at: new Date('2021-01-01 12:34:56'),
current_period_ends_at: new Date('2021-01-08 12:34:56'),
},
}
this.RecurlyEventHandler = SandboxedModule.require(modulePath, {
requires: {
'mongodb-legacy': { ObjectId },
'./SubscriptionEmailHandler': (this.SubscriptionEmailHandler = {
sendTrialOnboardingEmail: sinon.stub(),
}),
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
recordEventForUserInBackground: sinon.stub(),
setUserPropertyForUserInBackground: sinon.stub(),
}),
'../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
promises: {
getAssignmentForUser: sinon.stub().resolves({
variant: 'default',
}),
},
}),
},
})
})
it('with new_subscription_notification - free trial', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-started',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
subscriptionId: this.eventData.subscription.uuid,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('sends free trial onboarding email if user starting a trial', async function () {
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
sinon.assert.called(this.SubscriptionEmailHandler.sendTrialOnboardingEmail)
})
it('with new_subscription_notification - no free trial', function () {
this.eventData.subscription.current_period_started_at = new Date(
'2021-02-10 12:34:56'
)
this.eventData.subscription.current_period_ends_at = new Date(
'2021-02-17 12:34:56'
)
this.eventData.subscription.quantity = 3
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-started',
{
plan_code: this.planCode,
quantity: 3,
is_trial: false,
subscriptionId: this.eventData.subscription.uuid,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
false
)
})
it('with updated_subscription_notification', function () {
this.planCode = 'new-plan-code'
this.eventData.subscription.plan.plan_code = this.planCode
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'updated_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-updated',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
subscriptionId: this.eventData.subscription.uuid,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('with canceled_subscription_notification', async function () {
this.eventData.subscription.state = 'cancelled'
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'canceled_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-cancelled',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
subscriptionId: this.eventData.subscription.uuid,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'cancelled'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('with expired_subscription_notification', function () {
this.eventData.subscription.state = 'expired'
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'expired_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-expired',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
subscriptionId: this.eventData.subscription.uuid,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-state',
'expired'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserPropertyForUserInBackground,
this.userId,
'subscription-is-trial',
true
)
})
it('with renewed_subscription_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'renewed_subscription_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-renewed',
{
plan_code: this.planCode,
quantity: 1,
is_trial: true,
subscriptionId: this.eventData.subscription.uuid,
}
)
})
it('with reactivated_account_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'reactivated_account_notification',
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-reactivated',
{
plan_code: this.planCode,
quantity: 1,
subscriptionId: this.eventData.subscription.uuid,
}
)
})
it('with paid_charge_invoice_notification', function () {
const invoice = {
invoice_number: 1234,
currency: 'USD',
state: 'paid',
total_in_cents: 720,
tax_in_cents: 12,
address: {
country: 'Liurnia',
},
collection_method: 'automatic',
subscription_ids: ['abcd1234', 'defa3214'],
}
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'paid_charge_invoice_notification',
{
account: {
account_code: this.userId,
},
invoice,
}
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-invoice-collected',
{
invoiceNumber: invoice.invoice_number,
currency: invoice.currency,
totalInCents: invoice.total_in_cents,
taxInCents: invoice.tax_in_cents,
country: invoice.address.country,
collectionMethod: invoice.collection_method,
subscriptionId1: invoice.subscription_ids[0],
subscriptionId2: invoice.subscription_ids[1],
}
)
})
it('with paid_charge_invoice_notification and total_in_cents 0', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'paid_charge_invoice_notification',
{
account: {
account_code: this.userId,
},
invoice: {
state: 'paid',
total_in_cents: 0,
},
}
)
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
})
it('with closed_invoice_notification', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'closed_invoice_notification',
{
account: {
account_code: this.userId,
},
invoice: {
state: 'collected',
total_in_cents: 720,
},
}
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUserInBackground,
this.userId,
'subscription-invoice-collected'
)
})
it('with closed_invoice_notification and total_in_cents 0', function () {
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'closed_invoice_notification',
{
account: {
account_code: this.userId,
},
invoice: {
state: 'collected',
total_in_cents: 0,
},
}
)
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
})
it('nothing is called with invalid account code', function () {
this.eventData.account.account_code = 'foo_bar'
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
'new_subscription_notification',
this.eventData
)
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
sinon.assert.notCalled(
this.AnalyticsManager.setUserPropertyForUserInBackground
)
sinon.assert.notCalled(
this.AnalyticsManager.setUserPropertyForUserInBackground
)
sinon.assert.notCalled(
this.AnalyticsManager.setUserPropertyForUserInBackground
)
})
})