Ghost/ghost/core/test/e2e-api/members/create-stripe-checkout-session.test.js
Fabien "egg" O'Carroll 4718171b1d Removed out of date history items from UrlHistory
In case there is an issue with the filtering of items in our client
side attribution script, we also check for and remove out of date
items here. This ensures that we do not erroneously attribute signups
or conversions to webpages from more than 24h ago.
2022-08-25 16:09:34 -04:00

214 lines
8.0 KiB
JavaScript

const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework');
const nock = require('nock');
const should = require('should');
const models = require('../../../core/server/models');
const urlService = require('../../../core/server/services/url');
let membersAgent, adminAgent, membersService;
async function getPost(id) {
// eslint-disable-next-line dot-notation
return await models['Post'].where('id', id).fetch({require: true});
}
describe('Create Stripe Checkout Session', function () {
before(async function () {
const agents = await agentProvider.getAgentsForMembers();
membersAgent = agents.membersAgent;
adminAgent = agents.adminAgent;
membersService = require('../../../core/server/services/members');
await fixtureManager.init('posts', 'members');
await adminAgent.loginAsOwner();
});
beforeEach(function () {
mockManager.mockMail();
mockManager.mockStripe();
});
afterEach(function () {
mockManager.restore();
});
it('Does not allow to create a checkout session if the customerEmail is associated with a paid member', async function () {
const {body: {tiers}} = await adminAgent.get('/tiers/?include=monthly_price&yearly_price');
const paidTier = tiers.find(tier => tier.type === 'paid');
await membersAgent.post('/api/create-stripe-checkout-session/')
.body({
customerEmail: 'paid@test.com',
tierId: paidTier.id,
cadence: 'month'
})
.expectStatus(403)
.matchBodySnapshot({
errors: [{
id: matchers.anyUuid,
code: 'CANNOT_CHECKOUT_WITH_EXISTING_SUBSCRIPTION'
}]
})
.matchHeaderSnapshot({
etag: matchers.anyEtag
});
});
it('Does allow to create a checkout session if the customerEmail is not associated with a paid member', async function () {
const {body: {tiers}} = await adminAgent.get('/tiers/?include=monthly_price&yearly_price');
const paidTier = tiers.find(tier => tier.type === 'paid');
nock('https://api.stripe.com')
.persist()
.post(/v1\/.*/)
.reply((uri, body) => {
if (uri === '/v1/checkout/sessions') {
return [200, {id: 'cs_123'}];
}
return [500];
});
await membersAgent.post('/api/create-stripe-checkout-session/')
.body({
customerEmail: 'free@test.com',
tierId: paidTier.id,
cadence: 'month'
})
.expectStatus(200)
.matchBodySnapshot()
.matchHeaderSnapshot();
});
/**
* When a checkout session is created with an urlHistory, we should convert it to an
* attribution and check if that is set in the metadata of the stripe session
*/
describe('Member attribution', function () {
it('Does pass url attribution source to session metadata', async function () {
const {body: {tiers}} = await adminAgent.get('/tiers/?include=monthly_price&yearly_price');
const paidTier = tiers.find(tier => tier.type === 'paid');
const scope = nock('https://api.stripe.com')
.persist()
.post(/v1\/.*/)
.reply((uri, body) => {
if (uri === '/v1/checkout/sessions') {
const parsed = new URLSearchParams(body);
should(parsed.get('metadata[attribution_url]')).eql('/test');
should(parsed.get('metadata[attribution_type]')).eql('url');
should(parsed.get('metadata[attribution_id]')).be.null();
return [200, {id: 'cs_123'}];
}
throw new Error('Should not get called');
});
await membersAgent.post('/api/create-stripe-checkout-session/')
.body({
customerEmail: 'attribution@test.com',
tierId: paidTier.id,
cadence: 'month',
metadata: {
urlHistory: [
{
path: '/test',
time: Date.now()
}
]
}
})
.expectStatus(200)
.matchBodySnapshot()
.matchHeaderSnapshot();
should(scope.isDone()).eql(true);
});
it('Does pass post attribution source to session metadata', async function () {
const post = await getPost(fixtureManager.get('posts', 0).id);
const url = urlService.getUrlByResourceId(post.id, {absolute: false});
const {body: {tiers}} = await adminAgent.get('/tiers/?include=monthly_price&yearly_price');
const paidTier = tiers.find(tier => tier.type === 'paid');
const scope = nock('https://api.stripe.com')
.persist()
.post(/v1\/.*/)
.reply((uri, body) => {
if (uri === '/v1/checkout/sessions') {
const parsed = new URLSearchParams(body);
should(parsed.get('metadata[attribution_url]')).eql(url);
should(parsed.get('metadata[attribution_type]')).eql('post');
should(parsed.get('metadata[attribution_id]')).eql(post.id);
return [200, {id: 'cs_123'}];
}
throw new Error('Should not get called');
});
await membersAgent.post('/api/create-stripe-checkout-session/')
.body({
customerEmail: 'attribution-post@test.com',
tierId: paidTier.id,
cadence: 'month',
metadata: {
urlHistory: [
{
path: url,
time: Date.now()
}
]
}
})
.expectStatus(200)
.matchBodySnapshot()
.matchHeaderSnapshot();
should(scope.isDone()).eql(true);
});
it('Ignores attribution_* values in metadata', async function () {
const {body: {tiers}} = await adminAgent.get('/tiers/?include=monthly_price&yearly_price');
const paidTier = tiers.find(tier => tier.type === 'paid');
const scope = nock('https://api.stripe.com')
.persist()
.post(/v1\/.*/)
.reply((uri, body) => {
if (uri === '/v1/checkout/sessions') {
const parsed = new URLSearchParams(body);
should(parsed.get('metadata[attribution_url]')).be.null();
should(parsed.get('metadata[attribution_type]')).be.null();
should(parsed.get('metadata[attribution_id]')).be.null();
return [200, {id: 'cs_123'}];
}
throw new Error('Should not get called');
});
await membersAgent.post('/api/create-stripe-checkout-session/')
.body({
customerEmail: 'attribution-2@test.com',
tierId: paidTier.id,
cadence: 'month',
metadata: {
attribution_type: 'url',
attribution_url: '/',
attribution_id: null
}
})
.expectStatus(200)
.matchBodySnapshot()
.matchHeaderSnapshot();
should(scope.isDone()).eql(true);
});
});
});