create product endpoint
This commit is contained in:
@@ -2,6 +2,7 @@ import { Router } from "express"
|
|||||||
import admin from "./routes/admin"
|
import admin from "./routes/admin"
|
||||||
import store from "./routes/store"
|
import store from "./routes/store"
|
||||||
import users from "./routes/users"
|
import users from "./routes/users"
|
||||||
|
import errorHandler from "./middlewares/error-handler"
|
||||||
|
|
||||||
// guaranteed to get dependencies
|
// guaranteed to get dependencies
|
||||||
export default () => {
|
export default () => {
|
||||||
@@ -11,5 +12,7 @@ export default () => {
|
|||||||
admin(app)
|
admin(app)
|
||||||
store(app)
|
store(app)
|
||||||
|
|
||||||
|
app.use(errorHandler())
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (err, req, res, next) => {
|
||||||
|
const logger = req.scope.resolve("logger")
|
||||||
|
logger.error(err.message)
|
||||||
|
|
||||||
|
let statusCode = 500
|
||||||
|
switch (err.name) {
|
||||||
|
case MedusaError.Types.INVALID_DATA:
|
||||||
|
statusCode = 400
|
||||||
|
break
|
||||||
|
case MedusaError.Types.DB_ERROR:
|
||||||
|
statusCode = 500
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(statusCode).json(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,76 @@
|
|||||||
import IdMap from "../../../../../helpers/id-map"
|
import IdMap from "../../../../../helpers/id-map"
|
||||||
import { request } from "../../../../../helpers/test-request"
|
import { request } from "../../../../../helpers/test-request"
|
||||||
|
import { ProductServiceMock } from "../../../../../services/__mocks__/product"
|
||||||
|
|
||||||
describe("POST /admin/products", () => {
|
describe("POST /admin/products", () => {
|
||||||
describe("successful creation", () => {
|
describe("successful creation", () => {
|
||||||
it("calls mock function", async () => {
|
let subject
|
||||||
const res = await request("POST", "/admin/products", {
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
subject = await request("POST", "/admin/products", {
|
||||||
|
payload: {
|
||||||
|
title: "Test Product",
|
||||||
|
description: "Test Description",
|
||||||
|
tags: "hi,med,dig",
|
||||||
|
handle: "test-product",
|
||||||
|
},
|
||||||
adminSession: {
|
adminSession: {
|
||||||
jwt: {
|
jwt: {
|
||||||
userId: IdMap.getId("admin_user"),
|
userId: IdMap.getId("admin_user"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
expect(res.status).toEqual(200)
|
})
|
||||||
|
|
||||||
|
it("returns 200", () => {
|
||||||
|
expect(subject.status).toEqual(201)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns created product draft", () => {
|
||||||
|
expect(subject.body).toEqual({
|
||||||
|
title: "Test Product",
|
||||||
|
description: "Test Description",
|
||||||
|
tags: "hi,med,dig",
|
||||||
|
handle: "test-product",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls service createDraft", () => {
|
||||||
|
expect(ProductServiceMock.createDraft).toHaveBeenCalledTimes(1)
|
||||||
|
expect(ProductServiceMock.createDraft).toHaveBeenCalledWith({
|
||||||
|
title: "Test Product",
|
||||||
|
description: "Test Description",
|
||||||
|
tags: "hi,med,dig",
|
||||||
|
handle: "test-product",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("invalid data returns error details", () => {
|
||||||
|
let subject
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
subject = await request("POST", "/admin/products", {
|
||||||
|
payload: {
|
||||||
|
description: "Test Description",
|
||||||
|
tags: "hi,med,dig",
|
||||||
|
handle: "test-product",
|
||||||
|
},
|
||||||
|
adminSession: {
|
||||||
|
jwt: {
|
||||||
|
userId: IdMap.getId("admin_user"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns 400", () => {
|
||||||
|
expect(subject.status).toEqual(400)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns error details", () => {
|
||||||
|
expect(subject.body.name).toEqual("invalid_data")
|
||||||
|
expect(subject.body.message[0].message).toEqual(`"title" is required`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
import { Validator } from "medusa-core-utils"
|
import { MedusaError, Validator } from "medusa-core-utils"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
try {
|
const schema = Validator.object().keys({
|
||||||
const variantService = req.scope.resolve("productVariantService")
|
title: Validator.string().required(),
|
||||||
} catch (err) {
|
description: Validator.string(),
|
||||||
console.log(err)
|
tags: Validator.string(),
|
||||||
|
images: Validator.array().items(Validator.string()),
|
||||||
|
variants: Validator.array().items(Validator.string()),
|
||||||
|
metadata: Validator.object(),
|
||||||
|
handle: Validator.string().required(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const { value, error } = schema.validate(req.body)
|
||||||
|
if (error) {
|
||||||
|
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.sendStatus(200)
|
try {
|
||||||
|
const productService = req.scope.resolve("productService")
|
||||||
|
const data = await productService.createDraft(value)
|
||||||
|
|
||||||
|
// Return the created product draft
|
||||||
|
res.status(201).json(data)
|
||||||
|
} catch (err) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import "core-js/stable"
|
import "core-js/stable"
|
||||||
import "regenerator-runtime/runtime"
|
import "regenerator-runtime/runtime"
|
||||||
import express from "express"
|
import express from "express"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import loaders from "./loaders"
|
import loaders from "./loaders"
|
||||||
import Logger from "./loaders/logger"
|
import Logger from "./loaders/logger"
|
||||||
|
|
||||||
@@ -12,28 +11,6 @@ const startServer = async () => {
|
|||||||
|
|
||||||
await loaders({ expressApp: app })
|
await loaders({ expressApp: app })
|
||||||
|
|
||||||
app.use((err, req, res, next) => {
|
|
||||||
const logger = req.scope.resolve("logger")
|
|
||||||
logger.error(err.message)
|
|
||||||
|
|
||||||
let statusCode = 500
|
|
||||||
switch (err.name) {
|
|
||||||
case "ValidationError":
|
|
||||||
statusCode = 400
|
|
||||||
break
|
|
||||||
case MedusaError.Types.INVALID_DATA:
|
|
||||||
statusCode = 400
|
|
||||||
break
|
|
||||||
case MedusaError.Types.DB_ERROR:
|
|
||||||
statusCode = 500
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(err).status(statusCode)
|
|
||||||
})
|
|
||||||
|
|
||||||
app.listen(PORT, err => {
|
app.listen(PORT, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContainer } from "awilix"
|
import { createContainer, asValue } from "awilix"
|
||||||
import express from "express"
|
import express from "express"
|
||||||
import supertest from "supertest"
|
import supertest from "supertest"
|
||||||
import jwt from "jsonwebtoken"
|
import jwt from "jsonwebtoken"
|
||||||
@@ -13,6 +13,11 @@ import config from "../config"
|
|||||||
const testApp = express()
|
const testApp = express()
|
||||||
|
|
||||||
const container = createContainer()
|
const container = createContainer()
|
||||||
|
container.register({
|
||||||
|
logger: asValue({
|
||||||
|
error: () => {},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
servicesLoader({ container })
|
servicesLoader({ container })
|
||||||
expressLoader({ app: testApp })
|
expressLoader({ app: testApp })
|
||||||
@@ -29,13 +34,13 @@ apiLoader({ app: testApp })
|
|||||||
const supertestRequest = supertest(testApp)
|
const supertestRequest = supertest(testApp)
|
||||||
|
|
||||||
let adminSessionOpts = {
|
let adminSessionOpts = {
|
||||||
cookieName: "adminSession",
|
cookieName: "session",
|
||||||
secret: "test",
|
secret: "test",
|
||||||
}
|
}
|
||||||
export { adminSessionOpts }
|
export { adminSessionOpts }
|
||||||
|
|
||||||
let clientSessionOpts = {
|
let clientSessionOpts = {
|
||||||
cookieName: "clientSession",
|
cookieName: "session",
|
||||||
secret: "test",
|
secret: "test",
|
||||||
}
|
}
|
||||||
export { clientSessionOpts }
|
export { clientSessionOpts }
|
||||||
|
|||||||
@@ -90,39 +90,39 @@ export const variants = {
|
|||||||
empty_variant: emptyVariant,
|
empty_variant: emptyVariant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ProductVariantServiceMock = {
|
||||||
|
retrieve: jest.fn().mockImplementation(variantId => {
|
||||||
|
if (variantId === "1") {
|
||||||
|
return Promise.resolve(variant1)
|
||||||
|
}
|
||||||
|
if (variantId === "2") {
|
||||||
|
return Promise.resolve(variant2)
|
||||||
|
}
|
||||||
|
if (variantId === "3") {
|
||||||
|
return Promise.resolve(variant3)
|
||||||
|
}
|
||||||
|
if (variantId === "4") {
|
||||||
|
return Promise.resolve(variant4)
|
||||||
|
}
|
||||||
|
if (variantId === "invalid_option") {
|
||||||
|
return Promise.resolve(invalidVariant)
|
||||||
|
}
|
||||||
|
if (variantId === "empty_option") {
|
||||||
|
return Promise.resolve(emptyVariant)
|
||||||
|
}
|
||||||
|
return Promise.resolve(undefined)
|
||||||
|
}),
|
||||||
|
delete: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
addOptionValue: jest.fn().mockImplementation((variantId, optionId, value) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
}),
|
||||||
|
deleteOptionValue: jest.fn().mockImplementation((variantId, optionId) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
const mock = jest.fn().mockImplementation(() => {
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
return {
|
return ProductVariantServiceMock
|
||||||
retrieve: jest.fn().mockImplementation(variantId => {
|
|
||||||
if (variantId === "1") {
|
|
||||||
return Promise.resolve(variant1)
|
|
||||||
}
|
|
||||||
if (variantId === "2") {
|
|
||||||
return Promise.resolve(variant2)
|
|
||||||
}
|
|
||||||
if (variantId === "3") {
|
|
||||||
return Promise.resolve(variant3)
|
|
||||||
}
|
|
||||||
if (variantId === "4") {
|
|
||||||
return Promise.resolve(variant4)
|
|
||||||
}
|
|
||||||
if (variantId === "invalid_option") {
|
|
||||||
return Promise.resolve(invalidVariant)
|
|
||||||
}
|
|
||||||
if (variantId === "empty_option") {
|
|
||||||
return Promise.resolve(emptyVariant)
|
|
||||||
}
|
|
||||||
return Promise.resolve(undefined)
|
|
||||||
}),
|
|
||||||
delete: jest.fn().mockReturnValue(Promise.resolve()),
|
|
||||||
addOptionValue: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation((variantId, optionId, value) => {
|
|
||||||
return Promise.resolve({})
|
|
||||||
}),
|
|
||||||
deleteOptionValue: jest.fn().mockImplementation((variantId, optionId) => {
|
|
||||||
return Promise.resolve({})
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export default mock
|
export default mock
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export const ProductServiceMock = {
|
||||||
|
createDraft: jest.fn().mockImplementation(data => {
|
||||||
|
return Promise.resolve(data)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
|
return ProductServiceMock
|
||||||
|
})
|
||||||
|
|
||||||
|
export default mock
|
||||||
Reference in New Issue
Block a user