Fixed same product - diff opts in cart. Added confirm on cart empty.
parent
799ed301f2
commit
5d4c469e38
|
@ -7244,6 +7244,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"object-hash": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.1.tgz",
|
||||
"integrity": "sha512-HgcGMooY4JC2PBt9sdUdJ6PMzpin+YtY3r/7wg0uTifP+HJWW8rammseSEHuyt0UeShI183UGssCJqm1bJR7QA=="
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz",
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
"node-cron": "^2.0.3",
|
||||
"nodemailer": "^4.7.0",
|
||||
"numeral": "^2.0.6",
|
||||
"object-hash": "^2.0.1",
|
||||
"paypal-rest-sdk": "^1.6.9",
|
||||
"rand-token": "^0.4.0",
|
||||
"rimraf": "^2.7.1",
|
||||
|
|
|
@ -377,15 +377,17 @@ $(document).ready(function (){
|
|||
}
|
||||
});
|
||||
|
||||
// On empty cart click
|
||||
$(document).on('click', '#empty-cart', function(e){
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '/product/emptycart'
|
||||
})
|
||||
.done(function(msg){
|
||||
showNotification(msg.message, 'success', true);
|
||||
updateCartDiv();
|
||||
$('#confirmModal').modal('show');
|
||||
$('#buttonConfirm').attr('data-func', 'emptyCart');
|
||||
});
|
||||
|
||||
$(document).on('click', '#buttonConfirm', function(e){
|
||||
// Get the function and run it
|
||||
var func = $(e.target).attr('data-func');
|
||||
window[func]();
|
||||
$('#confirmModal').modal('hide');
|
||||
});
|
||||
|
||||
$('.qty-btn-minus').on('click', function(){
|
||||
|
@ -449,7 +451,9 @@ function deleteFromCart(element){
|
|||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '/product/removefromcart',
|
||||
data: { productId: element.attr('data-id') }
|
||||
data: {
|
||||
cartId: element.attr('data-cartid')
|
||||
}
|
||||
})
|
||||
.done(function(msg){
|
||||
showNotification(msg.message, 'success');
|
||||
|
@ -476,6 +480,7 @@ function updateCart(element){
|
|||
method: 'POST',
|
||||
url: '/product/updatecart',
|
||||
data: {
|
||||
cartId: element.attr('data-cartid'),
|
||||
productId: element.attr('data-id'),
|
||||
quantity: element.val()
|
||||
}
|
||||
|
@ -596,14 +601,14 @@ function updateCartDiv(){
|
|||
<div class="input-group-prepend">
|
||||
<button class="btn btn-primary btn-qty-minus" type="button">-</button>
|
||||
</div>
|
||||
<input type="number" class="form-control cart-product-quantity text-center" id="${productId}-qty" data-id="${productId}" maxlength="2" value="${item.quantity}">
|
||||
<input type="number" class="form-control cart-product-quantity text-center" data-cartid="${productId}" data-id="${item.id}" maxlength="2" value="${item.quantity}">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary btn-qty-add" type="button">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 col-md-2 no-pad-left">
|
||||
<button class="btn btn-danger btn-delete-from-cart" data-id="${productId}" type="button"><i class="far fa-trash-alt" data-id="${productId}" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-danger btn-delete-from-cart" data-cartid="${productId}" type="button"><i class="far fa-trash-alt" data-cartid="${productId}" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<div class="col-8 col-md-4 align-self-center text-right">
|
||||
<strong class="my-auto">${result.currencySymbol}${productTotalAmount}</strong>
|
||||
|
@ -663,3 +668,15 @@ function upperFirst(value){
|
|||
return chr.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function emptyCart(){
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '/product/emptycart'
|
||||
})
|
||||
.done(function(msg){
|
||||
showNotification(msg.message, 'success', true);
|
||||
updateCartDiv();
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@
|
|||
width: 500px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: 9999;
|
||||
z-index: 999;
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
visibility: hidden;
|
||||
|
@ -80,7 +80,7 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9998;
|
||||
z-index: 998;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
-webkit-animation: fade 500ms;
|
||||
animation: fade 500ms;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*! Pushy - v1.0.0 - 2016-3-1
|
||||
* Pushy is a responsive off-canvas navigation menu using CSS transforms & transitions.
|
||||
* https://github.com/christophery/pushy/
|
||||
* by Christopher Yee */.pushy{position:fixed;width:500px;height:100%;top:0;z-index:9999;background:#fff;overflow:auto;visibility:hidden;-webkit-overflow-scrolling:touch}.pushy ul:first-child{margin-top:10px}.pushy.pushy-left{left:0}.pushy.pushy-right{right:0}.pushy-left{-webkit-transform:translate3d(-500px,0,0);-ms-transform:translate3d(-500px,0,0);transform:translate3d(-500px,0,0)}.pushy-open-left #container,.pushy-open-left .push{-webkit-transform:translate3d(500px,0,0);-ms-transform:translate3d(500px,0,0);transform:translate3d(500px,0,0)}.pushy-right{-webkit-transform:translate3d(500px,0,0);-ms-transform:translate3d(500px,0,0);transform:translate3d(500px,0,0)}.pushy-open-right #container,.pushy-open-right .push{-webkit-transform:translate3d(-500px,0,0);-ms-transform:translate3d(-500px,0,0);transform:translate3d(-500px,0,0)}.pushy-open-left .pushy,.pushy-open-right .pushy{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}#container,.push,.pushy{transition:transform .2s cubic-bezier(.16,.68,.43,.99)}.site-overlay{display:none}.pushy-open-left .site-overlay,.pushy-open-right .site-overlay{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:9998;background-color:rgba(0,0,0,.5);-webkit-animation:fade .5s;animation:fade .5s}@keyframes fade{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes fade{0%{opacity:0}100%{opacity:1}}.pushy-submenu ul{padding-left:15px;transition:max-height .2s ease-in-out}.pushy-submenu ul .pushy-link{transition:opacity .2s ease-in-out}.pushy-submenu>a{position:relative}.pushy-submenu>a::after{content:'';display:block;height:11px;width:8px;position:absolute;top:50%;right:15px;background:url(../img/arrow.svg) no-repeat;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);transition:transform .2s}.pushy-submenu-closed ul{max-height:0;overflow:hidden}.pushy-submenu-closed .pushy-link{opacity:0}.pushy-submenu-open ul{max-height:1000px}.pushy-submenu-open .pushy-link{opacity:1}.pushy-submenu-open a::after{-webkit-transform:translateY(-50%) rotate(90deg);-ms-transform:translateY(-50%) rotate(90deg);transform:translateY(-50%) rotate(90deg)}.no-csstransforms3d .pushy-submenu-closed ul{max-height:none;display:none}
|
||||
* by Christopher Yee */.pushy{position:fixed;width:500px;height:100%;top:0;z-index:999;background:#fff;overflow:auto;visibility:hidden;-webkit-overflow-scrolling:touch}.pushy ul:first-child{margin-top:10px}.pushy.pushy-left{left:0}.pushy.pushy-right{right:0}.pushy-left{-webkit-transform:translate3d(-500px,0,0);-ms-transform:translate3d(-500px,0,0);transform:translate3d(-500px,0,0)}.pushy-open-left #container,.pushy-open-left .push{-webkit-transform:translate3d(500px,0,0);-ms-transform:translate3d(500px,0,0);transform:translate3d(500px,0,0)}.pushy-right{-webkit-transform:translate3d(500px,0,0);-ms-transform:translate3d(500px,0,0);transform:translate3d(500px,0,0)}.pushy-open-right #container,.pushy-open-right .push{-webkit-transform:translate3d(-500px,0,0);-ms-transform:translate3d(-500px,0,0);transform:translate3d(-500px,0,0)}.pushy-open-left .pushy,.pushy-open-right .pushy{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}#container,.push,.pushy{transition:transform .2s cubic-bezier(.16,.68,.43,.99)}.site-overlay{display:none}.pushy-open-left .site-overlay,.pushy-open-right .site-overlay{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:998;background-color:rgba(0,0,0,.5);-webkit-animation:fade .5s;animation:fade .5s}@keyframes fade{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes fade{0%{opacity:0}100%{opacity:1}}.pushy-submenu ul{padding-left:15px;transition:max-height .2s ease-in-out}.pushy-submenu ul .pushy-link{transition:opacity .2s ease-in-out}.pushy-submenu>a{position:relative}.pushy-submenu>a::after{content:'';display:block;height:11px;width:8px;position:absolute;top:50%;right:15px;background:url(../img/arrow.svg) no-repeat;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);transition:transform .2s}.pushy-submenu-closed ul{max-height:0;overflow:hidden}.pushy-submenu-closed .pushy-link{opacity:0}.pushy-submenu-open ul{max-height:1000px}.pushy-submenu-open .pushy-link{opacity:1}.pushy-submenu-open a::after{-webkit-transform:translateY(-50%) rotate(90deg);-ms-transform:translateY(-50%) rotate(90deg);transform:translateY(-50%) rotate(90deg)}.no-csstransforms3d .pushy-submenu-closed ul{max-height:none;display:none}
|
|
@ -1,6 +1,7 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const colors = require('colors');
|
||||
const hash = require('object-hash');
|
||||
const moment = require('moment');
|
||||
const _ = require('lodash');
|
||||
const {
|
||||
|
@ -362,12 +363,12 @@ router.post('/product/updatecart', async (req, res, next) => {
|
|||
|
||||
if(productQuantity === 0){
|
||||
// quantity equals zero so we remove the item
|
||||
delete req.session.cart[cartItem.productId];
|
||||
delete req.session.cart[cartItem.cartId];
|
||||
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
|
||||
return;
|
||||
}
|
||||
|
||||
const product = await db.products.findOne({ _id: getId(cartItem.productId) });
|
||||
const product = await db.products.findOne({ _id: getId(req.session.cart[cartItem.cartId].productId) });
|
||||
if(!product){
|
||||
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
|
||||
return;
|
||||
|
@ -382,14 +383,14 @@ router.post('/product/updatecart', async (req, res, next) => {
|
|||
}
|
||||
|
||||
const productPrice = parseFloat(product.productPrice).toFixed(2);
|
||||
if(!req.session.cart[cartItem.productId]){
|
||||
if(!req.session.cart[cartItem.cartId]){
|
||||
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the cart
|
||||
req.session.cart[cartItem.productId].quantity = productQuantity;
|
||||
req.session.cart[cartItem.productId].totalItemPrice = productPrice * productQuantity;
|
||||
req.session.cart[cartItem.cartId].quantity = productQuantity;
|
||||
req.session.cart[cartItem.cartId].totalItemPrice = productPrice * productQuantity;
|
||||
|
||||
// update total cart amount
|
||||
await updateTotalCart(req, res);
|
||||
|
@ -410,12 +411,12 @@ router.post('/product/removefromcart', async (req, res, next) => {
|
|||
const db = req.app.db;
|
||||
|
||||
// Check for item in cart
|
||||
if(!req.session.cart[req.body.productId]){
|
||||
if(!req.session.cart[req.body.cartId]){
|
||||
return res.status(400).json({ message: 'Product not found in cart' });
|
||||
}
|
||||
|
||||
// remove item from cart
|
||||
delete req.session.cart[req.body.productId];
|
||||
delete req.session.cart[req.body.cartId];
|
||||
|
||||
// If not items in cart, empty it
|
||||
if(Object.keys(req.session.cart).length === 0){
|
||||
|
@ -535,19 +536,25 @@ router.post('/product/addtocart', async (req, res, next) => {
|
|||
}catch(ex){}
|
||||
}
|
||||
|
||||
// Product with options hash
|
||||
const productHash = hash({
|
||||
productId: product._id.toString(),
|
||||
options
|
||||
});
|
||||
|
||||
// if exists we add to the existing value
|
||||
let cartQuantity = 0;
|
||||
if(req.session.cart[product._id]){
|
||||
cartQuantity = parseInt(req.session.cart[product._id].quantity) + productQuantity;
|
||||
req.session.cart[product._id].quantity = cartQuantity;
|
||||
req.session.cart[product._id].totalItemPrice = productPrice * parseInt(req.session.cart[product._id].quantity);
|
||||
if(req.session.cart[productHash]){
|
||||
cartQuantity = parseInt(req.session.cart[productHash].quantity) + productQuantity;
|
||||
req.session.cart[productHash].quantity = cartQuantity;
|
||||
req.session.cart[productHash].totalItemPrice = productPrice * parseInt(req.session.cart[productHash].quantity);
|
||||
}else{
|
||||
// Set the card quantity
|
||||
cartQuantity = productQuantity;
|
||||
|
||||
// new product deets
|
||||
const productObj = {};
|
||||
productObj.productId = req.body.productId;
|
||||
productObj.productId = product._id;
|
||||
productObj.title = product.productTitle;
|
||||
productObj.quantity = productQuantity;
|
||||
productObj.totalItemPrice = productPrice * productQuantity;
|
||||
|
@ -562,7 +569,7 @@ router.post('/product/addtocart', async (req, res, next) => {
|
|||
}
|
||||
|
||||
// merge into the current cart
|
||||
req.session.cart[product._id] = productObj;
|
||||
req.session.cart[productHash] = productObj;
|
||||
}
|
||||
|
||||
// Update cart to the DB
|
||||
|
@ -580,7 +587,11 @@ router.post('/product/addtocart', async (req, res, next) => {
|
|||
req.session.cartSubscription = product.productSubscription;
|
||||
}
|
||||
|
||||
return res.status(200).json({ message: 'Cart successfully updated', totalCartItems: req.session.totalCartItems });
|
||||
return res.status(200).json({
|
||||
message: 'Cart successfully updated',
|
||||
cartId: productHash,
|
||||
totalCartItems: req.session.totalCartItems
|
||||
});
|
||||
});
|
||||
|
||||
// search products
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
import{ serial as test }from'ava';
|
||||
const {
|
||||
runBefore,
|
||||
g
|
||||
} = require('../helper');
|
||||
|
||||
test.before(async () => {
|
||||
await runBefore();
|
||||
});
|
||||
|
||||
test('[Success] Add subscripton product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[7]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(200);
|
||||
const sessions = await g.db.cart.find({}).toArray();
|
||||
if(!sessions || sessions.length === 0){
|
||||
t.fail();
|
||||
}
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
});
|
||||
|
||||
test('[Fail] Add product to cart when subscription already added', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[1]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[1].productOptions)
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Subscription already existing in cart. You cannot add more.');
|
||||
});
|
||||
|
||||
test('[Fail] Add quantity which exceeds the maxQuantity', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[4]._id,
|
||||
productQuantity: 75,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'The quantity exceeds the max amount. Please contact us for larger orders.');
|
||||
});
|
||||
|
||||
test('[Success] Empty cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/emptycart')
|
||||
.expect(200);
|
||||
t.deepEqual(res.body.message, 'Cart successfully emptied');
|
||||
});
|
||||
|
||||
test('[Success] Add product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[0]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[0].productOptions)
|
||||
})
|
||||
.expect(200);
|
||||
const sessions = await g.db.cart.find({}).toArray();
|
||||
if(!sessions || sessions.length === 0){
|
||||
t.fail();
|
||||
}
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
});
|
||||
|
||||
test('[Success] Update cart', async t => {
|
||||
const cart = await g.request
|
||||
.get('/cart/retrieve')
|
||||
.expect(200);
|
||||
|
||||
const cartId = Object.keys(cart.body.cart)[0];
|
||||
const productId = cart.body.cart[cartId].id;
|
||||
|
||||
const res = await g.request
|
||||
.post('/product/updatecart')
|
||||
.send({
|
||||
productId: productId,
|
||||
cartId: cartId,
|
||||
quantity: 10
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
|
||||
const checkCart = await g.request
|
||||
.get('/cart/retrieve')
|
||||
.expect(200);
|
||||
|
||||
// Check new quantity and total price has been updated
|
||||
t.deepEqual(checkCart.body.cart[cartId].quantity, 10);
|
||||
t.deepEqual(checkCart.body.cart[cartId].totalItemPrice, cart.body.cart[cartId].totalItemPrice * 10);
|
||||
});
|
||||
|
||||
test('[Fail] Cannot add subscripton when other product in cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[7]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'You cannot combine subscription products with existing in your cart. Empty your cart and try again.');
|
||||
});
|
||||
|
||||
test('[Fail] Add product to cart with not enough stock', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[0]._id,
|
||||
productQuantity: 20,
|
||||
productOptions: JSON.stringify(g.products[0].productOptions)
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'There is insufficient stock of this product.');
|
||||
});
|
||||
|
||||
test('[Fail] Add incorrect product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: 'fake_product_id',
|
||||
productQuantity: 20,
|
||||
productOptions: JSON.stringify(g.products[0].productOptions)
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Error updating cart. Please try again.');
|
||||
});
|
||||
|
||||
test('[Success] Remove item previously added to cart', async t => {
|
||||
// Add a second product to cart
|
||||
const cart = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[1]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[1].productOptions)
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const res = await g.request
|
||||
.post('/product/removefromcart')
|
||||
.send({
|
||||
cartId: cart.body.cartId
|
||||
})
|
||||
.expect(200);
|
||||
t.deepEqual(res.body.message, 'Product successfully removed');
|
||||
});
|
||||
|
||||
test('[Fail] Try remove an item which is not in the cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/removefromcart')
|
||||
.send({
|
||||
cartId: 'bogus_product_id'
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Product not found in cart');
|
||||
});
|
|
@ -19,160 +19,6 @@ test('[Success] Get products JSON', async t => {
|
|||
}
|
||||
});
|
||||
|
||||
test('[Success] Add subscripton product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[7]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(200);
|
||||
const sessions = await g.db.cart.find({}).toArray();
|
||||
if(!sessions || sessions.length === 0){
|
||||
t.fail();
|
||||
}
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
});
|
||||
|
||||
test('[Fail] Add product to cart when subscription already added', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[1]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[1].productOptions)
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Subscription already existing in cart. You cannot add more.');
|
||||
});
|
||||
|
||||
test('[Fail] Add quantity which exceeds the maxQuantity', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[4]._id,
|
||||
productQuantity: 75,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'The quantity exceeds the max amount. Please contact us for larger orders.');
|
||||
});
|
||||
|
||||
test('[Success] Empty cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/emptycart')
|
||||
.expect(200);
|
||||
t.deepEqual(res.body.message, 'Cart successfully emptied');
|
||||
});
|
||||
|
||||
test('[Success] Add product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[0]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[0].productOptions)
|
||||
})
|
||||
.expect(200);
|
||||
const sessions = await g.db.cart.find({}).toArray();
|
||||
if(!sessions || sessions.length === 0){
|
||||
t.fail();
|
||||
}
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
});
|
||||
|
||||
test('[Success] Update cart', async t => {
|
||||
const cart = await g.request
|
||||
.get('/cart/retrieve')
|
||||
.expect(200);
|
||||
|
||||
const productId = g.products[0]._id;
|
||||
|
||||
const res = await g.request
|
||||
.post('/product/updatecart')
|
||||
.send({
|
||||
productId: productId,
|
||||
quantity: 10
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
t.deepEqual(res.body.message, 'Cart successfully updated');
|
||||
|
||||
const checkCart = await g.request
|
||||
.get('/cart/retrieve')
|
||||
.expect(200);
|
||||
|
||||
// Check new quantity and total price has been updated
|
||||
t.deepEqual(checkCart.body.cart[productId].quantity, 10);
|
||||
t.deepEqual(checkCart.body.cart[productId].totalItemPrice, cart.body.cart[productId].totalItemPrice * 10);
|
||||
});
|
||||
|
||||
test('[Fail] Cannot add subscripton when other product in cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[7]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: {}
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'You cannot combine subscription products with existing in your cart. Empty your cart and try again.');
|
||||
});
|
||||
|
||||
test('[Fail] Add product to cart with not enough stock', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[0]._id,
|
||||
productQuantity: 20,
|
||||
productOptions: JSON.stringify(g.products[0].productOptions)
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'There is insufficient stock of this product.');
|
||||
});
|
||||
|
||||
test('[Fail] Add incorrect product to cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
id: 'fake_product_id',
|
||||
state: false
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Error updating cart. Please try again.');
|
||||
});
|
||||
|
||||
test('[Success] Remove item previously added to cart', async t => {
|
||||
// Add a second product to cart
|
||||
await g.request
|
||||
.post('/product/addtocart')
|
||||
.send({
|
||||
productId: g.products[1]._id,
|
||||
productQuantity: 1,
|
||||
productOptions: JSON.stringify(g.products[1].productOptions)
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const res = await g.request
|
||||
.post('/product/removefromcart')
|
||||
.send({
|
||||
productId: g.products[0]._id
|
||||
})
|
||||
.expect(200);
|
||||
t.deepEqual(res.body.message, 'Product successfully removed');
|
||||
});
|
||||
|
||||
test('[Fail] Try remove an item which is not in the cart', async t => {
|
||||
const res = await g.request
|
||||
.post('/product/removefromcart')
|
||||
.send({
|
||||
cartId: 'bogus_product_id'
|
||||
})
|
||||
.expect(400);
|
||||
t.deepEqual(res.body.message, 'Product not found in cart');
|
||||
});
|
||||
|
||||
test('[Success] Search products', async t => {
|
||||
const res = await g.request
|
||||
.get('/category/backpack?json=true')
|
||||
|
|
|
@ -208,5 +208,6 @@
|
|||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{> partials/confirmModal}}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<div class="modal fade" id="confirmModal" tabindex="-1" role="dialog" aria-labelledby="confirmModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title text-danger" id="confirmModalLabel">Confirm</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure you want to proceed?
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary mr-auto" data-dismiss="modal">Close</button>
|
||||
<button type="button" id="buttonConfirm" class="btn btn-danger">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -31,14 +31,14 @@
|
|||
<div class="input-group-prepend">
|
||||
<button class="btn btn-primary btn-qty-minus" type="button">-</button>
|
||||
</div>
|
||||
<input type="number" class="form-control cart-product-quantity text-center" id="{{../this.productId}}-qty" data-id="{{../this.productId}}" maxlength="2" value="{{../this.quantity}}">
|
||||
<input type="number" class="form-control cart-product-quantity text-center" data-cartid="{{../this.productId}}" data-id="{{../this.id}}" maxlength="2" value="{{../this.quantity}}">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary btn-qty-add" type="button">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 col-md-2 no-pad-left">
|
||||
<button class="btn btn-danger btn-delete-from-cart" data-id="{{../this.productId}}" type="button"><i class="far fa-trash-alt" data-id="{{../this.productId}}" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-danger btn-delete-from-cart" data-id="{{../this.productId}}" data-cartid="{{../this.productId}}" type="button"><i class="far fa-trash-alt" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12 col-md-8 no-pad-left mb-2"></div>
|
||||
|
|
Loading…
Reference in New Issue