From 245557ac2e3e5348eb77a8a172c6fbba83fcbe7f Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Tue, 25 Feb 2020 16:50:40 +0100 Subject: [PATCH] POST /store/carts/:id to update email, addresses, dicsounts, region --- .../src/api/middlewares/error-handler.js | 3 + .../store/carts/__tests__/update-cart.js | 136 ++++++++++++++++++ .../src/api/routes/store/carts/get-cart.js | 4 +- .../src/api/routes/store/carts/index.js | 4 +- .../src/api/routes/store/carts/update-cart.js | 59 ++++++++ .../medusa/src/services/__mocks__/cart.js | 18 +++ 6 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js create mode 100644 packages/medusa/src/api/routes/store/carts/update-cart.js diff --git a/packages/medusa/src/api/middlewares/error-handler.js b/packages/medusa/src/api/middlewares/error-handler.js index 4f7c932ecb..d06fe5c0e0 100644 --- a/packages/medusa/src/api/middlewares/error-handler.js +++ b/packages/medusa/src/api/middlewares/error-handler.js @@ -10,6 +10,9 @@ export default () => { case MedusaError.Types.INVALID_DATA: statusCode = 400 break + case MedusaError.Types.NOT_FOUND: + statusCode = 404 + break case MedusaError.Types.DB_ERROR: statusCode = 500 break diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js new file mode 100644 index 0000000000..938c4d4696 --- /dev/null +++ b/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js @@ -0,0 +1,136 @@ +import { IdMap } from "medusa-test-utils" +import { request } from "../../../../../helpers/test-request" +import { CartServiceMock } from "../../../../../services/__mocks__/cart" + +describe("POST /store/carts/:id", () => { + describe("successfully updates all fields", () => { + let subject + const address = { + first_name: "LeBron", + last_name: "James", + country_code: "US", + address_1: "24 Dunk Dr", + address_2: "Ball Ave", + city: "Los Angeles", + province: "CA", + postal_code: "91092", + } + + beforeAll(async () => { + subject = await request( + "POST", + `/store/carts/${IdMap.getId("emptyCart")}`, + { + payload: { + region_id: IdMap.getId("testRegion"), + email: "test@admin.com", + shipping_address: address, + billing_address: address, + discounts: [ + { + code: "TESTCODE", + }, + ], + }, + } + ) + }) + + afterAll(() => { + jest.clearAllMocks() + }) + + it("sets new region", () => { + expect(CartServiceMock.setRegion).toHaveBeenCalledTimes(1) + expect(CartServiceMock.setRegion).toHaveBeenCalledWith( + IdMap.getId("emptyCart"), + IdMap.getId("testRegion") + ) + }) + + it("updates email", () => { + expect(CartServiceMock.updateEmail).toHaveBeenCalledTimes(1) + expect(CartServiceMock.updateEmail).toHaveBeenCalledWith( + IdMap.getId("emptyCart"), + "test@admin.com" + ) + }) + + it("updates shipping address", () => { + expect(CartServiceMock.updateShippingAddress).toHaveBeenCalledTimes(1) + expect(CartServiceMock.updateShippingAddress).toHaveBeenCalledWith( + IdMap.getId("emptyCart"), + address + ) + }) + + it("updates billing address", () => { + expect(CartServiceMock.updateBillingAddress).toHaveBeenCalledTimes(1) + expect(CartServiceMock.updateBillingAddress).toHaveBeenCalledWith( + IdMap.getId("emptyCart"), + address + ) + }) + + it("applies promo code", () => { + expect(CartServiceMock.applyPromoCode).toHaveBeenCalledTimes(1) + expect(CartServiceMock.applyPromoCode).toHaveBeenCalledWith( + IdMap.getId("emptyCart"), + "TESTCODE" + ) + }) + + it("returns 200", () => { + expect(subject.status).toEqual(200) + }) + + it("returns cart", () => { + expect(subject.body._id).toEqual(IdMap.getId("emptyCart")) + }) + }) + + describe("it bubbles errors", () => { + let subject + beforeAll(async () => { + subject = await request( + "POST", + `/store/carts/${IdMap.getId("emptyCart")}`, + { + payload: { + region_id: IdMap.getId("fail"), + }, + } + ) + }) + + afterAll(() => { + jest.clearAllMocks() + }) + + it("returns 404", () => { + expect(subject.status).toEqual(404) + expect(subject.body.message).toEqual("Region not found") + }) + }) + + describe("returns 404 on undefined cart", () => { + let subject + + beforeAll(async () => { + subject = await request("POST", `/store/carts/none`) + }) + + afterAll(() => { + jest.clearAllMocks() + }) + + it("calls get product from productSerice", () => { + expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) + expect(CartServiceMock.retrieve).toHaveBeenCalledWith("none") + }) + + it("returns 404", () => { + expect(subject.status).toEqual(404) + }) + }) +}) diff --git a/packages/medusa/src/api/routes/store/carts/get-cart.js b/packages/medusa/src/api/routes/store/carts/get-cart.js index 41771ed682..2d099cfdb9 100644 --- a/packages/medusa/src/api/routes/store/carts/get-cart.js +++ b/packages/medusa/src/api/routes/store/carts/get-cart.js @@ -1,8 +1,8 @@ export default async (req, res) => { - const { cartId } = req.params + const { id } = req.params const cartService = req.scope.resolve("cartService") - const cart = await cartService.retrieve(cartId) + const cart = await cartService.retrieve(id) if (!cart) { res.sendStatus(404) diff --git a/packages/medusa/src/api/routes/store/carts/index.js b/packages/medusa/src/api/routes/store/carts/index.js index 92f1822682..d2e73c725f 100644 --- a/packages/medusa/src/api/routes/store/carts/index.js +++ b/packages/medusa/src/api/routes/store/carts/index.js @@ -6,8 +6,10 @@ const route = Router() export default app => { app.use("/carts", route) - route.get("/:cartId", middlewares.wrap(require("./get-cart").default)) + route.get("/:id", middlewares.wrap(require("./get-cart").default)) + route.post("/", middlewares.wrap(require("./create-cart").default)) + route.post("/:id", middlewares.wrap(require("./update-cart").default)) return app } diff --git a/packages/medusa/src/api/routes/store/carts/update-cart.js b/packages/medusa/src/api/routes/store/carts/update-cart.js new file mode 100644 index 0000000000..bb841cae5c --- /dev/null +++ b/packages/medusa/src/api/routes/store/carts/update-cart.js @@ -0,0 +1,59 @@ +import _ from "lodash" +import { Validator, MedusaError } from "medusa-core-utils" + +export default async (req, res) => { + const { id } = req.params + + const schema = Validator.object().keys({ + region_id: Validator.string(), + email: Validator.string().email(), + billing_address: Validator.address(), + shipping_address: Validator.address(), + discounts: Validator.array().items({ + code: Validator.string(), + }), + }) + + const { value, error } = schema.validate(req.body) + if (error) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details) + } + + const cartService = req.scope.resolve("cartService") + const oldCart = await cartService.retrieve(id) + if (!oldCart) { + res.sendStatus(404) + return + } + + try { + if (value.region_id) { + await cartService.setRegion(id, value.region_id) + } + + if (value.email) { + await cartService.updateEmail(id, value.email) + } + + if (!_.isEmpty(value.shipping_address)) { + await cartService.updateShippingAddress(id, value.shipping_address) + } + + if (!_.isEmpty(value.billing_address)) { + await cartService.updateBillingAddress(id, value.billing_address) + } + + if (value.discounts && value.discounts.length) { + await Promise.all( + value.discounts.map(async ({ code }) => + cartService.applyPromoCode(id, code) + ) + ) + } + + const newCart = await cartService.retrieve(id) + res.json(newCart) + } catch (err) { + throw err + } +} diff --git a/packages/medusa/src/services/__mocks__/cart.js b/packages/medusa/src/services/__mocks__/cart.js index c972ec4ab7..7472bae86c 100644 --- a/packages/medusa/src/services/__mocks__/cart.js +++ b/packages/medusa/src/services/__mocks__/cart.js @@ -34,6 +34,24 @@ export const CartServiceMock = { addLineItem: jest.fn().mockImplementation((cartId, lineItem) => { return Promise.resolve() }), + setRegion: jest.fn().mockImplementation((cartId, regionId) => { + if (regionId === IdMap.getId("fail")) { + throw new MedusaError(MedusaError.Types.NOT_FOUND, "Region not found") + } + return Promise.resolve() + }), + updateEmail: jest.fn().mockImplementation((cartId, email) => { + return Promise.resolve() + }), + updateShippingAddress: jest.fn().mockImplementation((cartId, address) => { + return Promise.resolve() + }), + updateBillingAddress: jest.fn().mockImplementation((cartId, address) => { + return Promise.resolve() + }), + applyPromoCode: jest.fn().mockImplementation((cartId, code) => { + return Promise.resolve() + }), } const mock = jest.fn().mockImplementation(() => {