mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-27 12:53:13 +03:00
e2ba19b0df
- there's a few different ways we can import it but I've chosen to append `.default` as we have done in several other places in the code
394 lines
13 KiB
JavaScript
394 lines
13 KiB
JavaScript
const should = require('should');
|
|
const ObjectID = require('bson-objectid').default;
|
|
const errors = require('../../../../lib/domain/errors');
|
|
const Offer = require('../../../../lib/domain/models/Offer');
|
|
const OfferName = require('../../../../lib/domain/models/OfferName');
|
|
const OfferCode = require('../../../../lib/domain/models/OfferCode');
|
|
|
|
function createUniqueChecker(dupe) {
|
|
return {
|
|
async isUniqueCode(code) {
|
|
return code.value !== dupe;
|
|
},
|
|
async isUniqueName(name) {
|
|
return name.value !== dupe;
|
|
}
|
|
};
|
|
}
|
|
|
|
const mockUniqueChecker = createUniqueChecker('dupe');
|
|
|
|
describe('Offer', function () {
|
|
describe('Offer#create factory', function () {
|
|
it('Creates a valid instance of an Offer', async function () {
|
|
const offer = await Offer.create({
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'forever',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
}, mockUniqueChecker);
|
|
should.ok(
|
|
offer instanceof Offer,
|
|
'Offer.create should return an instance of Offer'
|
|
);
|
|
});
|
|
|
|
it('Creates a valid instance of a trial Offer', async function () {
|
|
const offer = await Offer.create({
|
|
name: 'My Trial Offer',
|
|
code: 'offer-code-trial',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'trial',
|
|
amount: 10,
|
|
duration: 'trial',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
}, mockUniqueChecker);
|
|
should.ok(
|
|
offer instanceof Offer,
|
|
'Offer.create should return an instance of Offer'
|
|
);
|
|
});
|
|
|
|
it('Throws an error if the duration for trial offer is not right', async function () {
|
|
await Offer.create({
|
|
name: 'My Trial Offer',
|
|
code: 'trial-test',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'trial',
|
|
amount: 10,
|
|
duration: 'forever',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
}, mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
});
|
|
|
|
it('Throws an error if the code is not unique', async function () {
|
|
await Offer.create({
|
|
name: 'My Offer',
|
|
code: 'dupe',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'forever',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
}, mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
});
|
|
|
|
it('Throws an error if the name is not unique', async function () {
|
|
await Offer.create({
|
|
name: 'dupe',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'forever',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
}, mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
});
|
|
|
|
it('Wraps the input values in value objects', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'forever',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
should.ok(offer.name.equals(OfferName.create(data.name)));
|
|
});
|
|
|
|
it('Errors if the repeating duration is applied to the year cadence', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'year',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
try {
|
|
await Offer.create(data, mockUniqueChecker);
|
|
should.fail();
|
|
} catch (err) {
|
|
should.ok(err instanceof errors.InvalidOfferDuration);
|
|
}
|
|
});
|
|
|
|
it('Has a currency of null if the type is percent', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'year',
|
|
type: 'percent',
|
|
amount: 20,
|
|
duration: 'once',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
should.equal(offer.currency, null);
|
|
});
|
|
|
|
it('Has a currency of null if the type is trial', async function () {
|
|
const data = {
|
|
name: 'My Trial Offer',
|
|
code: 'offer-code-trial',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'year',
|
|
type: 'trial',
|
|
amount: 20,
|
|
duration: 'trial',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
should.equal(offer.currency, null);
|
|
});
|
|
|
|
it('Can handle ObjectID, string and no id', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'year',
|
|
type: 'percent',
|
|
amount: 20,
|
|
duration: 'once',
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
await Offer.create({...data, id: ObjectID()}, mockUniqueChecker);
|
|
await Offer.create({...data, id: ObjectID().toHexString()}, mockUniqueChecker);
|
|
await Offer.create({...data, id: undefined}, mockUniqueChecker);
|
|
});
|
|
|
|
it('Does not accept a redemptionCount for new Offers', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
await Offer.create(data, mockUniqueChecker);
|
|
|
|
await Offer.create({...data, redemptionCount: 2}, mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#updateCode', function () {
|
|
it('Requires the code to be unique if it has changed', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
await offer.updateCode(OfferCode.create('dupe'), mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
|
|
const offer2 = await Offer.create({...data, code: 'dupe'}, createUniqueChecker());
|
|
|
|
await offer2.updateCode(OfferCode.create('dupe'), mockUniqueChecker);
|
|
});
|
|
|
|
it('Does not allow code to be changed twice', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
await offer.updateCode(OfferCode.create('changed'), mockUniqueChecker);
|
|
await offer.updateCode(OfferCode.create('changed-again'), mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#updateName', function () {
|
|
it('Requires the name to be unique if it has changed', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
await offer.updateName(OfferName.create('Unique!'), mockUniqueChecker);
|
|
|
|
await offer.updateName(OfferName.create('dupe'), mockUniqueChecker).then(() => {
|
|
should.fail('Expected an error');
|
|
}, (err) => {
|
|
should.ok(err);
|
|
});
|
|
|
|
const offer2 = await Offer.create({...data, name: 'dupe'}, createUniqueChecker());
|
|
|
|
await offer2.updateName(OfferName.create('dupe'), mockUniqueChecker);
|
|
});
|
|
});
|
|
|
|
describe('Properties', function () {
|
|
it('Exposes getters for its properties', async function () {
|
|
const data = {
|
|
name: 'My Offer',
|
|
code: 'offer-code',
|
|
display_title: 'My Offer Title',
|
|
display_description: 'My Offer Description',
|
|
cadence: 'month',
|
|
type: 'fixed',
|
|
amount: 1000,
|
|
duration: 'repeating',
|
|
duration_in_months: 12,
|
|
currency: 'USD',
|
|
tier: {
|
|
id: ObjectID()
|
|
}
|
|
};
|
|
|
|
const offer = await Offer.create(data, mockUniqueChecker);
|
|
|
|
should.exist(offer.id);
|
|
should.exist(offer.name);
|
|
should.exist(offer.code);
|
|
should.exist(offer.currency);
|
|
should.exist(offer.duration);
|
|
should.exist(offer.status);
|
|
should.exist(offer.redemptionCount);
|
|
should.exist(offer.displayTitle);
|
|
should.exist(offer.displayDescription);
|
|
should.exist(offer.tier);
|
|
should.exist(offer.cadence);
|
|
should.exist(offer.type);
|
|
should.exist(offer.amount);
|
|
should.exist(offer.isNew);
|
|
});
|
|
});
|
|
});
|