const assert = require('assert/strict'); const sinon = require('sinon'); const MemberBreadService = require('../../../../lib/services/MemberBREADService'); const moment = require('moment'); describe('MemberBreadService', function () { describe('read', function () { const MEMBER_ID = 123; const DEFAULT_RELATIONS = [ 'labels', 'stripeSubscriptions', 'stripeSubscriptions.customer', 'stripeSubscriptions.stripePrice', 'stripeSubscriptions.stripePrice.stripeProduct', 'stripeSubscriptions.stripePrice.stripeProduct.product', 'products', 'newsletters', 'productEvents' ]; let memberModelStub, memberModelJSON, memberRepositoryStub, memberAttributionServiceStub, emailSuppressionListStub; const getService = () => { return new MemberBreadService({ memberRepository: memberRepositoryStub, memberAttributionService: memberAttributionServiceStub, emailSuppressionList: emailSuppressionListStub }); }; beforeEach(function () { memberModelJSON = { id: MEMBER_ID, name: 'foo bar', email: 'foo@bar.baz', subscriptions: [] }; memberModelStub = { id: MEMBER_ID, related: sinon.stub().returns([]), toJSON: sinon.stub().returns({...memberModelJSON}), get: function (key) { return this[key]; } }; memberRepositoryStub = { get: sinon.stub().resolves(null), related: sinon.stub().returns([]) }; memberAttributionServiceStub = { getMemberCreatedAttribution: sinon.stub().resolves(null) }; emailSuppressionListStub = { getSuppressionData: sinon.stub().resolves({}) }; memberRepositoryStub.get .withArgs( {id: MEMBER_ID}, {withRelated: DEFAULT_RELATIONS} ) .resolves(memberModelStub); }); it('returns a member', async function () { const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); assert.equal(member.id, memberModelJSON.id); assert.equal(member.email, memberModelJSON.email); }); it('returns a member with subscriptions', async function () { const subscriptionsJSON = [ { subscription_id: 'sub_123', price: {} } ]; const subscriptionModels = [ { get: sinon.stub() } ]; subscriptionModels[0].get .withArgs('subscription_id') .returns(subscriptionsJSON[0].subscription_id); memberModelStub.related .withArgs('stripeSubscriptions') .returns(subscriptionModels); memberModelStub.toJSON.returns({ ...memberModelJSON, subscriptions: subscriptionsJSON }); const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); assert.deepEqual(member.subscriptions, subscriptionsJSON); }); it('returns a member with subscriptions that only have a price', async function () { const subscriptionsJSON = [ { subscription_id: 'sub_123', price: {} }, { subscription_id: 'sub_456' } ]; const subscriptionModels = subscriptionsJSON.map((subscription) => { const model = { get: sinon.stub() }; model.get.withArgs('subscription_id').returns(subscription.subscription_id); model.get.withArgs('offer_id').returns(undefined); return model; }); memberModelStub.related .withArgs('stripeSubscriptions') .returns(subscriptionModels); memberModelStub.toJSON.returns({ ...memberModelJSON, subscriptions: subscriptionsJSON }); const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); assert.deepEqual(member.subscriptions, [ subscriptionsJSON[0] ]); }); it('returns a member with a comped subscription', async function () { const productsJSON = [ { id: 'prod_123', expiry_at: new Date('2023-10-13T15:15:00') }, { id: 'prod_456', expiry_at: new Date('2023-10-13T15:15:00') } ]; const productEventsJSON = [ { product_id: productsJSON[0].id, created_at: new Date('2023-09-13T15:15:00'), action: 'added' }, { product_id: productsJSON[1].id, created_at: new Date('2023-09-13T15:20:00'), action: 'added' } ]; const subscriptionsJSON = [ { subscription_id: 'sub_123', price: { product: { product_id: productsJSON[0].id } }, status: 'cancelled', product_id: productsJSON[0].id }, // Comped subscription - Has no price { subscription_id: 'sub_456', status: 'active', product_id: productsJSON[1].id } ]; const subscriptionModels = subscriptionsJSON.map((subscription) => { const model = { get: sinon.stub() }; model.get.withArgs('subscription_id').returns(subscription.subscription_id); model.get.withArgs('offer_id').returns(undefined); return model; }); memberModelStub.related .withArgs('stripeSubscriptions') .returns(subscriptionModels); memberModelStub.toJSON.returns({ ...memberModelJSON, subscriptions: subscriptionsJSON, products: productsJSON, productEvents: productEventsJSON }); memberRepositoryStub.isActiveSubscriptionStatus = sinon.stub().returns(true); const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); // Ensure only 2 subscriptions are returned assert.equal(member.subscriptions.length, 2); const compedSubscription = member.subscriptions[1]; // Ensure the 2nd subscription is the comped one sinon.assert.match(compedSubscription, { id: '', tier: productsJSON[1], customer: { id: '', name: memberModelJSON.name, email: memberModelJSON.email }, plan: { id: '', nickname: 'Complimentary', interval: 'year', currency: 'USD', amount: 0 }, status: 'active', start_date: moment(productEventsJSON[1].created_at), default_payment_card_last4: '****', cancel_at_period_end: false, cancellation_reason: null, current_period_end: moment(productsJSON[1].expiry_at), price: { id: '', price_id: '', nickname: 'Complimentary', amount: 0, interval: 'year', type: 'recurring', currency: 'USD', product: { id: '', product_id: productsJSON[1].id } } }); }); it('returns a member with attribution data', async function () { const attributionData = { url: 'https://example.com' }; memberAttributionServiceStub.getMemberCreatedAttribution .withArgs(MEMBER_ID) .resolves(attributionData); const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); assert.deepEqual(member.attribution, attributionData); }); it('returns a member with suppression data', async function () { emailSuppressionListStub.getSuppressionData .withArgs(memberModelJSON.email) .resolves({ suppressed: true, info: 'bounce' }); const memberBreadService = getService(); const member = await memberBreadService.read({id: MEMBER_ID}); assert.deepEqual(member.email_suppression, { suppressed: true, info: 'bounce' }); }); }); });