Chore/integration tests modules utils (#6581)

new wrapper for medusa integration tests.
for now it is only applied to the modules directory, but it could be used in the api integration tests or any other integrations that requires a db and a server up and running. 

It is not perfect, but I wanted to have something working and centralised before improving it, also avoiding too many conflicts with other prs
This commit is contained in:
Adrien de Peretti
2024-03-06 10:03:07 +00:00
committed by GitHub
parent a6736c7ee0
commit 51bb6f1e89
99 changed files with 10164 additions and 10303 deletions
@@ -1,17 +1,12 @@
import { PricingModuleService } from "@medusajs/pricing"
import { ProductModuleService } from "@medusajs/product"
import { AxiosInstance } from "axios"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { medusaIntegrationTestRunner } from "medusa-test-utils"
jest.setTimeout(50000)
@@ -25,180 +20,171 @@ const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/products/:id/variants", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
medusaIntegrationTestRunner({
env,
testSuite: ({ dbConnection, getContainer, api }) => {
describe.skip("POST /admin/products/:id/variants", () => {
let appContainer
let product
let variant
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
})
beforeAll(async () => {
appContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
beforeEach(async () => {
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
await simpleRegionFactory(dbConnection, {
id: "test-region",
name: "Test Region",
currency_code: "usd",
tax_rate: 0,
})
product = await simpleProductFactory(dbConnection, {
id: "test-product-with-variant",
variants: [
{
options: [{ option_id: "test-product-option-1", value: "test" }],
},
],
options: [
{
id: "test-product-option-1",
title: "Test option 1",
},
],
})
variant = product.variants[0]
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a product variant with its price sets and prices through the workflow", async () => {
const api = useApi()! as AxiosInstance
const data = {
title: "test variant create",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
await simpleRegionFactory(dbConnection, {
id: "test-region",
name: "Test Region",
currency_code: "usd",
region_id: null,
},
],
material: "boo",
mid_code: "234asdfadsf",
hs_code: "asdfasdf234",
origin_country: "DE",
sku: "asdf",
ean: "234",
upc: "234",
barcode: "asdf",
inventory_quantity: 234,
manage_inventory: true,
allow_backorder: true,
weight: 234,
width: 234,
height: 234,
length: 234,
metadata: { asdf: "asdf" },
options: [{ option_id: "test-product-option-1", value: "test option" }],
}
tax_rate: 0,
})
let response = await api.post(
`/admin/products/${product.id}/variants`,
data,
adminHeaders
)
product = await simpleProductFactory(dbConnection, {
id: "test-product-with-variant",
variants: [
{
options: [{ option_id: "test-product-option-1", value: "test" }],
},
],
options: [
{
id: "test-product-option-1",
title: "Test option 1",
},
],
})
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
variant = product.variants[0]
})
it("should create a product variant with its price sets and prices through the workflow", async () => {
const data = {
title: "test variant create",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
currency_code: "usd",
region_id: null,
},
],
material: "boo",
mid_code: "234asdfadsf",
hs_code: "asdfasdf234",
origin_country: "DE",
sku: "asdf",
ean: "234",
upc: "234",
barcode: "asdf",
inventory_quantity: 234,
manage_inventory: true,
allow_backorder: true,
weight: 234,
width: 234,
height: 234,
length: 234,
metadata: { asdf: "asdf" },
options: [
{ option_id: "test-product-option-1", value: "test option" },
],
}
let response = await api.post(
`/admin/products/${product.id}/variants`,
data,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
title: "test variant create",
prices: expect.arrayContaining([
variants: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 55500,
currency_code: "usd",
id: expect.any(String),
title: "test variant create",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 55500,
currency_code: "usd",
}),
]),
}),
]),
}),
]),
})
)
})
it("should compensate creating product variants when error throws in future step", async () => {
jest
.spyOn(PricingModuleService.prototype, "create")
.mockImplementation(() => {
throw new Error("Random Error")
})
)
})
const productSpy = jest.spyOn(
ProductModuleService.prototype,
"deleteVariants"
)
it("should compensate creating product variants when error throws in future step", async () => {
jest
.spyOn(PricingModuleService.prototype, "create")
.mockImplementation(() => {
throw new Error("Random Error")
})
const api = useApi()! as AxiosInstance
const data = {
title: "test variant create",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
currency_code: "usd",
region_id: null,
},
],
material: "boo",
mid_code: "234asdfadsf",
hs_code: "asdfasdf234",
origin_country: "DE",
sku: "asdf",
ean: "234",
upc: "234",
barcode: "asdf",
inventory_quantity: 234,
manage_inventory: true,
allow_backorder: true,
weight: 234,
width: 234,
height: 234,
length: 234,
metadata: { asdf: "asdf" },
options: [{ option_id: "test-product-option-1", value: "test option" }],
}
const productSpy = jest.spyOn(
ProductModuleService.prototype,
"deleteVariants"
)
await api
.post(`/admin/products/${product.id}/variants`, data, adminHeaders)
.catch((e) => e)
const data = {
title: "test variant create",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
currency_code: "usd",
region_id: null,
},
],
material: "boo",
mid_code: "234asdfadsf",
hs_code: "asdfasdf234",
origin_country: "DE",
sku: "asdf",
ean: "234",
upc: "234",
barcode: "asdf",
inventory_quantity: 234,
manage_inventory: true,
allow_backorder: true,
weight: 234,
width: 234,
height: 234,
length: 234,
metadata: { asdf: "asdf" },
options: [
{ option_id: "test-product-option-1", value: "test option" },
],
}
expect(productSpy).toBeCalledWith([expect.any(String)])
await api
.post(`/admin/products/${product.id}/variants`, data, adminHeaders)
.catch((e) => e)
const getProductResponse = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(getProductResponse.data.product.variants).toHaveLength(1)
})
expect(productSpy).toBeCalledWith([expect.any(String)])
const getProductResponse = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(getProductResponse.data.product.variants).toHaveLength(1)
})
})
},
})
@@ -1,18 +1,5 @@
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import productSeeder from "../../../../helpers/product-seeder"
import { AxiosInstance } from "axios"
import { getContainer } from "../../../../environment-helpers/use-container"
import {
simpleProductFactory,
simpleSalesChannelFactory,
} from "../../../../factories"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createAdminUser } from "../../../helpers/create-admin-user"
import { medusaIntegrationTestRunner } from "medusa-test-utils/dist"
jest.setTimeout(50000)
@@ -26,469 +13,448 @@ const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe("/admin/products", () => {
let dbConnection
let shutdownServer
let medusaContainer
medusaIntegrationTestRunner({
env,
testSuite: ({ dbConnection, getContainer, api }) => {
describe("/admin/products", () => {
let medusaContainer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env })
shutdownServer = await startBootstrapApp({ cwd, env })
medusaContainer = getContainer()
})
beforeAll(async () => {
medusaContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders, medusaContainer)
describe("POST /admin/products", () => {
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
// await productSeeder(dbConnection)
// await createDefaultRuleTypes(medusaContainer)
// await simpleSalesChannelFactory(dbConnection, {
// name: "Default channel",
// id: "default-channel",
// is_default: true,
// })
})
// await productSeeder(dbConnection)
// await createDefaultRuleTypes(medusaContainer)
// await simpleSalesChannelFactory(dbConnection, {
// name: "Default channel",
// id: "default-channel",
// is_default: true,
// })
})
describe("POST /admin/products", () => {
it("should create a product", async () => {
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" }],
},
],
}
afterEach(async () => {
const db = useDb()
await db.teardown()
})
const response = await api
.post("/admin/products", payload, adminHeaders)
.catch((err) => {
console.log(err)
})
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",
// profile_id: expect.stringMatching(/^sp_*/),
thumbnail: "test-image.png",
created_at: expect.any(String),
updated_at: expect.any(String),
})
)
expect(response?.data.product.images).toEqual(
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),
}),
])
)
console.log(response?.data.product)
expect(response?.data.product.variants).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.stringMatching(/^variant_*/),
title: "Test variant",
// product_id: expect.stringMatching(/^prod_*/),
updated_at: expect.any(String),
created_at: expect.any(String),
// prices: expect.arrayContaining([
// expect.objectContaining({
// id: expect.stringMatching(/^ma_*/),
// currency_code: "usd",
// amount: 100,
// // TODO: enable this in the Pricing Module PR
// // 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,
// // TODO: enable this in the Pricing Module PR
// // 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,
// // TODO: enable this in the Pricing Module PR
// // 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_*/),
// }),
// ]),
}),
])
)
expect(response?.data.product.options).toEqual(
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),
}),
])
)
// 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),
// }),
})
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}?fields=title,variants.title`,
adminHeaders
)
.catch((err) => {
console.log(err)
})
expect(response?.data.product).toEqual(
expect.objectContaining({
title: "Test product - 1",
variants: [
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
title: "Test variant 1",
}),
id: expect.stringMatching(/^prod_*/),
title: "Test",
discountable: true,
is_giftcard: false,
handle: "test",
status: "draft",
// profile_id: expect.stringMatching(/^sp_*/),
thumbnail: "test-image.png",
created_at: expect.any(String),
updated_at: expect.any(String),
})
)
expect(response?.data.product.images).toEqual(
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),
}),
])
)
console.log(response?.data.product)
expect(response?.data.product.variants).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.stringMatching(/^variant_*/),
title: "Test variant",
// product_id: expect.stringMatching(/^prod_*/),
updated_at: expect.any(String),
created_at: expect.any(String),
// prices: expect.arrayContaining([
// expect.objectContaining({
// id: expect.stringMatching(/^ma_*/),
// currency_code: "usd",
// amount: 100,
// // TODO: enable this in the Pricing Module PR
// // 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,
// // TODO: enable this in the Pricing Module PR
// // 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,
// // TODO: enable this in the Pricing Module PR
// // 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_*/),
// }),
// ]),
}),
])
)
expect(response?.data.product.options).toEqual(
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),
}),
])
)
// 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),
// }),
})
it("should create a product that is not discountable", async () => {
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({
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)
discountable: false,
})
)
})
expect(response?.status).toEqual(200)
it("should sets the variant ranks when creating a product", async () => {
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" }],
},
],
}
expect(response?.data.product).toEqual(
expect.objectContaining({
title: "Test Giftcard",
discountable: false,
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}?fields=title,variants.title`,
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 variants with inventory items", async () => {
const api = useApi()! as AxiosInstance
it("should create a giftcard", async () => {
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`,
{
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: [
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,
})
)
})
it("should create variants with inventory items", async () => {
const response = await api.post(
`/admin/products`,
{
title: "Test variant 1",
inventory_quantity: 10,
// prices: [{ currency_code: "usd", amount: 100 }],
// options: [{ value: "large" }, { value: "green" }],
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" }],
},
],
},
{
title: "Test variant 2",
inventory_quantity: 10,
// prices: [{ currency_code: "usd", amount: 100 }],
// options: [{ value: "large" }, { value: "green" }],
},
],
},
adminHeaders
)
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.status).toEqual(200)
// const variantIds = response.data.product.variants.map(
// (v: { id: string }) => v.id
// )
// const variantIds = response.data.product.variants.map(
// (v: { id: string }) => v.id
// )
// const variantInventoryService = medusaContainer.resolve(
// "productVariantInventoryService"
// )
// const inventory = await variantInventoryService.listByVariant(variantIds)
// const variantInventoryService = medusaContainer.resolve(
// "productVariantInventoryService"
// )
// const inventory = await variantInventoryService.listByVariant(variantIds)
// expect(inventory).toHaveLength(2)
// expect(inventory).toContainEqual(
// expect.objectContaining({
// variant_id: variantIds[0],
// required_quantity: 1,
// })
// )
// expect(inventory).toContainEqual(
// expect.objectContaining({
// variant_id: variantIds[1],
// required_quantity: 1,
// })
// )
// expect(inventory).toHaveLength(2)
// expect(inventory).toContainEqual(
// expect.objectContaining({
// variant_id: variantIds[0],
// required_quantity: 1,
// })
// )
// expect(inventory).toContainEqual(
// expect.objectContaining({
// variant_id: variantIds[1],
// required_quantity: 1,
// })
// )
})
// it("should create prices with region_id and currency_code context", async () => {
// const api = useApi()! as AxiosInstance
// const data = {
// title: "test product",
// options: [{ title: "test-option" }],
// variants: [
// {
// title: "test variant",
// prices: [
// {
// amount: 66600,
// region_id: "test-region",
// },
// {
// amount: 55500,
// currency_code: "usd",
// },
// ],
// options: [{ value: "test-option" }],
// },
// ],
// }
// let response = await api.post(
// "/admin/products?relations=variants.prices",
// data,
// adminHeaders
// )
// expect(response.status).toEqual(200)
// expect(response.data).toEqual({
// product: expect.objectContaining({
// id: expect.any(String),
// title: "test product",
// variants: expect.arrayContaining([
// expect.objectContaining({
// id: expect.any(String),
// title: "test variant",
// prices: expect.arrayContaining([
// expect.objectContaining({
// amount: 66600,
// currency_code: "usd",
// }),
// expect.objectContaining({
// amount: 55500,
// currency_code: "usd",
// }),
// ]),
// }),
// ]),
// }),
// })
// const pricingModuleService: IPricingModuleService = appContainer.resolve(
// "pricingModuleService"
// )
// const [_, count] = await pricingModuleService.listAndCount()
// expect(count).toEqual(1)
// })
})
})
// it("should create prices with region_id and currency_code context", async () => {
// const api = useApi()! as AxiosInstance
// const data = {
// title: "test product",
// options: [{ title: "test-option" }],
// variants: [
// {
// title: "test variant",
// prices: [
// {
// amount: 66600,
// region_id: "test-region",
// },
// {
// amount: 55500,
// currency_code: "usd",
// },
// ],
// options: [{ value: "test-option" }],
// },
// ],
// }
// let response = await api.post(
// "/admin/products?relations=variants.prices",
// data,
// adminHeaders
// )
// expect(response.status).toEqual(200)
// expect(response.data).toEqual({
// product: expect.objectContaining({
// id: expect.any(String),
// title: "test product",
// variants: expect.arrayContaining([
// expect.objectContaining({
// id: expect.any(String),
// title: "test variant",
// prices: expect.arrayContaining([
// expect.objectContaining({
// amount: 66600,
// currency_code: "usd",
// }),
// expect.objectContaining({
// amount: 55500,
// currency_code: "usd",
// }),
// ]),
// }),
// ]),
// }),
// })
// const pricingModuleService: IPricingModuleService = appContainer.resolve(
// "pricingModuleService"
// )
// const [_, count] = await pricingModuleService.listAndCount()
// expect(count).toEqual(1)
// })
})
},
})
@@ -24,6 +24,10 @@ const env: Record<any, any> = {
jest.setTimeout(180000)
// TODO SEE to use new test runner medusaIntegrationTestRunner({
// env,
// testSuite: ({ dbConnection, getContainer, api }) => {})
describe.skip("Batch job of product-export type", () => {
let medusaProcess
let dbConnection
@@ -56,6 +56,10 @@ const env: Record<any, any> = {
MEDUSA_FF_MEDUSA_V2: true,
}
// TODO SEE to use new test runner medusaIntegrationTestRunner({
// env,
// testSuite: ({ dbConnection, getContainer, api }) => {})
describe.skip("Product import batch job", () => {
let dbConnection
let shutdownServer
@@ -0,0 +1,659 @@
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { 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 { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
import { MedusaV2Flag } from "@medusajs/utils"
import { AxiosInstance } from "axios"
import { getContainer } from "../../../../environment-helpers/use-container"
import {
simpleProductFactory,
simpleSalesChannelFactory,
} from "../../../../factories"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
// TODO SEE to use new test runner medusaIntegrationTestRunner({
// env,
// testSuite: ({ dbConnection, getContainer, api }) => {})
describe.skip("/admin/products", () => {
let dbConnection
let shutdownServer
let medusaContainer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env })
shutdownServer = await startBootstrapApp({ cwd, env })
medusaContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
it("Should have loaded the product module", function () {
const productRegistrationName =
ModulesDefinition[Modules.PRODUCT].registrationName
expect(
medusaContainer.hasRegistration(productRegistrationName)
).toBeTruthy()
})
it("Should have enabled workflows feature flag", function () {
const flagRouter = medusaContainer.resolve("featureFlagRouter")
const workflowsFlag = flagRouter.isFeatureEnabled(MedusaV2Flag.key)
expect(workflowsFlag).toBe(true)
})
describe("POST /admin/products", () => {
beforeEach(async () => {
await productSeeder(dbConnection)
await adminSeeder(dbConnection)
await createDefaultRuleTypes(medusaContainer)
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,
// TODO: enable this in the Pricing Module PR
// 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,
// TODO: enable this in the Pricing Module PR
// 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,
// TODO: enable this in the Pricing Module PR
// 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,
})
)
})
it("should create variants with inventory items", async () => {
const api = useApi()! as AxiosInstance
const response = await api.post(
`/admin/products`,
{
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" }],
},
],
},
{ headers: { "x-medusa-access-token": "test_token" } }
)
expect(response.status).toEqual(200)
const variantIds = response.data.product.variants.map(
(v: { id: string }) => v.id
)
const variantInventoryService = medusaContainer.resolve(
"productVariantInventoryService"
)
const inventory = await variantInventoryService.listByVariant(variantIds)
expect(inventory).toHaveLength(2)
expect(inventory).toContainEqual(
expect.objectContaining({
variant_id: variantIds[0],
required_quantity: 1,
})
)
expect(inventory).toContainEqual(
expect.objectContaining({
variant_id: variantIds[1],
required_quantity: 1,
})
)
})
})
describe("POST /admin/products/:id", () => {
const toUpdateWithSalesChannels = "to-update-with-sales-channels"
const toUpdateWithVariants = "to-update-with-variants"
const toUpdate = "to-update"
beforeEach(async () => {
await productSeeder(dbConnection)
await adminSeeder(dbConnection)
await createDefaultRuleTypes(medusaContainer)
await simpleSalesChannelFactory(dbConnection, {
name: "Default channel",
id: "default-channel",
is_default: true,
})
await simpleSalesChannelFactory(dbConnection, {
name: "Channel 3",
id: "channel-3",
is_default: true,
})
await simpleProductFactory(dbConnection, {
title: "To update product",
id: toUpdate,
})
await simpleProductFactory(dbConnection, {
title: "To update product with channels",
id: toUpdateWithSalesChannels,
sales_channels: [
{ name: "channel 1", id: "channel-1" },
{ name: "channel 2", id: "channel-2" },
],
})
await simpleSalesChannelFactory(dbConnection, {
name: "To be added",
id: "to-be-added",
})
await simpleProductFactory(dbConnection, {
title: "To update product with variants",
id: toUpdateWithVariants,
variants: [
{
id: "variant-1",
title: "Variant 1",
},
{
id: "variant-2",
title: "Variant 2",
},
],
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should do a basic product update", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "New title",
description: "test-product-description",
}
const response = await api
.post(`/admin/products/${toUpdate}`, payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
id: toUpdate,
title: "New title",
description: "test-product-description",
})
)
})
it("should update product and also update a variant and create a variant", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "New title",
description: "test-product-description",
variants: [
{
id: "variant-1",
title: "Variant 1 updated",
},
{
title: "Variant 3",
},
],
}
const response = await api
.post(`/admin/products/${toUpdateWithVariants}`, payload, adminHeaders)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
id: toUpdateWithVariants,
title: "New title",
description: "test-product-description",
variants: expect.arrayContaining([
expect.objectContaining({
id: "variant-1",
title: "Variant 1 updated",
}),
expect.objectContaining({
title: "Variant 3",
}),
]),
})
)
})
it("should update product's sales channels", async () => {
const api = useApi()! as AxiosInstance
const payload = {
title: "New title",
description: "test-product-description",
sales_channels: [{ id: "channel-2" }, { id: "channel-3" }],
}
const response = await api
.post(
`/admin/products/${toUpdateWithSalesChannels}?expand=sales_channels`,
payload,
adminHeaders
)
.catch((err) => {
console.log(err)
})
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
id: toUpdateWithSalesChannels,
sales_channels: [
expect.objectContaining({ id: "channel-2" }),
expect.objectContaining({ id: "channel-3" }),
],
})
)
})
it("should update inventory when variants are updated", async () => {
const api = useApi()! as AxiosInstance
const variantInventoryService = medusaContainer.resolve(
"productVariantInventoryService"
)
const payload = {
title: "New title",
description: "test-product-description",
variants: [
{
id: "variant-1",
title: "Variant 1 updated",
},
{
title: "Variant 3",
},
],
}
const response = await api
.post(`/admin/products/${toUpdateWithVariants}`, payload, adminHeaders)
.catch((err) => {
console.log(err)
})
let inventory = await variantInventoryService.listInventoryItemsByVariant(
"variant-2"
)
expect(response?.status).toEqual(200)
expect(response?.data.product).toEqual(
expect.objectContaining({
id: toUpdateWithVariants,
title: "New title",
description: "test-product-description",
variants: expect.arrayContaining([
expect.objectContaining({
id: "variant-1",
title: "Variant 1 updated",
}),
expect.objectContaining({
title: "Variant 3",
}),
]),
})
)
expect(inventory).toEqual([]) // no inventory items for removed variant
inventory = await variantInventoryService.listInventoryItemsByVariant(
response?.data.product.variants.find((v) => v.title === "Variant 3").id
)
expect(inventory).toEqual([
expect.objectContaining({ id: expect.any(String) }),
])
})
})
})
@@ -1,17 +1,16 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
import {initDb, useDb} from "../../../../environment-helpers/use-db"
import {simpleProductFactory, simpleRegionFactory,} from "../../../../factories"
import { AxiosInstance } from "axios"
import {AxiosInstance} from "axios"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
import { getContainer } from "../../../../environment-helpers/use-container"
import {
createDefaultRuleTypes
} from "../../../helpers/create-default-rule-types"
import {createVariantPriceSet} from "../../../helpers/create-variant-price-set"
import {getContainer} from "../../../../environment-helpers/use-container"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import {startBootstrapApp} from "../../../../environment-helpers/bootstrap-app"
import {useApi} from "../../../../environment-helpers/use-api"
jest.setTimeout(50000)
@@ -25,6 +24,10 @@ const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
// TODO SEE to use new test runner medusaIntegrationTestRunner({
// env,
// testSuite: ({ dbConnection, getContainer, api }) => {})
describe.skip("POST /admin/products/:id/variants/:id", () => {
let dbConnection
let appContainer
@@ -23,6 +23,10 @@ const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
// TODO SEE to use new test runner medusaIntegrationTestRunner({
// env,
// testSuite: ({ dbConnection, getContainer, api }) => {})
describe.skip("POST /admin/products/:id", () => {
let dbConnection
let appContainer