From fa7f19642b62dae753322adfa1d0dca9ee051a0c Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 3 Jun 2022 16:57:40 -0400 Subject: [PATCH 01/31] without stripe --- .../.netlify/edge-functions-import-map.json | 1 + .../functions/addToCart/addToCart.js | 23 ++++ .../functions/checkout/checkout.js | 31 +++++ .../functions/getCart/getCart.js | 15 ++ .../functions/getProducts/getProducts.js | 14 ++ .../removeFromCart/removeFromCart.js | 19 +++ examples/netlify-functions/models.js | 128 ++++++++++++++++++ 7 files changed, 231 insertions(+) create mode 100644 examples/netlify-functions/.netlify/edge-functions-import-map.json create mode 100644 examples/netlify-functions/functions/addToCart/addToCart.js create mode 100644 examples/netlify-functions/functions/checkout/checkout.js create mode 100644 examples/netlify-functions/functions/getCart/getCart.js create mode 100644 examples/netlify-functions/functions/getProducts/getProducts.js create mode 100644 examples/netlify-functions/functions/removeFromCart/removeFromCart.js create mode 100644 examples/netlify-functions/models.js diff --git a/examples/netlify-functions/.netlify/edge-functions-import-map.json b/examples/netlify-functions/.netlify/edge-functions-import-map.json new file mode 100644 index 00000000000..aee80cf31b4 --- /dev/null +++ b/examples/netlify-functions/.netlify/edge-functions-import-map.json @@ -0,0 +1 @@ +{"imports":{"netlify:edge":"https://edge-bootstrap.netlify.app/v1/index.ts"}} \ No newline at end of file diff --git a/examples/netlify-functions/functions/addToCart/addToCart.js b/examples/netlify-functions/functions/addToCart/addToCart.js new file mode 100644 index 00000000000..cd9c1c2eb6a --- /dev/null +++ b/examples/netlify-functions/functions/addToCart/addToCart.js @@ -0,0 +1,23 @@ +'use strict'; + +const { Cart } = require('../../models'); + +const handler = async(event) => { + try { + if (event.body.cartId) { + // get the document containing the specified cartId + const cart = await Cart.findOne({ _id: event.body.cartId }); + cart.products.push(event.body.product); + await cart.save(); + return { statusCode: 500, body: cart }; + } else { + // If no cartId, create a new cart + const cart = await Cart.create({ products: event.body.product }); + return { statusCode: 500, body: cart }; + } + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/checkout/checkout.js b/examples/netlify-functions/functions/checkout/checkout.js new file mode 100644 index 00000000000..595e98d7e60 --- /dev/null +++ b/examples/netlify-functions/functions/checkout/checkout.js @@ -0,0 +1,31 @@ +'use strict'; + +const { Cart, Order } = require('../../models'); + +const handler = async(event) => { + try { + const order = await Order.create({ + items: event.body.products, + total: event.body.total, + orderNumber: event.body.orderNumber, + name: event.body.name, + email: event.body.email, + address1: event.body.address1, + city: event.body.city, + state: event.body.state, + zip: event.body.zip, + location: { lat: event.body.lat, lng: event.body.lng }, + shipping: event.body.shipping, + paymentMethod: { id: event.body.paymentMethod.id, brand: event.body.paymentMethod.brand, last4: event.body.paymentMethod.last4 }, + trackingNumber: event.body.trackingNumber + }); + const cart = await Cart.findOne({ _id: event.body.cartId }); + cart.orderId = order._id; + await cart.save(); + return { statusCode: 500, body: { order: order, cart: cart } }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/getCart/getCart.js b/examples/netlify-functions/functions/getCart/getCart.js new file mode 100644 index 00000000000..a7ddf74446b --- /dev/null +++ b/examples/netlify-functions/functions/getCart/getCart.js @@ -0,0 +1,15 @@ +'use strict'; + +const { Cart } = require('../../models'); + +const handler = async(event) => { + try { + // get the document containing the specified cartId + const cart = await Cart.findOne({ _id: event.queryStringParameters.cartId }); + return { statusCode: 200, body: cart }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/getProducts/getProducts.js b/examples/netlify-functions/functions/getProducts/getProducts.js new file mode 100644 index 00000000000..5c23ef98381 --- /dev/null +++ b/examples/netlify-functions/functions/getProducts/getProducts.js @@ -0,0 +1,14 @@ +'use strict'; + +const { Product } = require('../../models'); + +const handler = async(event) => { + try { + const Products = await Product.find(); + return { statusCode: 200, body: Products }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/removeFromCart/removeFromCart.js b/examples/netlify-functions/functions/removeFromCart/removeFromCart.js new file mode 100644 index 00000000000..9ae84196fc5 --- /dev/null +++ b/examples/netlify-functions/functions/removeFromCart/removeFromCart.js @@ -0,0 +1,19 @@ +'use strict'; + +const { Cart } = require('../../models'); + +const handler = async(event) => { + try { + const cart = await Cart.findOne({ _id: event.body.cartId }); + const index = cart.products.findIndex((item) => { + return item._id == event.body.productId; + }); + cart.products.splice(index, 1); + await cart.save(); + return { statusCode: 200, body: cart }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/models.js b/examples/netlify-functions/models.js new file mode 100644 index 00000000000..407e83b2b9c --- /dev/null +++ b/examples/netlify-functions/models.js @@ -0,0 +1,128 @@ +'use strict'; +const mongoose = require('mongoose'); + +const productSchema = new mongoose.Schema({ + productName: String, + productPrice: Number, + quantity: Number +}); + +const Product = mongoose.model('Product', productSchema); + +module.exports.Product = Product; + +const orderSchema = new mongoose.Schema({ + items: [productSchema], + total: { + type: Number, + default: 0 + }, + status: { + type: String, + enum: ['PAID', 'IN_PROGRESS', 'SHIPPED', 'DELIVERED'], + default: 'PAID' + }, + orderNumber: { + type: Number, + required: true + }, + name: { + type: String, + required: true + }, + email: { + type: String, + required: true + }, + address1: { + type: String, + required: true + }, + address2: { + type: String + }, + city: { + type: String, + required: true + }, + state: { + type: String, + required: true + }, + zip: { + type: String, + required: true + }, + location: new mongoose.Schema({ + lat: { + type: Number, + required: true + }, + lng: { + type: Number, + required: true + } + }, { _id: false }), + shipping: { + type: String, + required: true, + enum: ['standard', '2day'] + }, + paymentMethod: { + id: String, + brand: String, + last4: String + }, + salesTax: { + type: Number, + default: 0 + }, + trackingNumber: { + type: String + } +}); + +const Order = mongoose.model('Order', orderSchema); + +module.exports.Order = Order; + +const cartSchema = new mongoose.Schema({ + products: [productSchema], + orderId: { type: mongoose.Types.ObjectId, ref: 'Order' } +}, { timestamps: true }); + +const Cart = mongoose.model('Cart', cartSchema); + +module.exports.Cart = Cart; + +async function run() { + await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); + + await Product.create({ + productName: 'Netlify\'s First Flight', + productPrice: 2000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify The Movie', + productPrice: 4000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify vs The Internet', + productPrice: 6000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify and The Wasp', + productPrice: 8000, + quantity: 5 + }); +} + +run(); + From 200668b85d17fbefc9a3af4a9e83e205c55ee4dc Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 3 Jun 2022 17:57:59 -0400 Subject: [PATCH 02/31] not entirely sure how to redirect --- .../functions/checkout/checkout.js | 30 ++++++++++++++++++- package.json | 3 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/examples/netlify-functions/functions/checkout/checkout.js b/examples/netlify-functions/functions/checkout/checkout.js index 595e98d7e60..98918ef3e75 100644 --- a/examples/netlify-functions/functions/checkout/checkout.js +++ b/examples/netlify-functions/functions/checkout/checkout.js @@ -1,9 +1,37 @@ 'use strict'; +const stripe = require('stripe')('insert your stripe key here'); const { Cart, Order } = require('../../models'); const handler = async(event) => { try { + const stripeProducts = { line_items: [] }; + for (let i = 0; i < event.body.products.length; i++) { + stripeProducts.line_items.push({ + price_data: { + currency: 'usd', + product_data: { + name: event.body.products[i].name + }, + unit_amount: event.body.products[i].productPrice, + }, + quantity: event.body.quantity + }); + } + const session = await stripe.checkout.sessions.create({ + line_items: [{ + price_data: { + currency: 'usd', + product_data: { + name: event.body.products + } + } + }], + mode: 'payment', + success_url: 'insert a url here', + cancel_url: 'insert a url here' + }); + const order = await Order.create({ items: event.body.products, total: event.body.total, @@ -22,7 +50,7 @@ const handler = async(event) => { const cart = await Cart.findOne({ _id: event.body.cartId }); cart.orderId = order._id; await cart.save(); - return { statusCode: 500, body: { order: order, cart: cart } }; + return { statusCode: 500, body: { order: order, cart: cart }, headers: { Location: session.url } }; } catch (error) { return { statusCode: 500, body: error.toString() }; } diff --git a/package.json b/package.json index 523cfa39c14..cfd9979d67e 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.0", + "stripe": "^9.6.0" }, "devDependencies": { "@babel/core": "7.18.2", From 92787e852eca4a8d59fbdc6ecd8296ad6cf278d6 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 3 Jun 2022 17:58:10 -0400 Subject: [PATCH 03/31] Update checkout.js --- examples/netlify-functions/functions/checkout/checkout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/netlify-functions/functions/checkout/checkout.js b/examples/netlify-functions/functions/checkout/checkout.js index 98918ef3e75..77f616a8fd5 100644 --- a/examples/netlify-functions/functions/checkout/checkout.js +++ b/examples/netlify-functions/functions/checkout/checkout.js @@ -31,7 +31,7 @@ const handler = async(event) => { success_url: 'insert a url here', cancel_url: 'insert a url here' }); - + const order = await Order.create({ items: event.body.products, total: event.body.total, From c9baa825d547966f7543066e6a5c88a35cd5098a Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:09:36 -0400 Subject: [PATCH 04/31] All thats left is checkout --- .../.netlify/edge-functions-import-map.json | 0 .../functions/addToCart/addToCart.js | 32 +++++++++ .../functions/checkout/checkout.js | 0 .../functions/getCart/getCart.js | 0 .../functions/getProducts/getProducts.js | 0 .../removeFromCart/removeFromCart.js | 24 +++++++ .../models.js | 40 ++--------- .../ecommerce-netlify-functions/package.json | 12 ++++ examples/ecommerce-netlify-functions/seed.js | 35 ++++++++++ .../test/addToCart.test.js | 52 ++++++++++++++ .../test/getCart.test.js | 39 +++++++++++ .../test/getProducts.test.js | 22 ++++++ .../test/removeFromCart.test.js | 69 +++++++++++++++++++ .../functions/addToCart/addToCart.js | 23 ------- .../removeFromCart/removeFromCart.js | 19 ----- package.json | 3 +- 16 files changed, 290 insertions(+), 80 deletions(-) rename examples/{netlify-functions => ecommerce-netlify-functions}/.netlify/edge-functions-import-map.json (100%) create mode 100644 examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js rename examples/{netlify-functions => ecommerce-netlify-functions}/functions/checkout/checkout.js (100%) rename examples/{netlify-functions => ecommerce-netlify-functions}/functions/getCart/getCart.js (100%) rename examples/{netlify-functions => ecommerce-netlify-functions}/functions/getProducts/getProducts.js (100%) create mode 100644 examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js rename examples/{netlify-functions => ecommerce-netlify-functions}/models.js (66%) create mode 100644 examples/ecommerce-netlify-functions/package.json create mode 100644 examples/ecommerce-netlify-functions/seed.js create mode 100644 examples/ecommerce-netlify-functions/test/addToCart.test.js create mode 100644 examples/ecommerce-netlify-functions/test/getCart.test.js create mode 100644 examples/ecommerce-netlify-functions/test/getProducts.test.js create mode 100644 examples/ecommerce-netlify-functions/test/removeFromCart.test.js delete mode 100644 examples/netlify-functions/functions/addToCart/addToCart.js delete mode 100644 examples/netlify-functions/functions/removeFromCart/removeFromCart.js diff --git a/examples/netlify-functions/.netlify/edge-functions-import-map.json b/examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json similarity index 100% rename from examples/netlify-functions/.netlify/edge-functions-import-map.json rename to examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json diff --git a/examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js b/examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js new file mode 100644 index 00000000000..cb7b45dfa77 --- /dev/null +++ b/examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js @@ -0,0 +1,32 @@ +'use strict'; + +const { Cart } = require('../../models'); + +const handler = async(event) => { + try { + if (event.body.cartId) { + // get the document containing the specified cartId + const cart = await Cart.findOne({ _id: event.body.cartId }); + for (const product of event.body.product) { + const exists = cart.items.find(item => + item.productId.toString() === product.productId.toString() + ); + if (!exists) { + cart.items.push(product); + } else { + exists.quantity += product.quantity; + } + } + await cart.save(); + return { statusCode: 200, body: cart }; + } else { + // If no cartId, create a new cart + const cart = await Cart.create({ items: event.body.product }); + return { statusCode: 200, body: cart }; + } + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/checkout/checkout.js b/examples/ecommerce-netlify-functions/functions/checkout/checkout.js similarity index 100% rename from examples/netlify-functions/functions/checkout/checkout.js rename to examples/ecommerce-netlify-functions/functions/checkout/checkout.js diff --git a/examples/netlify-functions/functions/getCart/getCart.js b/examples/ecommerce-netlify-functions/functions/getCart/getCart.js similarity index 100% rename from examples/netlify-functions/functions/getCart/getCart.js rename to examples/ecommerce-netlify-functions/functions/getCart/getCart.js diff --git a/examples/netlify-functions/functions/getProducts/getProducts.js b/examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js similarity index 100% rename from examples/netlify-functions/functions/getProducts/getProducts.js rename to examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js b/examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js new file mode 100644 index 00000000000..54529ce1993 --- /dev/null +++ b/examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js @@ -0,0 +1,24 @@ +'use strict'; + +const { Cart } = require('../../models'); + +const handler = async(event) => { + try { + const cart = await Cart.findOne({ _id: event.body.cartId }); + const index = cart.items.findIndex((item) => + item.productId == event.body.product.productId + ); + if (event.body.product.quantity) { + cart.items[index].quantity -= event.body.product.quantity; + await cart.save(); + } else { + cart.items.splice(index, 1); + await cart.save(); + } + return { statusCode: 200, body: cart }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/models.js b/examples/ecommerce-netlify-functions/models.js similarity index 66% rename from examples/netlify-functions/models.js rename to examples/ecommerce-netlify-functions/models.js index 407e83b2b9c..0945572ef37 100644 --- a/examples/netlify-functions/models.js +++ b/examples/ecommerce-netlify-functions/models.js @@ -3,8 +3,7 @@ const mongoose = require('mongoose'); const productSchema = new mongoose.Schema({ productName: String, - productPrice: Number, - quantity: Number + productPrice: Number }); const Product = mongoose.model('Product', productSchema); @@ -12,7 +11,7 @@ const Product = mongoose.model('Product', productSchema); module.exports.Product = Product; const orderSchema = new mongoose.Schema({ - items: [productSchema], + items: [{ productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, quantity: { type: Number, required: true } }], total: { type: Number, default: 0 @@ -87,42 +86,11 @@ const Order = mongoose.model('Order', orderSchema); module.exports.Order = Order; const cartSchema = new mongoose.Schema({ - products: [productSchema], - orderId: { type: mongoose.Types.ObjectId, ref: 'Order' } + items: [{ productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, quantity: { type: Number, required: true } }], + orderId: { type: mongoose.ObjectId, ref: 'Order' } }, { timestamps: true }); const Cart = mongoose.model('Cart', cartSchema); module.exports.Cart = Cart; -async function run() { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - - await Product.create({ - productName: 'Netlify\'s First Flight', - productPrice: 2000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify The Movie', - productPrice: 4000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify vs The Internet', - productPrice: 6000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify and The Wasp', - productPrice: 8000, - quantity: 5 - }); -} - -run(); - diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json new file mode 100644 index 00000000000..6648ce2eacd --- /dev/null +++ b/examples/ecommerce-netlify-functions/package.json @@ -0,0 +1,12 @@ +{ + "dependencies": { + "stripe": "^9.6.0", + "mongoose": "^6.3.5" + }, + "devDependencies": { + "mocha": "10.0.0" + }, + "scripts": { + "test": "mocha --exit ./test/*.test.js" + } +} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js new file mode 100644 index 00000000000..b77dd69167d --- /dev/null +++ b/examples/ecommerce-netlify-functions/seed.js @@ -0,0 +1,35 @@ +'use strict'; +const mongoose = require('mongoose'); +const { Product } = require('./models'); + +async function run() { + await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); + + await Product.create({ + productName: 'Netlify\'s First Flight', + productPrice: 2000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify The Movie', + productPrice: 4000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify vs The Internet', + productPrice: 6000, + quantity: 5 + }); + + await Product.create({ + productName: 'Netlify and The Wasp', + productPrice: 8000, + quantity: 5 + }); + console.log('done'); +} + +run(); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js new file mode 100644 index 00000000000..232c8b8598d --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -0,0 +1,52 @@ +'use strict'; + +const { describe, it, before, after } = require('mocha'); +const assert = require('assert'); +const { handler: addToCart } = require('../functions/addToCart/addToCart'); +const mongoose = require('mongoose'); + + + +describe('Add to Cart', function() { + before(async() => { + await mongoose.connect('mongodb://localhost:27017/netlify'); + }); + + after(async() => { + await mongoose.disconnect(); + }); + it('Should create a cart and add a product to the cart.', async function() { + const params = { + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert(result.body.items.length); + }); + it('Should find the cart and add to it.', async function() { + const params = { + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert(result.body.items.length); + params.body.cartId = result.body._id; + const findCart = await addToCart(params); + assert(findCart.body); + assert.deepStrictEqual(findCart.body._id, result.body._id); + assert.equal(findCart.body.items[0].quantity, 4); + assert.equal(findCart.body.items[1].quantity, 2); + }); +}); diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js new file mode 100644 index 00000000000..1c912da129c --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -0,0 +1,39 @@ +'use strict'; + +const { describe, it, before, after } = require('mocha'); +const assert = require('assert'); +const { handler: getCart } = require('../functions/getCart/getCart'); +const { handler: addToCart } = require('../functions/addToCart/addToCart'); +const mongoose = require('mongoose'); + + + +describe('Get the cart given an id', function() { + before(async() => { + await mongoose.connect('mongodb://localhost:27017/netlify'); + }); + + after(async() => { + await mongoose.disconnect(); + }); + it('Should create a cart and then find the cart.', async function() { + const params = { + queryStringParameters: { + cartId: null + }, + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert(result.body.items.length); + params.queryStringParameters.cartId = result.body._id; + const findCart = await getCart(params); + assert.equal(findCart.statusCode, 200); + }); +}); diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js new file mode 100644 index 00000000000..9548d67fb6c --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -0,0 +1,22 @@ +'use strict'; + +const { describe, it, before, after } = require('mocha'); +const assert = require('assert'); +const { handler: getProducts } = require('../functions/getProducts/getProducts'); +const mongoose = require('mongoose'); + +describe('Products', function() { + before(async() => { + await mongoose.connect('mongodb://localhost:27017/netlify'); + }); + + after(async() => { + await mongoose.disconnect(); + }); + + it('Should get all products.', async function() { + const result = await getProducts(); + console.log(result); + assert(result); + }); +}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js new file mode 100644 index 00000000000..90e4b95ebf3 --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -0,0 +1,69 @@ +'use strict'; + +const { describe, it, before, after } = require('mocha'); +const assert = require('assert'); +const { handler: addToCart } = require('../functions/addToCart/addToCart'); +const { handler: removeFromCart } = require('../functions/removeFromCart/removeFromCart'); +const mongoose = require('mongoose'); + + + +describe('Remove From Cart', function() { + before(async() => { + await mongoose.connect('mongodb://localhost:27017/netlify'); + }); + + after(async() => { + await mongoose.disconnect(); + }); + + it('Should create a cart and then it should remove the entire item from it.', async function() { + const params = { + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert.equal(result.body.items.length, 2); + const newParams = { + body: { + cartId: result.body._id, + productId: '629e5f3686d82fc73b95b396' + } + }; + const remove = await removeFromCart(newParams); + assert.equal(remove.body.items.length, 1); + }); + + it('Should create a cart and then it should reduce the quantity of an item from it.', async function() { + const params = { + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert(result.body.items.length); + const newParams = { + body: { + cartId: result.body._id, + product: { + productId: '629e5f3686d82fc73b95b396', + quantity: 1 + } + } + }; + const remove = await removeFromCart(newParams); + assert.equal(remove.body.items[0].quantity, 1); + }); + +}); \ No newline at end of file diff --git a/examples/netlify-functions/functions/addToCart/addToCart.js b/examples/netlify-functions/functions/addToCart/addToCart.js deleted file mode 100644 index cd9c1c2eb6a..00000000000 --- a/examples/netlify-functions/functions/addToCart/addToCart.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -const { Cart } = require('../../models'); - -const handler = async(event) => { - try { - if (event.body.cartId) { - // get the document containing the specified cartId - const cart = await Cart.findOne({ _id: event.body.cartId }); - cart.products.push(event.body.product); - await cart.save(); - return { statusCode: 500, body: cart }; - } else { - // If no cartId, create a new cart - const cart = await Cart.create({ products: event.body.product }); - return { statusCode: 500, body: cart }; - } - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/netlify-functions/functions/removeFromCart/removeFromCart.js b/examples/netlify-functions/functions/removeFromCart/removeFromCart.js deleted file mode 100644 index 9ae84196fc5..00000000000 --- a/examples/netlify-functions/functions/removeFromCart/removeFromCart.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const { Cart } = require('../../models'); - -const handler = async(event) => { - try { - const cart = await Cart.findOne({ _id: event.body.cartId }); - const index = cart.products.findIndex((item) => { - return item._id == event.body.productId; - }); - cart.products.splice(index, 1); - await cart.save(); - return { statusCode: 200, body: cart }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/package.json b/package.json index cfd9979d67e..523cfa39c14 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", - "sift": "16.0.0", - "stripe": "^9.6.0" + "sift": "16.0.0" }, "devDependencies": { "@babel/core": "7.18.2", From e865463048195a64623472963f93e0fed913615a Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:38:39 -0400 Subject: [PATCH 05/31] not done yet --- .../functions/{addToCart => }/addToCart.js | 2 +- .../functions/{checkout => }/checkout.js | 34 +++++++++---------- .../functions/{getCart => }/getCart.js | 4 +-- .../functions/getProducts.js | 14 ++++++++ .../functions/getProducts/getProducts.js | 14 -------- .../{removeFromCart => }/removeFromCart.js | 5 ++- .../ecommerce-netlify-functions/models.js | 5 +-- .../ecommerce-netlify-functions/package.json | 6 ++-- .../test/addToCart.test.js | 2 +- .../test/checkout.test.js | 34 +++++++++++++++++++ .../test/getCart.test.js | 4 +-- .../test/getProducts.test.js | 2 +- .../test/removeFromCart.test.js | 4 +-- 13 files changed, 81 insertions(+), 49 deletions(-) rename examples/ecommerce-netlify-functions/functions/{addToCart => }/addToCart.js (92%) rename examples/ecommerce-netlify-functions/functions/{checkout => }/checkout.js (61%) rename examples/ecommerce-netlify-functions/functions/{getCart => }/getCart.js (71%) create mode 100644 examples/ecommerce-netlify-functions/functions/getProducts.js delete mode 100644 examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js rename examples/ecommerce-netlify-functions/functions/{removeFromCart => }/removeFromCart.js (78%) create mode 100644 examples/ecommerce-netlify-functions/test/checkout.test.js diff --git a/examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js b/examples/ecommerce-netlify-functions/functions/addToCart.js similarity index 92% rename from examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js rename to examples/ecommerce-netlify-functions/functions/addToCart.js index cb7b45dfa77..97ea6c4b70b 100644 --- a/examples/ecommerce-netlify-functions/functions/addToCart/addToCart.js +++ b/examples/ecommerce-netlify-functions/functions/addToCart.js @@ -1,6 +1,6 @@ 'use strict'; -const { Cart } = require('../../models'); +const { Cart } = require('../models'); const handler = async(event) => { try { diff --git a/examples/ecommerce-netlify-functions/functions/checkout/checkout.js b/examples/ecommerce-netlify-functions/functions/checkout.js similarity index 61% rename from examples/ecommerce-netlify-functions/functions/checkout/checkout.js rename to examples/ecommerce-netlify-functions/functions/checkout.js index 77f616a8fd5..25139150214 100644 --- a/examples/ecommerce-netlify-functions/functions/checkout/checkout.js +++ b/examples/ecommerce-netlify-functions/functions/checkout.js @@ -1,41 +1,39 @@ 'use strict'; -const stripe = require('stripe')('insert your stripe key here'); +const stripe = require('stripe')(process.env.STRIPE_KEY); -const { Cart, Order } = require('../../models'); +const { Cart, Order, Product } = require('../models'); const handler = async(event) => { try { const stripeProducts = { line_items: [] }; + const total = 0; for (let i = 0; i < event.body.products.length; i++) { + const product = await Product.findOne({_id: event.body.products[i].productId}); stripeProducts.line_items.push({ price_data: { currency: 'usd', product_data: { - name: event.body.products[i].name + name: product.productName }, - unit_amount: event.body.products[i].productPrice, + unit_amount: product.productPrice, }, - quantity: event.body.quantity + quantity: event.body.products[i].quantity }); + total = total + (product.productPrice * event.body.products[i].quantity); } + const salesTax = total * .06; const session = await stripe.checkout.sessions.create({ - line_items: [{ - price_data: { - currency: 'usd', - product_data: { - name: event.body.products - } - } - }], + line_items: stripeProducts.line_items, mode: 'payment', success_url: 'insert a url here', cancel_url: 'insert a url here' }); - + const orders = await Order.find(); + const orderNumber = orders.length ? orders.length + 1 : 1; const order = await Order.create({ items: event.body.products, - total: event.body.total, - orderNumber: event.body.orderNumber, + total: total, + orderNumber: orderNumber, name: event.body.name, email: event.body.email, address1: event.body.address1, @@ -45,12 +43,12 @@ const handler = async(event) => { location: { lat: event.body.lat, lng: event.body.lng }, shipping: event.body.shipping, paymentMethod: { id: event.body.paymentMethod.id, brand: event.body.paymentMethod.brand, last4: event.body.paymentMethod.last4 }, - trackingNumber: event.body.trackingNumber + salesTax: salesTax }); const cart = await Cart.findOne({ _id: event.body.cartId }); cart.orderId = order._id; await cart.save(); - return { statusCode: 500, body: { order: order, cart: cart }, headers: { Location: session.url } }; + return { statusCode: 200, body: { order: order, cart: cart }, headers: { Location: session.url } }; } catch (error) { return { statusCode: 500, body: error.toString() }; } diff --git a/examples/ecommerce-netlify-functions/functions/getCart/getCart.js b/examples/ecommerce-netlify-functions/functions/getCart.js similarity index 71% rename from examples/ecommerce-netlify-functions/functions/getCart/getCart.js rename to examples/ecommerce-netlify-functions/functions/getCart.js index a7ddf74446b..85bbef68586 100644 --- a/examples/ecommerce-netlify-functions/functions/getCart/getCart.js +++ b/examples/ecommerce-netlify-functions/functions/getCart.js @@ -1,11 +1,11 @@ 'use strict'; -const { Cart } = require('../../models'); +const { Cart } = require('../models'); const handler = async(event) => { try { // get the document containing the specified cartId - const cart = await Cart.findOne({ _id: event.queryStringParameters.cartId }); + const cart = await Cart.findOne({ _id: event.queryStringParameters.cartId }).setOptions({ sanitizeFilter: true }); return { statusCode: 200, body: cart }; } catch (error) { return { statusCode: 500, body: error.toString() }; diff --git a/examples/ecommerce-netlify-functions/functions/getProducts.js b/examples/ecommerce-netlify-functions/functions/getProducts.js new file mode 100644 index 00000000000..6950a7538a0 --- /dev/null +++ b/examples/ecommerce-netlify-functions/functions/getProducts.js @@ -0,0 +1,14 @@ +'use strict'; + +const { Product } = require('../models'); + +const handler = async(event) => { + try { + const products = await Product.find(); + return { statusCode: 200, body: products }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js b/examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js deleted file mode 100644 index 5c23ef98381..00000000000 --- a/examples/ecommerce-netlify-functions/functions/getProducts/getProducts.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const { Product } = require('../../models'); - -const handler = async(event) => { - try { - const Products = await Product.find(); - return { statusCode: 200, body: Products }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js b/examples/ecommerce-netlify-functions/functions/removeFromCart.js similarity index 78% rename from examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js rename to examples/ecommerce-netlify-functions/functions/removeFromCart.js index 54529ce1993..896cade612a 100644 --- a/examples/ecommerce-netlify-functions/functions/removeFromCart/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/functions/removeFromCart.js @@ -1,6 +1,6 @@ 'use strict'; -const { Cart } = require('../../models'); +const { Cart } = require('../models'); const handler = async(event) => { try { @@ -8,6 +8,9 @@ const handler = async(event) => { const index = cart.items.findIndex((item) => item.productId == event.body.product.productId ); + if (index == -1) { + return { statusCode: 500, body: 'Product not found' }; + } if (event.body.product.quantity) { cart.items[index].quantity -= event.body.product.quantity; await cart.save(); diff --git a/examples/ecommerce-netlify-functions/models.js b/examples/ecommerce-netlify-functions/models.js index 0945572ef37..9bb7453f7e8 100644 --- a/examples/ecommerce-netlify-functions/models.js +++ b/examples/ecommerce-netlify-functions/models.js @@ -76,10 +76,7 @@ const orderSchema = new mongoose.Schema({ type: Number, default: 0 }, - trackingNumber: { - type: String - } -}); +}, { optimisticConcurrency: true }); const Order = mongoose.model('Order', orderSchema); diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json index 6648ce2eacd..abda81d845f 100644 --- a/examples/ecommerce-netlify-functions/package.json +++ b/examples/ecommerce-netlify-functions/package.json @@ -1,7 +1,7 @@ { "dependencies": { - "stripe": "^9.6.0", - "mongoose": "^6.3.5" + "mongoose": "^6.3.5", + "stripe": "^9.6.0" }, "devDependencies": { "mocha": "10.0.0" @@ -9,4 +9,4 @@ "scripts": { "test": "mocha --exit ./test/*.test.js" } -} \ No newline at end of file +} diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index 232c8b8598d..baa8290fb2d 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -2,7 +2,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: addToCart } = require('../functions/addToCart/addToCart'); +const { handler: addToCart } = require('../functions/addToCart'); const mongoose = require('mongoose'); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js new file mode 100644 index 00000000000..3b7ddc18091 --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -0,0 +1,34 @@ +'use strict'; + +const { describe, it, before, after } = require('mocha'); +const assert = require('assert'); +const { handler: addToCart } = require('../functions/addToCart'); +const { handler: checkout } = require('../functions/checkout'); +const mongoose = require('mongoose'); + + + +describe('Add to Cart', function() { + before(async() => { + await mongoose.connect('mongodb://localhost:27017/netlify'); + }); + + after(async() => { + await mongoose.disconnect(); + }); + it('Should do a successfult checkout run', async function() { + const params = { + body: { + cartId: null, + product: [ + { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, + { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + ] + } + }; + const result = await addToCart(params); + assert(result.body); + assert(result.body.items.length); + params.body.cartId = result.body._id; + }); +}); diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js index 1c912da129c..30395449c38 100644 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -2,8 +2,8 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: getCart } = require('../functions/getCart/getCart'); -const { handler: addToCart } = require('../functions/addToCart/addToCart'); +const { handler: getCart } = require('../functions/getCart'); +const { handler: addToCart } = require('../functions/addToCart'); const mongoose = require('mongoose'); diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js index 9548d67fb6c..631871af1ba 100644 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -2,7 +2,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: getProducts } = require('../functions/getProducts/getProducts'); +const { handler: getProducts } = require('../functions/getProducts'); const mongoose = require('mongoose'); describe('Products', function() { diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 90e4b95ebf3..61a0fc77110 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -2,8 +2,8 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: addToCart } = require('../functions/addToCart/addToCart'); -const { handler: removeFromCart } = require('../functions/removeFromCart/removeFromCart'); +const { handler: addToCart } = require('../functions/addToCart'); +const { handler: removeFromCart } = require('../functions/removeFromCart'); const mongoose = require('mongoose'); From 062ca30831bdb2782d71482e2270b9083b3342ff Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Mon, 13 Jun 2022 14:34:33 -0400 Subject: [PATCH 06/31] added checkout test --- .../functions/addToCart.js | 2 +- .../functions/checkout.js | 24 ++++++++++--------- .../functions/removeFromCart.js | 2 +- .../ecommerce-netlify-functions/models.js | 22 +++++------------ .../test/checkout.test.js | 7 ++++-- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/examples/ecommerce-netlify-functions/functions/addToCart.js b/examples/ecommerce-netlify-functions/functions/addToCart.js index 97ea6c4b70b..68e2c88e3dc 100644 --- a/examples/ecommerce-netlify-functions/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/functions/addToCart.js @@ -6,7 +6,7 @@ const handler = async(event) => { try { if (event.body.cartId) { // get the document containing the specified cartId - const cart = await Cart.findOne({ _id: event.body.cartId }); + const cart = await Cart.findOne({ _id: event.body.cartId }).setOptions({ sanitizeFilter: true }); for (const product of event.body.product) { const exists = cart.items.find(item => item.productId.toString() === product.productId.toString() diff --git a/examples/ecommerce-netlify-functions/functions/checkout.js b/examples/ecommerce-netlify-functions/functions/checkout.js index 25139150214..05163bfeb3a 100644 --- a/examples/ecommerce-netlify-functions/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/functions/checkout.js @@ -6,32 +6,36 @@ const { Cart, Order, Product } = require('../models'); const handler = async(event) => { try { const stripeProducts = { line_items: [] }; - const total = 0; - for (let i = 0; i < event.body.products.length; i++) { - const product = await Product.findOne({_id: event.body.products[i].productId}); + let total = 0; + for (let i = 0; i < event.body.product.length; i++) { + const product = await Product.findOne({ _id: event.body.product[i].productId }); stripeProducts.line_items.push({ price_data: { currency: 'usd', product_data: { name: product.productName }, - unit_amount: product.productPrice, + unit_amount: product.productPrice }, - quantity: event.body.products[i].quantity + quantity: event.body.product[i].quantity }); - total = total + (product.productPrice * event.body.products[i].quantity); + total = total + (product.productPrice * event.body.product[i].quantity); } - const salesTax = total * .06; const session = await stripe.checkout.sessions.create({ line_items: stripeProducts.line_items, mode: 'payment', success_url: 'insert a url here', cancel_url: 'insert a url here' }); + const intent = await stripe.paymentIntents.retrieve(session.payment_intent); + if (intent.status !== 'succeeded') { + throw new Error(`Checkout failed because intent has status "${intent.status}"`); + } + const paymentMethod = await stripe.paymentMethods.retrieve(intent['payment_method']); const orders = await Order.find(); const orderNumber = orders.length ? orders.length + 1 : 1; const order = await Order.create({ - items: event.body.products, + items: event.body.product, total: total, orderNumber: orderNumber, name: event.body.name, @@ -40,10 +44,8 @@ const handler = async(event) => { city: event.body.city, state: event.body.state, zip: event.body.zip, - location: { lat: event.body.lat, lng: event.body.lng }, shipping: event.body.shipping, - paymentMethod: { id: event.body.paymentMethod.id, brand: event.body.paymentMethod.brand, last4: event.body.paymentMethod.last4 }, - salesTax: salesTax + paymentMethod: paymentMethod ? { id: paymentMethod.id, brand: paymentMethod.brand, last4: paymentMethod.last4 } : null }); const cart = await Cart.findOne({ _id: event.body.cartId }); cart.orderId = order._id; diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/functions/removeFromCart.js index 896cade612a..a7e9d3967f3 100644 --- a/examples/ecommerce-netlify-functions/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/functions/removeFromCart.js @@ -11,7 +11,7 @@ const handler = async(event) => { if (index == -1) { return { statusCode: 500, body: 'Product not found' }; } - if (event.body.product.quantity) { + if (event.body?.product?.quantity) { cart.items[index].quantity -= event.body.product.quantity; await cart.save(); } else { diff --git a/examples/ecommerce-netlify-functions/models.js b/examples/ecommerce-netlify-functions/models.js index 9bb7453f7e8..501ecdd7c63 100644 --- a/examples/ecommerce-netlify-functions/models.js +++ b/examples/ecommerce-netlify-functions/models.js @@ -11,7 +11,11 @@ const Product = mongoose.model('Product', productSchema); module.exports.Product = Product; const orderSchema = new mongoose.Schema({ - items: [{ productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, quantity: { type: Number, required: true } }], + items: [ + { productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, + quantity: { type: Number, required: true, validate: v => v > 0 } + } + ], total: { type: Number, default: 0 @@ -52,16 +56,6 @@ const orderSchema = new mongoose.Schema({ type: String, required: true }, - location: new mongoose.Schema({ - lat: { - type: Number, - required: true - }, - lng: { - type: Number, - required: true - } - }, { _id: false }), shipping: { type: String, required: true, @@ -71,11 +65,7 @@ const orderSchema = new mongoose.Schema({ id: String, brand: String, last4: String - }, - salesTax: { - type: Number, - default: 0 - }, + } }, { optimisticConcurrency: true }); const Order = mongoose.model('Order', orderSchema); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 3b7ddc18091..7fc3e60e839 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -8,7 +8,7 @@ const mongoose = require('mongoose'); -describe('Add to Cart', function() { +describe('Checkout', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); }); @@ -16,7 +16,7 @@ describe('Add to Cart', function() { after(async() => { await mongoose.disconnect(); }); - it('Should do a successfult checkout run', async function() { + it('Should do a successful checkout run', async function() { const params = { body: { cartId: null, @@ -30,5 +30,8 @@ describe('Add to Cart', function() { assert(result.body); assert(result.body.items.length); params.body.cartId = result.body._id; + const finish = await checkout(params); + assert(finish.body.order); + assert(finish.body.cart); }); }); From d983d3397a6d8871c9d07d66f8d6a0ccc27bbb6c Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 1 Jul 2022 16:03:17 -0400 Subject: [PATCH 07/31] created fixtures --- examples/ecommerce-netlify-functions/index.js | 5 +++++ .../test/fixtures/createCart.js | 7 +++++++ .../test/fixtures/createOrder.js | 7 +++++++ .../test/fixtures/createProducts.js | 7 +++++++ 4 files changed, 26 insertions(+) create mode 100644 examples/ecommerce-netlify-functions/index.js create mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createCart.js create mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createOrder.js create mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createProducts.js diff --git a/examples/ecommerce-netlify-functions/index.js b/examples/ecommerce-netlify-functions/index.js new file mode 100644 index 00000000000..94b0e3009d5 --- /dev/null +++ b/examples/ecommerce-netlify-functions/index.js @@ -0,0 +1,5 @@ +'use strict'; + +const mongoose = require('mongoose'); + +mongoose.connect('mongodb://localhost/netlify-functions'); diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createCart.js b/examples/ecommerce-netlify-functions/test/fixtures/createCart.js new file mode 100644 index 00000000000..e242cb5885e --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/fixtures/createCart.js @@ -0,0 +1,7 @@ +const {Cart} = require('../../models'); + + +module.exports = async function createCart(params) { + const cart = await Cart.create({products: [params.products]}); + return { cart }; +} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js b/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js new file mode 100644 index 00000000000..83396855605 --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js @@ -0,0 +1,7 @@ +const { Order } = require('../../models'); + +module.exports = async function createOrder(params) { + + const order = await Order.create(params.order); + return { order }; +}; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js b/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js new file mode 100644 index 00000000000..50d1e56e9e5 --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js @@ -0,0 +1,7 @@ +const { Product } = require('../../models'); + +module.exports = async function createProducts(params) { + const products = await Product.create(params.product); + + return { products }; +}; \ No newline at end of file From ad97863700edc18b1fa77718e283b08530e22e19 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 1 Jul 2022 17:06:59 -0400 Subject: [PATCH 08/31] fix addToCart test --- examples/ecommerce-netlify-functions/seed.js | 35 ------------------- .../test/addToCart.test.js | 24 ++++++------- .../test/fixtures/createCart.js | 2 +- .../test/fixtures/index.js | 11 ++++++ 4 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 examples/ecommerce-netlify-functions/seed.js create mode 100644 examples/ecommerce-netlify-functions/test/fixtures/index.js diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js deleted file mode 100644 index b77dd69167d..00000000000 --- a/examples/ecommerce-netlify-functions/seed.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; -const mongoose = require('mongoose'); -const { Product } = require('./models'); - -async function run() { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - - await Product.create({ - productName: 'Netlify\'s First Flight', - productPrice: 2000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify The Movie', - productPrice: 4000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify vs The Internet', - productPrice: 6000, - quantity: 5 - }); - - await Product.create({ - productName: 'Netlify and The Wasp', - productPrice: 8000, - quantity: 5 - }); - console.log('done'); -} - -run(); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index baa8290fb2d..7756f797cbb 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -4,6 +4,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); const { handler: addToCart } = require('../functions/addToCart'); const mongoose = require('mongoose'); +const fixtures = require('../test/fixtures'); @@ -16,12 +17,14 @@ describe('Add to Cart', function() { await mongoose.disconnect(); }); it('Should create a cart and add a product to the cart.', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); const params = { body: { cartId: null, product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } ] } }; @@ -30,23 +33,20 @@ describe('Add to Cart', function() { assert(result.body.items.length); }); it('Should find the cart and add to it.', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); + const cart = await fixtures.createCart({products: null}); const params = { body: { - cartId: null, + cartId: cart._id, product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } ] } }; - const result = await addToCart(params); - assert(result.body); - assert(result.body.items.length); - params.body.cartId = result.body._id; const findCart = await addToCart(params); assert(findCart.body); - assert.deepStrictEqual(findCart.body._id, result.body._id); - assert.equal(findCart.body.items[0].quantity, 4); - assert.equal(findCart.body.items[1].quantity, 2); + assert.equal(findCart.body.items.length, 2) }); }); diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createCart.js b/examples/ecommerce-netlify-functions/test/fixtures/createCart.js index e242cb5885e..ea8ad627257 100644 --- a/examples/ecommerce-netlify-functions/test/fixtures/createCart.js +++ b/examples/ecommerce-netlify-functions/test/fixtures/createCart.js @@ -2,6 +2,6 @@ const {Cart} = require('../../models'); module.exports = async function createCart(params) { - const cart = await Cart.create({products: [params.products]}); + const cart = await Cart.create({items: params.products}); return { cart }; } \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/index.js b/examples/ecommerce-netlify-functions/test/fixtures/index.js new file mode 100644 index 00000000000..aa1b62a407a --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/fixtures/index.js @@ -0,0 +1,11 @@ +'use strict'; + +const createCart = require('./createCart'); +const createProducts = require('./createProducts'); +const createOrder = require('./createOrder'); + +module.exports = { + createCart: createCart, + createProducts: createProducts, + createOrder: createOrder +} \ No newline at end of file From e852249248bfebf5c7487fdb01e0e0287c142691 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 1 Jul 2022 17:10:53 -0400 Subject: [PATCH 09/31] fix getCart test --- .../test/getCart.test.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js index 30395449c38..c2f970c813d 100644 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -3,7 +3,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); const { handler: getCart } = require('../functions/getCart'); -const { handler: addToCart } = require('../functions/addToCart'); +const fixtures = require('./fixtures'); const mongoose = require('mongoose'); @@ -16,23 +16,13 @@ describe('Get the cart given an id', function() { after(async() => { await mongoose.disconnect(); }); - it('Should create a cart and then find the cart.', async function() { + it('Should create a cart and then find the cart. 111', async function() { + const cart = await fixtures.createCart({ products: null }); const params = { queryStringParameters: { - cartId: null + cartId: cart._id }, - body: { - cartId: null, - product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } - ] - } }; - const result = await addToCart(params); - assert(result.body); - assert(result.body.items.length); - params.queryStringParameters.cartId = result.body._id; const findCart = await getCart(params); assert.equal(findCart.statusCode, 200); }); From a85e5a5772cb3ff3ac886c589d3a6131366eb718 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 1 Jul 2022 17:16:05 -0400 Subject: [PATCH 10/31] fix getProducts test and remove test data on test completion --- examples/ecommerce-netlify-functions/index.js | 3 ++- examples/ecommerce-netlify-functions/test/addToCart.test.js | 1 + examples/ecommerce-netlify-functions/test/checkout.test.js | 1 + examples/ecommerce-netlify-functions/test/getCart.test.js | 3 ++- .../ecommerce-netlify-functions/test/getProducts.test.js | 5 ++++- .../ecommerce-netlify-functions/test/removeFromCart.test.js | 1 + 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/ecommerce-netlify-functions/index.js b/examples/ecommerce-netlify-functions/index.js index 94b0e3009d5..c1b1eb9f12e 100644 --- a/examples/ecommerce-netlify-functions/index.js +++ b/examples/ecommerce-netlify-functions/index.js @@ -2,4 +2,5 @@ const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost/netlify-functions'); +mongoose.connect('mongodb://localhost/netlify'); +mongoose.connection.dropDatabase(); diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index 7756f797cbb..f52a6515fac 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -11,6 +11,7 @@ const fixtures = require('../test/fixtures'); describe('Add to Cart', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); }); after(async() => { diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 7fc3e60e839..63501467574 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -11,6 +11,7 @@ const mongoose = require('mongoose'); describe('Checkout', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); }); after(async() => { diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js index c2f970c813d..5b6db98306a 100644 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -11,12 +11,13 @@ const mongoose = require('mongoose'); describe('Get the cart given an id', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); }); after(async() => { await mongoose.disconnect(); }); - it('Should create a cart and then find the cart. 111', async function() { + it('Should create a cart and then find the cart.', async function() { const cart = await fixtures.createCart({ products: null }); const params = { queryStringParameters: { diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js index 631871af1ba..f247809d55c 100644 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -3,11 +3,13 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); const { handler: getProducts } = require('../functions/getProducts'); +const fixtures = require('./fixtures'); const mongoose = require('mongoose'); describe('Products', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); }); after(async() => { @@ -15,8 +17,9 @@ describe('Products', function() { }); it('Should get all products.', async function() { + await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); const result = await getProducts(); - console.log(result); assert(result); }); }); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 61a0fc77110..cb6a81bbbd4 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -11,6 +11,7 @@ const mongoose = require('mongoose'); describe('Remove From Cart', function() { before(async() => { await mongoose.connect('mongodb://localhost:27017/netlify'); + await mongoose.connection.dropDatabase(); }); after(async() => { From 9a8fad2f66cd979e0d708646caad126f3813b224 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 1 Jul 2022 17:46:31 -0400 Subject: [PATCH 11/31] fix removeFromCart and removeFromCart test --- .../functions/removeFromCart.js | 2 +- .../test/checkout.test.js | 2 +- .../test/removeFromCart.test.js | 19 +++++++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/functions/removeFromCart.js index a7e9d3967f3..c876c5c42db 100644 --- a/examples/ecommerce-netlify-functions/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/functions/removeFromCart.js @@ -6,7 +6,7 @@ const handler = async(event) => { try { const cart = await Cart.findOne({ _id: event.body.cartId }); const index = cart.items.findIndex((item) => - item.productId == event.body.product.productId + item.productId.toString() == event.body.product.productId.toString() ); if (index == -1) { return { statusCode: 500, body: 'Product not found' }; diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 63501467574..8a1756a5798 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -5,7 +5,7 @@ const assert = require('assert'); const { handler: addToCart } = require('../functions/addToCart'); const { handler: checkout } = require('../functions/checkout'); const mongoose = require('mongoose'); - +const fixtures = require('./fixtures'); describe('Checkout', function() { diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index cb6a81bbbd4..d85813c9c30 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -5,6 +5,7 @@ const assert = require('assert'); const { handler: addToCart } = require('../functions/addToCart'); const { handler: removeFromCart } = require('../functions/removeFromCart'); const mongoose = require('mongoose'); +const fixtures = require('./fixtures'); @@ -19,12 +20,14 @@ describe('Remove From Cart', function() { }); it('Should create a cart and then it should remove the entire item from it.', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); const params = { body: { cartId: null, product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } ] } }; @@ -34,7 +37,9 @@ describe('Remove From Cart', function() { const newParams = { body: { cartId: result.body._id, - productId: '629e5f3686d82fc73b95b396' + product: { + productId: products[0]._id, + } } }; const remove = await removeFromCart(newParams); @@ -42,12 +47,14 @@ describe('Remove From Cart', function() { }); it('Should create a cart and then it should reduce the quantity of an item from it.', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); const params = { body: { cartId: null, product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } ] } }; @@ -58,7 +65,7 @@ describe('Remove From Cart', function() { body: { cartId: result.body._id, product: { - productId: '629e5f3686d82fc73b95b396', + productId: products[0]._id, quantity: 1 } } From e89b2f9fe54688c048cc2337954e1eb8ee4c972e Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 5 Jul 2022 12:23:39 -0400 Subject: [PATCH 12/31] almost done --- .../functions/addToCart.js | 16 +++++++++---- .../functions/checkout.js | 23 +++++++++++++------ .../functions/getCart.js | 6 +++-- .../functions/removeFromCart.js | 13 +++++++---- .../test/addToCart.test.js | 4 ++-- .../test/removeFromCart.test.js | 8 +++---- 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/examples/ecommerce-netlify-functions/functions/addToCart.js b/examples/ecommerce-netlify-functions/functions/addToCart.js index 68e2c88e3dc..217bb74e56b 100644 --- a/examples/ecommerce-netlify-functions/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/functions/addToCart.js @@ -1,27 +1,35 @@ 'use strict'; -const { Cart } = require('../models'); +const { Cart, Product } = require('../models'); + const handler = async(event) => { try { + // event.body = JSON.parse(event.body || {}); + const products = await Product.find(); if (event.body.cartId) { // get the document containing the specified cartId const cart = await Cart.findOne({ _id: event.body.cartId }).setOptions({ sanitizeFilter: true }); - for (const product of event.body.product) { + for (const product of event.body.items) { const exists = cart.items.find(item => item.productId.toString() === product.productId.toString() ); - if (!exists) { + if (!exists && products.find(p => item.productId === product.id.toString())) { cart.items.push(product); } else { exists.quantity += product.quantity; } } + + if (!cart.items.length) { + return { statusCode: 200, body: { cart: null } }; + } + await cart.save(); return { statusCode: 200, body: cart }; } else { // If no cartId, create a new cart - const cart = await Cart.create({ items: event.body.product }); + const cart = await Cart.create({ items: event.body.items }); return { statusCode: 200, body: cart }; } } catch (error) { diff --git a/examples/ecommerce-netlify-functions/functions/checkout.js b/examples/ecommerce-netlify-functions/functions/checkout.js index 05163bfeb3a..28f75f3ddd6 100644 --- a/examples/ecommerce-netlify-functions/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/functions/checkout.js @@ -1,14 +1,19 @@ 'use strict'; -const stripe = require('stripe')(process.env.STRIPE_KEY); + +const config = require('../.config'); +const stripe = require('stripe')(config.stripeSecretKey); const { Cart, Order, Product } = require('../models'); const handler = async(event) => { try { + + const cart = await Cart.findOne({ _id: event.body.cartId }); + const stripeProducts = { line_items: [] }; let total = 0; - for (let i = 0; i < event.body.product.length; i++) { - const product = await Product.findOne({ _id: event.body.product[i].productId }); + for (let i = 0; i < cart.items.length; i++) { + const product = await Product.findOne({ _id: cart.items[i].productId }); stripeProducts.line_items.push({ price_data: { currency: 'usd', @@ -17,9 +22,9 @@ const handler = async(event) => { }, unit_amount: product.productPrice }, - quantity: event.body.product[i].quantity + quantity: cart.items[i].quantity }); - total = total + (product.productPrice * event.body.product[i].quantity); + total = total + (product.productPrice * cart.items[i].quantity); } const session = await stripe.checkout.sessions.create({ line_items: stripeProducts.line_items, @@ -47,10 +52,14 @@ const handler = async(event) => { shipping: event.body.shipping, paymentMethod: paymentMethod ? { id: paymentMethod.id, brand: paymentMethod.brand, last4: paymentMethod.last4 } : null }); - const cart = await Cart.findOne({ _id: event.body.cartId }); + cart.orderId = order._id; await cart.save(); - return { statusCode: 200, body: { order: order, cart: cart }, headers: { Location: session.url } }; + return { + statusCode: 200, + body: { order: order, cart: cart }, + headers: { Location: session.url } + }; } catch (error) { return { statusCode: 500, body: error.toString() }; } diff --git a/examples/ecommerce-netlify-functions/functions/getCart.js b/examples/ecommerce-netlify-functions/functions/getCart.js index 85bbef68586..dae1be74466 100644 --- a/examples/ecommerce-netlify-functions/functions/getCart.js +++ b/examples/ecommerce-netlify-functions/functions/getCart.js @@ -5,8 +5,10 @@ const { Cart } = require('../models'); const handler = async(event) => { try { // get the document containing the specified cartId - const cart = await Cart.findOne({ _id: event.queryStringParameters.cartId }).setOptions({ sanitizeFilter: true }); - return { statusCode: 200, body: cart }; + const cart = await Cart. + findOne({ _id: event.queryStringParameters.cartId }). + setOptions({ sanitizeFilter: true }); + return { statusCode: 200, body: JSON.stringify({ cart }) }; } catch (error) { return { statusCode: 500, body: error.toString() }; } diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/functions/removeFromCart.js index c876c5c42db..58eb7e87c5a 100644 --- a/examples/ecommerce-netlify-functions/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/functions/removeFromCart.js @@ -4,15 +4,19 @@ const { Cart } = require('../models'); const handler = async(event) => { try { + const cart = await Cart.findOne({ _id: event.body.cartId }); const index = cart.items.findIndex((item) => - item.productId.toString() == event.body.product.productId.toString() + item.productId.toString() == event.body.item.productId.toString() ); if (index == -1) { - return { statusCode: 500, body: 'Product not found' }; + return { statusCode: 200, body: cart }; } - if (event.body?.product?.quantity) { - cart.items[index].quantity -= event.body.product.quantity; + if (event.body?.item?.quantity) { + cart.items[index].quantity -= event.body.item.quantity; + if (cart.items[index].quantity <= 0) { + cart.items.splice(index, 1); + } await cart.save(); } else { cart.items.splice(index, 1); @@ -20,6 +24,7 @@ const handler = async(event) => { } return { statusCode: 200, body: cart }; } catch (error) { + console.log(error); return { statusCode: 500, body: error.toString() }; } }; diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index f52a6515fac..a2881588db3 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -23,7 +23,7 @@ describe('Add to Cart', function() { const params = { body: { cartId: null, - product: [ + items: [ { productId: products[0]._id, quantity: 2 }, { productId: products[1]._id, quantity: 1 } ] @@ -40,7 +40,7 @@ describe('Add to Cart', function() { const params = { body: { cartId: cart._id, - product: [ + items: [ { productId: products[0]._id, quantity: 2 }, { productId: products[1]._id, quantity: 1 } ] diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index d85813c9c30..2e54056faa1 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -25,7 +25,7 @@ describe('Remove From Cart', function() { const params = { body: { cartId: null, - product: [ + items: [ { productId: products[0]._id, quantity: 2 }, { productId: products[1]._id, quantity: 1 } ] @@ -37,7 +37,7 @@ describe('Remove From Cart', function() { const newParams = { body: { cartId: result.body._id, - product: { + item: { productId: products[0]._id, } } @@ -52,7 +52,7 @@ describe('Remove From Cart', function() { const params = { body: { cartId: null, - product: [ + items: [ { productId: products[0]._id, quantity: 2 }, { productId: products[1]._id, quantity: 1 } ] @@ -64,7 +64,7 @@ describe('Remove From Cart', function() { const newParams = { body: { cartId: result.body._id, - product: { + item: { productId: products[0]._id, quantity: 1 } From 0d2d2992978aafc280f8ea5a5cd4374452267438 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 5 Jul 2022 13:12:27 -0400 Subject: [PATCH 13/31] sinon not doing sinon things --- .../ecommerce-netlify-functions/package.json | 1 + .../test/checkout.test.js | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json index abda81d845f..9959a4ef31c 100644 --- a/examples/ecommerce-netlify-functions/package.json +++ b/examples/ecommerce-netlify-functions/package.json @@ -1,6 +1,7 @@ { "dependencies": { "mongoose": "^6.3.5", + "sinon": "^14.0.0", "stripe": "^9.6.0" }, "devDependencies": { diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 8a1756a5798..945969e7f26 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -6,7 +6,9 @@ const { handler: addToCart } = require('../functions/addToCart'); const { handler: checkout } = require('../functions/checkout'); const mongoose = require('mongoose'); const fixtures = require('./fixtures'); - +const sinon = require('sinon'); +const config = require('../.config'); +const stripe = require('stripe')(config.stripeSecretKey); describe('Checkout', function() { before(async() => { @@ -18,12 +20,14 @@ describe('Checkout', function() { await mongoose.disconnect(); }); it('Should do a successful checkout run', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); const params = { body: { cartId: null, - product: [ - { productId: '629e5f3686d82fc73b95b396', quantity: 2 }, - { productId: '629e5f3686d82fc73b95b398', quantity: 1 } + items: [ + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } ] } }; @@ -31,7 +35,12 @@ describe('Checkout', function() { assert(result.body); assert(result.body.items.length); params.body.cartId = result.body._id; + const stub = sinon.stub(stripe, 'paymentIntents.retrieve').callsFake(() => Promise.resolve({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'})); + // stub.callsFake(() => Promise.resolve({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'})); + // const stub = sinon.createStubInstance(stripe); + // stub.paymentIntents.retrieve.returns({status: '200'}) const finish = await checkout(params); + console.log(finish); assert(finish.body.order); assert(finish.body.cart); }); From 3c87f27edbd53d3091e4833a2e8aa4c7dde892f2 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 5 Jul 2022 13:21:35 -0400 Subject: [PATCH 14/31] not getting sinon error messages --- examples/ecommerce-netlify-functions/test/checkout.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 945969e7f26..23cd029b582 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -35,7 +35,9 @@ describe('Checkout', function() { assert(result.body); assert(result.body.items.length); params.body.cartId = result.body._id; - const stub = sinon.stub(stripe, 'paymentIntents.retrieve').callsFake(() => Promise.resolve({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'})); + const stub = sinon.stub(stripe, 'paymentIntents').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); + sinon.stub(stripe, 'paymentMethods').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); + sinon.stub(stripe, 'checkout').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); // stub.callsFake(() => Promise.resolve({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'})); // const stub = sinon.createStubInstance(stripe); // stub.paymentIntents.retrieve.returns({status: '200'}) From 6dec0c5873a9a606a8543ffb579c97b89b36f6f5 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 5 Jul 2022 13:49:10 -0400 Subject: [PATCH 15/31] thanks val --- .../functions/checkout.js | 2 +- .../integrations/stripe.js | 5 +++++ .../test/checkout.test.js | 21 +++++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 examples/ecommerce-netlify-functions/integrations/stripe.js diff --git a/examples/ecommerce-netlify-functions/functions/checkout.js b/examples/ecommerce-netlify-functions/functions/checkout.js index 28f75f3ddd6..2dfbd3272fd 100644 --- a/examples/ecommerce-netlify-functions/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/functions/checkout.js @@ -1,7 +1,7 @@ 'use strict'; const config = require('../.config'); -const stripe = require('stripe')(config.stripeSecretKey); +const stripe = require('../integrations/stripe') const { Cart, Order, Product } = require('../models'); diff --git a/examples/ecommerce-netlify-functions/integrations/stripe.js b/examples/ecommerce-netlify-functions/integrations/stripe.js new file mode 100644 index 00000000000..5349ae6cbb0 --- /dev/null +++ b/examples/ecommerce-netlify-functions/integrations/stripe.js @@ -0,0 +1,5 @@ +'use strict'; + +const config = require('../.config') + +module.exports = require('stripe')(config.stripeSecretKey); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 23cd029b582..d6503a3ab6e 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -7,8 +7,7 @@ const { handler: checkout } = require('../functions/checkout'); const mongoose = require('mongoose'); const fixtures = require('./fixtures'); const sinon = require('sinon'); -const config = require('../.config'); -const stripe = require('stripe')(config.stripeSecretKey); +const stripe = require('../integrations/stripe') describe('Checkout', function() { before(async() => { @@ -35,14 +34,18 @@ describe('Checkout', function() { assert(result.body); assert(result.body.items.length); params.body.cartId = result.body._id; - const stub = sinon.stub(stripe, 'paymentIntents').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - sinon.stub(stripe, 'paymentMethods').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - sinon.stub(stripe, 'checkout').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - // stub.callsFake(() => Promise.resolve({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'})); - // const stub = sinon.createStubInstance(stripe); - // stub.paymentIntents.retrieve.returns({status: '200'}) + sinon.stub(stripe.paymentIntents, 'retrieve').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); + sinon.stub(stripe.paymentMethods, 'retrieve').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); + sinon.stub(stripe.checkout.sessions, 'create').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); + params.body.product = params.body.items; + params.body.name = 'Test Testerson'; + params.body.email = 'test@localhost.com'; + params.body.address1 = '12345 Syndey Street'; + params.body.city = 'Miami'; + params.body.state = 'Florida'; + params.body.zip = '33145'; + params.body.shipping = 'standard'; const finish = await checkout(params); - console.log(finish); assert(finish.body.order); assert(finish.body.cart); }); From b693176f6626ddea9a12a1fedbd042fba68c0e0a Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 5 Jul 2022 16:42:23 -0400 Subject: [PATCH 16/31] Update index.js --- examples/ecommerce-netlify-functions/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/ecommerce-netlify-functions/index.js b/examples/ecommerce-netlify-functions/index.js index c1b1eb9f12e..e0a6c45e6d9 100644 --- a/examples/ecommerce-netlify-functions/index.js +++ b/examples/ecommerce-netlify-functions/index.js @@ -2,5 +2,8 @@ const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost/netlify'); +mongoose.connect('mongodb://localhost:27017/netlify'); mongoose.connection.dropDatabase(); +mongoose.connection.on('connected', () => { + console.log('connected') +}); \ No newline at end of file From dfb75b4da3abb6d7c9422052e3b1003b67983741 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:00:56 -0400 Subject: [PATCH 17/31] add --- .gitignore | 4 +++- examples/ecommerce-netlify-functions/package.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b62e157cc43..c8a9a0f27c9 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,6 @@ docs/*.html docs/tutorials/*.html docs/typescript/*.html docs/api/*.html -index.html \ No newline at end of file +index.html +# Local Netlify folder +.netlify diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json index 9959a4ef31c..678161257d8 100644 --- a/examples/ecommerce-netlify-functions/package.json +++ b/examples/ecommerce-netlify-functions/package.json @@ -5,7 +5,8 @@ "stripe": "^9.6.0" }, "devDependencies": { - "mocha": "10.0.0" + "mocha": "10.0.0", + "netlify-cli": "^10.7.1" }, "scripts": { "test": "mocha --exit ./test/*.test.js" From 115f9fa838c7c1b95f788649dc451d352a61b7ab Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:33:53 -0400 Subject: [PATCH 18/31] need to fix tests --- .../functions/getProducts.js | 14 -------------- examples/ecommerce-netlify-functions/index.js | 17 ++++++++++++++--- .../{ => netlify}/functions/addToCart.js | 10 +++++----- .../{ => netlify}/functions/checkout.js | 10 +++++----- .../{ => netlify}/functions/getCart.js | 4 +++- .../netlify/functions/getProducts.js | 16 ++++++++++++++++ .../{ => netlify}/functions/removeFromCart.js | 7 ++++--- .../test/addToCart.test.js | 2 +- .../test/checkout.test.js | 4 ++-- .../test/getCart.test.js | 2 +- .../test/getProducts.test.js | 2 +- .../test/removeFromCart.test.js | 4 ++-- 12 files changed, 54 insertions(+), 38 deletions(-) delete mode 100644 examples/ecommerce-netlify-functions/functions/getProducts.js rename examples/ecommerce-netlify-functions/{ => netlify}/functions/addToCart.js (79%) rename examples/ecommerce-netlify-functions/{ => netlify}/functions/checkout.js (88%) rename examples/ecommerce-netlify-functions/{ => netlify}/functions/getCart.js (74%) create mode 100644 examples/ecommerce-netlify-functions/netlify/functions/getProducts.js rename examples/ecommerce-netlify-functions/{ => netlify}/functions/removeFromCart.js (79%) diff --git a/examples/ecommerce-netlify-functions/functions/getProducts.js b/examples/ecommerce-netlify-functions/functions/getProducts.js deleted file mode 100644 index 6950a7538a0..00000000000 --- a/examples/ecommerce-netlify-functions/functions/getProducts.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const { Product } = require('../models'); - -const handler = async(event) => { - try { - const products = await Product.find(); - return { statusCode: 200, body: products }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/index.js b/examples/ecommerce-netlify-functions/index.js index e0a6c45e6d9..94fbdd718c7 100644 --- a/examples/ecommerce-netlify-functions/index.js +++ b/examples/ecommerce-netlify-functions/index.js @@ -2,8 +2,19 @@ const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost:27017/netlify'); -mongoose.connection.dropDatabase(); + mongoose.connection.on('connected', () => { console.log('connected') -}); \ No newline at end of file +}); + +let conn = null; + +module.exports = async function connect() { + if (conn != null) { + return conn; + } + conn = mongoose.connection; + await mongoose.connect('mongodb://localhost:27017/netlify'); + return conn; + +} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/functions/addToCart.js b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js similarity index 79% rename from examples/ecommerce-netlify-functions/functions/addToCart.js rename to examples/ecommerce-netlify-functions/netlify/functions/addToCart.js index 217bb74e56b..a032a03165d 100644 --- a/examples/ecommerce-netlify-functions/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js @@ -1,11 +1,11 @@ 'use strict'; -const { Cart, Product } = require('../models'); - +const { Cart, Product } = require('../../models'); +const connect = require('../../index'); const handler = async(event) => { try { - // event.body = JSON.parse(event.body || {}); + await connect(); const products = await Product.find(); if (event.body.cartId) { // get the document containing the specified cartId @@ -26,11 +26,11 @@ const handler = async(event) => { } await cart.save(); - return { statusCode: 200, body: cart }; + return { statusCode: 200, body: JSON.stringify(cart) }; } else { // If no cartId, create a new cart const cart = await Cart.create({ items: event.body.items }); - return { statusCode: 200, body: cart }; + return { statusCode: 200, body: JSON.stringify(cart) }; } } catch (error) { return { statusCode: 500, body: error.toString() }; diff --git a/examples/ecommerce-netlify-functions/functions/checkout.js b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js similarity index 88% rename from examples/ecommerce-netlify-functions/functions/checkout.js rename to examples/ecommerce-netlify-functions/netlify/functions/checkout.js index 2dfbd3272fd..ab5a71bfac2 100644 --- a/examples/ecommerce-netlify-functions/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js @@ -1,13 +1,13 @@ 'use strict'; -const config = require('../.config'); -const stripe = require('../integrations/stripe') +const stripe = require('../../integrations/stripe') -const { Cart, Order, Product } = require('../models'); +const { Cart, Order, Product } = require('../../models'); +const connect = require('../../index'); const handler = async(event) => { try { - + await connect(); const cart = await Cart.findOne({ _id: event.body.cartId }); const stripeProducts = { line_items: [] }; @@ -57,7 +57,7 @@ const handler = async(event) => { await cart.save(); return { statusCode: 200, - body: { order: order, cart: cart }, + body: JSON.stringify({ order: order, cart: cart }), headers: { Location: session.url } }; } catch (error) { diff --git a/examples/ecommerce-netlify-functions/functions/getCart.js b/examples/ecommerce-netlify-functions/netlify/functions/getCart.js similarity index 74% rename from examples/ecommerce-netlify-functions/functions/getCart.js rename to examples/ecommerce-netlify-functions/netlify/functions/getCart.js index dae1be74466..a56ba55b155 100644 --- a/examples/ecommerce-netlify-functions/functions/getCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/getCart.js @@ -1,9 +1,11 @@ 'use strict'; -const { Cart } = require('../models'); +const { Cart } = require('../../models'); +const connect = require('../../index'); const handler = async(event) => { try { + await connect(); // get the document containing the specified cartId const cart = await Cart. findOne({ _id: event.queryStringParameters.cartId }). diff --git a/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js b/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js new file mode 100644 index 00000000000..1797b2a7f06 --- /dev/null +++ b/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js @@ -0,0 +1,16 @@ +'use strict'; + +const { Product } = require('../../models'); +const connect = require('../../index'); + +const handler = async(event) => { + try { + await connect(); + const products = await Product.find(); + return { statusCode: 200, body: JSON.stringify(products) }; + } catch (error) { + return { statusCode: 500, body: error.toString() }; + } +}; + +module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js similarity index 79% rename from examples/ecommerce-netlify-functions/functions/removeFromCart.js rename to examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js index 58eb7e87c5a..07df448b1ef 100644 --- a/examples/ecommerce-netlify-functions/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js @@ -1,10 +1,11 @@ 'use strict'; -const { Cart } = require('../models'); +const { Cart } = require('../../models'); +const connect = require('../../index'); const handler = async(event) => { try { - + await connect(); const cart = await Cart.findOne({ _id: event.body.cartId }); const index = cart.items.findIndex((item) => item.productId.toString() == event.body.item.productId.toString() @@ -22,7 +23,7 @@ const handler = async(event) => { cart.items.splice(index, 1); await cart.save(); } - return { statusCode: 200, body: cart }; + return { statusCode: 200, body: JSON.stringify(cart) }; } catch (error) { console.log(error); return { statusCode: 500, body: error.toString() }; diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index a2881588db3..cbda86d8e0b 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -2,7 +2,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: addToCart } = require('../functions/addToCart'); +const { handler: addToCart } = require('../netlify/functions/addToCart'); const mongoose = require('mongoose'); const fixtures = require('../test/fixtures'); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index d6503a3ab6e..91fb4fe4ab2 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -2,8 +2,8 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: addToCart } = require('../functions/addToCart'); -const { handler: checkout } = require('../functions/checkout'); +const { handler: addToCart } = require('../netlify/functions/addToCart'); +const { handler: checkout } = require('../netlify/functions/checkout'); const mongoose = require('mongoose'); const fixtures = require('./fixtures'); const sinon = require('sinon'); diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js index 5b6db98306a..24251508b98 100644 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -2,7 +2,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: getCart } = require('../functions/getCart'); +const { handler: getCart } = require('../netlify/functions/getCart'); const fixtures = require('./fixtures'); const mongoose = require('mongoose'); diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js index f247809d55c..714ba2b6477 100644 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -2,7 +2,7 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: getProducts } = require('../functions/getProducts'); +const { handler: getProducts } = require('../netlify/functions/getProducts'); const fixtures = require('./fixtures'); const mongoose = require('mongoose'); diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 2e54056faa1..0350d8c5dab 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -2,8 +2,8 @@ const { describe, it, before, after } = require('mocha'); const assert = require('assert'); -const { handler: addToCart } = require('../functions/addToCart'); -const { handler: removeFromCart } = require('../functions/removeFromCart'); +const { handler: addToCart } = require('../netlify/functions/addToCart'); +const { handler: removeFromCart } = require('../netlify/functions/removeFromCart'); const mongoose = require('mongoose'); const fixtures = require('./fixtures'); From 41712f198434d7c22877cc96bbae80dc02ba2134 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:41:26 -0400 Subject: [PATCH 19/31] tests fixed --- examples/ecommerce-netlify-functions/test/addToCart.test.js | 6 ++++-- examples/ecommerce-netlify-functions/test/checkout.test.js | 2 ++ .../ecommerce-netlify-functions/test/removeFromCart.test.js | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index cbda86d8e0b..bf14f634041 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -17,7 +17,7 @@ describe('Add to Cart', function() { after(async() => { await mongoose.disconnect(); }); - it('Should create a cart and add a product to the cart.', async function() { + it('Should create a cart and add a product to the cart', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); const params = { @@ -30,10 +30,11 @@ describe('Add to Cart', function() { } }; const result = await addToCart(params); + result.body = JSON.parse(result.body); assert(result.body); assert(result.body.items.length); }); - it('Should find the cart and add to it.', async function() { + it('Should find the cart and add to the cart', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); const cart = await fixtures.createCart({products: null}); @@ -47,6 +48,7 @@ describe('Add to Cart', function() { } }; const findCart = await addToCart(params); + findCart.body = JSON.parse(findCart.body) assert(findCart.body); assert.equal(findCart.body.items.length, 2) }); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 91fb4fe4ab2..b66380e5b58 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -31,6 +31,7 @@ describe('Checkout', function() { } }; const result = await addToCart(params); + result.body = JSON.parse(result.body); assert(result.body); assert(result.body.items.length); params.body.cartId = result.body._id; @@ -46,6 +47,7 @@ describe('Checkout', function() { params.body.zip = '33145'; params.body.shipping = 'standard'; const finish = await checkout(params); + finish.body = JSON.parse(finish.body); assert(finish.body.order); assert(finish.body.cart); }); diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 0350d8c5dab..8ccbe8da58f 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -32,6 +32,7 @@ describe('Remove From Cart', function() { } }; const result = await addToCart(params); + result.body = JSON.parse(result.body); assert(result.body); assert.equal(result.body.items.length, 2); const newParams = { @@ -43,6 +44,7 @@ describe('Remove From Cart', function() { } }; const remove = await removeFromCart(newParams); + remove.body = JSON.parse(remove.body); assert.equal(remove.body.items.length, 1); }); @@ -59,6 +61,7 @@ describe('Remove From Cart', function() { } }; const result = await addToCart(params); + result.body = JSON.parse(result.body); assert(result.body); assert(result.body.items.length); const newParams = { @@ -71,6 +74,7 @@ describe('Remove From Cart', function() { } }; const remove = await removeFromCart(newParams); + remove.body = JSON.parse(remove.body); assert.equal(remove.body.items[0].quantity, 1); }); From 28b55570f26c456c48f66b3972cc0442d93d0a63 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:45:11 -0400 Subject: [PATCH 20/31] added dummy product script --- .../dummyProducts.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 examples/ecommerce-netlify-functions/dummyProducts.js diff --git a/examples/ecommerce-netlify-functions/dummyProducts.js b/examples/ecommerce-netlify-functions/dummyProducts.js new file mode 100644 index 00000000000..67fe16034a4 --- /dev/null +++ b/examples/ecommerce-netlify-functions/dummyProducts.js @@ -0,0 +1,20 @@ +const { Product } = require('./models'); +const mongoose = require('mongoose'); + +async function createProducts() { + await mongoose.connect('mongodb://localhost:27017/netlify'); + + await Product.create({ + productName: 'Dummy Product', + productPrice: 500 + }); + + await Product.create({ + productName: 'Another Dummy Product', + productPrice: 600 + }); + + console.log('done'); +} + +createProducts(); \ No newline at end of file From 42f40d58373bf9828cc3332016dfe98f7a00d930 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Thu, 7 Jul 2022 12:32:57 -0400 Subject: [PATCH 21/31] made tests work with live build --- .../netlify/functions/addToCart.js | 11 +++--- .../netlify/functions/checkout.js | 1 + .../netlify/functions/removeFromCart.js | 1 + .../test/addToCart.test.js | 34 +++++++++++++++++-- .../test/checkout.test.js | 2 ++ .../test/removeFromCart.test.js | 4 +++ 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js index a032a03165d..a6c3ecee44a 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js @@ -5,24 +5,25 @@ const connect = require('../../index'); const handler = async(event) => { try { + event.body = JSON.parse(event.body || {}); await connect(); const products = await Product.find(); if (event.body.cartId) { // get the document containing the specified cartId const cart = await Cart.findOne({ _id: event.body.cartId }).setOptions({ sanitizeFilter: true }); for (const product of event.body.items) { - const exists = cart.items.find(item => - item.productId.toString() === product.productId.toString() - ); - if (!exists && products.find(p => item.productId === product.id.toString())) { + const exists = cart.items.find(item => item.productId.toString() === product.productId.toString()); + if (!exists && products.find(p => product.productId.toString() === p._id.toString())) { cart.items.push(product); + await cart.save(); } else { exists.quantity += product.quantity; + await cart.save(); } } if (!cart.items.length) { - return { statusCode: 200, body: { cart: null } }; + return { statusCode: 200, body: JSON.stringify({ cart: null }) }; } await cart.save(); diff --git a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js index ab5a71bfac2..f0a530b95a6 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js @@ -7,6 +7,7 @@ const connect = require('../../index'); const handler = async(event) => { try { + event.body = JSON.parse(event.body || {}); await connect(); const cart = await Cart.findOne({ _id: event.body.cartId }); diff --git a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js index 07df448b1ef..9d1ca4ebf88 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js @@ -5,6 +5,7 @@ const connect = require('../../index'); const handler = async(event) => { try { + event.body = JSON.parse(event.body || {}); await connect(); const cart = await Cart.findOne({ _id: event.body.cartId }); const index = cart.items.findIndex((item) => diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index bf14f634041..07a1f516bb6 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -29,6 +29,7 @@ describe('Add to Cart', function() { ] } }; + params.body = JSON.stringify(params.body); const result = await addToCart(params); result.body = JSON.parse(result.body); assert(result.body); @@ -37,7 +38,7 @@ describe('Add to Cart', function() { it('Should find the cart and add to the cart', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); - const cart = await fixtures.createCart({products: null}); + const { cart } = await fixtures.createCart({products: []}); const params = { body: { cartId: cart._id, @@ -47,9 +48,38 @@ describe('Add to Cart', function() { ] } }; + params.body = JSON.stringify(params.body); const findCart = await addToCart(params); - findCart.body = JSON.parse(findCart.body) + findCart.body = JSON.parse(findCart.body); assert(findCart.body); assert.equal(findCart.body.items.length, 2) }); + it('Should find the cart and increase the quantity of the item(s) in the cart', async function() { + const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) + .then((res) => res.products); + const { cart } = await fixtures.createCart({products: []}); + const params = { + body: { + cartId: cart._id, + items: [ + { productId: products[0]._id, quantity: 2 }, + { productId: products[1]._id, quantity: 1 } + ] + } + }; + params.body = JSON.stringify(params.body); + const findCart = await addToCart(params); + findCart.body = JSON.parse(findCart.body); + assert(findCart.body); + assert.equal(findCart.body.items.length, 2); + assert.equal(findCart.body.items[0].quantity, 2); + assert.equal(findCart.body.items[1].quantity, 1); + params.body = JSON.stringify(params.body) + const updateCart = await addToCart(params); + updateCart.body = JSON.parse(updateCart.body); + assert(updateCart.body); + assert.equal(updateCart.body.items.length, 2); + assert.equal(updateCart.body.items[0].quantity, 4); + assert.equal(updateCart.body.items[1].quantity, 2); + }); }); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index b66380e5b58..73a96c86fe0 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -30,6 +30,7 @@ describe('Checkout', function() { ] } }; + params.body = JSON.stringify(params.body); const result = await addToCart(params); result.body = JSON.parse(result.body); assert(result.body); @@ -46,6 +47,7 @@ describe('Checkout', function() { params.body.state = 'Florida'; params.body.zip = '33145'; params.body.shipping = 'standard'; + params.body = JSON.stringify(params.body); const finish = await checkout(params); finish.body = JSON.parse(finish.body); assert(finish.body.order); diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 8ccbe8da58f..f75113c1cd3 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -31,6 +31,7 @@ describe('Remove From Cart', function() { ] } }; + params.body = JSON.stringify(params.body); const result = await addToCart(params); result.body = JSON.parse(result.body); assert(result.body); @@ -43,6 +44,7 @@ describe('Remove From Cart', function() { } } }; + newParams.body = JSON.stringify(newParams.body); const remove = await removeFromCart(newParams); remove.body = JSON.parse(remove.body); assert.equal(remove.body.items.length, 1); @@ -60,6 +62,7 @@ describe('Remove From Cart', function() { ] } }; + params.body = JSON.stringify(params.body); const result = await addToCart(params); result.body = JSON.parse(result.body); assert(result.body); @@ -73,6 +76,7 @@ describe('Remove From Cart', function() { } } }; + newParams.body = JSON.stringify(newParams.body); const remove = await removeFromCart(newParams); remove.body = JSON.parse(remove.body); assert.equal(remove.body.items[0].quantity, 1); From 5301deb4ba5fb03c557c144f277b1f38cdd7d5ee Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 16 Jul 2022 21:55:29 -0400 Subject: [PATCH 22/31] fix: cleanup and various updates --- .gitignore | 2 +- .../.config/development.js | 6 +++ .../.config/index.js | 13 +++++ .../.config/test.js | 6 +++ .../ecommerce-netlify-functions/README.md | 54 +++++++++++++++++++ .../ecommerce-netlify-functions/connect.js | 15 ++++++ .../dummyProducts.js | 20 ------- examples/ecommerce-netlify-functions/index.js | 20 ------- .../netlify/functions/addToCart.js | 7 ++- .../netlify/functions/checkout.js | 2 +- .../netlify/functions/getCart.js | 2 +- .../netlify/functions/getProducts.js | 2 +- .../netlify/functions/removeFromCart.js | 2 +- .../ecommerce-netlify-functions/package.json | 26 ++++----- examples/ecommerce-netlify-functions/seed.js | 24 +++++++++ .../test/addToCart.test.js | 10 ---- .../test/checkout.test.js | 8 --- .../test/getCart.test.js | 10 ---- .../test/getProducts.test.js | 9 ---- .../test/removeFromCart.test.js | 12 ----- .../test/setup.test.js | 14 +++++ 21 files changed, 157 insertions(+), 107 deletions(-) create mode 100644 examples/ecommerce-netlify-functions/.config/development.js create mode 100644 examples/ecommerce-netlify-functions/.config/index.js create mode 100644 examples/ecommerce-netlify-functions/.config/test.js create mode 100644 examples/ecommerce-netlify-functions/README.md create mode 100644 examples/ecommerce-netlify-functions/connect.js delete mode 100644 examples/ecommerce-netlify-functions/dummyProducts.js delete mode 100644 examples/ecommerce-netlify-functions/index.js create mode 100644 examples/ecommerce-netlify-functions/seed.js create mode 100644 examples/ecommerce-netlify-functions/test/setup.test.js diff --git a/.gitignore b/.gitignore index b63c90b7be8..70b24471080 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ test/files/main.js package-lock.json -.config* +.config.js # Compiled docs docs/*.html diff --git a/examples/ecommerce-netlify-functions/.config/development.js b/examples/ecommerce-netlify-functions/.config/development.js new file mode 100644 index 00000000000..bf40f91362b --- /dev/null +++ b/examples/ecommerce-netlify-functions/.config/development.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = Object.freeze({ + mongodbUri: 'mongodb://localhost:27017/ecommerce', + stripeSecretKey: 'YOUR STRIPE KEY HERE' +}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.config/index.js b/examples/ecommerce-netlify-functions/.config/index.js new file mode 100644 index 00000000000..2c58f15f9ac --- /dev/null +++ b/examples/ecommerce-netlify-functions/.config/index.js @@ -0,0 +1,13 @@ +'use strict'; + +if (process.env.NODE_ENV) { + try { + module.exports = require('./' + process.env.NODE_ENV); + console.log('Using ' + process.env.NODE_ENV); + } catch (err) { + module.exports = require('./development'); + } +} else { + console.log('using production'); + module.exports = require('./production'); +} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.config/test.js b/examples/ecommerce-netlify-functions/.config/test.js new file mode 100644 index 00000000000..05ceb8eee09 --- /dev/null +++ b/examples/ecommerce-netlify-functions/.config/test.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = Object.freeze({ + mongodbUri: 'mongodb://localhost:27017/ecommerce_test', + stripeSecretKey: 'test' +}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/README.md b/examples/ecommerce-netlify-functions/README.md new file mode 100644 index 00000000000..8889dddd8c9 --- /dev/null +++ b/examples/ecommerce-netlify-functions/README.md @@ -0,0 +1,54 @@ +# ecommerce-netlify-functions + +This sample demonstrates using Mongoose to build an eCommerce shopping cart using [Netlify Functions](https://www.netlify.com/products/functions/), which runs on [AWS Lambda](https://mongoosejs.com/docs/lambda.html). + +Other tools include: + +1. Stripe for payment processing +2. [Mocha](https://masteringjs.io/mocha) and [Sinon](https://masteringjs.io/sinon) for testing + +## Running This Example + +1. Make sure you have a MongoDB instance running on `localhost:27017`, or update `mongodbUri` in `.config/development.js` to your MongoDB server's address. +2. Run `npm install` +3. Run `npm run seed` +4. Run `npm start` +5. Visit `http://localhost:8888/.netlify/functions/getProducts` to list all available products +6. Run other endpoints using curl or postman + +## Testing + +Make sure you have a MongoDB instance running on `localhost:27017`, or update `mongodbUri` in `.config/test.js` to your MongoDB server's address. +Then run `npm test`. + +``` +$ npm test + +> test +> env NODE_ENV=test mocha ./test/*.test.js + +Using test + + + Add to Cart + ✔ Should create a cart and add a product to the cart + ✔ Should find the cart and add to the cart + ✔ Should find the cart and increase the quantity of the item(s) in the cart + + Checkout + ✔ Should do a successful checkout run + + Get the cart given an id + ✔ Should create a cart and then find the cart. + + Products + ✔ Should get all products. + + Remove From Cart + ✔ Should create a cart and then it should remove the entire item from it. + ✔ Should create a cart and then it should reduce the quantity of an item from it. + + + 8 passing (112ms) + +``` \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/connect.js b/examples/ecommerce-netlify-functions/connect.js new file mode 100644 index 00000000000..22c325f054c --- /dev/null +++ b/examples/ecommerce-netlify-functions/connect.js @@ -0,0 +1,15 @@ +'use strict'; + +const config = require('./.config'); +const mongoose = require('mongoose'); + +let conn = null; + +module.exports = async function connect() { + if (conn != null) { + return conn; + } + conn = mongoose.connection; + await mongoose.connect(config.mongodbUri); + return conn; +} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/dummyProducts.js b/examples/ecommerce-netlify-functions/dummyProducts.js deleted file mode 100644 index 67fe16034a4..00000000000 --- a/examples/ecommerce-netlify-functions/dummyProducts.js +++ /dev/null @@ -1,20 +0,0 @@ -const { Product } = require('./models'); -const mongoose = require('mongoose'); - -async function createProducts() { - await mongoose.connect('mongodb://localhost:27017/netlify'); - - await Product.create({ - productName: 'Dummy Product', - productPrice: 500 - }); - - await Product.create({ - productName: 'Another Dummy Product', - productPrice: 600 - }); - - console.log('done'); -} - -createProducts(); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/index.js b/examples/ecommerce-netlify-functions/index.js deleted file mode 100644 index 94fbdd718c7..00000000000 --- a/examples/ecommerce-netlify-functions/index.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -const mongoose = require('mongoose'); - - -mongoose.connection.on('connected', () => { - console.log('connected') -}); - -let conn = null; - -module.exports = async function connect() { - if (conn != null) { - return conn; - } - conn = mongoose.connection; - await mongoose.connect('mongodb://localhost:27017/netlify'); - return conn; - -} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js index a6c3ecee44a..30ee3fc8330 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js @@ -1,7 +1,7 @@ 'use strict'; const { Cart, Product } = require('../../models'); -const connect = require('../../index'); +const connect = require('../../connect'); const handler = async(event) => { try { @@ -11,6 +11,11 @@ const handler = async(event) => { if (event.body.cartId) { // get the document containing the specified cartId const cart = await Cart.findOne({ _id: event.body.cartId }).setOptions({ sanitizeFilter: true }); + + if (cart == null) { + return { statusCode: 404, body: JSON.stringify({ message: 'Cart not found' }) }; + } + for (const product of event.body.items) { const exists = cart.items.find(item => item.productId.toString() === product.productId.toString()); if (!exists && products.find(p => product.productId.toString() === p._id.toString())) { diff --git a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js index f0a530b95a6..bccf1f923c9 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js @@ -3,7 +3,7 @@ const stripe = require('../../integrations/stripe') const { Cart, Order, Product } = require('../../models'); -const connect = require('../../index'); +const connect = require('../../connect'); const handler = async(event) => { try { diff --git a/examples/ecommerce-netlify-functions/netlify/functions/getCart.js b/examples/ecommerce-netlify-functions/netlify/functions/getCart.js index a56ba55b155..a2b72ad998e 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/getCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/getCart.js @@ -1,7 +1,7 @@ 'use strict'; const { Cart } = require('../../models'); -const connect = require('../../index'); +const connect = require('../../connect'); const handler = async(event) => { try { diff --git a/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js b/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js index 1797b2a7f06..3fbc8fd9a9b 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js @@ -1,7 +1,7 @@ 'use strict'; const { Product } = require('../../models'); -const connect = require('../../index'); +const connect = require('../../connect'); const handler = async(event) => { try { diff --git a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js index 9d1ca4ebf88..7124f4d36d3 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js @@ -1,7 +1,7 @@ 'use strict'; const { Cart } = require('../../models'); -const connect = require('../../index'); +const connect = require('../../connect'); const handler = async(event) => { try { diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json index 678161257d8..94e19c2dbb8 100644 --- a/examples/ecommerce-netlify-functions/package.json +++ b/examples/ecommerce-netlify-functions/package.json @@ -1,14 +1,16 @@ { - "dependencies": { - "mongoose": "^6.3.5", - "sinon": "^14.0.0", - "stripe": "^9.6.0" - }, - "devDependencies": { - "mocha": "10.0.0", - "netlify-cli": "^10.7.1" - }, - "scripts": { - "test": "mocha --exit ./test/*.test.js" - } + "dependencies": { + "mongoose": "6.3.5", + "sinon": "14.0.0", + "stripe": "9.6.0" + }, + "devDependencies": { + "mocha": "10.0.0", + "netlify-cli": "10.7.1" + }, + "scripts": { + "seed": "env NODE_ENV=development node ./seed", + "start": "env NODE_ENV=development netlify dev", + "test": "env NODE_ENV=test mocha ./test/*.test.js" + } } diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js new file mode 100644 index 00000000000..41a97a4eb09 --- /dev/null +++ b/examples/ecommerce-netlify-functions/seed.js @@ -0,0 +1,24 @@ +'use strict'; + +const { Product } = require('./models'); +const config = require('./.config'); +const mongoose = require('mongoose'); + +async function createProducts() { + await mongoose.connect(config.mongodbUri); + + await Product.create({ + productName: 'Dummy Product', + productPrice: 500 + }); + + await Product.create({ + productName: 'Another Dummy Product', + productPrice: 600 + }); + + console.log('done'); + process.exit(0); +} + +createProducts(); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index 07a1f516bb6..fb0ecb541c8 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -6,17 +6,7 @@ const { handler: addToCart } = require('../netlify/functions/addToCart'); const mongoose = require('mongoose'); const fixtures = require('../test/fixtures'); - - describe('Add to Cart', function() { - before(async() => { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - }); - - after(async() => { - await mongoose.disconnect(); - }); it('Should create a cart and add a product to the cart', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 73a96c86fe0..71e9483f26e 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -10,14 +10,6 @@ const sinon = require('sinon'); const stripe = require('../integrations/stripe') describe('Checkout', function() { - before(async() => { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - }); - - after(async() => { - await mongoose.disconnect(); - }); it('Should do a successful checkout run', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js index 24251508b98..847e39e31ea 100644 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ b/examples/ecommerce-netlify-functions/test/getCart.test.js @@ -6,17 +6,7 @@ const { handler: getCart } = require('../netlify/functions/getCart'); const fixtures = require('./fixtures'); const mongoose = require('mongoose'); - - describe('Get the cart given an id', function() { - before(async() => { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - }); - - after(async() => { - await mongoose.disconnect(); - }); it('Should create a cart and then find the cart.', async function() { const cart = await fixtures.createCart({ products: null }); const params = { diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js index 714ba2b6477..0328f2c9e54 100644 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -7,15 +7,6 @@ const fixtures = require('./fixtures'); const mongoose = require('mongoose'); describe('Products', function() { - before(async() => { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - }); - - after(async() => { - await mongoose.disconnect(); - }); - it('Should get all products.', async function() { await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index f75113c1cd3..24de63946d6 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -7,18 +7,7 @@ const { handler: removeFromCart } = require('../netlify/functions/removeFromCart const mongoose = require('mongoose'); const fixtures = require('./fixtures'); - - describe('Remove From Cart', function() { - before(async() => { - await mongoose.connect('mongodb://localhost:27017/netlify'); - await mongoose.connection.dropDatabase(); - }); - - after(async() => { - await mongoose.disconnect(); - }); - it('Should create a cart and then it should remove the entire item from it.', async function() { const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) .then((res) => res.products); @@ -81,5 +70,4 @@ describe('Remove From Cart', function() { remove.body = JSON.parse(remove.body); assert.equal(remove.body.items[0].quantity, 1); }); - }); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/setup.test.js b/examples/ecommerce-netlify-functions/test/setup.test.js new file mode 100644 index 00000000000..7870e5a8bde --- /dev/null +++ b/examples/ecommerce-netlify-functions/test/setup.test.js @@ -0,0 +1,14 @@ +'use strict'; + +const { after } = require('mocha'); +const config = require('../.config'); +const mongoose = require('mongoose'); + +before(async() => { + await mongoose.connect(config.mongodbUri); + await mongoose.connection.dropDatabase(); +}); + +after(async function() { + await mongoose.disconnect(); +}); \ No newline at end of file From a45cfb6b0ce0067ae9794cfa80f7917e1fb3c6f8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 18 Jul 2022 22:21:57 -0400 Subject: [PATCH 23/31] fix(schema): disallow setting __proto__ when creating schema with dotted properties Fix #12085 --- lib/schema.js | 7 +++++++ test/schema.test.js | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/schema.js b/lib/schema.js index 781ccdbbcf8..730bddeac49 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -554,6 +554,10 @@ Schema.prototype.add = function add(obj, prefix) { const keys = Object.keys(obj); const typeKey = this.options.typeKey; for (const key of keys) { + if (utils.specialProperties.has(key)) { + continue; + } + const fullPath = prefix + key; const val = obj[key]; @@ -854,6 +858,9 @@ Schema.prototype.path = function(path, obj) { let fullPath = ''; for (const sub of subpaths) { + if (utils.specialProperties.has(sub)) { + throw new Error('Cannot set special property `' + sub + '` on a schema'); + } fullPath = fullPath += (fullPath.length > 0 ? '.' : '') + sub; if (!branch[sub]) { this.nested[fullPath] = true; diff --git a/test/schema.test.js b/test/schema.test.js index 7bc6299e23e..6ef548b0059 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -2792,4 +2792,14 @@ describe('schema', function() { }); }, /Cannot use schema-level projections.*subdocument_mapping.not_selected/); }); + + it('disallows setting special properties with `add()` or constructor (gh-12085)', async function() { + const maliciousPayload = '{"__proto__.toString": "Number"}'; + + assert.throws(() => { + mongoose.Schema(JSON.parse(maliciousPayload)); + }, /__proto__/); + + assert.ok({}.toString()); + }); }); From 1344214cc152159f7788fd3b2a013590e1c0c679 Mon Sep 17 00:00:00 2001 From: Nagalokesh <20608938+LokeshKanumoori@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:11:43 +0530 Subject: [PATCH 24/31] Update migrating_to_6.md correct the proof/example statement of isObjectIdOrHexString --- docs/migrating_to_6.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/migrating_to_6.md b/docs/migrating_to_6.md index 270624e3368..68e4a8249e0 100644 --- a/docs/migrating_to_6.md +++ b/docs/migrating_to_6.md @@ -194,8 +194,8 @@ mongoose.isValidObjectId(new User({ name: 'test' })); // true // character hex strings. mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true -mongoose.isValidObjectId('0123456789ab'); // false -mongoose.isValidObjectId(6); // false +mongoose.isObjectIdOrHexString('0123456789ab'); // false +mongoose.isObjectIdOrHexString(6); // false ```

Schema Defined Document Key Order

From 086bd9f3f9aa06396a922d9948eee0248cf4bbb8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 19 Jul 2022 11:54:05 -0400 Subject: [PATCH 25/31] fix(query): apply lean transform option to top-level document Fix #12093 --- lib/query.js | 10 ++++++++-- test/query.test.js | 38 ++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/query.js b/lib/query.js index 1bfed85a27e..634616fe79a 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4019,7 +4019,9 @@ Query.prototype._findAndModify = function(type, callback) { */ function _completeOneLean(schema, doc, path, res, opts, callback) { - if (opts.lean && opts.lean.transform) { + if (opts.lean && typeof opts.lean.transform === 'function') { + opts.lean.transform(doc); + for (let i = 0; i < schema.childSchemas.length; i++) { const childPath = path ? path + '.' + schema.childSchemas[i].model.path : schema.childSchemas[i].model.path; const _schema = schema.childSchemas[i].schema; @@ -4053,7 +4055,11 @@ function _completeOneLean(schema, doc, path, res, opts, callback) { */ function _completeManyLean(schema, docs, path, opts, callback) { - if (opts.lean && opts.lean.transform) { + if (opts.lean && typeof opts.lean.transform === 'function') { + for (const doc of docs) { + opts.lean.transform(doc); + } + for (let i = 0; i < schema.childSchemas.length; i++) { const childPath = path ? path + '.' + schema.childSchemas[i].model.path : schema.childSchemas[i].model.path; const _schema = schema.childSchemas[i].schema; diff --git a/test/query.test.js b/test/query.test.js index 746774c5c42..1ebc5320aa4 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4006,22 +4006,28 @@ describe('Query', function() { }); const Test = db.model('gh10423', testSchema); await Test.create({ name: 'foo', foo: [{ sub: 'Test' }, { sub: 'Testerson' }], otherName: { nickName: 'Bar' } }); - const result = await Test.find().lean({ transform: (doc) => { - delete doc._id; - return doc; - } }); - assert(result[0]._id); - assert.equal(result[0].otherName._id, undefined); - assert.equal(result[0].foo[0]._id, undefined); - assert.equal(result[0].foo[1]._id, undefined); - const single = await Test.findOne().lean({ transform: (doc) => { - delete doc._id; - return doc; - } }); - assert(single._id); - assert.equal(single.otherName._id, undefined); - assert.equal(single.foo[0]._id, undefined); - assert.equal(single.foo[0]._id, undefined); + + const result = await Test.find().lean({ + transform: (doc) => { + delete doc._id; + return doc; + } + }); + assert.strictEqual(result[0]._id, undefined); + assert.strictEqual(result[0].otherName._id, undefined); + assert.strictEqual(result[0].foo[0]._id, undefined); + assert.strictEqual(result[0].foo[1]._id, undefined); + + const single = await Test.findOne().lean({ + transform: (doc) => { + delete doc._id; + return doc; + } + }); + assert.strictEqual(single._id, undefined); + assert.strictEqual(single.otherName._id, undefined); + assert.strictEqual(single.foo[0]._id, undefined); + assert.strictEqual(single.foo[0]._id, undefined); }); it('skips applying default projections over slice projections (gh-11940)', async function() { From 2e6b0643b1978fc7bee07030dcd2ff00aa6641a4 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Tue, 19 Jul 2022 14:04:45 -0400 Subject: [PATCH 26/31] made requested changes --- .../.config/development.js | 4 +++- .../.config/test.js | 5 ++++- .../ecommerce-netlify-functions/models.js | 5 +++-- .../netlify/functions/addToCart.js | 8 ++++--- .../netlify/functions/checkout.js | 12 +++++----- examples/ecommerce-netlify-functions/seed.js | 22 +++++++++++++++---- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/examples/ecommerce-netlify-functions/.config/development.js b/examples/ecommerce-netlify-functions/.config/development.js index bf40f91362b..b0629c97c88 100644 --- a/examples/ecommerce-netlify-functions/.config/development.js +++ b/examples/ecommerce-netlify-functions/.config/development.js @@ -2,5 +2,7 @@ module.exports = Object.freeze({ mongodbUri: 'mongodb://localhost:27017/ecommerce', - stripeSecretKey: 'YOUR STRIPE KEY HERE' + stripeSecretKey: 'YOUR STRIPE KEY HERE', + success_url: 'localhost:3000/success', + cancel_url: 'localhost:3000/cancel' }); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.config/test.js b/examples/ecommerce-netlify-functions/.config/test.js index 05ceb8eee09..6dc295150ea 100644 --- a/examples/ecommerce-netlify-functions/.config/test.js +++ b/examples/ecommerce-netlify-functions/.config/test.js @@ -2,5 +2,8 @@ module.exports = Object.freeze({ mongodbUri: 'mongodb://localhost:27017/ecommerce_test', - stripeSecretKey: 'test' + stripeSecretKey: 'test', + success_url: 'localhost:3000/success', + cancel_url: 'localhost:3000/cancel' + }); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/models.js b/examples/ecommerce-netlify-functions/models.js index 501ecdd7c63..7514b9986a2 100644 --- a/examples/ecommerce-netlify-functions/models.js +++ b/examples/ecommerce-netlify-functions/models.js @@ -2,8 +2,9 @@ const mongoose = require('mongoose'); const productSchema = new mongoose.Schema({ - productName: String, - productPrice: Number + name: String, + price: Number, + image: String }); const Product = mongoose.model('Product', productSchema); diff --git a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js index 30ee3fc8330..70182f7021e 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js @@ -15,10 +15,12 @@ const handler = async(event) => { if (cart == null) { return { statusCode: 404, body: JSON.stringify({ message: 'Cart not found' }) }; } - + if(!Array.isArray(event.body.items)) { + return { statusCode: 500, body: JSON.stringify({ error: 'items is not an array' }) }; + } for (const product of event.body.items) { - const exists = cart.items.find(item => item.productId.toString() === product.productId.toString()); - if (!exists && products.find(p => product.productId.toString() === p._id.toString())) { + const exists = cart.items.find(item => item?.productId?.toString() === product?.productId?.toString()); + if (!exists && products.find(p => product?.productId?.toString() === p?._id?.toString())) { cart.items.push(product); await cart.save(); } else { diff --git a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js index bccf1f923c9..579f62e7c42 100644 --- a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js +++ b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js @@ -1,7 +1,7 @@ 'use strict'; const stripe = require('../../integrations/stripe') - +const config = require('../../.config'); const { Cart, Order, Product } = require('../../models'); const connect = require('../../connect'); @@ -19,19 +19,19 @@ const handler = async(event) => { price_data: { currency: 'usd', product_data: { - name: product.productName + name: product.name }, - unit_amount: product.productPrice + unit_amount: product.price }, quantity: cart.items[i].quantity }); - total = total + (product.productPrice * cart.items[i].quantity); + total = total + (product.price * cart.items[i].quantity); } const session = await stripe.checkout.sessions.create({ line_items: stripeProducts.line_items, mode: 'payment', - success_url: 'insert a url here', - cancel_url: 'insert a url here' + success_url: config.success_url, + cancel_url: config.cancel_url }); const intent = await stripe.paymentIntents.retrieve(session.payment_intent); if (intent.status !== 'succeeded') { diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js index 41a97a4eb09..9f14ddb88c7 100644 --- a/examples/ecommerce-netlify-functions/seed.js +++ b/examples/ecommerce-netlify-functions/seed.js @@ -8,13 +8,27 @@ async function createProducts() { await mongoose.connect(config.mongodbUri); await Product.create({ - productName: 'Dummy Product', - productPrice: 500 + name: 'iPhone 12', + price: 500, + image: 'https://images.unsplash.com/photo-1611472173362-3f53dbd65d80' }); await Product.create({ - productName: 'Another Dummy Product', - productPrice: 600 + name: 'iPhone SE', + price: 600, + image: 'https://images.unsplash.com/photo-1529618160092-2f8ccc8e087b' + }); + + await Product.create({ + name: 'iPhone 12 Pro', + price: 700, + image: 'https://images.unsplash.com/photo-1603921326210-6edd2d60ca68' + }); + + await Product.create({ + name: 'iPhone 11', + price: 800, + image: 'https://images.unsplash.com/photo-1574755393849-623942496936' }); console.log('done'); From 2262a7709fe72ea255d23e1aea4ac84e9627e523 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 19 Jul 2022 20:16:53 -0400 Subject: [PATCH 27/31] fix(document): avoid mutating original object passed to $set() when applying defaults to nested properties Fix #12102 --- lib/document.js | 2 +- test/document.test.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/document.js b/lib/document.js index 72c12c75442..e6f73aeb774 100644 --- a/lib/document.js +++ b/lib/document.js @@ -1149,8 +1149,8 @@ Document.prototype.$set = function $set(path, val, type, options) { } if (utils.isNonBuiltinObject(valForKey) && pathtype === 'nested') { - $applyDefaultsToNested(path[key], prefix + key, this); this.$set(prefix + key, path[key], constructing, Object.assign({}, options, { _skipMarkModified: true })); + $applyDefaultsToNested(this.$get(prefix + key), prefix + key, this); continue; } else if (strict) { // Don't overwrite defaults with undefined keys (gh-3981) (gh-9039) diff --git a/test/document.test.js b/test/document.test.js index 160b14fbe3d..359a0ee050d 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -8831,7 +8831,7 @@ describe('document', function() { assert.ok(!user.updatedAt); }); - it('Sets default when passing undefined as value for a key in a nested subdoc (gh-9039)', async function() { + it('Sets default when passing undefined as value for a key in a nested subdoc (gh-12102) (gh-9039)', async function() { const Test = db.model('Test', { nested: { prop: { @@ -8841,9 +8841,11 @@ describe('document', function() { } }); - - const doc = await Test.create({ nested: { prop: undefined } }); + const obj = { nested: { prop: undefined } }; + const doc = await Test.create(obj); assert.equal(doc.nested.prop, 'some default value'); + + assert.deepStrictEqual(obj, { nested: { prop: undefined } }); }); it('allows accessing $locals when initializing (gh-9098)', function() { From 422f9da02d2e8c0c227887265bce25cecaecf403 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 19 Jul 2022 20:23:54 -0400 Subject: [PATCH 28/31] test(schema): add coverage for calling `plugin()` with options Fix #12077 --- test/schema.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/schema.test.js b/test/schema.test.js index 7bc6299e23e..8cfac9618a2 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -924,6 +924,19 @@ describe('schema', function() { assert.equal(called, true); }); + + it('options param (gh-12077)', function() { + const Tobi = new Schema(); + let called = false; + + Tobi.plugin(function(schema, opts) { + assert.equal(schema, Tobi); + assert.deepStrictEqual(opts, { answer: 42 }); + called = true; + }, { answer: 42 }); + + assert.equal(called, true); + }); }); describe('options', function() { From 2751883b3265d5e16345329f110154427ca7af79 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 20 Jul 2022 11:37:50 -0400 Subject: [PATCH 29/31] fix tests --- examples/ecommerce-netlify-functions/package.json | 4 ++-- examples/ecommerce-netlify-functions/seed.js | 1 + .../ecommerce-netlify-functions/test/addToCart.test.js | 8 ++++++-- .../ecommerce-netlify-functions/test/checkout.test.js | 8 ++++++-- .../ecommerce-netlify-functions/test/getProducts.test.js | 8 ++++++-- .../test/removeFromCart.test.js | 8 ++++++-- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json index 94e19c2dbb8..3252c62446f 100644 --- a/examples/ecommerce-netlify-functions/package.json +++ b/examples/ecommerce-netlify-functions/package.json @@ -9,8 +9,8 @@ "netlify-cli": "10.7.1" }, "scripts": { - "seed": "env NODE_ENV=development node ./seed", - "start": "env NODE_ENV=development netlify dev", + "seed": "env NODE_ENV=local node ./seed", + "start": "env NODE_ENV=local netlify dev", "test": "env NODE_ENV=test mocha ./test/*.test.js" } } diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js index 9f14ddb88c7..bb7a6ceae5a 100644 --- a/examples/ecommerce-netlify-functions/seed.js +++ b/examples/ecommerce-netlify-functions/seed.js @@ -6,6 +6,7 @@ const mongoose = require('mongoose'); async function createProducts() { await mongoose.connect(config.mongodbUri); + await mongoose.connection.dropDatabase(); await Product.create({ name: 'iPhone 12', diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js index fb0ecb541c8..f771516490e 100644 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ b/examples/ecommerce-netlify-functions/test/addToCart.test.js @@ -8,8 +8,12 @@ const fixtures = require('../test/fixtures'); describe('Add to Cart', function() { it('Should create a cart and add a product to the cart', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); + const products = await fixtures.createProducts({ + product: [ + { name: 'A Test Products', price: 500 }, + { name: 'Another Test Product', price: 600 } + ] + }).then((res) => res.products); const params = { body: { cartId: null, diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js index 71e9483f26e..82844554bc2 100644 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ b/examples/ecommerce-netlify-functions/test/checkout.test.js @@ -11,8 +11,12 @@ const stripe = require('../integrations/stripe') describe('Checkout', function() { it('Should do a successful checkout run', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); + const products = await fixtures.createProducts({ + product: [ + { name: 'A Test Products', price: 500 }, + { name: 'Another Test Product', price: 600 } + ] + }).then((res) => res.products); const params = { body: { cartId: null, diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js index 0328f2c9e54..8ed414645c7 100644 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ b/examples/ecommerce-netlify-functions/test/getProducts.test.js @@ -8,8 +8,12 @@ const mongoose = require('mongoose'); describe('Products', function() { it('Should get all products.', async function() { - await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); + await fixtures.createProducts({ + product: [ + { name: 'A Test Products', price: 500 }, + { name: 'Another Test Product', price: 600 } + ] + }).then((res) => res.products); const result = await getProducts(); assert(result); }); diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js index 24de63946d6..1c646ef4718 100644 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js @@ -9,8 +9,12 @@ const fixtures = require('./fixtures'); describe('Remove From Cart', function() { it('Should create a cart and then it should remove the entire item from it.', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); + const products = await fixtures.createProducts({ + product: [ + { name: 'A Test Products', price: 500 }, + { name: 'Another Test Product', price: 600 } + ] + }).then((res) => res.products); const params = { body: { cartId: null, From 5449ab9e51a779a889b3751416bab1480630b037 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 20 Jul 2022 13:28:29 -0400 Subject: [PATCH 30/31] chore: release 6.4.6 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74093f5ef3f..31bb554a7d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +6.4.6 / 2022-07-20 +================== + * fix(schema): disallow setting __proto__ when creating schema with dotted properties #12085 + * fix(document): avoid mutating original object passed to $set() when applying defaults to nested properties #12102 + * fix(query): apply lean transform option to top-level document #12093 + * docs(migrating_to_6): correct example for `isObjectIdOrHexString()` #12123 [LokeshKanumoori](https://github.com/LokeshKanumoori) + 6.4.5 / 2022-07-18 ================== * fix(model+timestamps): set timestamps on subdocuments in insertMany() #12060 diff --git a/package.json b/package.json index bfb28d8cf16..4bf90f236f9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mongoose", "description": "Mongoose MongoDB ODM", - "version": "6.4.5", + "version": "6.4.6", "author": "Guillermo Rauch ", "keywords": [ "mongodb", From d2d0c01058b8cb22e03dbd6b04d2e975a0ee0d0e Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 21 Jul 2022 20:11:55 -0400 Subject: [PATCH 31/31] chore: remove ecommerce-netlify-functions example, moving to mongoosejs/sample-apps repo --- .../.config/development.js | 8 -- .../.config/index.js | 13 --- .../.config/test.js | 9 -- .../.netlify/edge-functions-import-map.json | 1 - .../ecommerce-netlify-functions/README.md | 54 ------------ .../ecommerce-netlify-functions/connect.js | 15 ---- .../integrations/stripe.js | 5 -- .../ecommerce-netlify-functions/models.js | 84 ------------------- .../netlify/functions/addToCart.js | 48 ----------- .../netlify/functions/checkout.js | 69 --------------- .../netlify/functions/getCart.js | 19 ----- .../netlify/functions/getProducts.js | 16 ---- .../netlify/functions/removeFromCart.js | 34 -------- .../ecommerce-netlify-functions/package.json | 16 ---- examples/ecommerce-netlify-functions/seed.js | 39 --------- .../test/addToCart.test.js | 79 ----------------- .../test/checkout.test.js | 52 ------------ .../test/fixtures/createCart.js | 7 -- .../test/fixtures/createOrder.js | 7 -- .../test/fixtures/createProducts.js | 7 -- .../test/fixtures/index.js | 11 --- .../test/getCart.test.js | 20 ----- .../test/getProducts.test.js | 20 ----- .../test/removeFromCart.test.js | 77 ----------------- .../test/setup.test.js | 14 ---- 25 files changed, 724 deletions(-) delete mode 100644 examples/ecommerce-netlify-functions/.config/development.js delete mode 100644 examples/ecommerce-netlify-functions/.config/index.js delete mode 100644 examples/ecommerce-netlify-functions/.config/test.js delete mode 100644 examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json delete mode 100644 examples/ecommerce-netlify-functions/README.md delete mode 100644 examples/ecommerce-netlify-functions/connect.js delete mode 100644 examples/ecommerce-netlify-functions/integrations/stripe.js delete mode 100644 examples/ecommerce-netlify-functions/models.js delete mode 100644 examples/ecommerce-netlify-functions/netlify/functions/addToCart.js delete mode 100644 examples/ecommerce-netlify-functions/netlify/functions/checkout.js delete mode 100644 examples/ecommerce-netlify-functions/netlify/functions/getCart.js delete mode 100644 examples/ecommerce-netlify-functions/netlify/functions/getProducts.js delete mode 100644 examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js delete mode 100644 examples/ecommerce-netlify-functions/package.json delete mode 100644 examples/ecommerce-netlify-functions/seed.js delete mode 100644 examples/ecommerce-netlify-functions/test/addToCart.test.js delete mode 100644 examples/ecommerce-netlify-functions/test/checkout.test.js delete mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createCart.js delete mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createOrder.js delete mode 100644 examples/ecommerce-netlify-functions/test/fixtures/createProducts.js delete mode 100644 examples/ecommerce-netlify-functions/test/fixtures/index.js delete mode 100644 examples/ecommerce-netlify-functions/test/getCart.test.js delete mode 100644 examples/ecommerce-netlify-functions/test/getProducts.test.js delete mode 100644 examples/ecommerce-netlify-functions/test/removeFromCart.test.js delete mode 100644 examples/ecommerce-netlify-functions/test/setup.test.js diff --git a/examples/ecommerce-netlify-functions/.config/development.js b/examples/ecommerce-netlify-functions/.config/development.js deleted file mode 100644 index b0629c97c88..00000000000 --- a/examples/ecommerce-netlify-functions/.config/development.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -module.exports = Object.freeze({ - mongodbUri: 'mongodb://localhost:27017/ecommerce', - stripeSecretKey: 'YOUR STRIPE KEY HERE', - success_url: 'localhost:3000/success', - cancel_url: 'localhost:3000/cancel' -}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.config/index.js b/examples/ecommerce-netlify-functions/.config/index.js deleted file mode 100644 index 2c58f15f9ac..00000000000 --- a/examples/ecommerce-netlify-functions/.config/index.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -if (process.env.NODE_ENV) { - try { - module.exports = require('./' + process.env.NODE_ENV); - console.log('Using ' + process.env.NODE_ENV); - } catch (err) { - module.exports = require('./development'); - } -} else { - console.log('using production'); - module.exports = require('./production'); -} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.config/test.js b/examples/ecommerce-netlify-functions/.config/test.js deleted file mode 100644 index 6dc295150ea..00000000000 --- a/examples/ecommerce-netlify-functions/.config/test.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -module.exports = Object.freeze({ - mongodbUri: 'mongodb://localhost:27017/ecommerce_test', - stripeSecretKey: 'test', - success_url: 'localhost:3000/success', - cancel_url: 'localhost:3000/cancel' - -}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json b/examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json deleted file mode 100644 index aee80cf31b4..00000000000 --- a/examples/ecommerce-netlify-functions/.netlify/edge-functions-import-map.json +++ /dev/null @@ -1 +0,0 @@ -{"imports":{"netlify:edge":"https://edge-bootstrap.netlify.app/v1/index.ts"}} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/README.md b/examples/ecommerce-netlify-functions/README.md deleted file mode 100644 index 8889dddd8c9..00000000000 --- a/examples/ecommerce-netlify-functions/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# ecommerce-netlify-functions - -This sample demonstrates using Mongoose to build an eCommerce shopping cart using [Netlify Functions](https://www.netlify.com/products/functions/), which runs on [AWS Lambda](https://mongoosejs.com/docs/lambda.html). - -Other tools include: - -1. Stripe for payment processing -2. [Mocha](https://masteringjs.io/mocha) and [Sinon](https://masteringjs.io/sinon) for testing - -## Running This Example - -1. Make sure you have a MongoDB instance running on `localhost:27017`, or update `mongodbUri` in `.config/development.js` to your MongoDB server's address. -2. Run `npm install` -3. Run `npm run seed` -4. Run `npm start` -5. Visit `http://localhost:8888/.netlify/functions/getProducts` to list all available products -6. Run other endpoints using curl or postman - -## Testing - -Make sure you have a MongoDB instance running on `localhost:27017`, or update `mongodbUri` in `.config/test.js` to your MongoDB server's address. -Then run `npm test`. - -``` -$ npm test - -> test -> env NODE_ENV=test mocha ./test/*.test.js - -Using test - - - Add to Cart - ✔ Should create a cart and add a product to the cart - ✔ Should find the cart and add to the cart - ✔ Should find the cart and increase the quantity of the item(s) in the cart - - Checkout - ✔ Should do a successful checkout run - - Get the cart given an id - ✔ Should create a cart and then find the cart. - - Products - ✔ Should get all products. - - Remove From Cart - ✔ Should create a cart and then it should remove the entire item from it. - ✔ Should create a cart and then it should reduce the quantity of an item from it. - - - 8 passing (112ms) - -``` \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/connect.js b/examples/ecommerce-netlify-functions/connect.js deleted file mode 100644 index 22c325f054c..00000000000 --- a/examples/ecommerce-netlify-functions/connect.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -const config = require('./.config'); -const mongoose = require('mongoose'); - -let conn = null; - -module.exports = async function connect() { - if (conn != null) { - return conn; - } - conn = mongoose.connection; - await mongoose.connect(config.mongodbUri); - return conn; -} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/integrations/stripe.js b/examples/ecommerce-netlify-functions/integrations/stripe.js deleted file mode 100644 index 5349ae6cbb0..00000000000 --- a/examples/ecommerce-netlify-functions/integrations/stripe.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const config = require('../.config') - -module.exports = require('stripe')(config.stripeSecretKey); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/models.js b/examples/ecommerce-netlify-functions/models.js deleted file mode 100644 index 7514b9986a2..00000000000 --- a/examples/ecommerce-netlify-functions/models.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; -const mongoose = require('mongoose'); - -const productSchema = new mongoose.Schema({ - name: String, - price: Number, - image: String -}); - -const Product = mongoose.model('Product', productSchema); - -module.exports.Product = Product; - -const orderSchema = new mongoose.Schema({ - items: [ - { productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, - quantity: { type: Number, required: true, validate: v => v > 0 } - } - ], - total: { - type: Number, - default: 0 - }, - status: { - type: String, - enum: ['PAID', 'IN_PROGRESS', 'SHIPPED', 'DELIVERED'], - default: 'PAID' - }, - orderNumber: { - type: Number, - required: true - }, - name: { - type: String, - required: true - }, - email: { - type: String, - required: true - }, - address1: { - type: String, - required: true - }, - address2: { - type: String - }, - city: { - type: String, - required: true - }, - state: { - type: String, - required: true - }, - zip: { - type: String, - required: true - }, - shipping: { - type: String, - required: true, - enum: ['standard', '2day'] - }, - paymentMethod: { - id: String, - brand: String, - last4: String - } -}, { optimisticConcurrency: true }); - -const Order = mongoose.model('Order', orderSchema); - -module.exports.Order = Order; - -const cartSchema = new mongoose.Schema({ - items: [{ productId: { type: mongoose.ObjectId, required: true, ref: 'Product' }, quantity: { type: Number, required: true } }], - orderId: { type: mongoose.ObjectId, ref: 'Order' } -}, { timestamps: true }); - -const Cart = mongoose.model('Cart', cartSchema); - -module.exports.Cart = Cart; - diff --git a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js b/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js deleted file mode 100644 index 70182f7021e..00000000000 --- a/examples/ecommerce-netlify-functions/netlify/functions/addToCart.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -const { Cart, Product } = require('../../models'); -const connect = require('../../connect'); - -const handler = async(event) => { - try { - event.body = JSON.parse(event.body || {}); - await connect(); - const products = await Product.find(); - if (event.body.cartId) { - // get the document containing the specified cartId - const cart = await Cart.findOne({ _id: event.body.cartId }).setOptions({ sanitizeFilter: true }); - - if (cart == null) { - return { statusCode: 404, body: JSON.stringify({ message: 'Cart not found' }) }; - } - if(!Array.isArray(event.body.items)) { - return { statusCode: 500, body: JSON.stringify({ error: 'items is not an array' }) }; - } - for (const product of event.body.items) { - const exists = cart.items.find(item => item?.productId?.toString() === product?.productId?.toString()); - if (!exists && products.find(p => product?.productId?.toString() === p?._id?.toString())) { - cart.items.push(product); - await cart.save(); - } else { - exists.quantity += product.quantity; - await cart.save(); - } - } - - if (!cart.items.length) { - return { statusCode: 200, body: JSON.stringify({ cart: null }) }; - } - - await cart.save(); - return { statusCode: 200, body: JSON.stringify(cart) }; - } else { - // If no cartId, create a new cart - const cart = await Cart.create({ items: event.body.items }); - return { statusCode: 200, body: JSON.stringify(cart) }; - } - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js b/examples/ecommerce-netlify-functions/netlify/functions/checkout.js deleted file mode 100644 index 579f62e7c42..00000000000 --- a/examples/ecommerce-netlify-functions/netlify/functions/checkout.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -const stripe = require('../../integrations/stripe') -const config = require('../../.config'); -const { Cart, Order, Product } = require('../../models'); -const connect = require('../../connect'); - -const handler = async(event) => { - try { - event.body = JSON.parse(event.body || {}); - await connect(); - const cart = await Cart.findOne({ _id: event.body.cartId }); - - const stripeProducts = { line_items: [] }; - let total = 0; - for (let i = 0; i < cart.items.length; i++) { - const product = await Product.findOne({ _id: cart.items[i].productId }); - stripeProducts.line_items.push({ - price_data: { - currency: 'usd', - product_data: { - name: product.name - }, - unit_amount: product.price - }, - quantity: cart.items[i].quantity - }); - total = total + (product.price * cart.items[i].quantity); - } - const session = await stripe.checkout.sessions.create({ - line_items: stripeProducts.line_items, - mode: 'payment', - success_url: config.success_url, - cancel_url: config.cancel_url - }); - const intent = await stripe.paymentIntents.retrieve(session.payment_intent); - if (intent.status !== 'succeeded') { - throw new Error(`Checkout failed because intent has status "${intent.status}"`); - } - const paymentMethod = await stripe.paymentMethods.retrieve(intent['payment_method']); - const orders = await Order.find(); - const orderNumber = orders.length ? orders.length + 1 : 1; - const order = await Order.create({ - items: event.body.product, - total: total, - orderNumber: orderNumber, - name: event.body.name, - email: event.body.email, - address1: event.body.address1, - city: event.body.city, - state: event.body.state, - zip: event.body.zip, - shipping: event.body.shipping, - paymentMethod: paymentMethod ? { id: paymentMethod.id, brand: paymentMethod.brand, last4: paymentMethod.last4 } : null - }); - - cart.orderId = order._id; - await cart.save(); - return { - statusCode: 200, - body: JSON.stringify({ order: order, cart: cart }), - headers: { Location: session.url } - }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/netlify/functions/getCart.js b/examples/ecommerce-netlify-functions/netlify/functions/getCart.js deleted file mode 100644 index a2b72ad998e..00000000000 --- a/examples/ecommerce-netlify-functions/netlify/functions/getCart.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const { Cart } = require('../../models'); -const connect = require('../../connect'); - -const handler = async(event) => { - try { - await connect(); - // get the document containing the specified cartId - const cart = await Cart. - findOne({ _id: event.queryStringParameters.cartId }). - setOptions({ sanitizeFilter: true }); - return { statusCode: 200, body: JSON.stringify({ cart }) }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js b/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js deleted file mode 100644 index 3fbc8fd9a9b..00000000000 --- a/examples/ecommerce-netlify-functions/netlify/functions/getProducts.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const { Product } = require('../../models'); -const connect = require('../../connect'); - -const handler = async(event) => { - try { - await connect(); - const products = await Product.find(); - return { statusCode: 200, body: JSON.stringify(products) }; - } catch (error) { - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js b/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js deleted file mode 100644 index 7124f4d36d3..00000000000 --- a/examples/ecommerce-netlify-functions/netlify/functions/removeFromCart.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -const { Cart } = require('../../models'); -const connect = require('../../connect'); - -const handler = async(event) => { - try { - event.body = JSON.parse(event.body || {}); - await connect(); - const cart = await Cart.findOne({ _id: event.body.cartId }); - const index = cart.items.findIndex((item) => - item.productId.toString() == event.body.item.productId.toString() - ); - if (index == -1) { - return { statusCode: 200, body: cart }; - } - if (event.body?.item?.quantity) { - cart.items[index].quantity -= event.body.item.quantity; - if (cart.items[index].quantity <= 0) { - cart.items.splice(index, 1); - } - await cart.save(); - } else { - cart.items.splice(index, 1); - await cart.save(); - } - return { statusCode: 200, body: JSON.stringify(cart) }; - } catch (error) { - console.log(error); - return { statusCode: 500, body: error.toString() }; - } -}; - -module.exports = { handler }; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/package.json b/examples/ecommerce-netlify-functions/package.json deleted file mode 100644 index 3252c62446f..00000000000 --- a/examples/ecommerce-netlify-functions/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "dependencies": { - "mongoose": "6.3.5", - "sinon": "14.0.0", - "stripe": "9.6.0" - }, - "devDependencies": { - "mocha": "10.0.0", - "netlify-cli": "10.7.1" - }, - "scripts": { - "seed": "env NODE_ENV=local node ./seed", - "start": "env NODE_ENV=local netlify dev", - "test": "env NODE_ENV=test mocha ./test/*.test.js" - } -} diff --git a/examples/ecommerce-netlify-functions/seed.js b/examples/ecommerce-netlify-functions/seed.js deleted file mode 100644 index bb7a6ceae5a..00000000000 --- a/examples/ecommerce-netlify-functions/seed.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -const { Product } = require('./models'); -const config = require('./.config'); -const mongoose = require('mongoose'); - -async function createProducts() { - await mongoose.connect(config.mongodbUri); - await mongoose.connection.dropDatabase(); - - await Product.create({ - name: 'iPhone 12', - price: 500, - image: 'https://images.unsplash.com/photo-1611472173362-3f53dbd65d80' - }); - - await Product.create({ - name: 'iPhone SE', - price: 600, - image: 'https://images.unsplash.com/photo-1529618160092-2f8ccc8e087b' - }); - - await Product.create({ - name: 'iPhone 12 Pro', - price: 700, - image: 'https://images.unsplash.com/photo-1603921326210-6edd2d60ca68' - }); - - await Product.create({ - name: 'iPhone 11', - price: 800, - image: 'https://images.unsplash.com/photo-1574755393849-623942496936' - }); - - console.log('done'); - process.exit(0); -} - -createProducts(); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/addToCart.test.js b/examples/ecommerce-netlify-functions/test/addToCart.test.js deleted file mode 100644 index f771516490e..00000000000 --- a/examples/ecommerce-netlify-functions/test/addToCart.test.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; - -const { describe, it, before, after } = require('mocha'); -const assert = require('assert'); -const { handler: addToCart } = require('../netlify/functions/addToCart'); -const mongoose = require('mongoose'); -const fixtures = require('../test/fixtures'); - -describe('Add to Cart', function() { - it('Should create a cart and add a product to the cart', async function() { - const products = await fixtures.createProducts({ - product: [ - { name: 'A Test Products', price: 500 }, - { name: 'Another Test Product', price: 600 } - ] - }).then((res) => res.products); - const params = { - body: { - cartId: null, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const result = await addToCart(params); - result.body = JSON.parse(result.body); - assert(result.body); - assert(result.body.items.length); - }); - it('Should find the cart and add to the cart', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); - const { cart } = await fixtures.createCart({products: []}); - const params = { - body: { - cartId: cart._id, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const findCart = await addToCart(params); - findCart.body = JSON.parse(findCart.body); - assert(findCart.body); - assert.equal(findCart.body.items.length, 2) - }); - it('Should find the cart and increase the quantity of the item(s) in the cart', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); - const { cart } = await fixtures.createCart({products: []}); - const params = { - body: { - cartId: cart._id, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const findCart = await addToCart(params); - findCart.body = JSON.parse(findCart.body); - assert(findCart.body); - assert.equal(findCart.body.items.length, 2); - assert.equal(findCart.body.items[0].quantity, 2); - assert.equal(findCart.body.items[1].quantity, 1); - params.body = JSON.stringify(params.body) - const updateCart = await addToCart(params); - updateCart.body = JSON.parse(updateCart.body); - assert(updateCart.body); - assert.equal(updateCart.body.items.length, 2); - assert.equal(updateCart.body.items[0].quantity, 4); - assert.equal(updateCart.body.items[1].quantity, 2); - }); -}); diff --git a/examples/ecommerce-netlify-functions/test/checkout.test.js b/examples/ecommerce-netlify-functions/test/checkout.test.js deleted file mode 100644 index 82844554bc2..00000000000 --- a/examples/ecommerce-netlify-functions/test/checkout.test.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -const { describe, it, before, after } = require('mocha'); -const assert = require('assert'); -const { handler: addToCart } = require('../netlify/functions/addToCart'); -const { handler: checkout } = require('../netlify/functions/checkout'); -const mongoose = require('mongoose'); -const fixtures = require('./fixtures'); -const sinon = require('sinon'); -const stripe = require('../integrations/stripe') - -describe('Checkout', function() { - it('Should do a successful checkout run', async function() { - const products = await fixtures.createProducts({ - product: [ - { name: 'A Test Products', price: 500 }, - { name: 'Another Test Product', price: 600 } - ] - }).then((res) => res.products); - const params = { - body: { - cartId: null, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const result = await addToCart(params); - result.body = JSON.parse(result.body); - assert(result.body); - assert(result.body.items.length); - params.body.cartId = result.body._id; - sinon.stub(stripe.paymentIntents, 'retrieve').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - sinon.stub(stripe.paymentMethods, 'retrieve').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - sinon.stub(stripe.checkout.sessions, 'create').returns({status: 'succeeded', id: '123', brand: 'visa', last4: '1234'}); - params.body.product = params.body.items; - params.body.name = 'Test Testerson'; - params.body.email = 'test@localhost.com'; - params.body.address1 = '12345 Syndey Street'; - params.body.city = 'Miami'; - params.body.state = 'Florida'; - params.body.zip = '33145'; - params.body.shipping = 'standard'; - params.body = JSON.stringify(params.body); - const finish = await checkout(params); - finish.body = JSON.parse(finish.body); - assert(finish.body.order); - assert(finish.body.cart); - }); -}); diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createCart.js b/examples/ecommerce-netlify-functions/test/fixtures/createCart.js deleted file mode 100644 index ea8ad627257..00000000000 --- a/examples/ecommerce-netlify-functions/test/fixtures/createCart.js +++ /dev/null @@ -1,7 +0,0 @@ -const {Cart} = require('../../models'); - - -module.exports = async function createCart(params) { - const cart = await Cart.create({items: params.products}); - return { cart }; -} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js b/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js deleted file mode 100644 index 83396855605..00000000000 --- a/examples/ecommerce-netlify-functions/test/fixtures/createOrder.js +++ /dev/null @@ -1,7 +0,0 @@ -const { Order } = require('../../models'); - -module.exports = async function createOrder(params) { - - const order = await Order.create(params.order); - return { order }; -}; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js b/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js deleted file mode 100644 index 50d1e56e9e5..00000000000 --- a/examples/ecommerce-netlify-functions/test/fixtures/createProducts.js +++ /dev/null @@ -1,7 +0,0 @@ -const { Product } = require('../../models'); - -module.exports = async function createProducts(params) { - const products = await Product.create(params.product); - - return { products }; -}; \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/fixtures/index.js b/examples/ecommerce-netlify-functions/test/fixtures/index.js deleted file mode 100644 index aa1b62a407a..00000000000 --- a/examples/ecommerce-netlify-functions/test/fixtures/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const createCart = require('./createCart'); -const createProducts = require('./createProducts'); -const createOrder = require('./createOrder'); - -module.exports = { - createCart: createCart, - createProducts: createProducts, - createOrder: createOrder -} \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/getCart.test.js b/examples/ecommerce-netlify-functions/test/getCart.test.js deleted file mode 100644 index 847e39e31ea..00000000000 --- a/examples/ecommerce-netlify-functions/test/getCart.test.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -const { describe, it, before, after } = require('mocha'); -const assert = require('assert'); -const { handler: getCart } = require('../netlify/functions/getCart'); -const fixtures = require('./fixtures'); -const mongoose = require('mongoose'); - -describe('Get the cart given an id', function() { - it('Should create a cart and then find the cart.', async function() { - const cart = await fixtures.createCart({ products: null }); - const params = { - queryStringParameters: { - cartId: cart._id - }, - }; - const findCart = await getCart(params); - assert.equal(findCart.statusCode, 200); - }); -}); diff --git a/examples/ecommerce-netlify-functions/test/getProducts.test.js b/examples/ecommerce-netlify-functions/test/getProducts.test.js deleted file mode 100644 index 8ed414645c7..00000000000 --- a/examples/ecommerce-netlify-functions/test/getProducts.test.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -const { describe, it, before, after } = require('mocha'); -const assert = require('assert'); -const { handler: getProducts } = require('../netlify/functions/getProducts'); -const fixtures = require('./fixtures'); -const mongoose = require('mongoose'); - -describe('Products', function() { - it('Should get all products.', async function() { - await fixtures.createProducts({ - product: [ - { name: 'A Test Products', price: 500 }, - { name: 'Another Test Product', price: 600 } - ] - }).then((res) => res.products); - const result = await getProducts(); - assert(result); - }); -}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js b/examples/ecommerce-netlify-functions/test/removeFromCart.test.js deleted file mode 100644 index 1c646ef4718..00000000000 --- a/examples/ecommerce-netlify-functions/test/removeFromCart.test.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -const { describe, it, before, after } = require('mocha'); -const assert = require('assert'); -const { handler: addToCart } = require('../netlify/functions/addToCart'); -const { handler: removeFromCart } = require('../netlify/functions/removeFromCart'); -const mongoose = require('mongoose'); -const fixtures = require('./fixtures'); - -describe('Remove From Cart', function() { - it('Should create a cart and then it should remove the entire item from it.', async function() { - const products = await fixtures.createProducts({ - product: [ - { name: 'A Test Products', price: 500 }, - { name: 'Another Test Product', price: 600 } - ] - }).then((res) => res.products); - const params = { - body: { - cartId: null, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const result = await addToCart(params); - result.body = JSON.parse(result.body); - assert(result.body); - assert.equal(result.body.items.length, 2); - const newParams = { - body: { - cartId: result.body._id, - item: { - productId: products[0]._id, - } - } - }; - newParams.body = JSON.stringify(newParams.body); - const remove = await removeFromCart(newParams); - remove.body = JSON.parse(remove.body); - assert.equal(remove.body.items.length, 1); - }); - - it('Should create a cart and then it should reduce the quantity of an item from it.', async function() { - const products = await fixtures.createProducts({product: [{ productName: 'A Test Products', productPrice: 500 }, {productName: 'Another Test Product', productPrice: 600 }]}) - .then((res) => res.products); - const params = { - body: { - cartId: null, - items: [ - { productId: products[0]._id, quantity: 2 }, - { productId: products[1]._id, quantity: 1 } - ] - } - }; - params.body = JSON.stringify(params.body); - const result = await addToCart(params); - result.body = JSON.parse(result.body); - assert(result.body); - assert(result.body.items.length); - const newParams = { - body: { - cartId: result.body._id, - item: { - productId: products[0]._id, - quantity: 1 - } - } - }; - newParams.body = JSON.stringify(newParams.body); - const remove = await removeFromCart(newParams); - remove.body = JSON.parse(remove.body); - assert.equal(remove.body.items[0].quantity, 1); - }); -}); \ No newline at end of file diff --git a/examples/ecommerce-netlify-functions/test/setup.test.js b/examples/ecommerce-netlify-functions/test/setup.test.js deleted file mode 100644 index 7870e5a8bde..00000000000 --- a/examples/ecommerce-netlify-functions/test/setup.test.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const { after } = require('mocha'); -const config = require('../.config'); -const mongoose = require('mongoose'); - -before(async() => { - await mongoose.connect(config.mongodbUri); - await mongoose.connection.dropDatabase(); -}); - -after(async function() { - await mongoose.disconnect(); -}); \ No newline at end of file