mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-20 17:32:15 +03:00
72cc285184
refs https://github.com/TryGhost/Product/issues/3837 Moved the logic for validating specified newsletters to controller so that the request can be failed
314 lines
9.9 KiB
JavaScript
314 lines
9.9 KiB
JavaScript
const assert = require('assert/strict');
|
|
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: (relation) => {
|
|
return {
|
|
query: sinon.stub().returns({
|
|
fetchOne: sinon.stub().resolves({})
|
|
}),
|
|
toJSON: sinon.stub().returns(relation === 'products' ? [] : {}),
|
|
fetch: sinon.stub().resolves({
|
|
toJSON: sinon.stub().returns(relation === 'products' ? [] : {})
|
|
})
|
|
};
|
|
},
|
|
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();
|
|
});
|
|
});
|
|
});
|