Ghost/ghost/members-api/test/unit/lib/repositories/member.test.js

314 lines
9.9 KiB
JavaScript
Raw Normal View History

const assert = require('assert');
const sinon = require('sinon');
const DomainEvents = require('@tryghost/domain-events');
const MemberRepository = require('../../../../lib/repositories/MemberRepository');
const {SubscriptionCreatedEvent} = require('@tryghost/member-events');
const mockOfferRedemption = {
add: sinon.stub()
};
describe('MemberRepository', function () {
afterEach(function () {
sinon.restore();
});
describe('#isComplimentarySubscription', function () {
it('Does not error when subscription.plan is null', function () {
const repo = new MemberRepository({OfferRedemption: mockOfferRedemption});
repo.isComplimentarySubscription({});
});
});
describe('#resolveContextSource', function (){
it('Maps context to source', function (){
const repo = new MemberRepository({OfferRedemption: mockOfferRedemption});
let source = repo._resolveContextSource({
import: true
});
assert.equal(source, 'import');
source = repo._resolveContextSource({
importer: true
});
assert.equal(source, 'import');
source = repo._resolveContextSource({
user: true
});
assert.equal(source, 'admin');
source = repo._resolveContextSource({
user: true,
api_key: true
});
assert.equal(source, 'api');
source = repo._resolveContextSource({
api_key: true
});
assert.equal(source, 'api');
source = repo._resolveContextSource({
});
assert.equal(source, 'member');
source = repo._resolveContextSource({
generic_context: true
});
assert.equal(source, 'member');
});
});
describe('setComplimentarySubscription', function () {
let Member;
let productRepository;
beforeEach(function () {
Member = {
findOne: sinon.stub().resolves({
id: 'member_id_123',
related: () => {
return {
fetch: () => {
return {
models: []
};
}
};
}
})
};
});
it('throws an error when there is no default product', async function () {
productRepository = {
getDefaultProduct: sinon.stub().resolves(null)
};
const repo = new MemberRepository({
Member,
stripeAPIService: {
configured: true
},
productRepository,
OfferRedemption: mockOfferRedemption
});
try {
await repo.setComplimentarySubscription({
id: 'member_id_123'
}, {
transacting: true
});
assert.fail('setComplimentarySubscription should have thrown');
} catch (err) {
assert.equal(err.message, 'Could not find Product "default"');
}
});
it('uses the right options for fetching default product', async function () {
productRepository = {
getDefaultProduct: sinon.stub().resolves({
toJSON: () => {
return null;
}
})
};
const repo = new MemberRepository({
Member,
stripeAPIService: {
configured: true
},
productRepository,
OfferRedemption: mockOfferRedemption
});
try {
await repo.setComplimentarySubscription({
id: 'member_id_123'
}, {
transacting: true,
withRelated: ['labels']
});
assert.fail('setComplimentarySubscription should have thrown');
} catch (err) {
productRepository.getDefaultProduct.calledWith({withRelated: ['stripePrices'], transacting: true}).should.be.true();
assert.equal(err.message, 'Could not find Product "default"');
}
});
});
describe('linkSubscription', function (){
let Member;
let MemberPaidSubscriptionEvent;
let StripeCustomerSubscription;
let MemberProductEvent;
let stripeAPIService;
let productRepository;
let offerRepository;
let labsService;
let subscriptionData;
let notifySpy;
afterEach(function () {
sinon.restore();
});
beforeEach(async function () {
notifySpy = sinon.spy();
subscriptionData = {
id: 'sub_123',
customer: 'cus_123',
status: 'active',
items: {
type: 'list',
data: [{
id: 'item_123',
price: {
id: 'price_123',
product: 'product_123',
active: true,
nickname: 'Monthly',
currency: 'usd',
recurring: {
interval: 'month'
},
unit_amount: 500,
type: 'recurring'
}
}]
},
start_date: Date.now() / 1000,
current_period_end: Date.now() / 1000 + (60 * 60 * 24 * 31),
cancel_at_period_end: false
};
Member = {
findOne: sinon.stub().resolves({
related: () => {
return {
query: sinon.stub().returns({
fetchOne: sinon.stub().resolves({})
}),
toJSON: sinon.stub().returns([]),
fetch: sinon.stub().resolves({
toJSON: sinon.stub().returns({})
})
};
},
toJSON: sinon.stub().returns({})
}),
edit: sinon.stub().resolves({
attributes: {},
_previousAttributes: {}
})
};
MemberPaidSubscriptionEvent = {
add: sinon.stub().resolves()
};
StripeCustomerSubscription = {
add: sinon.stub().resolves({
get: sinon.stub().returns()
})
};
MemberProductEvent = {
add: sinon.stub().resolves({})
};
stripeAPIService = {
configured: true,
getSubscription: sinon.stub().resolves(subscriptionData)
};
productRepository = {
get: sinon.stub().resolves({
get: sinon.stub().returns(),
toJSON: sinon.stub().returns({})
}),
update: sinon.stub().resolves({})
};
labsService = {
isSet: sinon.stub().returns(true)
};
offerRepository = {
getById: sinon.stub().resolves({
id: 'offer_123'
})
};
});
it('dispatches paid subscription event', async function (){
const repo = new MemberRepository({
stripeAPIService,
StripeCustomerSubscription,
MemberPaidSubscriptionEvent,
MemberProductEvent,
productRepository,
labsService,
Member,
OfferRedemption: mockOfferRedemption
});
sinon.stub(repo, 'getSubscriptionByStripeID').resolves(null);
DomainEvents.subscribe(SubscriptionCreatedEvent, notifySpy);
await repo.linkSubscription({
subscription: subscriptionData
}, {
transacting: {
executionPromise: Promise.resolve()
},
context: {}
});
notifySpy.calledOnce.should.be.true();
});
it('attaches offer information to subscription event', async function (){
const repo = new MemberRepository({
stripeAPIService,
StripeCustomerSubscription,
MemberPaidSubscriptionEvent,
MemberProductEvent,
productRepository,
offerRepository,
labsService,
Member,
OfferRedemption: mockOfferRedemption
});
sinon.stub(repo, 'getSubscriptionByStripeID').resolves(null);
DomainEvents.subscribe(SubscriptionCreatedEvent, notifySpy);
await repo.linkSubscription({
id: 'member_id_123',
subscription: subscriptionData,
offerId: 'offer_123'
}, {
transacting: {
executionPromise: Promise.resolve()
},
context: {}
});
notifySpy.calledOnce.should.be.true();
notifySpy.calledWith(sinon.match((event) => {
if (event.data.offerId === 'offer_123') {
return true;
}
return false;
})).should.be.true();
});
});
});