Added initial tests for Offers

refs https://github.com/TryGhost/Team/issues/1198
This commit is contained in:
Fabien O'Carroll 2021-11-04 19:52:20 +02:00
parent 155d9b4f7d
commit 0b9c9968d0
22 changed files with 1079 additions and 7 deletions

View File

@ -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;

View File

@ -19,6 +19,8 @@ class OfferCadence extends ValueObject {
}
return new OfferCadence(cadence);
}
static InvalidOfferCadence = InvalidOfferCadence;
}
module.exports = OfferCadence;

View File

@ -23,6 +23,8 @@ class OfferCode extends ValueObject {
return new OfferCode(slugged);
}
static InvalidOfferCode = InvalidOfferCode;
}
module.exports = OfferCode;

View File

@ -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;

View File

@ -23,6 +23,8 @@ class OfferDescription extends ValueObject {
return new OfferDescription(description.trim());
}
static InvalidOfferDescription = InvalidOfferDescription;
}
module.exports = OfferDescription;

View File

@ -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;

View File

@ -17,8 +17,10 @@ class OfferName extends ValueObject {
});
}
return new OfferName(name);
return new OfferName(name.trim());
}
static InvalidOfferName = InvalidOfferName
}
module.exports = OfferName;

View File

@ -18,6 +18,8 @@ class OfferStatus extends ValueObject {
}
return new OfferStatus(status);
}
static InvalidOfferStatus = InvalidOfferStatus
}
module.exports = OfferStatus;

View File

@ -22,6 +22,8 @@ class OfferTitle extends ValueObject {
return new OfferTitle(title.trim());
}
static InvalidOfferTitle = InvalidOfferTitle;
}
module.exports = OfferTitle;

View File

@ -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')

View 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);
});
});
});

View 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);
});
});
});

View 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');
});
});
});

View 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');
});
});

View 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'
);
}
});
});
});

View 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));
});
});

View 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!');
});
});
});

View 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'
);
}
});
});
});

View 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!');
});
});
});

View 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'
);
}
});
});
});

View 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!');
});
});
});

View 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')));
});
});
});