mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added initial tests for Offers
refs https://github.com/TryGhost/Team/issues/1198
This commit is contained in:
parent
155d9b4f7d
commit
0b9c9968d0
22 changed files with 1079 additions and 7 deletions
|
@ -24,6 +24,8 @@ class OfferPercentageAmount extends OfferAmount {
|
|||
}
|
||||
return new OfferPercentageAmount(amount);
|
||||
}
|
||||
|
||||
static InvalidOfferAmount = InvalidOfferAmount;
|
||||
}
|
||||
|
||||
class OfferFixedAmount extends OfferAmount {
|
||||
|
@ -31,17 +33,23 @@ class OfferFixedAmount extends OfferAmount {
|
|||
static create(amount) {
|
||||
if (typeof amount !== 'number') {
|
||||
throw new InvalidOfferAmount({
|
||||
message: 'Offer `amount` must be a number greater than 0.'
|
||||
message: 'Offer `amount` must be an integer greater than 0.'
|
||||
});
|
||||
}
|
||||
if (!Number.isInteger(amount)) {
|
||||
throw new InvalidOfferAmount({
|
||||
message: 'Offer `amount` must be a integer greater than 0.'
|
||||
});
|
||||
}
|
||||
if (amount < 0) {
|
||||
throw new InvalidOfferAmount({
|
||||
message: 'Offer `amount` must be a number greater than 0.'
|
||||
message: 'Offer `amount` must be a integer greater than 0.'
|
||||
});
|
||||
}
|
||||
const withTwoDecimalPlaces = +amount.toFixed(2);
|
||||
return new OfferPercentageAmount(withTwoDecimalPlaces);
|
||||
return new OfferPercentageAmount(amount);
|
||||
}
|
||||
|
||||
static InvalidOfferAmount = InvalidOfferAmount;
|
||||
}
|
||||
|
||||
module.exports = OfferAmount;
|
||||
|
|
|
@ -19,6 +19,8 @@ class OfferCadence extends ValueObject {
|
|||
}
|
||||
return new OfferCadence(cadence);
|
||||
}
|
||||
|
||||
static InvalidOfferCadence = InvalidOfferCadence;
|
||||
}
|
||||
|
||||
module.exports = OfferCadence;
|
||||
|
|
|
@ -23,6 +23,8 @@ class OfferCode extends ValueObject {
|
|||
|
||||
return new OfferCode(slugged);
|
||||
}
|
||||
|
||||
static InvalidOfferCode = InvalidOfferCode;
|
||||
}
|
||||
|
||||
module.exports = OfferCode;
|
||||
|
|
|
@ -10,9 +10,17 @@ class OfferCurrency extends ValueObject {
|
|||
message: 'Offer `currency` must be a string.'
|
||||
});
|
||||
}
|
||||
// Check currency is a 3 character string consisting of only letters (case insensitive)
|
||||
if (!currency.match(/^[A-Z]{3}$/i)) {
|
||||
throw new InvalidOfferCurrency({
|
||||
message: 'Offer `currency` must be an ISO currency code.'
|
||||
});
|
||||
}
|
||||
// TODO: Validate it is a country code we support?
|
||||
return new OfferCurrency(currency);
|
||||
return new OfferCurrency(currency.toUpperCase());
|
||||
}
|
||||
|
||||
static InvalidOfferCurrency = InvalidOfferCurrency;
|
||||
}
|
||||
|
||||
module.exports = OfferCurrency;
|
||||
|
|
|
@ -23,6 +23,8 @@ class OfferDescription extends ValueObject {
|
|||
|
||||
return new OfferDescription(description.trim());
|
||||
}
|
||||
|
||||
static InvalidOfferDescription = InvalidOfferDescription;
|
||||
}
|
||||
|
||||
module.exports = OfferDescription;
|
||||
|
|
|
@ -41,11 +41,18 @@ class OfferDuration extends ValueObject {
|
|||
}
|
||||
if (!Number.isInteger(months)) {
|
||||
throw new InvalidOfferDuration({
|
||||
message: 'Offer `duration_in_months` must be an integer.'
|
||||
message: 'Offer `duration_in_months` must be an integer greater than 0.'
|
||||
});
|
||||
}
|
||||
if (months < 1) {
|
||||
throw new InvalidOfferDuration({
|
||||
message: 'Offer `duration_in_months` must be an integer greater than 0.'
|
||||
});
|
||||
}
|
||||
return new OfferDuration({type, months});
|
||||
}
|
||||
|
||||
static InvalidOfferDuration = InvalidOfferDuration;
|
||||
}
|
||||
|
||||
module.exports = OfferDuration;
|
||||
|
|
|
@ -17,8 +17,10 @@ class OfferName extends ValueObject {
|
|||
});
|
||||
}
|
||||
|
||||
return new OfferName(name);
|
||||
return new OfferName(name.trim());
|
||||
}
|
||||
|
||||
static InvalidOfferName = InvalidOfferName
|
||||
}
|
||||
|
||||
module.exports = OfferName;
|
||||
|
|
|
@ -18,6 +18,8 @@ class OfferStatus extends ValueObject {
|
|||
}
|
||||
return new OfferStatus(status);
|
||||
}
|
||||
|
||||
static InvalidOfferStatus = InvalidOfferStatus
|
||||
}
|
||||
|
||||
module.exports = OfferStatus;
|
||||
|
|
|
@ -22,6 +22,8 @@ class OfferTitle extends ValueObject {
|
|||
|
||||
return new OfferTitle(title.trim());
|
||||
}
|
||||
|
||||
static InvalidOfferTitle = InvalidOfferTitle;
|
||||
}
|
||||
|
||||
module.exports = OfferTitle;
|
||||
|
|
|
@ -19,6 +19,8 @@ class OfferType extends ValueObject {
|
|||
return new OfferType(type);
|
||||
}
|
||||
|
||||
static InvalidOfferType = InvalidOfferType
|
||||
|
||||
static Percentage = new OfferType('percent')
|
||||
|
||||
static Fixed = new OfferType('fixed')
|
||||
|
|
61
ghost/offers/test/lib/application/UniqueChecker.test.js
Normal file
61
ghost/offers/test/lib/application/UniqueChecker.test.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
const sinon = require('sinon');
|
||||
const should = require('should');
|
||||
const UniqueChecker = require('../../../lib/application/UniqueChecker');
|
||||
|
||||
describe('UniqueChecker', function () {
|
||||
describe('#isUniqueCode', function () {
|
||||
it('Returns true if there is no Offer found in the repository', async function () {
|
||||
const repository = {
|
||||
existsByCode: sinon.stub().resolves(false)
|
||||
};
|
||||
const transaction = {};
|
||||
|
||||
const checker = new UniqueChecker(repository, transaction);
|
||||
|
||||
const returnVal = await checker.isUniqueCode('code');
|
||||
|
||||
should.equal(returnVal, true);
|
||||
});
|
||||
|
||||
it('Returns false if there is an Offer found in the repository', async function () {
|
||||
const repository = {
|
||||
existsByCode: sinon.stub().resolves(true)
|
||||
};
|
||||
const transaction = {};
|
||||
|
||||
const checker = new UniqueChecker(repository, transaction);
|
||||
|
||||
const returnVal = await checker.isUniqueCode('code');
|
||||
|
||||
should.equal(returnVal, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isUniqueName', function () {
|
||||
it('Returns true if there is no Offer found in the repository', async function () {
|
||||
const repository = {
|
||||
existsByName: sinon.stub().resolves(false)
|
||||
};
|
||||
const transaction = {};
|
||||
|
||||
const checker = new UniqueChecker(repository, transaction);
|
||||
|
||||
const returnVal = await checker.isUniqueName('name');
|
||||
|
||||
should.equal(returnVal, true);
|
||||
});
|
||||
|
||||
it('Returns false if there is an Offer found in the repository', async function () {
|
||||
const repository = {
|
||||
existsByName: sinon.stub().resolves(true)
|
||||
};
|
||||
const transaction = {};
|
||||
|
||||
const checker = new UniqueChecker(repository, transaction);
|
||||
|
||||
const returnVal = await checker.isUniqueName('name');
|
||||
|
||||
should.equal(returnVal, false);
|
||||
});
|
||||
});
|
||||
});
|
330
ghost/offers/test/lib/domain/models/Offer.test.js
Normal file
330
ghost/offers/test/lib/domain/models/Offer.test.js
Normal file
|
@ -0,0 +1,330 @@
|
|||
const should = require('should');
|
||||
const ObjectID = require('bson-objectid');
|
||||
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('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('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);
|
||||
});
|
||||
});
|
||||
});
|
121
ghost/offers/test/lib/domain/models/OfferAmount.test.js
Normal file
121
ghost/offers/test/lib/domain/models/OfferAmount.test.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
const {OfferPercentageAmount, OfferFixedAmount} = require('../../../../lib/domain/models/OfferAmount');
|
||||
|
||||
describe('OfferAmount', function () {
|
||||
describe('OfferPercentageAmount', function () {
|
||||
describe('OfferPercentageAmount.create factory', function () {
|
||||
it('Will only create an OfferPercentageAmount containing an integer between 1 & 100 (inclusive)', function () {
|
||||
try {
|
||||
OfferPercentageAmount.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferPercentageAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferPercentageAmount.create('1');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferPercentageAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferPercentageAmount.create(-1);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferPercentageAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferPercentageAmount.create(200);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferPercentageAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferPercentageAmount.create(3.14);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferPercentageAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
OfferPercentageAmount.create(69); // nice
|
||||
});
|
||||
});
|
||||
|
||||
it('Exposes a number on the value property', function () {
|
||||
const cadence = OfferPercentageAmount.create(42);
|
||||
|
||||
should.ok(typeof cadence.value === 'number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('OfferFixedAmount', function () {
|
||||
describe('OfferFixedAmount.create factory', function () {
|
||||
it('Will only create an OfferFixedAmount containing an integer greater than 0', function () {
|
||||
try {
|
||||
OfferFixedAmount.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferFixedAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferFixedAmount.create('1');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferFixedAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferFixedAmount.create(-1);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferFixedAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferFixedAmount.create(3.14);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferFixedAmount.InvalidOfferAmount,
|
||||
'expected an InvalidOfferAmount error'
|
||||
);
|
||||
}
|
||||
|
||||
OfferFixedAmount.create(200);
|
||||
});
|
||||
});
|
||||
|
||||
it('Exposes a number on the value property', function () {
|
||||
const cadence = OfferFixedAmount.create(42);
|
||||
|
||||
should.ok(typeof cadence.value === 'number');
|
||||
});
|
||||
});
|
||||
});
|
46
ghost/offers/test/lib/domain/models/OfferCadence.test.js
Normal file
46
ghost/offers/test/lib/domain/models/OfferCadence.test.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const OfferCadence = require('../../../../lib/domain/models/OfferCadence');
|
||||
|
||||
describe('OfferCadence', function () {
|
||||
describe('OfferCadence.create factory', function () {
|
||||
it('Will only create an OfferCadence containing a string of either "month" or "year"', function () {
|
||||
OfferCadence.create('month');
|
||||
OfferCadence.create('year');
|
||||
|
||||
try {
|
||||
OfferCadence.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCadence.InvalidOfferCadence,
|
||||
'expected an InvalidOfferCadence error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCadence.create(12);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCadence.InvalidOfferCadence,
|
||||
'expected an InvalidOfferCadence error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCadence.create('daily');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCadence.InvalidOfferCadence,
|
||||
'expected an InvalidOfferCadence error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Exposes a string on the value property', function () {
|
||||
const cadence = OfferCadence.create('month');
|
||||
|
||||
should.ok(typeof cadence.value === 'string');
|
||||
});
|
||||
});
|
55
ghost/offers/test/lib/domain/models/OfferCode.test.js
Normal file
55
ghost/offers/test/lib/domain/models/OfferCode.test.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
const OfferCode = require('../../../../lib/domain/models/OfferCode');
|
||||
|
||||
describe('OfferCode', function () {
|
||||
describe('OfferCode.create factory', function () {
|
||||
it('Creates a sluggified code of a string', function () {
|
||||
OfferCode.create('code');
|
||||
|
||||
try {
|
||||
OfferCode.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCode.InvalidOfferCode,
|
||||
'expected an InvalidOfferCode error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCode.create(1234);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCode.InvalidOfferCode,
|
||||
'expected an InvalidOfferCode error'
|
||||
);
|
||||
}
|
||||
|
||||
const code = OfferCode.create('Hello, world');
|
||||
|
||||
should.equal(code.value, 'hello-world');
|
||||
});
|
||||
|
||||
it('Requires the string to be a maximum of 191 characters', function () {
|
||||
const maxLengthInput = Array.from({length: 191}).map(() => 'a').join('');
|
||||
|
||||
should.equal(maxLengthInput.length, 191);
|
||||
|
||||
OfferCode.create(maxLengthInput);
|
||||
|
||||
const tooLong = maxLengthInput + 'a';
|
||||
|
||||
should.equal(tooLong.length, 192);
|
||||
|
||||
try {
|
||||
OfferCode.create(tooLong);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCode.InvalidOfferCode,
|
||||
'expected an InvalidOfferCode error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
74
ghost/offers/test/lib/domain/models/OfferCurrency.test.js
Normal file
74
ghost/offers/test/lib/domain/models/OfferCurrency.test.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
const OfferCurrency = require('../../../../lib/domain/models/OfferCurrency');
|
||||
|
||||
describe('OfferCurrency', function () {
|
||||
describe('OfferCurrency.create factory', function () {
|
||||
it('Will only allow creating a currency with a 3 letter ISO string', function () {
|
||||
OfferCurrency.create('USD');
|
||||
OfferCurrency.create('gbp');
|
||||
|
||||
try {
|
||||
OfferCurrency.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCurrency.InvalidOfferCurrency,
|
||||
'expected an InvalidOfferCurrency error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCurrency.create('US Dollars');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCurrency.InvalidOfferCurrency,
|
||||
'expected an InvalidOfferCurrency error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCurrency.create('$');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCurrency.InvalidOfferCurrency,
|
||||
'expected an InvalidOfferCurrency error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCurrency.create('USDC');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCurrency.InvalidOfferCurrency,
|
||||
'expected an InvalidOfferCurrency error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferCurrency.create(2);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferCurrency.InvalidOfferCurrency,
|
||||
'expected an InvalidOfferCurrency error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Store the currency as a string on the value property', function () {
|
||||
const currency = OfferCurrency.create('usd');
|
||||
|
||||
should.equal(typeof currency.value, 'string');
|
||||
});
|
||||
|
||||
it('Considers currencies equal if they have the same ISO code', function () {
|
||||
const currencyA = OfferCurrency.create('usd');
|
||||
const currencyB = OfferCurrency.create('USD');
|
||||
|
||||
should.ok(currencyA.equals(currencyB));
|
||||
});
|
||||
});
|
||||
|
62
ghost/offers/test/lib/domain/models/OfferDescription.test.js
Normal file
62
ghost/offers/test/lib/domain/models/OfferDescription.test.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
const OfferDescription = require('../../../../lib/domain/models/OfferDescription');
|
||||
|
||||
describe('OfferDescription', function () {
|
||||
describe('OfferDescription.create factory', function () {
|
||||
it('Creates an Offer description containing a string', function () {
|
||||
OfferDescription.create('Hello, world');
|
||||
|
||||
should.equal(OfferDescription.create().value, '');
|
||||
should.equal(OfferDescription.create(undefined).value, '');
|
||||
should.equal(OfferDescription.create(null).value, '');
|
||||
|
||||
try {
|
||||
OfferDescription.create(12);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDescription.InvalidOfferDescription,
|
||||
'expected an InvalidOfferDescription error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDescription.create({});
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDescription.InvalidOfferDescription,
|
||||
'expected an InvalidOfferDescription error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Requires the string to be a maximum of 191 characters', function () {
|
||||
const maxLengthInput = Array.from({length: 191}).map(() => 'a').join('');
|
||||
|
||||
should.equal(maxLengthInput.length, 191);
|
||||
|
||||
OfferDescription.create(maxLengthInput);
|
||||
|
||||
const tooLong = maxLengthInput + 'a';
|
||||
|
||||
should.equal(tooLong.length, 192);
|
||||
|
||||
try {
|
||||
OfferDescription.create(tooLong);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDescription.InvalidOfferDescription,
|
||||
'expected an InvalidOfferDescription error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Trims the contents of the OfferDescription', function () {
|
||||
const description = OfferDescription.create(' Trim me! ');
|
||||
|
||||
should.equal(description.value, 'Trim me!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
71
ghost/offers/test/lib/domain/models/OfferDuration.test.js
Normal file
71
ghost/offers/test/lib/domain/models/OfferDuration.test.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
const OfferDuration = require('../../../../lib/domain/models/OfferDuration');
|
||||
|
||||
describe('OfferDuration', function () {
|
||||
describe('OfferDuration.create factory', function () {
|
||||
it('Will only allow creating a once, repeating or forever duration', function () {
|
||||
OfferDuration.create('once');
|
||||
OfferDuration.create('forever');
|
||||
OfferDuration.create('repeating', 2);
|
||||
|
||||
try {
|
||||
OfferDuration.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDuration.create('other');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDuration.create('repeating');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDuration.create('repeating', 1.5);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDuration.create('repeating', -12);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferDuration.create('repeating', '2');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferDuration.InvalidOfferDuration,
|
||||
'expected an InvalidOfferDuration error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
78
ghost/offers/test/lib/domain/models/OfferName.test.js
Normal file
78
ghost/offers/test/lib/domain/models/OfferName.test.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
const OfferName = require('../../../../lib/domain/models/OfferName');
|
||||
|
||||
describe('OfferName', function () {
|
||||
describe('OfferName.create factory', function () {
|
||||
it('Creates an Offer description containing a string', function () {
|
||||
OfferName.create('My Offer');
|
||||
|
||||
try {
|
||||
OfferName.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferName.InvalidOfferName,
|
||||
'expected an InvalidOfferName error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferName.create(null);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferName.InvalidOfferName,
|
||||
'expected an InvalidOfferName error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferName.create(12);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferName.InvalidOfferName,
|
||||
'expected an InvalidOfferName error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferName.create({});
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferName.InvalidOfferName,
|
||||
'expected an InvalidOfferName error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Requires the string to be a maximum of 191 characters', function () {
|
||||
const maxLengthInput = Array.from({length: 191}).map(() => 'a').join('');
|
||||
|
||||
should.equal(maxLengthInput.length, 191);
|
||||
|
||||
OfferName.create(maxLengthInput);
|
||||
|
||||
const tooLong = maxLengthInput + 'a';
|
||||
|
||||
should.equal(tooLong.length, 192);
|
||||
|
||||
try {
|
||||
OfferName.create(tooLong);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferName.InvalidOfferName,
|
||||
'expected an InvalidOfferName error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Trims the contents of the OfferName', function () {
|
||||
const description = OfferName.create(' Trim me! ');
|
||||
|
||||
should.equal(description.value, 'Trim me!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
31
ghost/offers/test/lib/domain/models/OfferStatus.test.js
Normal file
31
ghost/offers/test/lib/domain/models/OfferStatus.test.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const OfferStatus = require('../../../../lib/domain/models/OfferStatus');
|
||||
|
||||
describe('OfferStatus', function () {
|
||||
describe('OfferStatus.create factory', function () {
|
||||
it('Creates an Offer type containing either "active" or "archived"', function () {
|
||||
OfferStatus.create('active');
|
||||
OfferStatus.create('archived');
|
||||
|
||||
try {
|
||||
OfferStatus.create('other');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferStatus.InvalidOfferStatus,
|
||||
'expected an InvalidOfferStatus error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferStatus.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferStatus.InvalidOfferStatus,
|
||||
'expected an InvalidOfferStatus error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
62
ghost/offers/test/lib/domain/models/OfferTitle.test.js
Normal file
62
ghost/offers/test/lib/domain/models/OfferTitle.test.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
const OfferTitle = require('../../../../lib/domain/models/OfferTitle');
|
||||
|
||||
describe('OfferTitle', function () {
|
||||
describe('OfferTitle.create factory', function () {
|
||||
it('Creates an Offer description containing a string', function () {
|
||||
OfferTitle.create('Hello, world');
|
||||
|
||||
should.equal(OfferTitle.create().value, '');
|
||||
should.equal(OfferTitle.create(undefined).value, '');
|
||||
should.equal(OfferTitle.create(null).value, '');
|
||||
|
||||
try {
|
||||
OfferTitle.create(12);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferTitle.InvalidOfferTitle,
|
||||
'expected an InvalidOfferTitle error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferTitle.create({});
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferTitle.InvalidOfferTitle,
|
||||
'expected an InvalidOfferTitle error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Requires the string to be a maximum of 191 characters', function () {
|
||||
const maxLengthInput = Array.from({length: 191}).map(() => 'a').join('');
|
||||
|
||||
should.equal(maxLengthInput.length, 191);
|
||||
|
||||
OfferTitle.create(maxLengthInput);
|
||||
|
||||
const tooLong = maxLengthInput + 'a';
|
||||
|
||||
should.equal(tooLong.length, 192);
|
||||
|
||||
try {
|
||||
OfferTitle.create(tooLong);
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferTitle.InvalidOfferTitle,
|
||||
'expected an InvalidOfferTitle error'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Trims the contents of the OfferTitle', function () {
|
||||
const description = OfferTitle.create(' Trim me! ');
|
||||
|
||||
should.equal(description.value, 'Trim me!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
44
ghost/offers/test/lib/domain/models/OfferType.test.js
Normal file
44
ghost/offers/test/lib/domain/models/OfferType.test.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
const OfferType = require('../../../../lib/domain/models/OfferType');
|
||||
|
||||
describe('OfferType', function () {
|
||||
describe('OfferType.create factory', function () {
|
||||
it('Creates an Offer type containing either "fixed" or "percent"', function () {
|
||||
OfferType.create('fixed');
|
||||
OfferType.create('percent');
|
||||
|
||||
try {
|
||||
OfferType.create('other');
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferType.InvalidOfferType,
|
||||
'expected an InvalidOfferType error'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
OfferType.create();
|
||||
should.fail();
|
||||
} catch (err) {
|
||||
should.ok(
|
||||
err instanceof OfferType.InvalidOfferType,
|
||||
'expected an InvalidOfferType error'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('OfferType.Percentage', function () {
|
||||
it('Is an OfferType with a value of "percent"', function () {
|
||||
should.equal(OfferType.Percentage.value, 'percent');
|
||||
should.ok(OfferType.Percentage.equals(OfferType.create('percent')));
|
||||
});
|
||||
});
|
||||
|
||||
describe('OfferType.Fixed', function () {
|
||||
it('Is an OfferType with a value of "fixed"', function () {
|
||||
should.equal(OfferType.Fixed.value, 'fixed');
|
||||
should.ok(OfferType.Fixed.equals(OfferType.create('fixed')));
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue