@balena/balena-pricing
Version:
Balena pricing/savings calculators
900 lines • 50.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const src_1 = require("../src");
const dynamicPriceCents = 200;
const FEATURE_SLUG = 'foo:bar';
const now = Date.now();
const TEST_CREDITS = {
'foo:bar': [
{
version: 1,
validFrom: new Date(now - 60 * 60 * 2),
firstDiscountPriceCents: 148,
discountRate: 0.33,
discountThreshold: 12000,
discountThresholdPriceCents: 124,
},
{
version: 2,
validFrom: new Date(now - 60 * 60),
firstDiscountPriceCents: 199,
discountRate: 0.33,
discountThreshold: 12000,
discountThresholdPriceCents: 150,
},
{
version: 3,
validFrom: new Date(Date.now() + 60 * 60),
firstDiscountPriceCents: 209,
discountRate: 0.33,
discountThreshold: 12000,
discountThresholdPriceCents: 149,
},
],
'buz:baz': [
{
version: 1,
validFrom: new Date(now + 60 * 60),
firstDiscountPriceCents: 189,
discountRate: 0.33,
discountThreshold: 12000,
discountThresholdPriceCents: 149,
},
],
};
const pricing = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
const testCredit = TEST_CREDITS['foo:bar'][1];
const dollar = Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
/**
* Convert pennies to dollar format
* @param pennies - amount of pennies
* @returns price in dollar format
*
* @example
* const price = toDollar(149); // -> $1.49
*/
function toDollar(pennies) {
return dollar.format(pennies / 100);
}
describe('Instantiation', function () {
let instance;
it('should use passed in credit pricing', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
(0, chai_1.expect)(instance.credits).to.deep.equal(TEST_CREDITS);
});
it('should sort credit pricing definitions', function () {
instance = new src_1.CreditPricing({
credits: {
'foo:bar': [
{
version: 2,
validFrom: new Date(now),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
{
version: 3,
validFrom: new Date(now + 60 * 60),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
{
version: 1,
validFrom: new Date(now - 60 * 60),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
],
},
});
(0, chai_1.expect)(instance.credits['foo:bar'][0].version).to.equal(3);
(0, chai_1.expect)(instance.credits['foo:bar'][1].version).to.equal(2);
(0, chai_1.expect)(instance.credits['foo:bar'][2].version).to.equal(1);
});
it('should use default credit pricing if instance not specified', function () {
instance = new src_1.CreditPricing();
(0, chai_1.expect)(Object.keys(instance.credits)).to.include('device:microservices');
});
it('should throw on feature definitions with duplicate versions', function () {
(0, chai_1.expect)(() => {
instance = new src_1.CreditPricing({
credits: {
'foo:bar': [
{
version: 1,
validFrom: new Date(),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
{
version: 1,
validFrom: new Date(now - 60 * 60),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
],
},
});
}).to.throw('Duplicate version 1 for feature foo:bar');
});
it('should throw on feature definitions with duplicate validFroms', function () {
(0, chai_1.expect)(() => {
instance = new src_1.CreditPricing({
credits: {
'foo:bar': [
{
version: 1,
validFrom: new Date(now),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
{
version: 2,
validFrom: new Date(now),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
],
},
});
}).to.throw(`Duplicate validFrom ${new Date(now).toISOString()} for feature foo:bar`);
});
});
describe('getDefinition()', function () {
let instance;
it('should return latest version when target option is "latest"', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'latest',
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 3);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.have.property('version', 1);
});
it('should return current version when no target option is "current"', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 2);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.be.undefined;
});
it('should return current version when no target option is set', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 2);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.be.undefined;
});
it('should return specific version when target option is a number', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 1,
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 1);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.have.property('version', 1);
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 2,
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 2);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.be.undefined;
});
it('should return version valid up to given date when target option is a date', function () {
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now),
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 2);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.be.undefined;
instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now + 60 * 60 * 24),
});
(0, chai_1.expect)(instance.getDefinition('foo:bar')).to.have.property('version', 3);
(0, chai_1.expect)(instance.getDefinition('buz:baz')).to.have.property('version', 1);
});
it('should throw on undefined feature slug', function () {
(0, chai_1.expect)(() => {
instance = new src_1.CreditPricing({
credits: {
'foo:bar': [
{
version: 1,
validFrom: new Date(now),
firstDiscountPriceCents: 1,
discountRate: 0.1,
discountThreshold: 1,
discountThresholdPriceCents: 1,
},
],
},
});
instance.getDefinition('buz:baz');
}).to.throw('Feature buz:baz not supported for credits');
});
});
describe('getCreditRange()', function () {
it('should throw on invalid feature slug', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange('buz-bar', testCredit.firstDiscountPriceCents - 1);
}).to.throw('Feature buz-bar not supported for credits');
});
it('should throw on non-integer available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, testCredit.firstDiscountPriceCents - 1, NaN);
}).to.throw('Available credits must be a whole number');
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, testCredit.firstDiscountPriceCents - 1, 10.5);
}).to.throw('Available credits must be a whole number');
});
it('should throw on negative available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, testCredit.firstDiscountPriceCents - 1, -1);
}).to.throw('Available credits must be greater than or equal to 0');
});
it('should throw on non-integer unit cost', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, NaN);
}).to.throw('Unit cost must be a whole number');
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, 10.5);
}).to.throw('Unit cost must be a whole number');
});
it('should throw on negative unit cost', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, -1);
}).to.throw('Unit cost must be greater than 0');
});
it('should throw on 0 unit cost', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, 0);
}).to.throw('Unit cost must be greater than 0');
});
it('should throw on too high unit cost', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, testCredit.firstDiscountPriceCents + 1);
}).to.throw(`Unit cost cannot be greater than ${testCredit.firstDiscountPriceCents}`);
});
it('should throw when requested unit cost is too high after accounting for available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditRange(FEATURE_SLUG, testCredit.firstDiscountPriceCents, testCredit.discountThreshold * 2);
}).to.throw('Requested unit cost is too high');
});
[
{
description: 'when available credits are 0',
availableCredits: 0,
from: testCredit.firstDiscountPriceCents,
},
{
description: 'when available credits are at the aggressive discount threshold',
availableCredits: testCredit.discountThreshold,
from: testCredit.discountThresholdPriceCents,
},
].forEach(({ description, availableCredits, from }) => {
describe(description, function () {
for (let unitCost = from; unitCost >= 1; unitCost--) {
it(`should return correct credit bounds for ${unitCost} unit cost`, function () {
// Generate a credit range for the given unit cost,
// then check that the returned range numbers are exactly
// on the border between the higher and lower unit costs.
const creditRange = pricing.getCreditRange(FEATURE_SLUG, unitCost, availableCredits);
if (creditRange.from) {
(0, chai_1.expect)(unitCost).to.eq(pricing.getCreditPrice(FEATURE_SLUG, availableCredits, creditRange.from));
if (unitCost === testCredit.firstDiscountPriceCents) {
(0, chai_1.expect)(creditRange.from).to.eq(1);
}
else {
(0, chai_1.expect)(unitCost + 1).to.eq(pricing.getCreditPrice(FEATURE_SLUG, availableCredits, creditRange.from - 1));
}
}
if (creditRange.to) {
(0, chai_1.expect)(unitCost).to.eq(pricing.getCreditPrice(FEATURE_SLUG, availableCredits, creditRange.to));
(0, chai_1.expect)(unitCost - 1).to.eq(pricing.getCreditPrice(FEATURE_SLUG, availableCredits, creditRange.to + 1));
}
});
}
});
});
});
describe('getCreditPrice()', function () {
it('should throw on invalid feature slug', function () {
(0, chai_1.expect)(() => {
pricing.getCreditPrice('buz-bar', 0, 1);
}).to.throw('Feature buz-bar not supported for credits');
});
it('should throw on non-integer available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, NaN, 0);
}).to.throw('Available credits must be a whole number');
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, 10.5, 0);
}).to.throw('Available credits must be a whole number');
});
it('should throw on negative available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, -1, 0);
}).to.throw('Available credits must be greater than or equal to 0');
});
it('should throw on non-integer purchase amount', function () {
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, 0, NaN);
}).to.throw('Credit purchase amount must be a whole number');
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, 0, 10.5);
}).to.throw('Credit purchase amount must be a whole number');
});
it('should throw on negative purchase amount', function () {
(0, chai_1.expect)(() => {
pricing.getCreditPrice(FEATURE_SLUG, 0, -1);
}).to.throw('Credit purchase amount must be greater than 0');
});
describe('should respect constructor target options', function () {
it('should calculate using "current" version by default', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.99');
});
it('should calculate using "current" version by when target is "current"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.99');
});
it('should calculate using "latest" version by when target is "latest"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'latest',
});
// Should be using version 3 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$2.09');
});
it('should calculate using specified version by when target is a number', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 1,
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.48');
});
it('should calculate using version valid up to given date by when target is a date', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now - 60 * 60 * 2),
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.48');
});
});
describe('when available credits are 0', function () {
it('should throw when purchase amount is 0', function () {
(0, chai_1.expect)(() => toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 0))).to.throw('Credit purchase amount must be greater than 0');
});
it('should calculate price of a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.99');
});
it('should calculate price of 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1.95');
});
it('should calculate price of 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1000000))).to.equal('$0.70');
});
it('should calculate price of 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1050000))).to.equal('$0.69');
});
it('should calculate price of 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1160000))).to.equal('$0.68');
});
it('should calculate price of 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1280000))).to.equal('$0.67');
});
it('should calculate price of 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1420000))).to.equal('$0.65');
});
it('should calculate price of 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1580000))).to.equal('$0.64');
});
it('should calculate price of 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1760000))).to.equal('$0.63');
});
it('should calculate price of 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 1970000))).to.equal('$0.62');
});
it('should calculate price of 2,200,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 2200000))).to.equal('$0.61');
});
it('should calculate price of 2,470,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, 0, 2470000))).to.equal('$0.59');
});
});
describe('when available credits are at the aggressive discount threshold', function () {
it('should throw when purchase amount is 0', function () {
(0, chai_1.expect)(() => toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 0))).to.throw('Credit purchase amount must be greater than 0');
});
it('should calculate price of a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1))).to.equal('$1.50');
});
it('should calculate price of 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1000))).to.equal('$1.48');
});
it('should calculate price of 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1000000))).to.equal('$0.69');
});
it('should calculate price of 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1050000))).to.equal('$0.69');
});
it('should calculate price of 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1160000))).to.equal('$0.68');
});
it('should calculate price of 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1280000))).to.equal('$0.66');
});
it('should calculate price of 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1420000))).to.equal('$0.65');
});
it('should calculate price of 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1580000))).to.equal('$0.64');
});
it('should calculate price of 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1760000))).to.equal('$0.63');
});
it('should calculate price of 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 1970000))).to.equal('$0.62');
});
it('should calculate price of 2,200,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 2200000))).to.equal('$0.61');
});
it('should calculate price of 2,470,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditPrice(FEATURE_SLUG, testCredit.discountThreshold, 2470000))).to.equal('$0.59');
});
});
});
describe('getCreditTotalPrice()', function () {
it('should throw on invalid feature slug', function () {
(0, chai_1.expect)(() => {
pricing.getCreditTotalPrice('buz-bar', 0, 1);
}).to.throw('Feature buz-bar not supported for credits');
});
it('should throw on negative available credits', function () {
(0, chai_1.expect)(() => {
pricing.getCreditTotalPrice(FEATURE_SLUG, -1, 0);
}).to.throw('Available credits must be greater than or equal to 0');
});
it('should throw on negative purchase amount', function () {
(0, chai_1.expect)(() => {
pricing.getCreditTotalPrice(FEATURE_SLUG, 0, -1);
}).to.throw('Credit purchase amount must be greater than 0');
});
describe('should respect constructor target options', function () {
it('should calculate using "current" version by default', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1,950.00');
});
it('should calculate using "current" version by when target is "current"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1,950.00');
});
it('should calculate using "latest" version by when target is "latest"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'latest',
});
// Should be using version 3 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$2,040.00');
});
it('should calculate using specified version by when target is a number', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 1,
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1,460.00');
});
it('should calculate using version valid up to given date by when target is a date', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now - 60 * 60 * 2),
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1,460.00');
});
});
describe('when available credits are 0', function () {
it('should throw when credit total is 0', function () {
(0, chai_1.expect)(() => toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 0))).to.throw('Credit purchase amount must be greater than 0');
});
it('should calculate price of a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1))).to.equal('$1.99');
});
it('should calculate price of 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1000))).to.equal('$1,950.00');
});
it('should calculate price of 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1000000))).to.equal('$700,000.00');
});
it('should calculate price of 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1050000))).to.equal('$724,500.00');
});
it('should calculate price of 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1160000))).to.equal('$788,800.00');
});
it('should calculate price of 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1280000))).to.equal('$857,600.00');
});
it('should calculate price of 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1420000))).to.equal('$923,000.00');
});
it('should calculate price of 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1580000))).to.equal('$1,011,200.00');
});
it('should calculate price of 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1760000))).to.equal('$1,108,800.00');
});
it('should calculate price of 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 1970000))).to.equal('$1,221,400.00');
});
it('should calculate price of 2,200,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 2200000))).to.equal('$1,342,000.00');
});
it('should calculate price of 2,470,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, 0, 2470000))).to.equal('$1,457,300.00');
});
});
describe('when available credits are at the aggressive discount threshold', function () {
it('should throw when purchase amount is 0', function () {
(0, chai_1.expect)(() => toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 0))).to.throw('Credit purchase amount must be greater than 0');
});
it('should calculate price of a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1))).to.equal('$1.50');
});
it('should calculate price of 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1000))).to.equal('$1,480.00');
});
it('should calculate price of 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1000000))).to.equal('$690,000.00');
});
it('should calculate price of 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1050000))).to.equal('$724,500.00');
});
it('should calculate price of 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1160000))).to.equal('$788,800.00');
});
it('should calculate price of 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1280000))).to.equal('$844,800.00');
});
it('should calculate price of 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1420000))).to.equal('$923,000.00');
});
it('should calculate price of 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1580000))).to.equal('$1,011,200.00');
});
it('should calculate price of 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1760000))).to.equal('$1,108,800.00');
});
it('should calculate price of 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 1970000))).to.equal('$1,221,400.00');
});
it('should calculate price of 2,200,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 2200000))).to.equal('$1,342,000.00');
});
it('should calculate price of 2,470,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getCreditTotalPrice(FEATURE_SLUG, testCredit.discountThreshold, 2470000))).to.equal('$1,457,300.00');
});
});
it('should be monotonically increasing until it throws an exception when the the max credits cap is reached ', function () {
let lastResult;
let i = 1;
let error;
try {
for (; i < 20; i++) {
const creditsToBuy = 10 ** i / 2;
const currentCredits = creditsToBuy;
const result = pricing.getCreditTotalPrice(FEATURE_SLUG, currentCredits, creditsToBuy);
if (lastResult != null) {
(0, chai_1.expect)(result).to.be.greaterThan(lastResult);
}
lastResult = result;
}
}
catch (err) {
error = err;
}
(0, chai_1.expect)(10 ** i).to.be.greaterThan(1_000_000_000_000); // A trillion
(0, chai_1.expect)(error)
.to.be.an.instanceof(src_1.InvalidParametersError)
.that.has.property('message', 'The provided quantity surpasses the maximum supported amount of credits');
});
});
describe('getDiscountOverDynamic()', function () {
it('should throw on invalid feature slug', function () {
(0, chai_1.expect)(() => {
pricing.getDiscountOverDynamic('buz-bar', 0, 1, dynamicPriceCents);
}).to.throw('Feature buz-bar not supported for credits');
});
it('should throw on negative available credits', function () {
(0, chai_1.expect)(() => {
pricing.getDiscountOverDynamic(FEATURE_SLUG, -1, 0, dynamicPriceCents);
}).to.throw('Available credits must be greater than or equal to 0');
});
it('should throw on negative purchase amount', function () {
(0, chai_1.expect)(() => {
pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, -1, dynamicPriceCents);
}).to.throw('Credit purchase amount must be greater than 0');
});
describe('should respect constructor target options', function () {
it('should calculate using "current" version by default', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
// Should be using version 2 in this case.
(0, chai_1.expect)(`${instance.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('3%');
});
it('should calculate using "current" version by when target is "current"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
// Should be using version 2 in this case.
(0, chai_1.expect)(`${instance.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('3%');
});
it('should calculate using "latest" version by when target is "latest"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'latest',
});
// Should be using version 3 in this case.
(0, chai_1.expect)(`${instance.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('-2%');
});
it('should calculate using specified version by when target is a number', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 1,
});
// Should be using version 1 in this case.
(0, chai_1.expect)(`${instance.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('27%');
});
it('should calculate using version valid up to given date by when target is a date', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now - 60 * 60 * 2),
});
// Should be using version 1 in this case.
(0, chai_1.expect)(`${instance.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('27%');
});
});
describe('when available credits are 0', function () {
it('should calculate discount for a single credit', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1, dynamicPriceCents)}%`).to.equal('1%');
});
it('should calculate discount for 1000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000, dynamicPriceCents)}%`).to.equal('3%');
});
it('should calculate price of 1,000,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1000000, dynamicPriceCents)}%`).to.equal('65%');
});
it('should calculate price of 1,050,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1050000, dynamicPriceCents)}%`).to.equal('66%');
});
it('should calculate price of 1,160,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1160000, dynamicPriceCents)}%`).to.equal('66%');
});
it('should calculate price of 1,280,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1280000, dynamicPriceCents)}%`).to.equal('67%');
});
it('should calculate price of 1,420,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1420000, dynamicPriceCents)}%`).to.equal('68%');
});
it('should calculate price of 1,580,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1580000, dynamicPriceCents)}%`).to.equal('68%');
});
it('should calculate price of 1,760,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1760000, dynamicPriceCents)}%`).to.equal('69%');
});
it('should calculate price of 1,970,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 1970000, dynamicPriceCents)}%`).to.equal('69%');
});
it('should calculate price of 2,200,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 2200000, dynamicPriceCents)}%`).to.equal('70%');
});
it('should calculate price of 2,470,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, 0, 2470000, dynamicPriceCents)}%`).to.equal('71%');
});
});
describe('when available credits are at the aggressive discount threshold', function () {
it('should calculate discount for a single credit', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1, dynamicPriceCents)}%`).to.equal('25%');
});
it('should calculate discount for 1000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1000, dynamicPriceCents)}%`).to.equal('26%');
});
it('should calculate discount for 1,000,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1000000, dynamicPriceCents)}%`).to.equal('66%');
});
it('should calculate discount for 1,050,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1050000, dynamicPriceCents)}%`).to.equal('66%');
});
it('should calculate discount for 1,160,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1160000, dynamicPriceCents)}%`).to.equal('66%');
});
it('should calculate discount for 1,280,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1280000, dynamicPriceCents)}%`).to.equal('67%');
});
it('should calculate discount for 1,420,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1420000, dynamicPriceCents)}%`).to.equal('68%');
});
it('should calculate discount for 1,580,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1580000, dynamicPriceCents)}%`).to.equal('68%');
});
it('should calculate discount for 1,760,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1760000, dynamicPriceCents)}%`).to.equal('69%');
});
it('should calculate discount for 1,970,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 1970000, dynamicPriceCents)}%`).to.equal('69%');
});
it('should calculate discount for 2,200,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 2200000, dynamicPriceCents)}%`).to.equal('70%');
});
it('should calculate discount for 2,470,000 credits', function () {
(0, chai_1.expect)(`${pricing.getDiscountOverDynamic(FEATURE_SLUG, testCredit.discountThreshold, 2470000, dynamicPriceCents)}%`).to.equal('71%');
});
});
});
describe('getTotalSavings()', function () {
it('should throw on invalid feature slug', function () {
(0, chai_1.expect)(() => {
pricing.getTotalSavings('buz-bar', 0, 1, dynamicPriceCents);
}).to.throw('Feature buz-bar not supported for credits');
});
it('should throw on negative available credits', function () {
(0, chai_1.expect)(() => {
pricing.getTotalSavings(FEATURE_SLUG, -1, 0, dynamicPriceCents);
}).to.throw('Available credits must be greater than or equal to 0');
});
it('should throw on negative purchase amount', function () {
(0, chai_1.expect)(() => {
pricing.getTotalSavings(FEATURE_SLUG, 0, -1, dynamicPriceCents);
}).to.throw('Credit purchase amount must be greater than 0');
});
describe('should respect constructor target options', function () {
it('should calculate using "current" version by default', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('$50.00');
});
it('should calculate using "current" version by when target is "current"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'current',
});
// Should be using version 2 in this case.
(0, chai_1.expect)(toDollar(instance.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('$50.00');
});
it('should calculate using "latest" version by when target is "latest"', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 'latest',
});
// Should be using version 3 in this case.
(0, chai_1.expect)(toDollar(instance.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('-$40.00');
});
it('should calculate using specified version by when target is a number', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: 1,
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('$540.00');
});
it('should calculate using version valid up to given date by when target is a date', function () {
const instance = new src_1.CreditPricing({
credits: TEST_CREDITS,
target: new Date(now - 60 * 60 * 2),
});
// Should be using version 1 in this case.
(0, chai_1.expect)(toDollar(instance.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('$540.00');
});
});
describe('when available credits are 0', function () {
it('should calculate total savings for a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1, dynamicPriceCents))).to.equal('$0.01');
});
it('should calculate total savings for 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1000, dynamicPriceCents))).to.equal('$50.00');
});
it('should calculate total savings for 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1000000, dynamicPriceCents))).to.equal('$1,300,000.00');
});
it('should calculate total savings for 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1050000, dynamicPriceCents))).to.equal('$1,375,500.00');
});
it('should calculate total savings for 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1160000, dynamicPriceCents))).to.equal('$1,531,200.00');
});
it('should calculate total savings for 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1280000, dynamicPriceCents))).to.equal('$1,702,400.00');
});
it('should calculate total savings for 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1420000, dynamicPriceCents))).to.equal('$1,917,000.00');
});
it('should calculate total savings for 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1580000, dynamicPriceCents))).to.equal('$2,148,800.00');
});
it('should calculate total savings for 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1760000, dynamicPriceCents))).to.equal('$2,411,200.00');
});
it('should calculate total savings for 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 1970000, dynamicPriceCents))).to.equal('$2,718,600.00');
});
it('should calculate total savings for 2,200,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 2200000, dynamicPriceCents))).to.equal('$3,058,000.00');
});
it('should calculate total savings for 2,470,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, 0, 2470000, dynamicPriceCents))).to.equal('$3,482,700.00');
});
});
describe('when available credits are at the aggressive discount threshold', function () {
it('should calculate total savings for a single credit', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1, dynamicPriceCents))).to.equal('$0.50');
});
it('should calculate total savings for 1000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1000, dynamicPriceCents))).to.equal('$520.00');
});
it('should calculate total savings for 1,000,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1000000, dynamicPriceCents))).to.equal('$1,310,000.00');
});
it('should calculate total savings for 1,050,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1050000, dynamicPriceCents))).to.equal('$1,375,500.00');
});
it('should calculate total savings for 1,160,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1160000, dynamicPriceCents))).to.equal('$1,531,200.00');
});
it('should calculate total savings for 1,280,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1280000, dynamicPriceCents))).to.equal('$1,715,200.00');
});
it('should calculate total savings for 1,420,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1420000, dynamicPriceCents))).to.equal('$1,917,000.00');
});
it('should calculate total savings for 1,580,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1580000, dynamicPriceCents))).to.equal('$2,148,800.00');
});
it('should calculate total savings for 1,760,000 credits', function () {
(0, chai_1.expect)(toDollar(pricing.getTotalSavings(FEATURE_SLUG, testCredit.discountThreshold, 1760000, dynamicPriceCents))).to.equal('$2,411,200.00');
});
it('should calculate total savings for 1,970,000 credits', function () {
(0, chai_1.expect)(toDollar(p