chore: V2 core loader + modules integration-tests (#6544)

This commit is contained in:
Oli Juhl
2024-02-29 16:46:30 +01:00
committed by GitHub
parent dc025302a1
commit 296d7faad4
100 changed files with 318 additions and 78 deletions

View File

@@ -1,197 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ApiKeyType } from "@medusajs/utils"
import { IApiKeyModuleService, IRegionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("API Keys - Admin", () => {
let dbConnection
let appContainer
let shutdownServer
let service: IApiKeyModuleService
let regionService: IRegionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.API_KEY)
regionService = appContainer.resolve(ModuleRegistrationName.REGION)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
// Used for testing cross-module authentication checks
await regionService.createDefaultCountries()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly implement the entire lifecycle of an api key", async () => {
const api = useApi() as any
const created = await api.post(
`/admin/api-keys`,
{
title: "Test Secret Key",
type: ApiKeyType.SECRET,
},
adminHeaders
)
expect(created.status).toEqual(200)
expect(created.data.apiKey).toEqual(
expect.objectContaining({
id: created.data.apiKey.id,
title: "Test Secret Key",
created_by: "admin_user",
})
)
// On create we get the token in raw form so we can store it.
expect(created.data.apiKey.token).toContain("sk_")
const updated = await api.post(
`/admin/api-keys/${created.data.apiKey.id}`,
{
title: "Updated Secret Key",
},
adminHeaders
)
expect(updated.status).toEqual(200)
expect(updated.data.apiKey).toEqual(
expect.objectContaining({
id: created.data.apiKey.id,
title: "Updated Secret Key",
})
)
const revoked = await api.post(
`/admin/api-keys/${created.data.apiKey.id}/revoke`,
{},
adminHeaders
)
expect(revoked.status).toEqual(200)
expect(revoked.data.apiKey).toEqual(
expect.objectContaining({
id: created.data.apiKey.id,
revoked_by: "admin_user",
})
)
expect(revoked.data.apiKey.revoked_at).toBeTruthy()
const deleted = await api.delete(
`/admin/api-keys/${created.data.apiKey.id}`,
adminHeaders
)
const listedApiKeys = await api.get(`/admin/api-keys`, adminHeaders)
expect(deleted.status).toEqual(200)
expect(listedApiKeys.data.apiKeys).toHaveLength(0)
})
it("can use a secret api key for authentication", async () => {
const api = useApi() as any
const created = await api.post(
`/admin/api-keys`,
{
title: "Test Secret Key",
type: ApiKeyType.SECRET,
},
adminHeaders
)
const createdRegion = await api.post(
`/admin/regions`,
{
name: "Test Region",
currency_code: "usd",
countries: ["us", "ca"],
},
{
auth: {
username: created.data.apiKey.token,
},
}
)
expect(createdRegion.status).toEqual(200)
expect(createdRegion.data.region.name).toEqual("Test Region")
})
it("falls back to other mode of authentication when an api key is not valid", async () => {
const api = useApi() as any
const created = await api.post(
`/admin/api-keys`,
{
title: "Test Secret Key",
type: ApiKeyType.SECRET,
},
adminHeaders
)
await api.post(
`/admin/api-keys/${created.data.apiKey.id}/revoke`,
{},
adminHeaders
)
const err = await api
.post(
`/admin/regions`,
{
name: "Test Region",
currency_code: "usd",
countries: ["us", "ca"],
},
{
auth: {
username: created.data.apiKey.token,
},
}
)
.catch((e) => e.message)
const createdRegion = await api.post(
`/admin/regions`,
{
name: "Test Region",
currency_code: "usd",
countries: ["us", "ca"],
},
{
auth: {
username: created.data.apiKey.token,
},
...adminHeaders,
}
)
expect(err).toEqual("Request failed with status code 401")
expect(createdRegion.status).toEqual(200)
expect(createdRegion.data.region.name).toEqual("Test Region")
})
})

View File

@@ -1,307 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService, IPromotionModuleService } from "@medusajs/types"
import { PromotionType } from "@medusajs/utils"
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 adminSeeder from "../../../../helpers/admin-seeder"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Store Carts API: Add promotions to cart", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
describe("POST /store/carts/:id/promotions", () => {
it("should add line item adjustments to a cart based on promotions", async () => {
const appliedPromotion = await promotionModuleService.create({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "each",
value: "300",
apply_to_quantity: 1,
max_quantity: 1,
target_rules: [
{
attribute: "product_id",
operator: "eq",
values: "prod_tshirt",
},
],
},
})
const createdPromotion = await promotionModuleService.create({
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "across",
value: "1000",
apply_to_quantity: 1,
target_rules: [
{
attribute: "product_id",
operator: "eq",
values: "prod_mat",
},
],
},
})
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
// Adjustment to add
{
id: "item-1",
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_mat",
} as any,
// This adjustment will be removed and recreated
{
id: "item-2",
unit_price: 1000,
quantity: 1,
title: "Test item",
product_id: "prod_tshirt",
} as any,
],
})
// Adjustment to keep
const [lineItemAdjustment] =
await cartModuleService.addLineItemAdjustments([
{
code: appliedPromotion.code!,
amount: 300,
item_id: "item-2",
promotion_id: appliedPromotion.id,
},
])
const api = useApi() as any
const created = await api.post(`/store/carts/${cart.id}/promotions`, {
promo_codes: [createdPromotion.code],
})
expect(created.status).toEqual(200)
expect(created.data.cart).toEqual(
expect.objectContaining({
id: expect.any(String),
items: expect.arrayContaining([
expect.objectContaining({
id: "item-1",
adjustments: expect.arrayContaining([
expect.objectContaining({
code: createdPromotion.code,
amount: 1000,
}),
]),
}),
expect.objectContaining({
adjustments: expect.arrayContaining([
expect.objectContaining({
id: expect.not.stringContaining(lineItemAdjustment.id),
code: appliedPromotion.code,
amount: 300,
}),
]),
}),
]),
})
)
})
it("should add shipping method adjustments to a cart based on promotions", async () => {
const [appliedPromotion] = await promotionModuleService.create([
{
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_id",
operator: "in",
values: ["cus_test"],
},
{
attribute: "currency_code",
operator: "in",
values: ["eur"],
},
],
application_method: {
type: "fixed",
target_type: "shipping_methods",
allocation: "each",
value: "100",
max_quantity: 1,
target_rules: [
{
attribute: "name",
operator: "in",
values: ["express"],
},
],
},
},
])
const [newPromotion] = await promotionModuleService.create([
{
code: "PROMOTION_NEW",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_id",
operator: "in",
values: ["cus_test"],
},
{
attribute: "currency_code",
operator: "in",
values: ["eur"],
},
],
application_method: {
type: "fixed",
target_type: "shipping_methods",
allocation: "each",
value: "200",
max_quantity: 1,
target_rules: [
{
attribute: "name",
operator: "in",
values: ["express", "standard"],
},
],
},
},
])
const cart = await cartModuleService.create({
currency_code: "eur",
customer_id: "cus_test",
items: [
{
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_mat",
} as any,
],
})
const [express, standard] = await cartModuleService.addShippingMethods(
cart.id,
[
{
amount: 500,
name: "express",
},
{
amount: 500,
name: "standard",
},
]
)
const [adjustment] = await cartModuleService.addShippingMethodAdjustments(
cart.id,
[
{
shipping_method_id: express.id,
amount: 100,
code: appliedPromotion.code!,
},
]
)
const api = useApi() as any
const created = await api.post(`/store/carts/${cart.id}/promotions`, {
promo_codes: [newPromotion.code],
})
expect(created.status).toEqual(200)
expect(created.data.cart).toEqual(
expect.objectContaining({
id: expect.any(String),
items: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
}),
]),
shipping_methods: expect.arrayContaining([
expect.objectContaining({
id: express.id,
adjustments: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
amount: 200,
code: newPromotion.code,
}),
expect.objectContaining({
id: expect.not.stringContaining(adjustment.id),
amount: 100,
code: appliedPromotion.code,
}),
]),
}),
expect.objectContaining({
id: standard.id,
adjustments: [
expect.objectContaining({
id: expect.any(String),
amount: 200,
code: newPromotion.code,
}),
],
}),
]),
})
)
})
})
})

View File

@@ -1,672 +0,0 @@
import {
addToCartWorkflow,
createCartWorkflow,
deleteLineItemsStepId,
deleteLineItemsWorkflow,
findOrCreateCustomerStepId,
updateLineItemInCartWorkflow,
updateLineItemsStepId,
} from "@medusajs/core-flows"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
ICartModuleService,
ICustomerModuleService,
IPricingModuleService,
IProductModuleService,
IRegionModuleService,
ISalesChannelModuleService,
} from "@medusajs/types"
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 adminSeeder from "../../../../helpers/admin-seeder"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Carts workflows", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let regionModuleService: IRegionModuleService
let scModuleService: ISalesChannelModuleService
let customerModule: ICustomerModuleService
let productModule: IProductModuleService
let pricingModule: IPricingModuleService
let remoteLink
let defaultRegion
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
regionModuleService = appContainer.resolve(ModuleRegistrationName.REGION)
scModuleService = appContainer.resolve(ModuleRegistrationName.SALES_CHANNEL)
customerModule = appContainer.resolve(ModuleRegistrationName.CUSTOMER)
productModule = appContainer.resolve(ModuleRegistrationName.PRODUCT)
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
remoteLink = appContainer.resolve("remoteLink")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
await regionModuleService.createDefaultCountries()
// Here, so we don't have to create a region for each test
defaultRegion = await regionModuleService.create({
name: "Default Region",
currency_code: "dkk",
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
describe("CreateCartWorkflow", () => {
it("should create a cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
const priceSet = await pricingModule.create({
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
])
const { result } = await createCartWorkflow(appContainer).run({
input: {
email: "tony@stark.com",
currency_code: "usd",
region_id: region.id,
sales_channel_id: salesChannel.id,
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
},
],
},
})
const cart = await cartModuleService.retrieve(result.id, {
relations: ["items"],
})
expect(cart).toEqual(
expect.objectContaining({
currency_code: "usd",
email: "tony@stark.com",
region_id: region.id,
sales_channel_id: salesChannel.id,
customer_id: expect.any(String),
items: expect.arrayContaining([
expect.objectContaining({
quantity: 1,
unit_price: 3000,
}),
]),
})
)
})
it("should throw when no regions exist", async () => {
await regionModuleService.delete(defaultRegion.id)
const { errors } = await createCartWorkflow(appContainer).run({
input: {
email: "tony@stark.com",
currency_code: "usd",
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "find-one-or-any-region",
handlerType: "invoke",
error: new Error("No regions found"),
},
])
})
it("should throw if sales channel is disabled", async () => {
const api = useApi() as any
const salesChannel = await scModuleService.create({
name: "Webshop",
is_disabled: true,
})
const { errors } = await createCartWorkflow(appContainer).run({
input: {
sales_channel_id: salesChannel.id,
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "find-sales-channel",
handlerType: "invoke",
error: new Error(
`Unable to assign cart to disabled Sales Channel: Webshop`
),
},
])
})
describe("compensation", () => {
it("should delete created customer if cart-creation fails", async () => {
expect.assertions(2)
const workflow = createCartWorkflow(appContainer)
workflow.appendAction("throw", findOrCreateCustomerStepId, {
invoke: async function failStep() {
throw new Error(`Failed to create cart`)
},
})
const { errors } = await workflow.run({
input: {
currency_code: "usd",
email: "tony@stark-industries.com",
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "throw",
handlerType: "invoke",
error: new Error(`Failed to create cart`),
},
])
const customers = await customerModule.list({
email: "tony@stark-industries.com",
})
expect(customers).toHaveLength(0)
})
it("should not delete existing customer if cart-creation fails", async () => {
expect.assertions(2)
const workflow = createCartWorkflow(appContainer)
workflow.appendAction("throw", findOrCreateCustomerStepId, {
invoke: async function failStep() {
throw new Error(`Failed to create cart`)
},
})
const customer = await customerModule.create({
email: "tony@stark-industries.com",
})
const { errors } = await workflow.run({
input: {
currency_code: "usd",
customer_id: customer.id,
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "throw",
handlerType: "invoke",
error: new Error(`Failed to create cart`),
},
])
const customers = await customerModule.list({
email: "tony@stark-industries.com",
})
expect(customers).toHaveLength(1)
})
})
})
describe("AddToCartWorkflow", () => {
it("should add item to cart", async () => {
let cart = await cartModuleService.create({
currency_code: "usd",
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
const priceSet = await pricingModule.create({
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
])
cart = await cartModuleService.retrieve(cart.id, {
select: ["id", "region_id", "currency_code"],
})
await addToCartWorkflow(appContainer).run({
input: {
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
},
],
cart,
},
})
cart = await cartModuleService.retrieve(cart.id, {
relations: ["items"],
})
expect(cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 3000,
quantity: 1,
title: "Test variant",
}),
]),
})
)
})
it("should throw if no price sets for variant exist", async () => {
const cart = await cartModuleService.create({
currency_code: "usd",
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
const { errors } = await addToCartWorkflow(appContainer).run({
input: {
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
},
],
cart,
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "get-variant-price-sets",
handlerType: "invoke",
error: new Error(
`Variants with IDs ${product.variants[0].id} do not have a price`
),
},
])
})
it("should throw if variant does not exist", async () => {
const cart = await cartModuleService.create({
currency_code: "usd",
})
const { errors } = await addToCartWorkflow(appContainer).run({
input: {
items: [
{
variant_id: "prva_foo",
quantity: 1,
},
],
cart,
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "validate-variants-exist",
handlerType: "invoke",
error: new Error(`Variants with IDs prva_foo do not exist`),
},
])
})
})
describe("updateLineItemInCartWorkflow", () => {
it("should update item in cart", async () => {
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
const priceSet = await pricingModule.create({
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
])
let cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
unit_price: 5000,
title: "Test item",
},
],
})
cart = await cartModuleService.retrieve(cart.id, {
select: ["id", "region_id", "currency_code"],
relations: ["items", "items.variant_id", "items.metadata"],
})
const item = cart.items?.[0]!
await updateLineItemInCartWorkflow(appContainer).run({
input: {
cart,
item,
update: {
metadata: {
foo: "bar",
},
quantity: 2,
},
},
throwOnError: false,
})
const updatedItem = await cartModuleService.retrieveLineItem(item.id)
expect(updatedItem).toEqual(
expect.objectContaining({
id: item.id,
unit_price: 3000,
quantity: 2,
title: "Test item",
})
)
})
describe("compensation", () => {
it("should revert line item update to original state", async () => {
expect.assertions(2)
const workflow = updateLineItemInCartWorkflow(appContainer)
workflow.appendAction("throw", updateLineItemsStepId, {
invoke: async function failStep() {
throw new Error(`Failed to update something after line items`)
},
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
let cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
unit_price: 3000,
title: "Test item",
},
],
})
const priceSet = await pricingModule.create({
prices: [
{
amount: 5000,
currency_code: "usd",
},
],
})
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
])
cart = await cartModuleService.retrieve(cart.id, {
select: ["id", "region_id", "currency_code"],
relations: ["items", "items.variant_id", "items.metadata"],
})
const item = cart.items?.[0]!
const { errors } = await workflow.run({
input: {
cart,
item,
update: {
metadata: {
foo: "bar",
},
title: "Test item updated",
quantity: 2,
},
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "throw",
handlerType: "invoke",
error: new Error(`Failed to update something after line items`),
},
])
const updatedItem = await cartModuleService.retrieveLineItem(item.id)
expect(updatedItem).toEqual(
expect.objectContaining({
id: item.id,
unit_price: 3000,
quantity: 1,
title: "Test item",
})
)
})
})
})
describe("deleteLineItems", () => {
it("should delete items in cart", async () => {
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
quantity: 1,
unit_price: 5000,
title: "Test item",
},
],
})
const items = await cartModuleService.listLineItems({ cart_id: cart.id })
await deleteLineItemsWorkflow(appContainer).run({
input: {
ids: items.map((i) => i.id),
},
throwOnError: false,
})
const [deletedItem] = await cartModuleService.listLineItems({
id: items.map((i) => i.id),
})
expect(deletedItem).toBeUndefined()
})
describe("compensation", () => {
it("should restore line item if delete fails", async () => {
const workflow = deleteLineItemsWorkflow(appContainer)
workflow.appendAction("throw", deleteLineItemsStepId, {
invoke: async function failStep() {
throw new Error(`Failed to do something after deleting line items`)
},
})
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
quantity: 1,
unit_price: 3000,
title: "Test item",
},
],
})
const items = await cartModuleService.listLineItems({
cart_id: cart.id,
})
const { errors } = await workflow.run({
input: {
ids: items.map((i) => i.id),
},
throwOnError: false,
})
expect(errors).toEqual([
{
action: "throw",
handlerType: "invoke",
error: new Error(
`Failed to do something after deleting line items`
),
},
])
const updatedItem = await cartModuleService.retrieveLineItem(
items[0].id
)
expect(updatedItem).not.toBeUndefined()
})
})
})
})

View File

@@ -1,673 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
ICartModuleService,
ICustomerModuleService,
IPricingModuleService,
IProductModuleService,
IPromotionModuleService,
IRegionModuleService,
ISalesChannelModuleService,
} from "@medusajs/types"
import { PromotionRuleOperator, PromotionType } from "@medusajs/utils"
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 adminSeeder from "../../../../helpers/admin-seeder"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Store Carts API", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let regionModuleService: IRegionModuleService
let scModuleService: ISalesChannelModuleService
let customerModule: ICustomerModuleService
let productModule: IProductModuleService
let pricingModule: IPricingModuleService
let remoteLink
let promotionModule: IPromotionModuleService
let defaultRegion
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
regionModuleService = appContainer.resolve(ModuleRegistrationName.REGION)
scModuleService = appContainer.resolve(ModuleRegistrationName.SALES_CHANNEL)
customerModule = appContainer.resolve(ModuleRegistrationName.CUSTOMER)
productModule = appContainer.resolve(ModuleRegistrationName.PRODUCT)
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
remoteLink = appContainer.resolve("remoteLink")
promotionModule = appContainer.resolve(ModuleRegistrationName.PROMOTION)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
await regionModuleService.createDefaultCountries()
// Here, so we don't have to create a region for each test
defaultRegion = await regionModuleService.create({
name: "Default Region",
currency_code: "dkk",
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
describe("POST /store/carts", () => {
it("should create a cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
{
title: "Test variant 2",
},
],
},
])
const [priceSet, priceSetTwo] = await pricingModule.create([
{
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
},
{
prices: [
{
amount: 4000,
currency_code: "usd",
},
],
},
])
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
{
productService: {
variant_id: product.variants[1].id,
},
pricingService: {
price_set_id: priceSetTwo.id,
},
},
])
const api = useApi() as any
const created = await api.post(`/store/carts`, {
email: "tony@stark.com",
currency_code: "usd",
region_id: region.id,
sales_channel_id: salesChannel.id,
items: [
{
variant_id: product.variants[0].id,
quantity: 1,
},
{
variant_id: product.variants[1].id,
quantity: 2,
},
],
})
expect(created.status).toEqual(200)
expect(created.data.cart).toEqual(
expect.objectContaining({
id: created.data.cart.id,
currency_code: "usd",
email: "tony@stark.com",
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
sales_channel_id: salesChannel.id,
customer: expect.objectContaining({
email: "tony@stark.com",
}),
items: expect.arrayContaining([
expect.objectContaining({
quantity: 1,
unit_price: 3000,
}),
expect.objectContaining({
quantity: 2,
unit_price: 4000,
}),
]),
})
)
})
it("should create cart with customer from email", async () => {
const api = useApi() as any
const created = await api.post(`/store/carts`, {
currency_code: "usd",
email: "tony@stark-industries.com",
})
expect(created.status).toEqual(200)
expect(created.data.cart).toEqual(
expect.objectContaining({
id: created.data.cart.id,
currency_code: "usd",
email: "tony@stark-industries.com",
customer: expect.objectContaining({
id: expect.any(String),
email: "tony@stark-industries.com",
}),
})
)
})
it("should create cart with any region", async () => {
await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "tony@stark.com",
currency_code: "usd",
})
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "tony@stark.com",
region: expect.objectContaining({
id: expect.any(String),
}),
})
)
})
it("should create cart with region currency code", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "tony@stark.com",
region_id: region.id,
})
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "tony@stark.com",
region: expect.objectContaining({
id: region.id,
}),
})
)
})
it("should create cart with logged-in customer", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
const api = useApi() as any
const response = await api.post(
`/store/carts`,
{},
{
headers: { authorization: `Bearer ${jwt}` },
}
)
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "dkk",
email: customer.email,
customer: expect.objectContaining({
id: customer.id,
email: customer.email,
}),
})
)
})
it("should respond 400 bad request on unknown props", async () => {
const api = useApi() as any
await expect(
api.post(`/store/carts`, {
foo: "bar",
})
).rejects.toThrow()
})
})
describe("POST /store/carts/:id", () => {
it("should update a cart with promo codes with a replace action", async () => {
const targetRules = [
{
attribute: "product_id",
operator: PromotionRuleOperator.IN,
values: ["prod_tshirt"],
},
]
const appliedPromotion = await promotionModule.create({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "each",
value: "300",
apply_to_quantity: 1,
max_quantity: 1,
target_rules: targetRules,
},
})
const createdPromotion = await promotionModule.create({
code: "PROMOTION_TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "across",
value: "1000",
apply_to_quantity: 1,
target_rules: targetRules,
},
})
const cart = await cartModuleService.create({
currency_code: "usd",
email: "tony@stark.com",
items: [
{
id: "item-1",
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_tshirt",
} as any,
],
})
const [adjustment] = await cartModuleService.addLineItemAdjustments([
{
code: appliedPromotion.code!,
amount: 300,
item_id: "item-1",
promotion_id: appliedPromotion.id,
},
])
const api = useApi() as any
// Should remove earlier adjustments from other promocodes
let updated = await api.post(`/store/carts/${cart.id}`, {
promo_codes: [createdPromotion.code],
})
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
items: [
expect.objectContaining({
id: "item-1",
adjustments: [
expect.objectContaining({
id: expect.not.stringContaining(adjustment.id),
code: createdPromotion.code,
}),
],
}),
],
})
)
// Should remove all adjustments from other promo codes
updated = await api.post(`/store/carts/${cart.id}`, {
promo_codes: [],
})
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
items: [
expect.objectContaining({
id: "item-1",
adjustments: [],
}),
],
})
)
})
it("should update a cart's region, sales channel and customer data", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const cart = await cartModuleService.create({
currency_code: "eur",
})
const api = useApi() as any
let updated = await api.post(`/store/carts/${cart.id}`, {
region_id: region.id,
email: "tony@stark.com",
sales_channel_id: salesChannel.id,
})
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
email: "tony@stark.com",
customer: expect.objectContaining({
email: "tony@stark.com",
}),
sales_channel_id: salesChannel.id,
})
)
updated = await api.post(`/store/carts/${cart.id}`, {
email: null,
sales_channel_id: null,
})
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
email: null,
customer_id: null,
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
sales_channel_id: null,
})
)
})
})
describe("GET /store/carts/:id", () => {
it("should create and update a cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const api = useApi() as any
const created = await api.post(`/store/carts`, {
email: "tony@stark.com",
currency_code: "usd",
region_id: region.id,
sales_channel_id: salesChannel.id,
})
expect(created.status).toEqual(200)
expect(created.data.cart).toEqual(
expect.objectContaining({
id: created.data.cart.id,
currency_code: "usd",
email: "tony@stark.com",
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
sales_channel_id: salesChannel.id,
})
)
const updated = await api.post(`/store/carts/${created.data.cart.id}`, {
email: "tony@stark-industries.com",
})
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: updated.data.cart.id,
currency_code: "usd",
email: "tony@stark-industries.com",
})
)
})
})
describe("GET /store/carts", () => {
it("should get cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
unit_price: 1000,
quantity: 1,
title: "Test item",
},
],
region_id: region.id,
sales_channel_id: salesChannel.id,
})
const api = useApi() as any
const response = await api.get(`/store/carts/${cart.id}`)
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 1000,
quantity: 1,
title: "Test item",
}),
]),
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
sales_channel_id: salesChannel.id,
})
)
})
})
describe("POST /store/carts/:id/line-items", () => {
it("should add item to cart", async () => {
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
},
],
},
])
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
id: "item-1",
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_mat",
} as any,
],
})
const appliedPromotion = await promotionModule.create({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "across",
value: "300",
apply_to_quantity: 2,
target_rules: [
{
attribute: "product_id",
operator: "in",
values: ["prod_mat", product.id],
},
],
},
})
const [lineItemAdjustment] =
await cartModuleService.addLineItemAdjustments([
{
code: appliedPromotion.code!,
amount: 300,
item_id: "item-1",
promotion_id: appliedPromotion.id,
},
])
const priceSet = await pricingModule.create({
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
await remoteLink.create([
{
productService: {
variant_id: product.variants[0].id,
},
pricingService: {
price_set_id: priceSet.id,
},
},
])
const api = useApi() as any
const response = await api.post(`/store/carts/${cart.id}/line-items`, {
variant_id: product.variants[0].id,
quantity: 1,
})
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
items: expect.arrayContaining([
expect.objectContaining({
unit_price: 3000,
quantity: 1,
title: "Test variant",
adjustments: [
expect.objectContaining({
code: "PROMOTION_APPLIED",
amount: 180,
}),
],
}),
expect.objectContaining({
unit_price: 2000,
quantity: 1,
title: "Test item",
adjustments: [
expect.objectContaining({
id: expect.not.stringContaining(lineItemAdjustment.id),
code: "PROMOTION_APPLIED",
amount: 120,
}),
],
}),
]),
})
)
})
})
})

View File

@@ -1,300 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService, IPromotionModuleService } from "@medusajs/types"
import { PromotionType } from "@medusajs/utils"
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 adminSeeder from "../../../../helpers/admin-seeder"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Store Carts API: Remove promotions from cart", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
describe("DELETE /store/carts/:id/promotions", () => {
it("should remove line item adjustments from a cart based on promotions", async () => {
const appliedPromotion = await promotionModuleService.create({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "each",
value: "300",
apply_to_quantity: 1,
max_quantity: 1,
target_rules: [
{
attribute: "product_id",
operator: "eq",
values: "prod_tshirt",
},
],
},
})
const appliedPromotionToRemove = await promotionModuleService.create({
code: "PROMOTION_APPLIED_TO_REMOVE",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "items",
allocation: "each",
value: "300",
apply_to_quantity: 1,
max_quantity: 1,
target_rules: [
{
attribute: "product_id",
operator: "eq",
values: "prod_tshirt",
},
],
},
})
const cart = await cartModuleService.create({
currency_code: "usd",
items: [
{
id: "item-1",
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_mat",
} as any,
{
id: "item-2",
unit_price: 1000,
quantity: 1,
title: "Test item",
product_id: "prod_tshirt",
} as any,
],
})
const [adjustment1, adjustment2] =
await cartModuleService.addLineItemAdjustments([
{
code: appliedPromotion.code!,
amount: 300,
item_id: "item-2",
promotion_id: appliedPromotionToRemove.id,
},
{
code: appliedPromotionToRemove.code!,
amount: 150,
item_id: "item-1",
promotion_id: appliedPromotionToRemove.id,
},
{
code: appliedPromotionToRemove.code!,
amount: 150,
item_id: "item-2",
promotion_id: appliedPromotionToRemove.id,
},
])
const api = useApi() as any
const response = await api.delete(`/store/carts/${cart.id}/promotions`, {
data: {
promo_codes: [appliedPromotionToRemove.code],
},
})
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: expect.any(String),
items: expect.arrayContaining([
expect.objectContaining({
id: "item-1",
adjustments: [],
}),
expect.objectContaining({
id: "item-2",
adjustments: [
expect.objectContaining({
amount: 300,
code: appliedPromotion.code,
}),
],
}),
]),
})
)
})
it("should add shipping method adjustments to a cart based on promotions", async () => {
const appliedPromotion = await promotionModuleService.create({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_id",
operator: "in",
values: ["cus_test"],
},
{
attribute: "currency_code",
operator: "in",
values: ["eur"],
},
],
application_method: {
type: "fixed",
target_type: "shipping_methods",
allocation: "each",
value: "100",
max_quantity: 1,
target_rules: [
{
attribute: "name",
operator: "in",
values: ["express"],
},
],
},
})
const appliedPromotionToRemove = await promotionModuleService.create({
code: "PROMOTION_APPLIED_TO_REMOVE",
type: PromotionType.STANDARD,
rules: [
{
attribute: "customer_id",
operator: "in",
values: ["cus_test"],
},
{
attribute: "currency_code",
operator: "in",
values: ["eur"],
},
],
application_method: {
type: "fixed",
target_type: "shipping_methods",
allocation: "each",
value: "100",
max_quantity: 1,
target_rules: [
{
attribute: "name",
operator: "in",
values: ["express"],
},
],
},
})
const cart = await cartModuleService.create({
currency_code: "eur",
customer_id: "cus_test",
items: [
{
unit_price: 2000,
quantity: 1,
title: "Test item",
product_id: "prod_mat",
},
],
})
const [express, standard] = await cartModuleService.addShippingMethods(
cart.id,
[
{
amount: 500,
name: "express",
},
{
amount: 500,
name: "standard",
},
]
)
await cartModuleService.addShippingMethodAdjustments(cart.id, [
{
shipping_method_id: express.id,
amount: 100,
code: appliedPromotion.code!,
},
{
shipping_method_id: express.id,
amount: 100,
code: appliedPromotionToRemove.code!,
},
])
const api = useApi() as any
const response = await api.delete(`/store/carts/${cart.id}/promotions`, {
data: { promo_codes: [appliedPromotionToRemove.code] },
})
expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: expect.any(String),
items: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
}),
]),
shipping_methods: expect.arrayContaining([
expect.objectContaining({
id: express.id,
adjustments: [
expect.objectContaining({
amount: 100,
code: appliedPromotion.code,
}),
],
}),
expect.objectContaining({
id: standard.id,
adjustments: [],
}),
]),
})
)
})
})
})

View File

@@ -1,67 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICurrencyModuleService } from "@medusajs/types"
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 { DataSource } from "typeorm"
import { createAdminUser } from "../../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("Currency - Admin", () => {
let dbConnection: DataSource
let appContainer
let shutdownServer
let service: ICurrencyModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.CURRENCY)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly retrieve and list currencies", async () => {
const api = useApi() as any
const listResp = await api.get("/admin/currencies", adminHeaders)
expect(listResp.data.currencies).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "aud",
}),
expect.objectContaining({
code: "cad",
}),
])
)
const retrieveResp = await api.get(`/admin/currencies/aud`, adminHeaders)
expect(retrieveResp.data.currency).toEqual(
listResp.data.currencies.find((c) => c.code === "aud")
)
})
})

View File

@@ -1,62 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICurrencyModuleService } from "@medusajs/types"
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 { DataSource } from "typeorm"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const storeHeaders = {
headers: {},
}
describe("Currency - Store", () => {
let dbConnection: DataSource
let appContainer
let shutdownServer
let service: ICurrencyModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.CURRENCY)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly retrieve and list currencies", async () => {
const api = useApi() as any
const listResp = await api.get("/store/currencies", storeHeaders)
expect(listResp.data.currencies).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "aud",
}),
expect.objectContaining({
code: "cad",
}),
])
)
const retrieveResp = await api.get(`/store/currencies/aud`, storeHeaders)
expect(retrieveResp.data.currency).toEqual(
listResp.data.currencies.find((c) => c.code === "aud")
)
})
})

View File

@@ -1,89 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customer-groups/:id/customers/batch", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should batch add customers to a group", async () => {
const api = useApi() as any
const group = await customerModuleService.createCustomerGroup({
name: "VIP",
})
const customers = await customerModuleService.create([
{
first_name: "Test",
last_name: "Test",
},
{
first_name: "Test2",
last_name: "Test2",
},
{
first_name: "Test3",
last_name: "Test3",
},
])
const response = await api.post(
`/admin/customer-groups/${group.id}/customers/batch`,
{
customer_ids: customers.map((c) => ({ id: c.id })),
},
adminHeaders
)
expect(response.status).toEqual(200)
const updatedGroup = await customerModuleService.retrieveCustomerGroup(
group.id,
{
relations: ["customers"],
}
)
expect(updatedGroup.customers?.length).toEqual(3)
})
})

View File

@@ -1,93 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/customer-groups/:id/customers/remove", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should batch delete customers from a group", async () => {
const api = useApi() as any
const group = await customerModuleService.createCustomerGroup({
name: "VIP",
})
const customers = await customerModuleService.create([
{
first_name: "Test",
last_name: "Test",
},
{
first_name: "Test2",
last_name: "Test2",
},
{
first_name: "Test3",
last_name: "Test3",
},
])
await customerModuleService.addCustomerToGroup(
customers.map((c) => ({ customer_id: c.id, customer_group_id: group.id }))
)
const response = await api.post(
`/admin/customer-groups/${group.id}/customers/remove`,
{
customer_ids: customers.map((c) => ({ id: c.id })),
},
adminHeaders
)
expect(response.status).toEqual(200)
const updatedGroup = await customerModuleService.retrieveCustomerGroup(
group.id,
{
relations: ["customers"],
}
)
expect(updatedGroup.customers?.length).toEqual(0)
})
})

View File

@@ -1,70 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customer-groups", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
// await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a customer group", async () => {
const api = useApi() as any
const response = await api.post(
`/admin/customer-groups`,
{
name: "VIP",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.customer_group).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "VIP",
created_by: "admin_user",
})
)
})
})

View File

@@ -1,69 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/customer-groups/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete a group", async () => {
const group = await customerModuleService.createCustomerGroup({
name: "VIP",
})
const api = useApi() as any
const response = await api.delete(
`/admin/customer-groups/${group.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
const deletedCustomer = await customerModuleService.retrieveCustomerGroup(
group.id,
{ withDeleted: true }
)
expect(deletedCustomer.deleted_at).toBeTruthy()
})
})

View File

@@ -1,92 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/customer-groups/:id/customers", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all customer groups and its count", async () => {
const group = await customerModuleService.createCustomerGroup({
name: "Test",
})
const customers = await customerModuleService.create([
{
first_name: "Test",
last_name: "Test",
},
{
first_name: "Test2",
last_name: "Test2",
},
])
// add to group
await customerModuleService.addCustomerToGroup(
customers.map((c) => ({ customer_id: c.id, customer_group_id: group.id }))
)
const api = useApi() as any
const response = await api.get(
`/admin/customer-groups/${group.id}/customers`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: customers[0].id,
}),
expect.objectContaining({
id: customers[1].id,
}),
])
)
})
})

View File

@@ -1,67 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/customer-groups", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all customer groups and its count", async () => {
await customerModuleService.createCustomerGroup({
name: "Test",
})
const api = useApi() as any
const response = await api.get(`/admin/customer-groups`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.customer_groups).toEqual([
expect.objectContaining({
id: expect.any(String),
name: "Test",
}),
])
})
})

View File

@@ -1,69 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/customer-groups/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should retrieve customer group", async () => {
const group = await customerModuleService.createCustomerGroup({
name: "Test",
})
const api = useApi() as any
const response = await api.get(
`/admin/customer-groups/${group.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.customer_group).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "Test",
})
)
})
})

View File

@@ -1,72 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customer-groups/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a customer group", async () => {
const customer = await customerModuleService.createCustomerGroup({
name: "VIP",
})
const api = useApi() as any
const response = await api.post(
`/admin/customer-groups/${customer.id}`,
{
name: "regular",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.customer_group).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "regular",
})
)
})
})

View File

@@ -1,157 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customers/:id/addresses", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a customer address", async () => {
// Create a customer
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses`,
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.address).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
)
const customerWithAddresses = await customerModuleService.retrieve(
customer.id,
{ relations: ["addresses"] }
)
expect(customerWithAddresses.addresses?.length).toEqual(1)
})
it("sets new shipping address as default and unsets the old one", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
addresses: [
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
is_default_shipping: true,
},
],
})
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses`,
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 2",
is_default_shipping: true,
},
adminHeaders
)
expect(response.status).toEqual(200)
const [address] = await customerModuleService.listAddresses({
customer_id: customer.id,
is_default_shipping: true,
})
expect(address.address_1).toEqual("Test street 2")
})
it("sets new billing address as default and unsets the old one", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
addresses: [
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
is_default_billing: true,
},
],
})
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses`,
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 2",
is_default_billing: true,
},
adminHeaders
)
expect(response.status).toEqual(200)
const [address] = await customerModuleService.listAddresses({
customer_id: customer.id,
is_default_billing: true,
})
expect(address.address_1).toEqual("Test street 2")
})
})

View File

@@ -1,71 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customers", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a customer", async () => {
const api = useApi() as any
const response = await api.post(
`/admin/customers`,
{
first_name: "John",
last_name: "Doe",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.customer).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "John",
last_name: "Doe",
created_by: "admin_user",
})
)
})
})

View File

@@ -1,77 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/customers/:id/addresses/:address_id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a customer address", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const address = await customerModuleService.addAddresses({
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api.delete(
`/admin/customers/${customer.id}/addresses/${address.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
const updatedCustomer = await customerModuleService.retrieve(customer.id, {
relations: ["addresses"],
})
expect(updatedCustomer.addresses?.length).toEqual(0)
})
})

View File

@@ -1,69 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/customers/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete a customer", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const api = useApi() as any
const response = await api.delete(
`/admin/customers/${customer.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
const deletedCustomer = await customerModuleService.retrieve(customer.id, {
withDeleted: true,
})
expect(deletedCustomer.deleted_at).toBeTruthy()
})
})

View File

@@ -1,115 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/customers/:id/addresses", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all customer addresses and its count", async () => {
const [customer] = await customerModuleService.create([
{
first_name: "Test",
last_name: "Test",
email: "test@me.com",
addresses: [
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 1",
},
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 2",
},
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 3",
},
],
},
{
first_name: "Test Test",
last_name: "Test Test",
addresses: [
{
first_name: "Test TEST",
last_name: "Test TEST",
address_1: "NOT street 1",
},
],
},
])
const api = useApi() as any
const response = await api.get(
`/admin/customers/${customer.id}/addresses`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(3)
expect(response.data.addresses).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 1",
}),
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 2",
}),
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 3",
}),
])
)
})
})

View File

@@ -1,123 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/customers", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all customers and its count", async () => {
await customerModuleService.create([
{
first_name: "Test",
last_name: "Test",
email: "test@me.com",
},
])
const api = useApi() as any
const response = await api.get(`/admin/customers`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.customers).toEqual([
expect.objectContaining({
id: expect.any(String),
first_name: "Test",
last_name: "Test",
email: "test@me.com",
}),
])
})
it("should filter customers by last name", async () => {
await customerModuleService.create([
{
first_name: "Jane",
last_name: "Doe",
email: "jane@me.com",
},
{
first_name: "John",
last_name: "Doe",
email: "john@me.com",
},
{
first_name: "LeBron",
last_name: "James",
email: "lebron@me.com",
},
{
first_name: "John",
last_name: "Silver",
email: "johns@me.com",
},
])
const api = useApi() as any
const response = await api.get(
`/admin/customers?last_name=Doe`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.customers).toContainEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "Jane",
last_name: "Doe",
email: "jane@me.com",
})
)
expect(response.data.customers).toContainEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "John",
last_name: "Doe",
email: "john@me.com",
})
)
})
})

View File

@@ -1,166 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customers/:id/addresses/:address_id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a customer address", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const address = await customerModuleService.addAddresses({
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses/${address.id}`,
{
first_name: "Jane",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.address).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "Jane",
last_name: "Doe",
})
)
})
it("updates a new address to be default and unsets old one", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const [, address] = await customerModuleService.addAddresses([
{
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
is_default_shipping: true,
},
{
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 2",
},
])
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses/${address.id}`,
{
first_name: "jane",
is_default_shipping: true,
},
adminHeaders
)
expect(response.status).toEqual(200)
const [defaultAddress] = await customerModuleService.listAddresses({
customer_id: customer.id,
is_default_shipping: true,
})
expect(defaultAddress.first_name).toEqual("jane")
expect(defaultAddress.address_1).toEqual("Test street 2")
})
// do the same as above but for billing address
it("updates a new address to be default and unsets old one", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const [, address] = await customerModuleService.addAddresses([
{
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
is_default_billing: true,
},
{
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 2",
},
])
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}/addresses/${address.id}`,
{
first_name: "jane",
is_default_billing: true,
},
adminHeaders
)
expect(response.status).toEqual(200)
const [defaultAddress] = await customerModuleService.listAddresses({
customer_id: customer.id,
is_default_billing: true,
})
expect(defaultAddress.first_name).toEqual("jane")
expect(defaultAddress.address_1).toEqual("Test street 2")
})
})

View File

@@ -1,74 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/customers/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a customer", async () => {
const customer = await customerModuleService.create({
first_name: "John",
last_name: "Doe",
})
const api = useApi() as any
const response = await api.post(
`/admin/customers/${customer.id}`,
{
first_name: "Jane",
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.customer).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "Jane",
last_name: "Doe",
})
)
})
})

View File

@@ -1,74 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("POST /store/customers/me/addresses", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a customer address", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
const api = useApi() as any
const response = await api.post(
`/store/customers/me/addresses`,
{
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
},
{ headers: { authorization: `Bearer ${jwt}` } }
)
expect(response.status).toEqual(200)
expect(response.data.address).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
customer_id: customer.id,
})
)
const customerWithAddresses = await customerModuleService.retrieve(
customer.id,
{ relations: ["addresses"] }
)
expect(customerWithAddresses.addresses?.length).toEqual(1)
})
})

View File

@@ -1,82 +0,0 @@
import { IAuthModuleService, ICustomerModuleService } from "@medusajs/types"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAdminUser } from "../../../helpers/create-admin-user"
import { getContainer } from "../../../../environment-helpers/use-container"
import jwt from "jsonwebtoken"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("POST /store/customers", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create a customer", async () => {
const authService: IAuthModuleService = appContainer.resolve(
ModuleRegistrationName.AUTH
)
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const authUser = await authService.create({
entity_id: "store_user",
provider: "emailpass",
scope: "store",
})
const token = jwt.sign(authUser, jwt_secret)
const api = useApi() as any
const response = await api.post(
`/store/customers`,
{
first_name: "John",
last_name: "Doe",
email: "john@me.com",
},
{ headers: { authorization: `Bearer ${token}` } }
)
expect(response.status).toEqual(200)
expect(response.data.customer).toEqual(
expect.objectContaining({
id: expect.any(String),
first_name: "John",
last_name: "Doe",
email: "john@me.com",
})
)
})
})

View File

@@ -1,90 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
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"
const env = { MEDUSA_FF_MEDUSA_V2: true }
jest.setTimeout(50000)
describe("DELETE /store/customers/me/addresses/:address_id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete a customer address", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
const address = await customerModuleService.addAddresses({
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api.delete(
`/store/customers/me/addresses/${address.id}`,
{ headers: { authorization: `Bearer ${jwt}` } }
)
expect(response.status).toEqual(200)
const updatedCustomer = await customerModuleService.retrieve(customer.id, {
relations: ["addresses"],
})
expect(updatedCustomer.addresses?.length).toEqual(0)
})
it("should fail to delete another customer's address", async () => {
const { jwt } = await createAuthenticatedCustomer(appContainer)
const otherCustomer = await customerModuleService.create({
first_name: "Jane",
last_name: "Doe",
})
const address = await customerModuleService.addAddresses({
customer_id: otherCustomer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api
.delete(`/store/customers/me/addresses/${address.id}`, {
headers: { authorization: `Bearer ${jwt}` },
})
.catch((e) => e.response)
expect(response.status).toEqual(404)
})
})

View File

@@ -1,60 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("GET /store/customers", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should retrieve auth user's customer", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
const api = useApi() as any
const response = await api.get(`/store/customers/me`, {
headers: { authorization: `Bearer ${jwt}` },
})
expect(response.status).toEqual(200)
expect(response.data.customer).toEqual(
expect.objectContaining({
id: customer.id,
first_name: "John",
last_name: "Doe",
email: "john@me.com",
})
)
})
})

View File

@@ -1,109 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
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"
const env = { MEDUSA_FF_MEDUSA_V2: true }
jest.setTimeout(100000)
describe("GET /store/customers/me/addresses", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
try {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
} catch (error) {
console.error(error)
}
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all customer addresses and its count", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
await customerModuleService.addAddresses([
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 1",
customer_id: customer.id,
},
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 2",
customer_id: customer.id,
},
{
first_name: "Test",
last_name: "Test",
address_1: "Test street 3",
customer_id: customer.id,
},
])
await customerModuleService.create({
first_name: "Test Test",
last_name: "Test Test",
addresses: [
{
first_name: "Test TEST",
last_name: "Test TEST",
address_1: "NOT street 1",
},
],
})
const api = useApi() as any
const response = await api.get(`/store/customers/me/addresses`, {
headers: { authorization: `Bearer ${jwt}` },
})
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(3)
expect(response.data.addresses).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 1",
}),
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 2",
}),
expect.objectContaining({
id: expect.any(String),
customer_id: customer.id,
address_1: "Test street 3",
}),
])
)
})
})

View File

@@ -1,97 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICustomerModuleService } from "@medusajs/types"
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 { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("POST /store/customers/:id/addresses/:address_id", () => {
let dbConnection
let appContainer
let shutdownServer
let customerModuleService: ICustomerModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
customerModuleService = appContainer.resolve(
ModuleRegistrationName.CUSTOMER
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a customer address", async () => {
const { customer, jwt } = await createAuthenticatedCustomer(appContainer)
const address = await customerModuleService.addAddresses({
customer_id: customer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api.post(
`/store/customers/me/addresses/${address.id}`,
{
first_name: "Jane",
},
{ headers: { authorization: `Bearer ${jwt}` } }
)
expect(response.status).toEqual(200)
expect(response.data.address).toEqual(
expect.objectContaining({
id: address.id,
first_name: "Jane",
last_name: "Doe",
})
)
})
it("should fail to update another customer's address", async () => {
const { jwt } = await createAuthenticatedCustomer(appContainer)
const otherCustomer = await customerModuleService.create({
first_name: "Jane",
last_name: "Doe",
})
const address = await customerModuleService.addAddresses({
customer_id: otherCustomer.id,
first_name: "John",
last_name: "Doe",
address_1: "Test street 1",
})
const api = useApi() as any
const response = await api
.post(
`/store/customers/me/addresses/${address.id}`,
{ first_name: "Jane" },
{ headers: { authorization: `Bearer ${jwt}` } }
)
.catch((e) => e.response)
expect(response.status).toEqual(404)
})
})

View File

@@ -1,112 +0,0 @@
import { IAuthModuleService, IUserModuleService } from "@medusajs/types"
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/invites/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should fail to accept an invite with an invalid invite token", async () => {
const api = useApi()! as AxiosInstance
const authResponse = await api.post(`/auth/admin/emailpass`, {
email: "potential_member@test.com",
password: "supersecret",
})
expect(authResponse.status).toEqual(200)
const token = authResponse.data.token
const acceptResponse = await api
.post(
`/admin/invites/accept?token=${"non-existing-token"}`,
{
first_name: "John",
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.catch((e) => e)
expect(acceptResponse.response.status).toEqual(401)
expect(acceptResponse.response.data.message).toEqual("Unauthorized")
})
it("should accept an invite", async () => {
const invite = await userModuleService.createInvites({
email: "potential_member@test.com",
})
const api = useApi()! as AxiosInstance
const authResponse = await api.post(`/auth/admin/emailpass`, {
email: "potential_member@test.com",
password: "supersecret",
})
expect(authResponse.status).toEqual(200)
const token = authResponse.data.token
const acceptResponse = await api.post(
`/admin/invites/accept?token=${invite.token}`,
{
first_name: "John",
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
expect(acceptResponse.status).toEqual(200)
expect(acceptResponse.data.user).toEqual(
expect.objectContaining({
email: "potential_member@test.com",
first_name: "John",
})
)
})
})

View File

@@ -1,56 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../environment-helpers/use-api"
import adminSeeder from "../../../helpers/admin-seeder"
import { AxiosInstance } from "axios"
import { createAdminUser } from "../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/invites", () => {
let dbConnection
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("create an invite", async () => {
const api = useApi()! as AxiosInstance
const body = {
email: "test_member@test.com",
}
const response = await api.post(`/admin/invites`, body, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
invite: expect.objectContaining(body),
})
})
})

View File

@@ -1,77 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
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 adminSeeder from "../../../helpers/admin-seeder"
import { AxiosInstance } from "axios"
import { createAdminUser } from "../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/invites/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete a single invite", async () => {
const invite = await userModuleService.createInvites({
email: "potential_member@test.com",
token: "test",
expires_at: new Date(),
})
const api = useApi()! as AxiosInstance
const response = await api.delete(
`/admin/invites/${invite.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
id: invite.id,
object: "invite",
deleted: true,
})
const { response: deletedResponse } = await api
.get(`/admin/invites/${invite.id}`, adminHeaders)
.catch((e) => e)
expect(deletedResponse.status).toEqual(404)
expect(deletedResponse.data.type).toEqual("not_found")
})
})

View File

@@ -1,70 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
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 adminSeeder from "../../../helpers/admin-seeder"
import { AxiosInstance } from "axios"
import { createAdminUser } from "../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/invites", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should list invites", async () => {
await userModuleService.createInvites({
email: "potential_member@test.com",
token: "test",
expires_at: new Date(),
})
const api = useApi()! as AxiosInstance
const response = await api.get(`/admin/invites`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
invites: [
expect.objectContaining({ email: "potential_member@test.com" }),
],
count: 1,
offset: 0,
limit: 50,
})
})
})

View File

@@ -1,67 +0,0 @@
import { IAuthModuleService, IUserModuleService } from "@medusajs/types"
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/invites/:id/resend", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should resend a single invite", async () => {
const invite = await userModuleService.createInvites({
email: "potential_member@test.com",
})
const api = useApi()! as AxiosInstance
const response = await api.post(
`/admin/invites/${invite.id}/resend`,
{},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.invite.token).not.toEqual(invite.token)
expect(response.data.invite).toEqual(
expect.objectContaining({ email: "potential_member@test.com" })
)
})
})

View File

@@ -1,62 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { IAuthModuleService, IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
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 { AxiosInstance } from "axios"
import { createAdminUser } from "../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/invites/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should retrieve a single invite", async () => {
const invite = await userModuleService.createInvites({
email: "potential_member@test.com",
})
const api = useApi()! as AxiosInstance
const response = await api.get(`/admin/invites/${invite.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.invite).toEqual(
expect.objectContaining({ email: "potential_member@test.com" })
)
})
})

View File

@@ -1,164 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
ICartModuleService,
ICustomerModuleService,
IRegionModuleService,
ISalesChannelModuleService,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { getContainer } from "../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../environment-helpers/use-db"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Cart links", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let regionModule: IRegionModuleService
let customerModule: ICustomerModuleService
let scModuleService: ISalesChannelModuleService
let remoteQuery
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
regionModule = appContainer.resolve(ModuleRegistrationName.REGION)
customerModule = appContainer.resolve(ModuleRegistrationName.CUSTOMER)
scModuleService = appContainer.resolve(ModuleRegistrationName.SALES_CHANNEL)
regionModule = appContainer.resolve(ModuleRegistrationName.REGION)
remoteQuery = appContainer.resolve("remoteQuery")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
// @ts-ignore
await regionModule.createDefaultCountries()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should query carts, sales channels, customers, regions with remote query", async () => {
const region = await regionModule.create({
name: "Region",
currency_code: "usd",
})
const customer = await customerModule.create({
email: "tony@stark.com",
})
const salesChannel = await scModuleService.create({
name: "Webshop",
})
const cart = await cartModuleService.create({
email: "tony@stark.com",
currency_code: "usd",
region_id: region.id,
sales_channel_id: salesChannel.id,
customer_id: customer.id,
})
const carts = await remoteQuery({
cart: {
fields: ["id"],
region: {
fields: ["id"],
},
customer: {
fields: ["id"],
},
sales_channel: {
fields: ["id"],
},
},
})
const salesChannels = await remoteQuery({
sales_channel: {
fields: ["id"],
carts: {
fields: ["id"],
},
},
})
const customers = await remoteQuery({
customer: {
fields: ["id"],
carts: {
fields: ["id"],
},
},
})
const regions = await remoteQuery({
region: {
fields: ["id"],
carts: {
fields: ["id"],
},
},
})
expect(carts).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: cart.id,
customer: expect.objectContaining({ id: customer.id }),
sales_channel: expect.objectContaining({ id: salesChannel.id }),
region: expect.objectContaining({ id: region.id }),
}),
])
)
expect(salesChannels).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: salesChannel.id,
carts: expect.arrayContaining([
expect.objectContaining({ id: cart.id }),
]),
}),
])
)
expect(customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: customer.id,
carts: expect.arrayContaining([
expect.objectContaining({ id: cart.id }),
]),
}),
])
)
expect(regions).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: region.id,
carts: expect.arrayContaining([
expect.objectContaining({ id: cart.id }),
]),
}),
])
)
})
})

View File

@@ -1,96 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService, IRegionModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { getContainer } from "../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../environment-helpers/use-db"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
describe("Link: Cart Region", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService
let regionModule: IRegionModuleService
let remoteQuery
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
regionModule = appContainer.resolve(ModuleRegistrationName.REGION)
remoteQuery = appContainer.resolve("remoteQuery")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
// @ts-ignore
await regionModule.createDefaultCountries()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should query carts and regions with remote query", async () => {
const region = await regionModule.create({
name: "Region",
currency_code: "usd",
})
const cart = await cartModuleService.create({
email: "tony@stark.com",
currency_code: "usd",
region_id: region.id,
})
const carts = await remoteQuery({
cart: {
fields: ["id"],
region: {
fields: ["id"],
},
},
})
const regions = await remoteQuery({
region: {
fields: ["id"],
carts: {
fields: ["id"],
},
},
})
expect(carts).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: cart.id,
region: expect.objectContaining({ id: region.id }),
}),
])
)
expect(regions).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: region.id,
carts: expect.arrayContaining([
expect.objectContaining({ id: cart.id }),
]),
}),
])
)
})
})

View File

@@ -1,188 +0,0 @@
import { initialize, runMigrations } from "@medusajs/link-modules"
import { MedusaModule, ModuleJoinerConfig } from "@medusajs/modules-sdk"
jest.setTimeout(5000000)
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}`
describe("Link Modules", () => {
let links
const linkDefinition: ModuleJoinerConfig[] = [
{
serviceName: "linkServiceName",
isLink: true,
databaseConfig: {
tableName: "linkTableName",
idPrefix: "prefix",
extraFields: {
extra_field: {
type: "integer",
defaultValue: "-1",
},
another_field: {
type: "string",
nullable: true,
},
},
},
relationships: [
{
serviceName: "moduleA",
primaryKey: "id",
foreignKey: "product_id",
alias: "product",
},
{
serviceName: "moduleB",
primaryKey: "id",
foreignKey: "inventory_item_id",
alias: "inventory",
},
],
},
]
const dbConfig = {
database: {
clientUrl: DB_URL,
},
}
beforeAll(async () => {
jest.spyOn(MedusaModule, "getLoadedModules").mockImplementation((() => {
return [{ moduleA: [{}] }, { moduleB: [{}] }]
}) as any)
await runMigrations({ options: dbConfig }, linkDefinition)
links = await initialize(dbConfig, linkDefinition)
})
afterAll(async () => {
jest.clearAllMocks()
})
it("Should insert values in a declared link", async function () {
// simple
await links.linkServiceName.create("modA_id", "modB_id")
// extra fields
await links.linkServiceName.create("123", "abc", {
extra_field: 333,
another_field: "value**",
})
// bulk
await links.linkServiceName.create([
["111", "aaa", { another_field: "test" }],
["222", "bbb"],
["333", "ccc", { extra_field: 2 }],
["444", "bbb"],
])
const values = await links.linkServiceName.list()
expect(values).toEqual([
{
product_id: "modA_id",
inventory_item_id: "modB_id",
id: expect.stringMatching("prefix_.+"),
extra_field: -1,
another_field: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
},
expect.objectContaining({
product_id: "123",
inventory_item_id: "abc",
id: expect.stringMatching("prefix_.+"),
extra_field: 333,
another_field: "value**",
}),
expect.objectContaining({
product_id: "111",
inventory_item_id: "aaa",
extra_field: -1,
another_field: "test",
}),
expect.objectContaining({
product_id: "222",
inventory_item_id: "bbb",
extra_field: -1,
another_field: null,
}),
expect.objectContaining({
product_id: "333",
inventory_item_id: "ccc",
id: expect.stringMatching("prefix_.+"),
extra_field: 2,
}),
expect.objectContaining({
product_id: "444",
inventory_item_id: "bbb",
}),
])
})
it("Should dismiss the link of a given pair of keys", async function () {
// simple
const dismissSingle = await links.linkServiceName.dismiss(
"modA_id",
"modB_id"
)
// bulk
const dismissMulti = await links.linkServiceName.dismiss([
["111", "aaa"],
["333", "ccc"],
])
expect(dismissSingle).toEqual([
expect.objectContaining({
product_id: "modA_id",
inventory_item_id: "modB_id",
deleted_at: expect.any(Date),
}),
])
expect(dismissMulti).toEqual([
expect.objectContaining({
product_id: "111",
inventory_item_id: "aaa",
deleted_at: expect.any(Date),
}),
expect.objectContaining({
product_id: "333",
inventory_item_id: "ccc",
deleted_at: expect.any(Date),
}),
])
})
it("Should delete all the links related to a given key", async function () {
await links.linkServiceName.softDelete({
inventory_item_id: "bbb",
})
const values = await links.linkServiceName.list(
{ inventory_item_id: "bbb" },
{ withDeleted: true }
)
expect(values).toEqual([
expect.objectContaining({
product_id: "222",
inventory_item_id: "bbb",
deleted_at: expect.any(Date),
}),
expect.objectContaining({
product_id: "444",
inventory_item_id: "bbb",
deleted_at: expect.any(Date),
}),
])
})
})

View File

@@ -1,29 +0,0 @@
import dbFactory from "./../../../environment-helpers/use-template-db"
jest.setTimeout(30000)
describe("Standalone Modules", () => {
beforeAll(async () => {
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
process.env.POSTGRES_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`
await dbFactory.createFromTemplate(DB_NAME)
})
afterAll(async () => {
process.env.POSTGRES_URL = undefined
})
it("Should migrate database and initialize Product module using connection string from environment variable ", async function () {
const { initialize, runMigrations } = require("@medusajs/product")
await runMigrations()
const product = await initialize()
const productList = await product.list()
expect(productList).toEqual(expect.arrayContaining([]))
})
})

View File

@@ -1,233 +0,0 @@
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 {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/price-lists/:id/prices/batch", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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 update money amounts if variant id is present in prices", async () => {
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date().toISOString(),
starts_at: new Date().toISOString(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
},
])
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
prices: [
{
variant_id: variant.id,
amount: 5000,
currency_code: "usd",
},
{
amount: 6000,
region_id: "test-region",
variant_id: variant.id,
},
],
}
await api.post(
`admin/price-lists/${priceList.id}/prices/batch`,
data,
adminHeaders
)
const response = await api.get(
`/admin/price-lists/${priceList.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.price_list).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "test price list",
description: "test",
type: "override",
status: "active",
starts_at: expect.any(String),
ends_at: expect.any(String),
customer_groups: [],
prices: [
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 5000,
min_quantity: null,
max_quantity: null,
price_list_id: expect.any(String),
region_id: null,
variant: expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
title: expect.any(String),
product_id: expect.any(String),
sku: null,
barcode: null,
ean: null,
upc: null,
variant_rank: 0,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
hs_code: null,
origin_country: null,
mid_code: null,
material: null,
weight: null,
length: null,
height: null,
width: null,
metadata: null,
}),
variant_id: expect.any(String),
}),
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 6000,
min_quantity: null,
max_quantity: null,
price_list_id: expect.any(String),
region_id: "test-region",
variant: expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
title: expect.any(String),
product_id: expect.any(String),
sku: null,
barcode: null,
ean: null,
upc: null,
variant_rank: 0,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
hs_code: null,
origin_country: null,
mid_code: null,
material: null,
weight: null,
length: null,
height: null,
width: null,
metadata: null,
}),
variant_id: expect.any(String),
}),
],
})
)
})
})

View File

@@ -1,191 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleCustomerGroupFactory,
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
import { IPricingModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/price-lists", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
await simpleCustomerGroupFactory(dbConnection, {
id: "customer-group-1",
name: "Test Group",
})
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 price list and money amounts", async () => {
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
name: "test price list",
description: "test",
type: "override",
customer_groups: [{ id: "customer-group-1" }],
status: "active",
starts_at: new Date(),
prices: [
{
amount: 400,
variant_id: variant.id,
currency_code: "usd",
},
],
}
const result = await api.post(`admin/price-lists`, data, adminHeaders)
let response = await api.get(
`/admin/price-lists/${result.data.price_list.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.price_list).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "test price list",
description: "test",
type: "override",
status: "active",
starts_at: expect.any(String),
ends_at: null,
customer_groups: [
{
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "Test Group",
metadata: null,
},
],
prices: [
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 400,
min_quantity: null,
max_quantity: null,
price_list_id: expect.any(String),
region_id: null,
variant: expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
title: expect.any(String),
product_id: expect.any(String),
sku: null,
barcode: null,
ean: null,
upc: null,
variant_rank: 0,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
hs_code: null,
origin_country: null,
mid_code: null,
material: null,
weight: null,
length: null,
height: null,
width: null,
metadata: null,
}),
variant_id: expect.any(String),
}),
],
})
)
})
})

View File

@@ -1,180 +0,0 @@
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 { IPricingModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
import { AxiosInstance } from "axios"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("DELETE /admin/price-lists/:id/products/:productId/batch", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant1
let priceSet
let priceListId
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
const api = useApi()! as AxiosInstance
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",
},
],
})
variant1 = product.variants[0]
priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant1.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const data = {
name: "test price list",
description: "test",
type: "override",
customer_groups: [],
status: "active",
prices: [
{
amount: 400,
variant_id: variant1.id,
currency_code: "usd",
},
],
}
const priceListResult = await api.post(
`admin/price-lists`,
data,
adminHeaders
)
priceListId = priceListResult.data.price_list.id
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete prices in batch based on product ids", async () => {
const api = useApi()! as AxiosInstance
let priceSetMoneyAmounts =
await pricingModuleService.listPriceSetMoneyAmounts({
price_set_id: [priceSet.id],
})
expect(priceSetMoneyAmounts.length).toEqual(2)
const deleteRes = await api.delete(
`/admin/price-lists/${priceListId}/products/prices/batch`,
{
headers: adminHeaders.headers,
data: {
product_ids: [product.id],
},
}
)
expect(deleteRes.status).toEqual(200)
priceSetMoneyAmounts = await pricingModuleService.listPriceSetMoneyAmounts({
price_set_id: [priceSet.id],
})
expect(priceSetMoneyAmounts.length).toEqual(1)
expect(priceSetMoneyAmounts).toEqual([
expect.objectContaining({
price_list: null,
}),
])
})
it("should delete prices based on single product id", async () => {
const api = useApi()! as AxiosInstance
let priceSetMoneyAmounts =
await pricingModuleService.listPriceSetMoneyAmounts({
price_set_id: [priceSet.id],
})
expect(priceSetMoneyAmounts.length).toEqual(2)
const deleteRes = await api.delete(
`/admin/price-lists/${priceListId}/products/${product.id}/prices`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
priceSetMoneyAmounts = await pricingModuleService.listPriceSetMoneyAmounts({
price_set_id: [priceSet.id],
})
expect(priceSetMoneyAmounts.length).toEqual(1)
expect(priceSetMoneyAmounts).toEqual([
expect.objectContaining({
price_list: null,
}),
])
})
})

View File

@@ -1,131 +0,0 @@
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 { IPricingModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("DELETE /admin/price-lists/:id/variants/:variantId/prices", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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 delete all prices based on product variant ids", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
name: "test price list",
description: "test",
type: "override",
customer_groups: [],
status: "active",
prices: [
{
amount: 400,
variant_id: variant.id,
currency_code: "usd",
},
],
}
const result = await api.post(`admin/price-lists`, data, adminHeaders)
const priceListId = result.data.price_list.id
let psmas = await pricingModuleService.listPriceSetMoneyAmounts({
price_list_id: [priceListId],
})
expect(psmas.length).toEqual(1)
const deleteRes = await api.delete(
`/admin/price-lists/${priceListId}/variants/${variant.id}/prices`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
psmas = await pricingModuleService.listPriceSetMoneyAmounts({
price_list_id: [priceListId],
})
expect(psmas.length).toEqual(0)
})
})

View File

@@ -1,145 +0,0 @@
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 { IPricingModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("DELETE /admin/price-lists/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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 delete price list prices by money amount ids", async () => {
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
name: "test price list",
description: "test",
type: "override",
status: "active",
prices: [
{
amount: 400,
variant_id: variant.id,
currency_code: "usd",
},
{
amount: 4000,
variant_id: variant.id,
currency_code: "usd",
},
],
}
const res = await api.post(`admin/price-lists`, data, adminHeaders)
const priceListId = res.data.price_list.id
let psmas = await pricingModuleService.listPriceSetMoneyAmounts(
{
price_list_id: [priceListId],
},
{ relations: ["money_amount"] }
)
expect(psmas.length).toEqual(2)
const deletePrice = psmas[0].money_amount
const deleteRes = await api.delete(
`/admin/price-lists/${priceListId}/prices/batch`,
{
data: {
price_ids: [deletePrice?.id],
},
...adminHeaders,
}
)
expect(deleteRes.status).toEqual(200)
psmas = await pricingModuleService.listPriceSetMoneyAmounts({
price_list_id: [priceListId],
})
expect(psmas.length).toEqual(1)
})
})

View File

@@ -1,144 +0,0 @@
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 { IPricingModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("DELETE /admin/price-lists/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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 delete price list and money amounts", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
name: "test price list",
description: "test",
type: "override",
customer_groups: [],
status: "active",
prices: [
{
amount: 400,
variant_id: variant.id,
currency_code: "usd",
},
],
}
const result = await api.post(`admin/price-lists`, data, adminHeaders)
const priceListId = result.data.price_list.id
const getResponse = await api.get(
`/admin/price-lists/${priceListId}`,
adminHeaders
)
expect(getResponse.status).toEqual(200)
let psmas = await pricingModuleService.listPriceSetMoneyAmounts({
price_list_id: [priceListId],
})
expect(psmas.length).toEqual(1)
const deleteRes = await api.delete(
`/admin/price-lists/${priceListId}`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
const afterDelete = await api
.get(`/admin/price-lists/${priceListId}`, adminHeaders)
.catch((err) => {
return err
})
expect(afterDelete.response.status).toEqual(404)
psmas = await pricingModuleService.listPriceSetMoneyAmounts({
price_list_id: [priceListId],
})
expect(psmas.length).toEqual(0)
})
})

View File

@@ -1,203 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { simpleProductFactory } from "../../../../factories"
import {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("GET /admin/price-lists/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
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 get price list and its money amounts with variants", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
rules: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 5000,
currency_code: "usd",
price_set_id: priceSet.id,
},
],
},
])
await pricingModuleService.createPriceLists([
{
title: "test price list 1",
description: "test 1",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 5000,
currency_code: "usd",
price_set_id: priceSet.id,
},
],
},
])
const api = useApi() as any
const response = await api.get(
`/admin/price-lists/${priceList.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.price_list).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "test price list",
description: "test",
type: "override",
status: "active",
starts_at: expect.any(String),
ends_at: expect.any(String),
customer_groups: [],
prices: [
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 5000,
min_quantity: null,
max_quantity: null,
price_list_id: expect.any(String),
region_id: null,
variant: expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
title: expect.any(String),
product_id: expect.any(String),
sku: null,
barcode: null,
ean: null,
upc: null,
variant_rank: 0,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
hs_code: null,
origin_country: null,
mid_code: null,
material: null,
weight: null,
length: null,
height: null,
width: null,
metadata: null,
}),
variant_id: expect.any(String),
}),
],
})
)
})
it("should throw an error when price list is not found", async () => {
const api = useApi() as any
const error = await api
.get(`/admin/price-lists/does-not-exist`, adminHeaders)
.catch((e) => e)
expect(error.response.status).toBe(404)
expect(error.response.data).toEqual({
type: "not_found",
message: "Price list with id: does-not-exist was not found",
})
})
})

View File

@@ -1,272 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { simpleProductFactory } from "../../../../factories"
import {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("GET /admin/price-lists/:id/products", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let product2
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
product = await simpleProductFactory(dbConnection, {
id: "test-product-with-variant",
title: "uniquely fun product",
variants: [
{
options: [{ option_id: "test-product-option-1", value: "test" }],
},
],
options: [
{
id: "test-product-option-1",
title: "Test option 1",
},
],
})
variant = product.variants[0]
product2 = await simpleProductFactory(dbConnection, {
id: "test-product-with-variant-2",
title: "uniquely fun product 2",
variants: [
{
options: [{ option_id: "test-product-option-2", value: "test 2" }],
},
],
options: [
{
id: "test-product-option-2",
title: "Test option 2",
},
],
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should list all products in a price list", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
rules: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 5000,
currency_code: "usd",
price_set_id: priceSet.id,
},
],
},
])
const api = useApi() as any
let response = await api.get(
`/admin/price-lists/${priceList.id}/products`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.products).toEqual([
expect.objectContaining({
id: expect.any(String),
title: expect.any(String),
handle: expect.any(String),
subtitle: null,
description: null,
is_giftcard: false,
status: "draft",
thumbnail: null,
weight: null,
length: null,
height: null,
width: null,
origin_country: null,
hs_code: null,
mid_code: null,
material: null,
collection_id: null,
collection: null,
type_id: null,
type: null,
discountable: true,
external_id: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
metadata: null,
}),
])
response = await api.get(
`/admin/products?price_list_id[]=${priceList.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.products).toEqual([
expect.objectContaining({
id: expect.any(String),
title: expect.any(String),
handle: expect.any(String),
subtitle: null,
description: null,
is_giftcard: false,
status: "draft",
thumbnail: null,
weight: null,
length: null,
height: null,
width: null,
origin_country: null,
hs_code: null,
mid_code: null,
material: null,
collection_id: null,
collection: null,
type_id: null,
type: null,
discountable: true,
external_id: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
metadata: null,
}),
])
})
it("should list all products constrained by search query in a price list", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
rules: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 5000,
currency_code: "usd",
price_set_id: priceSet.id,
},
],
},
])
const api = useApi() as any
let response = await api.get(
`/admin/price-lists/${priceList.id}/products?q=shouldnotreturnanything`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(0)
expect(response.data.products).toEqual([])
response = await api.get(
`/admin/price-lists/${priceList.id}/products?q=uniquely`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.products).toEqual([
expect.objectContaining({
id: expect.any(String),
}),
])
response = await api.get(
`/admin/price-lists/${priceList.id}/products?q=`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.products).toEqual([
expect.objectContaining({
id: expect.any(String),
}),
])
})
})

View File

@@ -1,169 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { simpleProductFactory } from "../../../../factories"
import {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("GET /admin/price-lists", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
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 get price list and its money amounts with variants", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
rules: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 5000,
currency_code: "usd",
price_set_id: priceSet.id,
},
],
},
])
const api = useApi() as any
const response = await api.get(`/admin/price-lists`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.price_lists).toEqual([
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "test price list",
description: "test",
type: "override",
status: "active",
starts_at: expect.any(String),
ends_at: expect.any(String),
customer_groups: [],
prices: [
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 5000,
min_quantity: null,
max_quantity: null,
price_list_id: expect.any(String),
region_id: null,
variant: expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
title: expect.any(String),
product_id: expect.any(String),
sku: null,
barcode: null,
ean: null,
upc: null,
variant_rank: 0,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
hs_code: null,
origin_country: null,
mid_code: null,
material: null,
weight: null,
length: null,
height: null,
width: null,
metadata: null,
}),
variant_id: expect.any(String),
}),
],
}),
])
})
})

View File

@@ -1,280 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleCustomerGroupFactory,
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
import {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/price-lists/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let variant2
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
await simpleCustomerGroupFactory(dbConnection, {
id: "customer-group-2",
name: "Test Group 2",
})
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: [{ option_id: "test-product-option-2", value: "test 2" }],
},
],
options: [
{
id: "test-product-option-1",
title: "Test option 1",
},
{
id: "test-product-option-2",
title: "Test option 2",
},
],
})
variant = product.variants[0]
variant2 = product.variants[1]
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update price lists successfully with prices", async () => {
const var2PriceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant2.id,
prices: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
ends_at: new Date(),
starts_at: new Date(),
status: PriceListStatus.ACTIVE,
type: PriceListType.OVERRIDE,
prices: [
{
amount: 3000,
currency_code: "usd",
price_set_id: var2PriceSet.id,
},
],
},
])
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const api = useApi() as any
const data = {
name: "new price list name",
description: "new price list description",
customer_groups: [{ id: "customer-group-2" }],
prices: [
{
variant_id: variant.id,
amount: 5000,
currency_code: "usd",
},
{
id: priceList?.price_set_money_amounts?.[0].money_amount?.id,
amount: 6000,
currency_code: "usd",
variant_id: variant2.id,
},
],
}
await api.post(`admin/price-lists/${priceList.id}`, data, adminHeaders)
const response = await api.get(
`/admin/price-lists/${priceList.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.price_list).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "new price list name",
description: "new price list description",
type: "override",
status: "active",
starts_at: expect.any(String),
ends_at: expect.any(String),
customer_groups: [
{
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "Test Group 2",
metadata: null,
},
],
prices: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 5000,
min_quantity: null,
max_quantity: null,
price_list_id: priceList.id,
region_id: null,
variant: expect.objectContaining({
id: variant.id,
}),
variant_id: variant.id,
}),
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
currency_code: "usd",
amount: 6000,
min_quantity: null,
max_quantity: null,
price_list_id: priceList.id,
region_id: null,
variant: expect.objectContaining({
id: variant2.id,
}),
variant_id: variant2.id,
}),
]),
})
)
})
it("should not delete customer groups if customer_groups is not passed as a param", async () => {
await createVariantPriceSet({
container: appContainer,
variantId: variant2.id,
prices: [],
})
const [priceList] = await pricingModuleService.createPriceLists([
{
title: "test price list",
description: "test",
status: PriceListStatus.DRAFT,
rules: {
customer_group_id: ["customer-group-2"],
},
prices: [],
},
])
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [],
})
const api = useApi() as any
const data = {
status: PriceListStatus.ACTIVE,
}
await api.post(`admin/price-lists/${priceList.id}`, data, adminHeaders)
const response = await api.get(
`/admin/price-lists/${priceList.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.price_list).toEqual(
expect.objectContaining({
id: expect.any(String),
customer_groups: [
{
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
name: "Test Group 2",
metadata: null,
},
],
})
)
})
})

View File

@@ -1,287 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleCustomerFactory,
simpleCustomerGroupFactory,
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
import {
IPricingModuleService,
PriceListStatus,
PriceListType,
} from "@medusajs/types"
import { AxiosInstance } from "axios"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("GET /store/products/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let product
let variant
let priceSetId
let pricingModuleService: IPricingModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
pricingModuleService = appContainer.resolve("pricingModuleService")
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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",
status: "published",
variants: [
{
options: [{ option_id: "test-product-option-1", value: "test" }],
},
],
options: [
{
id: "test-product-option-1",
title: "Test option 1",
},
],
})
variant = product.variants[0]
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
{
amount: 4000,
currency_code: "usd",
},
],
rules: [],
})
priceSetId = priceSet.id
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get product and its prices from price-list created through the price list workflow", async () => {
const api = useApi()! as AxiosInstance
const priceListResponse = await api.post(
`/admin/price-lists`,
{
name: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 2500,
currency_code: "usd",
variant_id: variant.id,
},
],
},
adminHeaders
)
let response = await api.get(
`/store/products/${product.id}?currency_code=usd`
)
expect(response.status).toEqual(200)
expect(response.data.product.variants[0].prices).toHaveLength(2)
expect(response.data.product.variants[0].prices).toEqual([
expect.objectContaining({
currency_code: "usd",
amount: 3000,
min_quantity: null,
max_quantity: null,
price_list_id: null,
}),
expect.objectContaining({
currency_code: "usd",
amount: 2500,
min_quantity: null,
max_quantity: null,
price_list_id: priceListResponse.data.price_list.id,
}),
])
expect(response.data.product.variants[0]).toEqual(
expect.objectContaining({
original_price: 3000,
calculated_price: 2500,
calculated_price_type: "sale",
})
)
})
it("should not list prices from price-list with customer groups if not logged in", async () => {
const api = useApi()! as AxiosInstance
const { id: customerGroupId } = await simpleCustomerGroupFactory(
dbConnection
)
const priceListResponse = await api.post(
`/admin/price-lists`,
{
name: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 2500,
currency_code: "usd",
variant_id: variant.id,
},
],
customer_groups: [{ id: customerGroupId }],
},
adminHeaders
)
let response = await api.get(
`/store/products/${product.id}?currency_code=usd`
)
expect(response.status).toEqual(200)
expect(response.data.product.variants[0].prices).toEqual([
expect.objectContaining({
currency_code: "usd",
amount: 3000,
min_quantity: null,
max_quantity: null,
price_list_id: null,
}),
])
expect(response.data.product.variants[0]).toEqual(
expect.objectContaining({
original_price: 3000,
calculated_price: 3000,
calculated_price_type: null,
})
)
})
it("should list prices from price-list with customer groups", async () => {
const api = useApi()! as AxiosInstance
await simpleCustomerFactory(dbConnection, {
id: "test-customer-5-pl",
email: "test5@email-pl.com",
first_name: "John",
last_name: "Deere",
password_hash:
"c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", // password matching "test"
has_account: true,
groups: [{ id: "customer-group-1" }],
})
const authResponse = await api.post("/store/auth", {
email: "test5@email-pl.com",
password: "test",
})
const [authCookie] = authResponse.headers["set-cookie"][0].split(";")
const priceListResponse = await api.post(
`/admin/price-lists`,
{
name: "test price list",
description: "test",
status: PriceListStatus.ACTIVE,
type: PriceListType.SALE,
prices: [
{
amount: 2500,
currency_code: "usd",
variant_id: variant.id,
},
],
customer_groups: [{ id: "customer-group-1" }],
},
adminHeaders
)
let response = await api.get(
`/store/products/${product.id}?currency_code=usd`,
{
headers: {
Cookie: authCookie,
},
}
)
expect(response.status).toEqual(200)
expect(response.data.product.variants[0].prices).toHaveLength(2)
expect(response.data.product.variants[0].prices).toEqual([
expect.objectContaining({
currency_code: "usd",
amount: 3000,
min_quantity: null,
max_quantity: null,
price_list_id: null,
}),
expect.objectContaining({
currency_code: "usd",
amount: 2500,
min_quantity: null,
max_quantity: null,
price_list_id: priceListResponse.data.price_list.id,
}),
])
expect(response.data.product.variants[0]).toEqual(
expect.objectContaining({
original_price: 3000,
calculated_price: 2500,
calculated_price_type: "sale",
})
)
})
})

View File

@@ -1,136 +0,0 @@
import { useApi } from "../../../environment-helpers/use-api"
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { simpleCartFactory, simpleRegionFactory } from "../../../factories"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { AxiosInstance } from "axios"
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { getContainer } from "../../../environment-helpers/use-container"
import adminSeeder from "../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../helpers/create-default-rule-types"
jest.setTimeout(5000000)
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}`
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("Link Modules", () => {
let medusaContainer
let dbConnection
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
medusaContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createDefaultRuleTypes(medusaContainer)
await adminSeeder(dbConnection)
await simpleRegionFactory(dbConnection, {
id: "region-1",
currency_code: "usd",
})
})
describe("get product price", () => {
let ruleType
let priceSet
let productId
const cartId = "test-cart"
beforeEach(async () => {
const pricingModuleService = medusaContainer.resolve(
ModuleRegistrationName.PRICING
)
const api = useApi()! as AxiosInstance
await simpleCartFactory(dbConnection, { id: cartId, region: "region-1" })
const payload = {
title: "Test",
description: "test-product-description",
images: ["test-image.png", "test-image-2.png"],
variants: [
{
title: "Test variant",
prices: [],
options: [],
},
],
}
const response = await api.post("/admin/products", payload, adminHeaders)
productId = response.data.product.id
const variant = response.data.product.variants[0]
ruleType = await pricingModuleService.createRuleTypes([
{ name: "region_id", rule_attribute: "region_id" },
])
priceSet = await pricingModuleService.create({
rules: [{ rule_attribute: "region_id" }],
prices: [
{
amount: 1000,
currency_code: "usd",
rules: { region_id: "region-1" },
},
{
amount: 900,
currency_code: "usd",
rules: { region_id: "region-2" },
},
],
})
const remoteLink = medusaContainer.resolve("remoteLink") as any
await remoteLink.create({
productService: {
variant_id: variant.id,
},
pricingService: {
price_set_id: priceSet.id,
},
})
})
it("Should get prices declared in pricing module", async () => {
const api = useApi()! as AxiosInstance
const response = await api.get(
`/store/products/${productId}?cart_id=${cartId}`
)
expect(response.data.product.variants[0].prices).toEqual([
expect.objectContaining({
amount: 1000,
currency_code: "usd",
}),
])
})
})
})

View File

@@ -1,204 +0,0 @@
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 { AxiosInstance } from "axios"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { ProductModuleService } from "@medusajs/product"
import { PricingModuleService } from "@medusajs/pricing"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/products/:id/variants", () => {
let dbConnection
let appContainer
let shutdownServer
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()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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,
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),
variants: expect.arrayContaining([
expect.objectContaining({
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"
)
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" }],
}
await api
.post(`/admin/products/${product.id}/variants`, data, adminHeaders)
.catch((e) => e)
expect(productSpy).toBeCalledWith([expect.any(String)])
const getProductResponse = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(getProductResponse.data.product.variants).toHaveLength(1)
})
})

View File

@@ -1,125 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { Region } from "@medusajs/medusa"
import { IPricingModuleService } from "@medusajs/types"
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 { simpleSalesChannelFactory } from "../../../../factories"
import adminSeeder from "../../../../helpers/admin-seeder"
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,
}
describe.skip("POST /admin/products", () => {
let dbConnection
let appContainer
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
const manager = dbConnection.manager
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
await manager.insert(Region, {
id: "test-region",
name: "Test Region",
currency_code: "usd",
tax_rate: 0,
})
await simpleSalesChannelFactory(dbConnection, { is_default: true })
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
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)
})
})

View File

@@ -1,471 +0,0 @@
import fs from "fs/promises"
import path, { resolve, sep } 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 { simpleSalesChannelFactory } from "../../../../factories"
import adminSeeder from "../../../../helpers/admin-seeder"
import productSeeder from "../../../../helpers/product-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
const setupServer = require("../../../../environment-helpers/setup-server")
const userSeeder = require("../../../../helpers/user-seeder")
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env: Record<any, any> = {
MEDUSA_FF_MEDUSA_V2: true,
}
jest.setTimeout(180000)
describe.skip("Batch job of product-export type", () => {
let medusaProcess
let dbConnection
let exportFilePath = ""
let topDir = ""
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
medusaProcess = await setupServer({
cwd,
uploadDir: __dirname,
env,
verbose: true,
})
})
afterAll(async () => {
if (topDir !== "") {
await fs.rm(resolve(__dirname, topDir), { recursive: true })
}
const db = useDb()
await db.shutdown()
await medusaProcess.kill()
await shutdownServer()
})
beforeEach(async () => {
const container = getContainer()
await createDefaultRuleTypes(container)
await productSeeder(dbConnection)
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
await simpleSalesChannelFactory(dbConnection, {
id: "test-channel",
is_default: true,
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
// @ts-ignore
try {
const isFileExists = (await fs.stat(exportFilePath))?.isFile()
if (isFileExists) {
const [, relativeRoot] = exportFilePath
.replace(__dirname, "")
.split(sep)
if ((await fs.stat(resolve(__dirname, relativeRoot)))?.isDirectory()) {
topDir = relativeRoot
}
await fs.unlink(exportFilePath)
}
} catch (err) {
// noop
}
})
it("should export a csv file containing the expected products", async () => {
const api = useApi()
const productPayload = {
title: "Test export product",
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,
sku: "test-variant-sku-product-export",
prices: [
{
currency_code: "usd",
amount: 100,
},
{
currency_code: "eur",
amount: 45,
},
{
currency_code: "dkk",
amount: 30,
},
],
options: [{ value: "large" }, { value: "green" }],
},
],
}
const createProductRes = await api.post(
"/admin/products",
productPayload,
adminReqConfig
)
const productId = createProductRes.data.product.id
const variantId = createProductRes.data.product.variants[0].id
const batchPayload = {
type: "product-export",
context: {
filterable_fields: {
title: "Test export product",
},
},
}
const batchJobRes = await api.post(
"/admin/batch-jobs",
batchPayload,
adminReqConfig
)
const batchJobId = batchJobRes.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
exportFilePath = path.resolve(__dirname, batchJob.result.file_key)
const isFileExists = (await fs.stat(exportFilePath)).isFile()
expect(isFileExists).toBeTruthy()
const fileSize = (await fs.stat(exportFilePath)).size
expect(batchJob.result?.file_size).toBe(fileSize)
const data = (await fs.readFile(exportFilePath)).toString()
const [, ...lines] = data.split("\r\n").filter((l) => l)
expect(lines.length).toBe(1)
const lineColumn = lines[0].split(";")
expect(lineColumn[0]).toBe(productId)
expect(lineColumn[2]).toBe(productPayload.title)
expect(lineColumn[4]).toBe(productPayload.description)
expect(lineColumn[23]).toBe(variantId)
expect(lineColumn[24]).toBe(productPayload.variants[0].title)
expect(lineColumn[25]).toBe(productPayload.variants[0].sku)
})
it("should export a csv file containing the expected products including new line char in the cells", async () => {
const api = useApi()
const productPayload = {
title: "Test export product",
description: "test-product-description\ntest line 2",
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,
sku: "test-variant-sku-product-export",
prices: [
{
currency_code: "usd",
amount: 100,
},
{
currency_code: "eur",
amount: 45,
},
{
currency_code: "dkk",
amount: 30,
},
],
options: [{ value: "large" }, { value: "green" }],
},
],
}
const createProductRes = await api.post(
"/admin/products",
productPayload,
adminReqConfig
)
const productId = createProductRes.data.product.id
const variantId = createProductRes.data.product.variants[0].id
const batchPayload = {
type: "product-export",
context: {
filterable_fields: {
title: "Test export product",
},
},
}
const batchJobRes = await api.post(
"/admin/batch-jobs",
batchPayload,
adminReqConfig
)
const batchJobId = batchJobRes.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
exportFilePath = path.resolve(__dirname, batchJob.result.file_key)
const isFileExists = (await fs.stat(exportFilePath)).isFile()
expect(isFileExists).toBeTruthy()
const fileSize = (await fs.stat(exportFilePath)).size
expect(batchJob.result?.file_size).toBe(fileSize)
const data = (await fs.readFile(exportFilePath)).toString()
const [, ...lines] = data.split("\r\n").filter((l) => l)
expect(lines.length).toBe(1)
const lineColumn = lines[0].split(";")
expect(lineColumn[0]).toBe(productId)
expect(lineColumn[2]).toBe(productPayload.title)
expect(lineColumn[4]).toBe(`"${productPayload.description}"`)
expect(lineColumn[23]).toBe(variantId)
expect(lineColumn[24]).toBe(productPayload.variants[0].title)
expect(lineColumn[25]).toBe(productPayload.variants[0].sku)
})
it("should export a csv file containing a limited number of products", async () => {
const api = useApi()
const batchPayload = {
type: "product-export",
context: {
batch_size: 1,
filterable_fields: { collection_id: "test-collection" },
order: "created_at",
},
}
const batchJobRes = await api.post(
"/admin/batch-jobs",
batchPayload,
adminReqConfig
)
const batchJobId = batchJobRes.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
exportFilePath = path.resolve(__dirname, batchJob.result.file_key)
const isFileExists = (await fs.stat(exportFilePath)).isFile()
expect(isFileExists).toBeTruthy()
const data = (await fs.readFile(exportFilePath)).toString()
const [, ...lines] = data.split("\r\n").filter((l) => l)
expect(lines.length).toBe(4)
const csvLine = lines[0].split(";")
expect(csvLine[0]).toBe("test-product")
})
it("should be able to import an exported csv file", async () => {
const api = useApi()
const batchPayload = {
type: "product-export",
context: {
batch_size: 1,
filterable_fields: { collection_id: "test-collection" },
order: "created_at",
},
}
const batchJobRes = await api.post(
"/admin/batch-jobs",
batchPayload,
adminReqConfig
)
let batchJobId = batchJobRes.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
exportFilePath = path.resolve(__dirname, batchJob.result.file_key)
const isFileExists = (await fs.stat(exportFilePath)).isFile()
expect(isFileExists).toBeTruthy()
const data = (await fs.readFile(exportFilePath)).toString()
const [header, ...lines] = data.split("\r\n").filter((l) => l)
expect(lines.length).toBe(4)
const csvLine = lines[0].split(";")
expect(csvLine[0]).toBe("test-product")
expect(csvLine[2]).toBe("Test product")
csvLine[2] = "Updated test product"
lines.splice(0, 1, csvLine.join(";"))
await fs.writeFile(exportFilePath, [header, ...lines].join("\r\n"))
const importBatchJobRes = await api.post(
"/admin/batch-jobs",
{
type: "product-import",
context: {
fileKey: exportFilePath,
},
},
adminReqConfig
)
batchJobId = importBatchJobRes.data.batch_job.id
expect(batchJobId).toBeTruthy()
shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
const productsResponse = await api.get("/admin/products", adminReqConfig)
expect(productsResponse.data.count).toBe(5)
expect(productsResponse.data.products).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: csvLine[0],
handle: csvLine[1],
title: csvLine[2],
}),
])
)
})
})

View File

@@ -1,406 +0,0 @@
import fs from "fs"
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 } from "../../../../factories"
import { simpleProductCollectionFactory } from "../../../../factories/simple-product-collection-factory"
import adminSeeder from "../../../../helpers/admin-seeder"
import batchJobSeeder from "../../../../helpers/batch-job-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
const setupServer = require("../../../../environment-helpers/setup-server")
const userSeeder = require("../../../../helpers/user-seeder")
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
function getImportFile() {
return path.resolve("__tests__", "product", "admin", "product-import.csv")
}
function copyTemplateFile() {
const csvTemplate = path.resolve(
"__tests__",
"product",
"admin",
"product-import-template.csv"
)
const destination = getImportFile()
fs.copyFileSync(csvTemplate, destination)
}
jest.setTimeout(1000000)
function cleanTempData() {
// cleanup tmp ops files
const opsFiles = path.resolve("__tests__", "product", "admin", "imports")
fs.rmSync(opsFiles, { recursive: true, force: true })
}
const env: Record<any, any> = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("Product import batch job", () => {
let dbConnection
let shutdownServer
let medusaProcess
const collectionHandle1 = "test-collection1"
const collectionHandle2 = "test-collection2"
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
env.UPLOAD_DIR = __dirname
cleanTempData() // cleanup if previous process didn't manage to do it
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
medusaProcess = await setupServer({
cwd,
uploadDir: __dirname,
env,
verbose: true,
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
cleanTempData()
await medusaProcess.kill()
await shutdownServer()
})
beforeEach(async () => {
const container = getContainer()
await createDefaultRuleTypes(container)
await batchJobSeeder(dbConnection)
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
await simpleProductCollectionFactory(dbConnection, [
{
handle: collectionHandle1,
},
{
handle: collectionHandle2,
},
])
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should import a csv file", async () => {
jest.setTimeout(1000000)
const api = useApi()
copyTemplateFile()
const existingProductToBeUpdated = await simpleProductFactory(
dbConnection,
{
id: "existing-product-id",
title: "Test product",
options: [{ id: "opt-1-id", title: "Size" }],
variants: [
{
id: "existing-variant-id",
title: "Initial tile",
sku: "test-sku-4",
options: [
{
option_id: "opt-1-id",
value: "Large",
},
],
},
],
}
)
const response = await api.post(
"/admin/batch-jobs",
{
type: "product-import",
context: {
fileKey: "product-import.csv",
},
},
adminReqConfig
)
const batchJobId = response.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
const productsResponse = await api.get("/admin/products", adminReqConfig)
expect(productsResponse.data.count).toBe(3)
expect(productsResponse.data.products).toEqual(
expect.arrayContaining([
// NEW PRODUCT
expect.objectContaining({
title: "Test product",
description:
"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",
handle: "test-product-product-1",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
variants: [
// NEW VARIANT
expect.objectContaining({
title: "Test variant",
sku: "test-sku-1",
barcode: "test-barcode-1",
ean: null,
upc: null,
// inventory_quantity: 10,
prices: expect.arrayContaining([
expect.objectContaining({
currency_code: "eur",
amount: 100,
region_id: "region-product-import-0",
}),
expect.objectContaining({
currency_code: "usd",
amount: 110,
}),
expect.objectContaining({
currency_code: "dkk",
amount: 130,
region_id: "region-product-import-1",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
value: "option 1 value red",
}),
expect.objectContaining({
value: "option 2 value 1",
}),
]),
}),
],
type: null,
images: expect.arrayContaining([
expect.objectContaining({
url: "test-image.png",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
title: "test-option-1",
}),
expect.objectContaining({
title: "test-option-2",
}),
]),
tags: expect.arrayContaining([
expect.objectContaining({
value: "123_1",
}),
]),
collection: expect.objectContaining({
handle: collectionHandle1,
}),
}),
expect.objectContaining({
title: "Test product",
description:
"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",
handle: "test-product-product-1-1",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
variants: [
// NEW VARIANT
expect.objectContaining({
title: "Test variant",
sku: "test-sku-1-1",
barcode: "test-barcode-1-1",
ean: null,
upc: null,
// inventory_quantity: 10,
prices: expect.arrayContaining([
expect.objectContaining({
currency_code: "eur",
amount: 100,
region_id: "region-product-import-0",
}),
expect.objectContaining({
currency_code: "usd",
amount: 110,
}),
expect.objectContaining({
currency_code: "dkk",
amount: 130,
region_id: "region-product-import-1",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
value: "option 1 value red",
}),
expect.objectContaining({
value: "option 2 value 1",
}),
]),
}),
],
type: null,
images: expect.arrayContaining([
expect.objectContaining({
url: "test-image.png",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
title: "test-option-1",
}),
expect.objectContaining({
title: "test-option-2",
}),
]),
tags: [],
collection: expect.objectContaining({
handle: collectionHandle1,
}),
}),
// // UPDATED PRODUCT
expect.objectContaining({
id: existingProductToBeUpdated?.id,
title: "Test product",
description: "test-product-description",
handle: "test-product-product-2",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
profile_id: expect.any(String),
variants: expect.arrayContaining([
// UPDATED VARIANT
expect.objectContaining({
id: "existing-variant-id",
title: "Test variant changed",
sku: "test-sku-4",
barcode: "test-barcode-4",
options: [
expect.objectContaining({
value: "Large",
option_id: "opt-1-id",
}),
],
}),
// CREATED VARIANT
expect.objectContaining({
title: "Test variant",
product_id: existingProductToBeUpdated.id,
sku: "test-sku-2",
barcode: "test-barcode-2",
ean: null,
upc: null,
// inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
prices: [
expect.objectContaining({
currency_code: "dkk",
amount: 110,
region_id: "region-product-import-2",
}),
],
options: [
expect.objectContaining({
value: "Small",
option_id: "opt-1-id",
}),
],
}),
// CREATED VARIANT
expect.objectContaining({
title: "Test variant",
product_id: existingProductToBeUpdated.id,
sku: "test-sku-3",
barcode: "test-barcode-3",
ean: null,
upc: null,
// inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
prices: [
expect.objectContaining({
currency_code: "usd",
amount: 120,
region_id: null,
}),
],
options: [
expect.objectContaining({
value: "Medium",
option_id: "opt-1-id",
}),
],
}),
]),
images: [
expect.objectContaining({
url: "test-image.png",
}),
],
options: [
expect.objectContaining({
product_id: existingProductToBeUpdated.id,
id: "opt-1-id",
title: "Size",
}),
],
type: expect.objectContaining({ value: "test-type" }),
tags: [
expect.objectContaining({
value: "123",
}),
],
collection: expect.objectContaining({
handle: collectionHandle2,
}),
}),
])
)
})
})

View File

@@ -1,655 +0,0 @@
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,
}
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) }),
])
})
})
})

View File

@@ -1,6 +0,0 @@
Product Id,Product Handle,Product Title,Product Subtitle,Product Description,Product Status,Product Thumbnail,Product Weight,Product Length,Product Width,Product Height,Product HS Code,Product Origin Country,Product MID Code,Product Material,Product Collection Title,Product Collection Handle,Product Type,Product Tags,Product Discountable,Product External Id,Variant Id,Variant Title,Variant SKU,Variant Barcode,Variant Inventory Quantity,Variant Allow Backorder,Variant Manage Inventory,Variant Weight,Variant Length,Variant Width,Variant Height,Variant HS Code,Variant Origin Country,Variant MID Code,Variant Material,Price ImportLand [EUR],Price USD,Price denmark [DKK],Price Denmark [DKK],Option 1 Name,Option 1 Value,Option 2 Name,Option 2 Value,Image 1 Url
,test-product-product-1,Test product,,"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",draft,,,,,,,,,,Test collection 1,test-collection1,,123_1,TRUE,,,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,1.00,1.10,1.30,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png
,test-product-product-1-1,Test product,,"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",draft,,,,,,,,,,Test collection 1,test-collection1,,,TRUE,,,Test variant,test-sku-1-1,test-barcode-1-1,10,FALSE,TRUE,,,,,,,,,1.00,1.10,1.30,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,test-image.png,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,1.10,Size,Small,,,test-image.png
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,1.20,,,Size,Medium,,,test-image.png
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,existing-variant-id,Test variant changed,test-sku-4,test-barcode-4,10,FALSE,TRUE,,,,,,,,,,,,,Size,Large,,,test-image.png
1 Product Id Product Handle Product Title Product Subtitle Product Description Product Status Product Thumbnail Product Weight Product Length Product Width Product Height Product HS Code Product Origin Country Product MID Code Product Material Product Collection Title Product Collection Handle Product Type Product Tags Product Discountable Product External Id Variant Id Variant Title Variant SKU Variant Barcode Variant Inventory Quantity Variant Allow Backorder Variant Manage Inventory Variant Weight Variant Length Variant Width Variant Height Variant HS Code Variant Origin Country Variant MID Code Variant Material Price ImportLand [EUR] Price USD Price denmark [DKK] Price Denmark [DKK] Option 1 Name Option 1 Value Option 2 Name Option 2 Value Image 1 Url
2 test-product-product-1 Test product Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal. draft Test collection 1 test-collection1 123_1 TRUE Test variant test-sku-1 test-barcode-1 10 FALSE TRUE 1.00 1.10 1.30 test-option-1 option 1 value red test-option-2 option 2 value 1 test-image.png
3 test-product-product-1-1 Test product Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal. draft Test collection 1 test-collection1 TRUE Test variant test-sku-1-1 test-barcode-1-1 10 FALSE TRUE 1.00 1.10 1.30 test-option-1 option 1 value red test-option-2 option 2 value 1 test-image.png
4 existing-product-id test-product-product-2 Test product test-product-description draft test-image.png Test collection test-collection2 test-type 123 TRUE Test variant test-sku-2 test-barcode-2 10 FALSE TRUE 1.10 Size Small test-image.png
5 existing-product-id test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE Test variant test-sku-3 test-barcode-3 10 FALSE TRUE 1.20 Size Medium test-image.png
6 existing-product-id test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE existing-variant-id Test variant changed test-sku-4 test-barcode-4 10 FALSE TRUE Size Large test-image.png

View File

@@ -1,482 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import {
simpleProductFactory,
simpleRegionFactory,
} from "../../../../factories"
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 path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/products/:id/variants/:id", () => {
let dbConnection
let appContainer
let shutdownServer
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()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
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: [{ option_id: "test-product-option-1", value: "test 2" }],
},
],
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 product variant price sets and prices", async () => {
const api = useApi()! as AxiosInstance
const data = {
title: "test variant update",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
currency_code: "usd",
region_id: null,
},
],
}
let response = await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
response = await api.get(`/admin/products/${product.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 55500,
currency_code: "usd",
}),
]),
}),
]),
})
)
})
it("should update money amounts if money amount id is present in prices", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const moneyAmountToUpdate = priceSet.money_amounts?.[0]
const api = useApi()! as AxiosInstance
const data = {
title: "test variant update",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
id: moneyAmountToUpdate?.id,
amount: 2222,
currency_code: "usd",
region_id: null,
},
],
}
let response = await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
response = await api.get(`/admin/products/${product.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
id: moneyAmountToUpdate?.id,
amount: 2222,
currency_code: "usd",
}),
]),
}),
]),
})
)
})
it("should add prices if price set is already present", async () => {
await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [],
})
const api = useApi()! as AxiosInstance
const data = {
title: "test variant update",
prices: [
{
amount: 123,
region_id: "test-region",
},
{
amount: 456,
currency_code: "usd",
region_id: null,
},
],
}
let response = await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
response = await api.get(`/admin/products/${product.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 123,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 456,
currency_code: "usd",
}),
]),
}),
]),
})
)
})
it("should update variant option value", async () => {
const api = useApi()! as AxiosInstance
const data = {
options: [
{
option_id: "test-product-option-1",
value: "updated",
},
],
}
await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
options: [
expect.objectContaining({
option_id: "test-product-option-1",
value: "updated",
}),
],
}),
expect.objectContaining({
id: product.variants[1].id,
options: [
expect.objectContaining({
option_id: "test-product-option-1",
value: "test 2",
}),
],
}),
]),
})
)
})
it("should update variant metadata", async () => {
const api = useApi()! as AxiosInstance
const data = {
metadata: {
test: "string",
},
}
await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
metadata: {
test: "string",
},
}),
]),
})
)
})
it("should remove options not present in update", async () => {
const api = useApi()! as AxiosInstance
product = await simpleProductFactory(dbConnection, {
id: "test-product-with-multiple-options",
variants: [
{
options: [
{ option_id: "test-product-multi-option-1", value: "test" },
{ option_id: "test-product-multi-option-2", value: "test value" },
],
},
],
options: [
{
id: "test-product-multi-option-1",
title: "Test option 1",
},
{
id: "test-product-multi-option-2",
title: "Test option 2",
},
],
})
variant = product.variants[0]
const data = {
options: [
{
option_id: "test-product-multi-option-1",
value: "updated",
},
],
}
await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: [
expect.objectContaining({
id: variant.id,
options: [
expect.objectContaining({
option_id: "test-product-multi-option-1",
value: "updated",
}),
],
}),
],
})
)
})
it("should update several options in the same api call", async () => {
const api = useApi()! as AxiosInstance
product = await simpleProductFactory(dbConnection, {
id: "test-product-with-multiple-options",
variants: [
{
options: [
{ option_id: "test-product-multi-option-1", value: "test" },
{ option_id: "test-product-multi-option-2", value: "test value" },
],
},
],
options: [
{
id: "test-product-multi-option-1",
title: "Test option 1",
},
{
id: "test-product-multi-option-2",
title: "Test option 2",
},
],
})
variant = product.variants[0]
const data = {
options: [
{
option_id: "test-product-multi-option-1",
value: "updated",
},
{
option_id: "test-product-multi-option-2",
value: "updated 2",
},
],
}
await api.post(
`/admin/products/${product.id}/variants/${variant.id}`,
data,
adminHeaders
)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: [
expect.objectContaining({
id: variant.id,
options: [
expect.objectContaining({
option_id: "test-product-multi-option-1",
value: "updated",
}),
expect.objectContaining({
option_id: "test-product-multi-option-2",
value: "updated 2",
}),
],
}),
],
})
)
})
})

View File

@@ -1,279 +0,0 @@
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { simpleProductFactory } from "../../../../factories"
import { Region } from "@medusajs/medusa"
import { AxiosInstance } from "axios"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
import { createVariantPriceSet } from "../../../helpers/create-variant-price-set"
jest.setTimeout(50000)
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
describe.skip("POST /admin/products/:id", () => {
let dbConnection
let appContainer
let shutdownServer
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()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
const manager = dbConnection.manager
await adminSeeder(dbConnection)
await createDefaultRuleTypes(appContainer)
await manager.insert(Region, {
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 update product variant price sets and prices", async () => {
const api = useApi() as any
const data = {
title: "test product update",
variants: [
{
id: variant.id,
title: "test variant update",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
amount: 55500,
currency_code: "usd",
region_id: null,
},
],
},
],
}
await api.post(`/admin/products/${product.id}`, data, adminHeaders)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product.variants).toHaveLength(1)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: [
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 55500,
currency_code: "usd",
}),
]),
}),
],
})
)
})
it("should update money amounts if money amount id is present in prices", async () => {
const priceSet = await createVariantPriceSet({
container: appContainer,
variantId: variant.id,
prices: [
{
amount: 3000,
currency_code: "usd",
},
],
})
const moneyAmountToUpdate = priceSet.money_amounts?.[0]
const api = useApi() as any
const data = {
title: "test product update",
variants: [
{
id: variant.id,
title: "test variant update",
prices: [
{
amount: 66600,
region_id: "test-region",
},
{
id: moneyAmountToUpdate?.id,
amount: 2222,
currency_code: "usd",
region_id: null,
},
],
},
],
}
await api.post(`/admin/products/${product.id}`, data, adminHeaders)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 66600,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
id: moneyAmountToUpdate?.id,
amount: 2222,
currency_code: "usd",
}),
]),
}),
]),
})
)
})
it("should add prices if price set is already present", async () => {
const remoteLink = appContainer.resolve("remoteLink")
const pricingModuleService = appContainer.resolve("pricingModuleService")
const priceSet = await pricingModuleService.create({
rules: [{ rule_attribute: "region_id" }],
prices: [],
})
await remoteLink.create({
productService: {
variant_id: variant.id,
},
pricingService: {
price_set_id: priceSet.id,
},
})
const api = useApi()! as AxiosInstance
const data = {
title: "test product update",
variants: [
{
id: variant.id,
title: "test variant update",
prices: [
{
amount: 123,
region_id: "test-region",
},
{
amount: 456,
currency_code: "usd",
region_id: null,
},
],
},
],
}
await api.post(`/admin/products/${product.id}`, data, adminHeaders)
const response = await api.get(
`/admin/products/${product.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.product).toEqual(
expect.objectContaining({
id: expect.any(String),
variants: expect.arrayContaining([
expect.objectContaining({
id: variant.id,
title: "test variant update",
prices: expect.arrayContaining([
expect.objectContaining({
amount: 123,
currency_code: "usd",
region_id: "test-region",
}),
expect.objectContaining({
amount: 456,
currency_code: "usd",
}),
]),
}),
]),
})
)
})
})

View File

@@ -1,198 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/campaigns", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should throw an error if required params are not passed", async () => {
const api = useApi() as any
const { response } = await api
.post(`/admin/campaigns`, {}, adminHeaders)
.catch((e) => e)
expect(response.status).toEqual(400)
expect(response.data.message).toEqual(
"name must be a string, name should not be empty"
)
})
it("should create a campaign successfully", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: "standard",
})
const api = useApi() as any
const response = await api.post(
`/admin/campaigns`,
{
name: "test",
campaign_identifier: "test",
starts_at: new Date("01/01/2024").toISOString(),
ends_at: new Date("01/01/2029").toISOString(),
promotions: [{ id: createdPromotion.id }],
budget: {
limit: 1000,
type: "usage",
},
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.campaign).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "test",
campaign_identifier: "test",
starts_at: expect.any(String),
ends_at: expect.any(String),
budget: expect.objectContaining({
limit: 1000,
type: "usage",
}),
promotions: [
expect.objectContaining({
id: createdPromotion.id,
}),
],
})
)
})
it("should create 3 campaigns in parallel and have the context passed as argument when calling createCampaigns with different transactionId", async () => {
const parallelPromotion = await promotionModuleService.create({
code: "PARALLEL",
type: "standard",
})
const spyCreateCampaigns = jest.spyOn(
promotionModuleService.constructor.prototype,
"createCampaigns"
)
const api = useApi() as any
const a = async () => {
return await api.post(
`/admin/campaigns`,
{
name: "camp_1",
campaign_identifier: "camp_1",
starts_at: new Date("01/01/2024").toISOString(),
ends_at: new Date("01/02/2024").toISOString(),
promotions: [{ id: parallelPromotion.id }],
budget: {
limit: 1000,
type: "usage",
},
},
adminHeaders
)
}
const b = async () => {
return await api.post(
`/admin/campaigns`,
{
name: "camp_2",
campaign_identifier: "camp_2",
starts_at: new Date("01/02/2024").toISOString(),
ends_at: new Date("01/03/2029").toISOString(),
promotions: [{ id: parallelPromotion.id }],
budget: {
limit: 500,
type: "usage",
},
},
adminHeaders
)
}
const c = async () => {
return await api.post(
`/admin/campaigns`,
{
name: "camp_3",
campaign_identifier: "camp_3",
starts_at: new Date("01/03/2024").toISOString(),
ends_at: new Date("01/04/2029").toISOString(),
promotions: [{ id: parallelPromotion.id }],
budget: {
limit: 250,
type: "usage",
},
},
{
headers: {
...adminHeaders.headers,
"x-request-id": "my-custom-request-id",
},
}
)
}
await Promise.all([a(), b(), c()])
expect(spyCreateCampaigns).toHaveBeenCalledTimes(3)
expect(spyCreateCampaigns.mock.calls[0][1].__type).toBe("MedusaContext")
const distinctTransactionId = [
...new Set(
spyCreateCampaigns.mock.calls.map((call) => call[1].transactionId)
),
]
expect(distinctTransactionId).toHaveLength(3)
const distinctRequestId = [
...new Set(
spyCreateCampaigns.mock.calls.map((call) => call[1].requestId)
),
]
expect(distinctRequestId).toHaveLength(3)
expect(distinctRequestId).toContain("my-custom-request-id")
})
})

View File

@@ -1,344 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { PromotionType } from "@medusajs/utils"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/promotions", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should throw an error if required params are not passed", async () => {
const api = useApi() as any
const { response } = await api
.post(
`/admin/promotions`,
{
type: PromotionType.STANDARD,
},
adminHeaders
)
.catch((e) => e)
expect(response.status).toEqual(400)
expect(response.data.message).toEqual(
"code must be a string, code should not be empty, application_method should not be empty"
)
})
it("should create a standard promotion successfully", async () => {
const api = useApi() as any
const response = await api.post(
`/admin/promotions`,
{
code: "TEST",
type: PromotionType.STANDARD,
is_automatic: true,
campaign: {
name: "test",
campaign_identifier: "test-1",
budget: {
type: "usage",
limit: 100,
},
},
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
target_rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual(
expect.objectContaining({
id: expect.any(String),
code: "TEST",
type: "standard",
is_automatic: true,
campaign: expect.objectContaining({
name: "test",
campaign_identifier: "test-1",
budget: expect.objectContaining({
type: "usage",
limit: 100,
}),
}),
application_method: expect.objectContaining({
value: 100,
max_quantity: 100,
type: "fixed",
target_type: "items",
allocation: "each",
target_rules: [
expect.objectContaining({
operator: "eq",
attribute: "test.test",
values: expect.arrayContaining([
expect.objectContaining({ value: "test1" }),
expect.objectContaining({ value: "test2" }),
]),
}),
],
}),
rules: [
expect.objectContaining({
operator: "eq",
attribute: "test.test",
values: expect.arrayContaining([
expect.objectContaining({ value: "test1" }),
expect.objectContaining({ value: "test2" }),
]),
}),
],
})
)
})
it("should throw an error if buy_rules params are not passed", async () => {
const api = useApi() as any
const { response } = await api
.post(
`/admin/promotions`,
{
code: "TEST",
type: PromotionType.BUYGET,
is_automatic: true,
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
target_rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
adminHeaders
)
.catch((e) => e)
expect(response.status).toEqual(400)
expect(response.data.message).toEqual(
"Buy rules are required for buyget promotion type"
)
})
it("should throw an error if buy_rules params are not passed", async () => {
const api = useApi() as any
const { response } = await api
.post(
`/admin/promotions`,
{
code: "TEST",
type: PromotionType.BUYGET,
is_automatic: true,
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
buy_rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
adminHeaders
)
.catch((e) => e)
expect(response.status).toEqual(400)
expect(response.data.message).toEqual(
"Target rules are required for buyget promotion type"
)
})
it("should create a buyget promotion successfully", async () => {
const api = useApi() as any
const response = await api.post(
`/admin/promotions`,
{
code: "TEST",
type: PromotionType.BUYGET,
is_automatic: true,
campaign: {
name: "test",
campaign_identifier: "test-1",
budget: {
type: "usage",
limit: 100,
},
},
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
apply_to_quantity: 1,
buy_rules_min_quantity: 1,
target_rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
buy_rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
rules: [
{
attribute: "test.test",
operator: "eq",
values: ["test1", "test2"],
},
],
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual(
expect.objectContaining({
id: expect.any(String),
code: "TEST",
type: "buyget",
is_automatic: true,
campaign: expect.objectContaining({
name: "test",
campaign_identifier: "test-1",
budget: expect.objectContaining({
type: "usage",
limit: 100,
}),
}),
application_method: expect.objectContaining({
value: 100,
max_quantity: 100,
type: "fixed",
target_type: "items",
allocation: "each",
apply_to_quantity: 1,
buy_rules_min_quantity: 1,
target_rules: [
expect.objectContaining({
operator: "eq",
attribute: "test.test",
values: expect.arrayContaining([
expect.objectContaining({ value: "test1" }),
expect.objectContaining({ value: "test2" }),
]),
}),
],
buy_rules: [
expect.objectContaining({
operator: "eq",
attribute: "test.test",
values: expect.arrayContaining([
expect.objectContaining({ value: "test1" }),
expect.objectContaining({ value: "test2" }),
]),
}),
],
}),
rules: [
expect.objectContaining({
operator: "eq",
attribute: "test.test",
values: expect.arrayContaining([
expect.objectContaining({ value: "test1" }),
expect.objectContaining({ value: "test2" }),
]),
}),
],
})
)
})
})

View File

@@ -1,73 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/campaigns/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete campaign successfully", async () => {
const [createdCampaign] = await promotionModuleService.createCampaigns([
{
name: "test",
campaign_identifier: "test",
starts_at: new Date("01/01/2024"),
ends_at: new Date("01/01/2025"),
},
])
const api = useApi() as any
const deleteRes = await api.delete(
`/admin/campaigns/${createdCampaign.id}`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
const campaigns = await promotionModuleService.listCampaigns({
id: [createdCampaign.id],
})
expect(campaigns.length).toEqual(0)
})
})

View File

@@ -1,74 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/promotions/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete promotion successfully", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: "standard",
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
})
const api = useApi() as any
const deleteRes = await api.delete(
`/admin/promotions/${createdPromotion.id}`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
const promotions = await promotionModuleService.list({
id: [createdPromotion.id],
})
expect(promotions.length).toEqual(0)
})
})

View File

@@ -1,186 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPromotionModuleService } from "@medusajs/types"
import { CampaignBudgetType } from "@medusajs/utils"
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 { createAdminUser } from "../../../helpers/create-admin-user"
jest.setTimeout(50000)
export const campaignsData = [
{
id: "campaign-id-1",
name: "campaign 1",
description: "test description",
currency: "USD",
campaign_identifier: "test-1",
starts_at: new Date("01/01/2023"),
ends_at: new Date("01/01/2024"),
budget: {
type: CampaignBudgetType.SPEND,
limit: 1000,
used: 0,
},
},
{
id: "campaign-id-2",
name: "campaign 2",
description: "test description",
currency: "USD",
campaign_identifier: "test-2",
starts_at: new Date("01/01/2023"),
ends_at: new Date("01/01/2024"),
budget: {
type: CampaignBudgetType.USAGE,
limit: 1000,
used: 0,
},
},
]
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/campaigns", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
await promotionModuleService.createCampaigns(campaignsData)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all campaigns and its count", async () => {
const api = useApi() as any
const response = await api.get(`/admin/campaigns`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.campaigns).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
name: "campaign 1",
description: "test description",
currency: "USD",
campaign_identifier: "test-1",
starts_at: expect.any(String),
ends_at: expect.any(String),
budget: {
id: expect.any(String),
campaign: expect.any(Object),
type: "spend",
limit: 1000,
used: 0,
raw_limit: {
precision: 20,
value: "1000",
},
raw_used: {
precision: 20,
value: "0",
},
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
},
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
}),
expect.objectContaining({
id: expect.any(String),
name: "campaign 2",
description: "test description",
currency: "USD",
campaign_identifier: "test-2",
starts_at: expect.any(String),
ends_at: expect.any(String),
budget: {
id: expect.any(String),
campaign: expect.any(Object),
type: "usage",
limit: 1000,
used: 0,
raw_limit: {
precision: 20,
value: "1000",
},
raw_used: {
precision: 20,
value: "0",
},
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
},
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
}),
])
)
})
it("should get all campaigns and its count filtered", async () => {
const api = useApi() as any
const response = await api.get(
`/admin/campaigns?fields=name,created_at,budget.id`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.campaigns).toEqual(
expect.arrayContaining([
{
id: expect.any(String),
name: "campaign 1",
created_at: expect.any(String),
budget: {
id: expect.any(String),
campaign: expect.any(Object),
},
},
{
id: expect.any(String),
name: "campaign 2",
created_at: expect.any(String),
budget: {
id: expect.any(String),
campaign: expect.any(Object),
},
},
])
)
})
})

View File

@@ -1,125 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { PromotionType } from "@medusajs/utils"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/promotions", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should get all promotions and its count", async () => {
await promotionModuleService.create([
{
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
},
])
const api = useApi() as any
const response = await api.get(`/admin/promotions`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.promotions).toEqual([
expect.objectContaining({
id: expect.any(String),
code: "TEST",
campaign: null,
is_automatic: false,
type: "standard",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
application_method: expect.objectContaining({
id: expect.any(String),
value: 100,
type: "fixed",
target_type: "order",
allocation: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
}),
}),
])
})
it("should get all promotions and its count filtered", async () => {
const [createdPromotion] = await promotionModuleService.create([
{
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
},
])
const api = useApi() as any
const response = await api.get(
`/admin/promotions?fields=code,created_at,application_method.id`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.promotions).toEqual([
{
id: expect.any(String),
code: "TEST",
created_at: expect.any(String),
application_method: {
id: expect.any(String),
promotion: expect.any(Object),
},
},
])
})
})

View File

@@ -1,141 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPromotionModuleService } from "@medusajs/types"
import { CampaignBudgetType } from "@medusajs/utils"
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 { createAdminUser } from "../../../helpers/create-admin-user"
jest.setTimeout(50000)
export const campaignData = {
name: "campaign 1",
description: "test description",
currency: "USD",
campaign_identifier: "test-1",
starts_at: new Date("01/01/2023"),
ends_at: new Date("01/01/2024"),
budget: {
type: CampaignBudgetType.SPEND,
limit: 1000,
used: 0,
},
}
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/campaigns", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
let campaigns
beforeEach(async () => {})
it("should throw an error if id does not exist", async () => {
const api = useApi() as any
const { response } = await api
.get(`/admin/campaigns/does-not-exist`, adminHeaders)
.catch((e) => e)
expect(response.status).toEqual(404)
expect(response.data.message).toEqual(
"Campaign with id: does-not-exist was not found"
)
})
it("should get the requested campaign", async () => {
const createdCampaign = await promotionModuleService.createCampaigns(
campaignData
)
const api = useApi() as any
const response = await api.get(
`/admin/campaigns/${createdCampaign.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.campaign).toEqual({
id: expect.any(String),
name: "campaign 1",
description: "test description",
currency: "USD",
campaign_identifier: "test-1",
starts_at: expect.any(String),
ends_at: expect.any(String),
budget: {
id: expect.any(String),
campaign: expect.any(Object),
type: "spend",
limit: 1000,
raw_limit: {
precision: 20,
value: "1000",
},
raw_used: {
precision: 20,
value: "0",
},
used: 0,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
},
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
})
})
it("should get the requested campaign with filtered fields and relations", async () => {
const createdCampaign = await promotionModuleService.createCampaigns(
campaignData
)
const api = useApi() as any
const response = await api.get(
`/admin/campaigns/${createdCampaign.id}?fields=name&expand=`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.campaign).toEqual({
id: expect.any(String),
name: "campaign 1",
})
})
})

View File

@@ -1,129 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { PromotionType } from "@medusajs/utils"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/promotions", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should throw an error if id does not exist", async () => {
const api = useApi() as any
const { response } = await api
.get(`/admin/promotions/does-not-exist`, adminHeaders)
.catch((e) => e)
expect(response.status).toEqual(404)
expect(response.data.message).toEqual(
"Promotion with id: does-not-exist was not found"
)
})
it("should get the requested promotion", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
})
const api = useApi() as any
const response = await api.get(
`/admin/promotions/${createdPromotion.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual(
expect.objectContaining({
id: expect.any(String),
code: "TEST",
campaign: null,
is_automatic: false,
type: "standard",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
application_method: expect.objectContaining({
id: expect.any(String),
promotion: expect.any(Object),
value: 100,
type: "fixed",
target_type: "order",
max_quantity: 0,
allocation: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
}),
})
)
})
it("should get the requested promotion with filtered fields and relations", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
})
const api = useApi() as any
const response = await api.get(
`/admin/promotions/${createdPromotion.id}?fields=id,code&expand=`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual({
id: expect.any(String),
code: "TEST",
})
})
})

View File

@@ -1,118 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/campaigns/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should throw an error if id does not exist", async () => {
const api = useApi() as any
const { response } = await api
.post(`/admin/campaigns/does-not-exist`, {}, adminHeaders)
.catch((e) => e)
expect(response.status).toEqual(404)
expect(response.data.message).toEqual(
`Campaign with id "does-not-exist" not found`
)
})
it("should update a campaign successfully", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: "standard",
})
const createdPromotion2 = await promotionModuleService.create({
code: "TEST_2",
type: "standard",
})
const createdCampaign = await promotionModuleService.createCampaigns({
name: "test",
campaign_identifier: "test",
starts_at: new Date("01/01/2024").toISOString(),
ends_at: new Date("01/01/2029").toISOString(),
promotions: [{ id: createdPromotion.id }],
budget: {
limit: 1000,
type: "usage",
used: 10,
},
})
const api = useApi() as any
const response = await api.post(
`/admin/campaigns/${createdCampaign.id}`,
{
name: "test-2",
campaign_identifier: "test-2",
budget: {
limit: 2000,
},
promotions: [{ id: createdPromotion2.id }],
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.campaign).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "test-2",
campaign_identifier: "test-2",
budget: expect.objectContaining({
limit: 2000,
type: "usage",
used: 10,
}),
promotions: [
expect.objectContaining({
id: createdPromotion2.id,
}),
],
})
)
})
})

View File

@@ -1,192 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IPromotionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { PromotionType } from "@medusajs/utils"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/promotions/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should throw an error if id does not exist", async () => {
const api = useApi() as any
const { response } = await api
.post(
`/admin/promotions/does-not-exist`,
{ type: PromotionType.STANDARD },
adminHeaders
)
.catch((e) => e)
expect(response.status).toEqual(404)
expect(response.data.message).toEqual(
`Promotion with id "does-not-exist" not found`
)
})
it("should throw an error when both campaign and campaign_id params are passed", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: PromotionType.STANDARD,
is_automatic: true,
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
},
})
const api = useApi() as any
const { response } = await api
.post(
`/admin/promotions/${createdPromotion.id}`,
{
campaign: {
name: "test campaign",
},
campaign_id: "test",
},
adminHeaders
)
.catch((e) => e)
expect(response.status).toEqual(400)
expect(response.data.message).toContain(
`Failed XOR relation between "campaign_id" and "campaign"`
)
})
it("should update a promotion successfully", async () => {
const createdPromotion = await promotionModuleService.create({
code: "TEST",
type: PromotionType.STANDARD,
is_automatic: true,
application_method: {
target_type: "items",
type: "fixed",
allocation: "each",
value: "100",
max_quantity: 100,
},
})
const api = useApi() as any
const response = await api.post(
`/admin/promotions/${createdPromotion.id}`,
{
code: "TEST_TWO",
application_method: {
value: "200",
},
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual(
expect.objectContaining({
id: expect.any(String),
code: "TEST_TWO",
application_method: expect.objectContaining({
value: 200,
}),
})
)
})
it("should update a buyget promotion successfully", async () => {
const createdPromotion = await promotionModuleService.create({
code: "PROMOTION_TEST",
type: PromotionType.BUYGET,
application_method: {
type: "fixed",
target_type: "items",
allocation: "across",
value: "100",
apply_to_quantity: 1,
buy_rules_min_quantity: 1,
buy_rules: [
{
attribute: "product_collection.id",
operator: "eq",
values: ["pcol_towel"],
},
],
target_rules: [
{
attribute: "product.id",
operator: "eq",
values: "prod_mat",
},
],
},
})
const api = useApi() as any
const response = await api.post(
`/admin/promotions/${createdPromotion.id}`,
{
code: "TEST_TWO",
application_method: {
value: "200",
buy_rules_min_quantity: 6,
},
},
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.promotion).toEqual(
expect.objectContaining({
id: expect.any(String),
code: "TEST_TWO",
application_method: expect.objectContaining({
value: 200,
buy_rules_min_quantity: 6,
}),
})
)
})
})

View File

@@ -1,223 +0,0 @@
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { IRegionModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("Regions - Admin", () => {
let dbConnection
let appContainer
let shutdownServer
let service: IRegionModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.REGION)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
await service.createDefaultCountries()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should create, update, and delete a region", async () => {
const api = useApi() as any
const created = await api.post(
`/admin/regions`,
{
name: "Test Region",
currency_code: "usd",
countries: ["us", "ca"],
metadata: { foo: "bar" },
},
adminHeaders
)
expect(created.status).toEqual(200)
expect(created.data.region).toEqual(
expect.objectContaining({
id: created.data.region.id,
name: "Test Region",
currency_code: "usd",
metadata: { foo: "bar" },
})
)
expect(created.data.region.countries.map((c) => c.iso_2)).toEqual([
"us",
"ca",
])
const updated = await api.post(
`/admin/regions/${created.data.region.id}`,
{
name: "United States",
currency_code: "usd",
countries: ["us"],
metadata: { foo: "baz" },
},
adminHeaders
)
expect(updated.status).toEqual(200)
expect(updated.data.region).toEqual(
expect.objectContaining({
id: updated.data.region.id,
name: "United States",
currency_code: "usd",
metadata: { foo: "baz" },
})
)
expect(updated.data.region.countries.map((c) => c.iso_2)).toEqual(["us"])
const deleted = await api.delete(
`/admin/regions/${updated.data.region.id}`,
adminHeaders
)
expect(deleted.status).toEqual(200)
expect(deleted.data).toEqual({
id: updated.data.region.id,
object: "region",
deleted: true,
})
const deletedRegion = await service.retrieve(updated.data.region.id, {
withDeleted: true,
})
// @ts-ignore
expect(deletedRegion.deleted_at).toBeTruthy()
})
it("should throw on missing required properties in create", async () => {
const api = useApi() as any
const err = await api
.post(`/admin/regions`, {}, adminHeaders)
.catch((e) => e)
expect(err.response.status).toEqual(400)
expect(err.response.data.message).toEqual(
"name must be a string, currency_code must be a string"
)
})
it("should throw on unknown properties in create", async () => {
const api = useApi() as any
const error = await api
.post(
`/admin/regions`,
{
foo: "bar",
currency_code: "usd",
name: "Test Region",
},
adminHeaders
)
.catch((e) => e)
expect(error.response.status).toEqual(400)
expect(error.response.data.message).toEqual("property foo should not exist")
})
it("should throw on unknown properties in update", async () => {
const api = useApi() as any
const created = await service.create({
name: "Test Region",
currency_code: "usd",
})
const error = await api
.post(
`/admin/regions/${created.id}`,
{
foo: "bar",
currency_code: "usd",
name: "Test Region",
},
adminHeaders
)
.catch((e) => e)
expect(error.response.status).toEqual(400)
expect(error.response.data.message).toEqual("property foo should not exist")
})
it("should get all regions and count", async () => {
await service.create([
{
name: "Test",
currency_code: "usd",
countries: ["jp"],
metadata: { foo: "bar" },
},
])
const api = useApi() as any
const response = await api.get(`/admin/regions`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.regions).toEqual([
expect.objectContaining({
id: expect.any(String),
name: "Test",
currency_code: "usd",
metadata: { foo: "bar" },
}),
])
expect(response.data.regions[0].countries.map((c) => c.iso_2)).toEqual([
"jp",
])
})
it("should get a region", async () => {
const [region] = await service.create([
{
name: "Test",
currency_code: "usd",
countries: ["jp"],
metadata: { foo: "bar" },
},
])
const api = useApi() as any
const response = await api.get(`/admin/regions/${region.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.region).toEqual(
expect.objectContaining({
id: region.id,
name: "Test",
currency_code: "usd",
metadata: { foo: "bar" },
})
)
expect(response.data.region.countries.map((c) => c.iso_2)).toEqual(["jp"])
})
})

View File

@@ -1,139 +0,0 @@
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { getContainer } from "../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../environment-helpers/use-db"
jest.setTimeout(30000)
describe("product", () => {
let medusaContainer
let productService
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
await initDb({ cwd })
shutdownServer = shutdownServer = await startBootstrapApp({ cwd })
medusaContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
jest.clearAllMocks()
const db = useDb()
await db.teardown()
})
describe("product service", () => {
it("should create variant prices correctly in service creation", async () => {
productService = medusaContainer.resolve("productService")
const payload = {
title: "test-product",
handle: "test-product",
options: [{ title: "test-option" }],
variants: [
{
title: "test-variant",
inventory_quantity: 10,
sku: "test",
options: [{ value: "large", title: "test-option" }],
prices: [{ amount: "100", currency_code: "usd" }],
},
],
}
const { id } = await productService.create(payload)
const result = await productService.retrieve(id, {
relations: ["variants", "variants.prices", "variants.options"],
})
expect(result).toEqual(
expect.objectContaining({
variants: [
expect.objectContaining({
options: [expect.objectContaining({ value: "large" })],
prices: [
expect.objectContaining({ amount: 100, currency_code: "usd" }),
],
}),
],
})
)
})
it("should fail to create a variant without options on for a product with options", async () => {
const payload = {
title: "test-product",
handle: "test-product",
options: [{ title: "test-option" }],
variants: [
{
title: "test-variant",
inventory_quantity: 10,
sku: "test",
prices: [{ amount: "100", currency_code: "usd" }],
},
],
}
let error
try {
await productService.create(payload)
} catch (err) {
error = err
}
expect(error.message).toEqual(
"Product options length does not match variant options length. Product has 1 and variant has 0."
)
})
it("should create a product and variant without options", async () => {
const payload = {
title: "test-product",
handle: "test-product",
variants: [
{
title: "test-variant",
inventory_quantity: 10,
sku: "test",
prices: [{ amount: "100", currency_code: "usd" }],
},
],
}
const { id } = await productService.create(payload)
const result = await productService.retrieve(id, {
relations: [
"options",
"variants",
"variants.prices",
"variants.options",
],
})
expect(result).toEqual(
expect.objectContaining({
options: [],
variants: [
expect.objectContaining({
prices: [
expect.objectContaining({ amount: 100, currency_code: "usd" }),
],
}),
],
})
)
})
})
})

View File

@@ -1,81 +0,0 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IStoreModuleService } from "@medusajs/types"
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 { DataSource } from "typeorm"
import { createAdminUser } from "../../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("Store - Admin", () => {
let dbConnection: DataSource
let appContainer
let shutdownServer
let service: IStoreModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.STORE)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
const existingStores = await service.list({})
await service.delete(existingStores.map((s) => s.id))
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly implement the entire lifecycle of a store", async () => {
const api = useApi() as any
const createdStore = await service.create({ name: "Test store" })
expect(createdStore).toEqual(
expect.objectContaining({
id: createdStore.id,
name: "Test store",
})
)
const updated = await api.post(
`/admin/stores/${createdStore.id}`,
{
name: "Updated store",
},
adminHeaders
)
expect(updated.status).toEqual(200)
expect(updated.data.store).toEqual(
expect.objectContaining({
id: createdStore.id,
name: "Updated store",
})
)
await service.delete(createdStore.id)
const listedStores = await api.get(`/admin/stores`, adminHeaders)
expect(listedStores.data.stores).toHaveLength(0)
})
})

View File

@@ -1,376 +0,0 @@
import path from "path"
import { ITaxModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../../helpers/create-admin-user"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { getContainer } from "../../../../environment-helpers/use-container"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("Taxes - Admin", () => {
let dbConnection
let appContainer
let shutdownServer
let service: ITaxModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.TAX)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("can retrieve a tax rate", async () => {
const region = await service.createTaxRegions({
country_code: "us",
})
const rate = await service.create({
tax_region_id: region.id,
code: "test",
rate: 2.5,
name: "Test Rate",
})
const api = useApi() as any
const response = await api.get(`/admin/tax-rates/${rate.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
tax_rate: {
id: rate.id,
code: "test",
rate: 2.5,
name: "Test Rate",
metadata: null,
tax_region_id: region.id,
is_default: false,
is_combinable: false,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: null,
},
})
})
it("can create a tax region with rates and rules", async () => {
const api = useApi() as any
const regionRes = await api.post(
`/admin/tax-regions`,
{
country_code: "us",
default_tax_rate: {
code: "default",
rate: 2,
name: "default rate",
},
},
adminHeaders
)
const usRegionId = regionRes.data.tax_region.id
expect(regionRes.status).toEqual(200)
expect(regionRes.data).toEqual({
tax_region: {
id: expect.any(String),
country_code: "us",
parent_id: null,
province_code: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
provider_id: null,
metadata: null,
},
})
const rateRes = await api.post(
`/admin/tax-rates`,
{
tax_region_id: usRegionId,
code: "RATE2",
name: "another rate",
rate: 10,
rules: [{ reference: "product", reference_id: "prod_1234" }],
},
adminHeaders
)
expect(rateRes.status).toEqual(200)
expect(rateRes.data).toEqual({
tax_rate: {
id: expect.any(String),
code: "RATE2",
rate: 10,
name: "another rate",
is_default: false,
metadata: null,
tax_region_id: usRegionId,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
is_combinable: false,
},
})
const provRegRes = await api.post(
`/admin/tax-regions`,
{
country_code: "US",
parent_id: usRegionId,
province_code: "cA",
},
adminHeaders
)
expect(provRegRes.status).toEqual(200)
expect(provRegRes.data).toEqual({
tax_region: {
id: expect.any(String),
country_code: "us",
parent_id: usRegionId,
province_code: "ca",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
metadata: null,
provider_id: null,
},
})
const defRes = await api.post(
`/admin/tax-rates`,
{
tax_region_id: provRegRes.data.tax_region.id,
code: "DEFAULT",
name: "DEFAULT",
rate: 10,
is_default: true,
},
adminHeaders
)
const listRes = await api.get(`/admin/tax-rates`, adminHeaders)
expect(listRes.status).toEqual(200)
expect(listRes.data.tax_rates).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: rateRes.data.tax_rate.id,
code: "RATE2",
rate: 10,
name: "another rate",
is_default: false,
metadata: null,
tax_region_id: usRegionId,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
}),
expect.objectContaining({ id: defRes.data.tax_rate.id }),
expect.objectContaining({
tax_region_id: usRegionId,
is_default: true,
rate: 2,
}),
])
)
})
it("can create a tax rate and update it", async () => {
const api = useApi() as any
const regionRes = await api.post(
`/admin/tax-regions`,
{
country_code: "us",
default_tax_rate: { code: "default", rate: 2, name: "default rate" },
},
adminHeaders
)
const usRegionId = regionRes.data.tax_region.id
expect(regionRes.status).toEqual(200)
expect(regionRes.data).toEqual({
tax_region: {
id: expect.any(String),
country_code: "us",
parent_id: null,
province_code: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
provider_id: null,
metadata: null,
},
})
const rateRes = await api.post(
`/admin/tax-rates`,
{
tax_region_id: usRegionId,
code: "RATE2",
name: "another rate",
rate: 10,
rules: [{ reference: "product", reference_id: "prod_1234" }],
},
adminHeaders
)
expect(rateRes.status).toEqual(200)
expect(rateRes.data).toEqual({
tax_rate: {
id: expect.any(String),
code: "RATE2",
rate: 10,
name: "another rate",
is_default: false,
metadata: null,
tax_region_id: usRegionId,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
is_combinable: false,
},
})
const updateRes = await api.post(
`/admin/tax-rates/${rateRes.data.tax_rate.id}`,
{
code: "updatedcode",
rate: 12,
is_combinable: true,
name: "Another Name",
metadata: { you: "know it" },
},
adminHeaders
)
expect(updateRes.status).toEqual(200)
expect(updateRes.data).toEqual({
tax_rate: {
id: expect.any(String),
code: "updatedcode",
rate: 12,
name: "Another Name",
is_default: false,
metadata: { you: "know it" },
tax_region_id: usRegionId,
deleted_at: null,
created_at: expect.any(String),
updated_at: expect.any(String),
created_by: "admin_user",
is_combinable: true,
},
})
})
it("can create a tax rate and delete it", async () => {
const api = useApi() as any
const regionRes = await api.post(
`/admin/tax-regions`,
{
country_code: "us",
default_tax_rate: { code: "default", rate: 2, name: "default rate" },
},
adminHeaders
)
const usRegionId = regionRes.data.tax_region.id
const rateRes = await api.post(
`/admin/tax-rates`,
{
tax_region_id: usRegionId,
code: "RATE2",
name: "another rate",
rate: 10,
rules: [{ reference: "product", reference_id: "prod_1234" }],
},
adminHeaders
)
const deleteRes = await api.delete(
`/admin/tax-rates/${rateRes.data.tax_rate.id}`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
expect(deleteRes.data).toEqual({
id: rateRes.data.tax_rate.id,
object: "tax_rate",
deleted: true,
})
const rates = await service.list(
{ id: rateRes.data.tax_rate.id },
{ withDeleted: true }
)
expect(rates.length).toEqual(1)
expect(rates[0].deleted_at).not.toBeNull()
})
it("can create a tax region and delete it", async () => {
const api = useApi() as any
const regionRes = await api.post(
`/admin/tax-regions`,
{
country_code: "us",
default_tax_rate: { code: "default", rate: 2, name: "default rate" },
},
adminHeaders
)
const usRegionId = regionRes.data.tax_region.id
const deleteRes = await api.delete(
`/admin/tax-regions/${usRegionId}`,
adminHeaders
)
expect(deleteRes.status).toEqual(200)
expect(deleteRes.data).toEqual({
id: usRegionId,
object: "tax_region",
deleted: true,
})
const rates = await service.listTaxRegions(
{ id: usRegionId },
{ withDeleted: true }
)
expect(rates.length).toEqual(1)
expect(rates[0].deleted_at).not.toBeNull()
})
})

View File

@@ -1,55 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { createAdminUser } from "../../helpers/create-admin-user"
import path from "path"
import { startBootstrapApp } from "../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../environment-helpers/use-api"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/users", () => {
let dbConnection
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("create a user", async () => {
const api = useApi()! as AxiosInstance
const body = {
email: "test_member@test.com",
}
const response = await api.post(`/admin/users`, body, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
user: expect.objectContaining(body),
})
})
})

View File

@@ -1,71 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("DELETE /admin/users/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should delete a single user", async () => {
const user = await userModuleService.create({
email: "member@test.com",
})
const api = useApi()! as AxiosInstance
const response = await api.delete(`/admin/users/${user.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
id: user.id,
object: "user",
deleted: true,
})
const { response: deletedResponse } = await api
.get(`/admin/users/${user.id}`, adminHeaders)
.catch((e) => e)
expect(deletedResponse.status).toEqual(404)
expect(deletedResponse.data.type).toEqual("not_found")
})
})

View File

@@ -1,72 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/users", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should list users", async () => {
await userModuleService.create([
{
email: "member@test.com",
},
])
const api = useApi()! as AxiosInstance
const response = await api.get(`/admin/users`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
users: expect.arrayContaining([
expect.objectContaining({
email: "admin@medusa.js",
}),
expect.objectContaining({ email: "member@test.com" }),
]),
count: 2,
offset: 0,
limit: 50,
})
})
})

View File

@@ -1,62 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("GET /admin/users/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should retrieve a single user", async () => {
const user = await userModuleService.create({
email: "member@test.com",
})
const api = useApi()! as AxiosInstance
const response = await api.get(`/admin/users/${user.id}`, adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.user).toEqual(
expect.objectContaining({ email: "member@test.com" })
)
})
})

View File

@@ -1,68 +0,0 @@
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import { IUserModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("POST /admin/users/:id", () => {
let dbConnection
let appContainer
let shutdownServer
let userModuleService: IUserModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
userModuleService = appContainer.resolve(ModuleRegistrationName.USER)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should update a single user", async () => {
const user = await userModuleService.create({
email: "member@test.com",
})
const api = useApi()! as AxiosInstance
const body = {
first_name: "John",
last_name: "Doe",
}
const response = await api.post(
`/admin/users/${user.id}`,
body,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.user).toEqual(expect.objectContaining(body))
})
})

View File

@@ -1,9 +0,0 @@
import { workflowEngineTestSuite } from "./tests"
jest.setTimeout(5000000)
const env = {
MEDUSA_FF_MEDUSA_V2: false,
}
workflowEngineTestSuite(env, { force_modules_migration: true })

View File

@@ -1,9 +0,0 @@
import { workflowEngineTestSuite } from "./tests"
jest.setTimeout(5000000)
const env = {
MEDUSA_FF_MEDUSA_V2: true,
}
workflowEngineTestSuite(env)

View File

@@ -1,274 +0,0 @@
import {
createStep,
createWorkflow,
StepResponse,
WorkflowData,
} from "@medusajs/workflows-sdk"
import { initDb, useDb } from "../../../environment-helpers/use-db"
import { AxiosInstance } from "axios"
import adminSeeder from "../../../helpers/admin-seeder"
import { createAdminUser } from "../../helpers/create-admin-user"
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"
export const workflowEngineTestSuite = (env, extraParams = {}) => {
const adminHeaders = {
headers: {
"x-medusa-access-token": "test_token",
},
}
describe("Workflow Engine API", () => {
let medusaContainer
let dbConnection
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd, env, ...extraParams } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
medusaContainer = getContainer()
await createAdminUser(dbConnection, adminHeaders)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
describe("running workflows", () => {
beforeAll(async () => {
const step1 = createStep(
{
name: "my-step",
},
async (input: { initial: string }) => {
return new StepResponse({
result: input.initial,
})
}
)
const step2 = createStep(
{
name: "my-step-async",
async: true,
},
async () => {}
)
createWorkflow(
{
name: "my-workflow-name",
retentionTime: 1000,
},
function (input: WorkflowData<{ initial: string }>) {
step1(input)
return step2()
}
)
})
it("Should list all workflows in execution or completed and retrieve them by id", async () => {
const api = useApi()! as AxiosInstance
for (let i = 3; i--; ) {
await api.post(
`/admin/workflows-executions/my-workflow-name/run`,
{
input: {
initial: "abc",
},
},
adminHeaders
)
}
const executions = await api.get(
`/admin/workflows-executions`,
adminHeaders
)
expect(executions.data.count).toEqual(3)
expect(executions.data.workflow_executions.length).toEqual(3)
expect(executions.data.workflow_executions[0]).toEqual({
workflow_id: "my-workflow-name",
transaction_id: expect.any(String),
id: expect.any(String),
state: "invoking",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
})
const retrivedById = await api.get(
`/admin/workflows-executions/` +
executions.data.workflow_executions[0].id,
adminHeaders
)
expect(retrivedById.data.workflow_execution).toEqual(
expect.objectContaining(executions.data.workflow_executions[0])
)
})
it("Should list all workflows matching the filters", async () => {
const api = useApi()! as AxiosInstance
for (let i = 3; i--; ) {
await api.post(
`/admin/workflows-executions/my-workflow-name/run`,
{
input: {
initial: "abc",
},
transaction_id: "transaction_" + (i + 1),
},
adminHeaders
)
}
const executions = await api.get(
`/admin/workflows-executions?transaction_id[]=transaction_1&transaction_id[]=transaction_2`,
adminHeaders
)
expect(executions.data.count).toEqual(2)
expect(executions.data.workflow_executions.length).toEqual(2)
expect(executions.data.workflow_executions[0]).toEqual({
workflow_id: "my-workflow-name",
transaction_id: expect.stringMatching(/transaction_1|transaction_2/),
id: expect.any(String),
state: "invoking",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
})
expect(executions.data.workflow_executions[1]).toEqual({
workflow_id: "my-workflow-name",
transaction_id: expect.stringMatching(/transaction_1|transaction_2/),
id: expect.any(String),
state: "invoking",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
})
})
it("Should execute a workflow and retrieve its execution while running and when it is completed", async () => {
const api = useApi()! as AxiosInstance
const wf = await api.post(
`/admin/workflows-executions/my-workflow-name/run`,
{
input: {
initial: "abc",
},
transaction_id: "trx_123",
},
adminHeaders
)
expect(wf.data).toEqual({
acknowledgement: {
transactionId: "trx_123",
workflowId: "my-workflow-name",
},
})
const execution = await api.get(
`/admin/workflows-executions/my-workflow-name/trx_123`,
adminHeaders
)
expect(execution.data).toEqual({
workflow_execution: expect.objectContaining({
workflow_id: "my-workflow-name",
transaction_id: "trx_123",
id: expect.any(String),
state: "invoking",
execution: expect.objectContaining({
hasAsyncSteps: true,
hasFailedSteps: false,
hasSkippedSteps: false,
hasWaitingSteps: false,
hasRevertedSteps: false,
}),
context: expect.objectContaining({
data: expect.objectContaining({
invoke: {
"my-step": {
__type: "Symbol(WorkflowWorkflowData)",
output: {
__type: "Symbol(WorkflowStepResponse)",
output: {
result: "abc",
},
compensateInput: {
result: "abc",
},
},
},
},
payload: {
initial: "abc",
},
}),
}),
}),
})
const respondAsync = await api.post(
`/admin/workflows-executions/my-workflow-name/steps/success`,
{
transaction_id: "trx_123",
step_id: "my-step-async",
response: {
all: "good",
},
},
adminHeaders
)
expect(respondAsync.data.success).toEqual(true)
const completed = await api.get(
`/admin/workflows-executions/my-workflow-name/trx_123`,
adminHeaders
)
expect(completed.data).toEqual({
workflow_execution: expect.objectContaining({
workflow_id: "my-workflow-name",
transaction_id: "trx_123",
state: "done",
context: expect.objectContaining({
data: expect.objectContaining({
invoke: expect.objectContaining({
"my-step-async": {
__type: "Symbol(WorkflowStepResponse)",
output: {
all: "good",
},
compensateInput: {
all: "good",
},
},
}),
}),
}),
}),
})
})
})
})
}
describe("Noop test", () => {
it("noop check", async () => {
expect(true).toBe(true)
})
})