Skip to content

Instantly share code, notes, and snippets.

@aemkei
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aemkei/892f83935a3c28bdcfdf to your computer and use it in GitHub Desktop.
Save aemkei/892f83935a3c28bdcfdf to your computer and use it in GitHub Desktop.
TDD Bin
// Item: Unit price Special Price
// it should return the price for a single item
// it shold fail it item does not exist
// it should sum up all prices
// it should apply special price (3 for 130) for A
// it should apply special price (2 for 45) for B
describe('cart should accept products', () => {
let cart;
beforeEach(function(){
cart = new Cart(checkout);
});
it('should be possible to add an item', () => {
cart.addProduct('a');
assert.equal(cart.size, 1);
})
it('should be possible to add more than one item', () => {
cart.addProduct('a');
cart.addProduct('b');
assert.equal(cart.size, 2);
})
it('should be possible to add multiple item of the same product', () => {
cart.addProduct('a', 3);
assert.equal(cart.size, 3);
assert.deepEqual(cart.items, ['a', 'a', 'a']);
})
});
describe('cart checkout', function() {
let cart;
beforeEach(function(){
cart = new Cart(checkout);
});
it('should return price', function() {
cart.addProduct('a');
assert.equal(cart.checkout(), 50)
})
})
describe('checkout process', function() {
describe('should return price', () => {
it ('50 for A', () =>
assert.equal(checkout('a'), 50)
);
it ('30 for B', () =>
assert.equal(checkout('b'), 30)
);
});
describe('should sum up', () => {
it ('A+B', () =>
assert.equal(checkout('a', 'b'), 80)
);
it ('A+A+C+C', () =>
assert.equal(checkout('a', 'a', 'b', 'c', 'c', 'd'), 185)
);
});
describe('sho uld apply special price', () => {
it ('if A+A+A', () =>
assert.equal(checkout('a', 'a', 'a'), 130)
);
it ('if B+B', () =>
assert.equal(checkout('b', 'b'), 45)
);
it ('if B+B + B', () =>
assert.equal(checkout('b', 'b', 'b'), 75)
);
it ('if B+B + B+B + B+B + B', () =>
assert.equal(checkout('b', 'b', 'b', 'b', 'b', 'b', 'b'), 165)
);
});
describe('should apply special price', () => {
describe('should be possible to mix', () => {
it('specials', () => {
assert.equal(checkout('a', 'a', 'a', 'b', 'b'), 175)
})
})
});
describe('should fail if', () => {
it ('item does not exist', () => {
assert.throws(() => checkout('e'), NotExistError)
});
it ('one item of many does not exist', () => {
assert.throws(() => checkout('a', 'e'), NotExistError)
});
it ('one item of many does not exist', () => {
assert.throws(() => checkout('c', 'e'), NotExistError)
});
});
});
class Product {
constructor(price, special){
this.price = price;
this.special = special;
}
}
const products = {
a: new Product(50, { count: 3, value: 130 }),
b: new Product(30, { count: 2, value: 45 }),
c: new Product(20),
d: new Product(15)
};
class Cart {
constructor (checkoutCallback) {
this.checkoutCallback = checkoutCallback;
this.items = [];
}
addProduct(productName, count=1){
while (count--) {
this.items.push(productName)
}
}
get size () {
return this.items.length;
}
checkout () {
return this.checkoutCallback(...this.items);
}
}
class NotExistError {}
class Checkout {
constructor (...items) {
this.items = items;
}
get sum () {
let sum = 0,
counts = this.count(this.items);
Object.keys(counts).forEach(key => {
const count = counts[key];
if (typeof products[key] == 'undefined'){
throw new NotExistError();
}
if (products[key].special){
sum += this.special(key, count);
} else {
sum += products[key].price * count;
}
});
return sum;
}
count(items){
let counter = {};
items.forEach(i => {
counter[i] = counter[i] || 0;
counter[i]++;
});
return counter; //items.length;
}
special(item, count) {
const special = products[item].special,
modulo = count % special.count;
count = Math.floor(count / special.count);
return special.value * count +
products[item].price * modulo;
}
}
function checkout(...items) {
return new Checkout(...items).sum;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment