feat(medusa): Continue create product workflow changes (#4473)

This commit is contained in:
Adrien de Peretti
2023-07-24 13:30:24 +02:00
committed by GitHub
parent edf93d972d
commit d2a8cf0378
103 changed files with 1859 additions and 524 deletions

View File

@@ -83,7 +83,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -240,7 +242,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -395,7 +399,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -515,7 +521,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -693,7 +701,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -861,7 +871,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -1112,7 +1124,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -1361,7 +1375,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -1570,7 +1586,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -1690,7 +1708,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -1868,7 +1888,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -2030,7 +2052,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -2139,7 +2163,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -2255,7 +2281,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,
@@ -2372,7 +2400,9 @@ Object {
"metadata": null,
"mid_code": null,
"origin_country": null,
"profile": Any<Object>,
"profile_id": Any<String>,
"profiles": Any<Array>,
"status": "draft",
"subtitle": null,
"thumbnail": null,

View File

@@ -120,6 +120,8 @@ describe("medusa-plugin-sendgrid", () => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},
@@ -242,6 +244,8 @@ describe("medusa-plugin-sendgrid", () => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},
@@ -303,6 +307,8 @@ describe("medusa-plugin-sendgrid", () => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},
@@ -485,6 +491,8 @@ describe("medusa-plugin-sendgrid", () => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},
@@ -592,6 +600,8 @@ describe("medusa-plugin-sendgrid", () => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},
@@ -780,6 +790,8 @@ const getReturnSnap = (received = false) => {
updated_at: expect.any(Date),
product: {
profile_id: expect.any(String),
profile: expect.any(Object),
profiles: expect.any(Array),
created_at: expect.any(Date),
updated_at: expect.any(Date),
},

View File

@@ -0,0 +1,351 @@
import path from "path"
import { bootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { setPort, useApi } from "../../../../environment-helpers/use-api"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"
import productSeeder from "../../../../helpers/product-seeder"
import { simpleSalesChannelFactory } from "../../../../factories"
import { AxiosInstance } from "axios"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
Authorization: "Bearer test_token",
},
}
describe("/admin/products", () => {
let medusaProcess
let dbConnection
let express
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd } as any)
const { app, port } = await bootstrapApp({ cwd })
setPort(port)
express = app.listen(port, () => {
process.send?.(port)
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("POST /admin/products", () => {
beforeEach(async () => {
await productSeeder(dbConnection)
await adminSeeder(dbConnection)
await simpleSalesChannelFactory(dbConnection, {
name: "Default channel",
id: "default-channel",
is_default: true,
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a product", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "Test",
description: "test-product-description",
type: { value: "test-type" },
images: ["test-image.png", "test-image-2.png"],
collection_id: "test-collection",
tags: [{ value: "123" }, { value: "456" }],
options: [{ title: "size" }, { title: "color" }],
variants: [
{
title: "Test variant",
inventory_quantity: 10,
prices: [
{
currency_code: "usd",
amount: 100,
},
{
currency_code: "eur",
amount: 45,
},
{
currency_code: "dkk",
amount: 30,
},
],
options: [{ value: "large" }, { value: "green" }],
},
],
}
const response = await api
.post("/admin/products", payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
id: expect.stringMatching(/^prod_*/),
title: "Test",
discountable: true,
is_giftcard: false,
handle: "test",
status: "draft",
created_at: expect.any(String),
updated_at: expect.any(String),
profile_id: expect.stringMatching(/^sp_*/),
images: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
url: "test-image.png",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
expect.objectContaining({
id: expect.any(String),
url: "test-image-2.png",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
]),
thumbnail: "test-image.png",
tags: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
value: "123",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
expect.objectContaining({
id: expect.any(String),
value: "456",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
]),
type: expect.objectContaining({
value: "test-type",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
collection: expect.objectContaining({
id: "test-collection",
title: "Test collection",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
options: expect.arrayContaining([
expect.objectContaining({
id: expect.stringMatching(/^opt_*/),
product_id: expect.stringMatching(/^prod_*/),
title: "size",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
expect.objectContaining({
id: expect.stringMatching(/^opt_*/),
product_id: expect.stringMatching(/^prod_*/),
title: "color",
created_at: expect.any(String),
updated_at: expect.any(String),
}),
]),
variants: expect.arrayContaining([
expect.objectContaining({
id: expect.stringMatching(/^variant_*/),
product_id: expect.stringMatching(/^prod_*/),
updated_at: expect.any(String),
created_at: expect.any(String),
title: "Test variant",
prices: expect.arrayContaining([
expect.objectContaining({
id: expect.stringMatching(/^ma_*/),
currency_code: "usd",
amount: 100,
created_at: expect.any(String),
updated_at: expect.any(String),
variant_id: expect.stringMatching(/^variant_*/),
}),
expect.objectContaining({
id: expect.stringMatching(/^ma_*/),
currency_code: "eur",
amount: 45,
created_at: expect.any(String),
updated_at: expect.any(String),
variant_id: expect.stringMatching(/^variant_*/),
}),
expect.objectContaining({
id: expect.stringMatching(/^ma_*/),
currency_code: "dkk",
amount: 30,
created_at: expect.any(String),
updated_at: expect.any(String),
variant_id: expect.stringMatching(/^variant_*/),
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
value: "large",
created_at: expect.any(String),
updated_at: expect.any(String),
variant_id: expect.stringMatching(/^variant_*/),
option_id: expect.stringMatching(/^opt_*/),
id: expect.stringMatching(/^optval_*/),
}),
expect.objectContaining({
value: "green",
created_at: expect.any(String),
updated_at: expect.any(String),
variant_id: expect.stringMatching(/^variant_*/),
option_id: expect.stringMatching(/^opt_*/),
id: expect.stringMatching(/^optval_*/),
}),
]),
}),
]),
})
)
})
it("should create a product that is not discountable", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "Test",
discountable: false,
description: "test-product-description",
type: { value: "test-type" },
images: ["test-image.png", "test-image-2.png"],
collection_id: "test-collection",
tags: [{ value: "123" }, { value: "456" }],
options: [{ title: "size" }, { title: "color" }],
variants: [
{
title: "Test variant",
inventory_quantity: 10,
prices: [{ currency_code: "usd", amount: 100 }],
options: [{ value: "large" }, { value: "green" }],
},
],
}
const response = await api
.post("/admin/products", payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
discountable: false,
})
)
})
it("should sets the variant ranks when creating a product", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "Test product - 1",
description: "test-product-description 1",
type: { value: "test-type 1" },
images: ["test-image.png", "test-image-2.png"],
collection_id: "test-collection",
tags: [{ value: "123" }, { value: "456" }],
options: [{ title: "size" }, { title: "color" }],
variants: [
{
title: "Test variant 1",
inventory_quantity: 10,
prices: [{ currency_code: "usd", amount: 100 }],
options: [{ value: "large" }, { value: "green" }],
},
{
title: "Test variant 2",
inventory_quantity: 10,
prices: [{ currency_code: "usd", amount: 100 }],
options: [{ value: "large" }, { value: "green" }],
},
],
}
const creationResponse = await api
.post("/admin/products", payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(creationResponse?.status).toEqual(200)
const productId = creationResponse?.data.product.id
const response = await api
.get(`/admin/products/${productId}`, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.data.product).toEqual(
expect.objectContaining({
title: "Test product - 1",
variants: [
expect.objectContaining({
title: "Test variant 1",
}),
expect.objectContaining({
title: "Test variant 2",
}),
],
})
)
})
it("should create a giftcard", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "Test Giftcard",
is_giftcard: true,
description: "test-giftcard-description",
options: [{ title: "Denominations" }],
variants: [
{
title: "Test variant",
prices: [{ currency_code: "usd", amount: 100 }],
options: [{ value: "100" }],
},
],
}
const response = await api
.post("/admin/products", payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
title: "Test Giftcard",
discountable: false,
})
)
})
})
})

View File

@@ -2,6 +2,7 @@ const DB_HOST = process.env.DB_HOST
const DB_USERNAME = process.env.DB_USERNAME
const DB_PASSWORD = process.env.DB_PASSWORD
const DB_NAME = process.env.DB_TEMP_NAME
const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`
module.exports = {
plugins: [
@@ -23,7 +24,7 @@ module.exports = {
],
projectConfig: {
// redis_url: REDIS_URL,
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`,
database_url: DB_URL,
database_type: "postgres",
jwt_secret: "test",
cookie_secret: "test",
@@ -44,5 +45,16 @@ module.exports = {
resolve: "@medusajs/cache-inmemory",
options: { ttl: 5 },
},
productModuleService: {
scope: "internal",
resources: "isolated",
resolve: "@medusajs/product",
options: {
database: {
clientUrl: DB_URL,
debug: false,
},
},
},
},
}

View File

@@ -12,6 +12,7 @@
"@medusajs/cache-inmemory": "workspace:*",
"@medusajs/event-bus-local": "workspace:*",
"@medusajs/medusa": "workspace:*",
"@medusajs/product": "workspace:^",
"faker": "^5.5.3",
"medusa-fulfillment-webshipper": "workspace:*",
"medusa-interfaces": "workspace:*",