Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(medusa): Shipping profile CRUD #3154

Merged
merged 16 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mean-ghosts-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---

fix(medusa): Fixes payloads associated with shipping profile requests, as well as fixes to the shippingProfileService. Also adds test suite for shipping profiles.
346 changes: 346 additions & 0 deletions integration-tests/api/__tests__/admin/shipping-profile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
const path = require("path")
kasperkristensen marked this conversation as resolved.
Show resolved Hide resolved

const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api")
const { initDb, useDb } = require("../../../helpers/use-db")
const {
simpleProductFactory,
simpleShippingOptionFactory,
simpleShippingProfileFactory,
} = require("../../factories")
const adminSeeder = require("../../helpers/admin-seeder")

const adminReqConfig = {
headers: {
Authorization: "Bearer test_token",
},
}

jest.setTimeout(30000)

describe("/admin/shipping-profiles", () => {
let medusaProcess
let dbConnection

beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd, verbose: false })
})

afterAll(async () => {
const db = useDb()
await db.shutdown()

medusaProcess.kill()
})

describe("GET /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})

afterEach(async () => {
const db = useDb()
await db.teardown()
})

it("lists shipping profiles", async () => {
const api = useApi()

const {
data: { shipping_profiles },
status,
} = await api.get("/admin/shipping-profiles", adminReqConfig)

expect(status).toEqual(200)

// Should contain default and gift_card profiles
expect(shipping_profiles.length).toEqual(2)
})

it("gets a shipping profile by id", async () => {
const api = useApi()

const profile = await simpleShippingProfileFactory(dbConnection)

const {
data: { shipping_profile },
status,
} = await api.get(
`/admin/shipping-profiles/${profile.id}`,
adminReqConfig
)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
...profile,
updated_at: expect.any(String),
created_at: expect.any(String),
})
)
})
})

describe("POST /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})

afterEach(async () => {
const db = useDb()
await db.teardown()
})

it("creates a custom shipping profile", async () => {
const api = useApi()

const payload = {
name: "test-profile-2023",
type: "custom",
}

const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})

it("creates a default shipping profile", async () => {
const api = useApi()

const payload = {
name: "test-profile-2023",
type: "default",
}

const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})

it("creates a gift_card shipping profile", async () => {
const api = useApi()

const payload = {
name: "test-profile-2023",
type: "gift_card",
}

const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})

it("creates a shipping profile with metadata", async () => {
const api = useApi()

const payload = {
name: "test-profile-2023",
type: "default",
metadata: {
custom_key: "custom_value",
},
}

const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})

it("fails to create a shipping profile with invalid type", async () => {
const api = useApi()
expect.assertions(2)

const payload = {
name: "test-profile-2023",
type: "invalid",
}

await api
.post("/admin/shipping-profiles", payload, adminReqConfig)
.catch((err) => {
expect(err.response.status).toEqual(400)
expect(err.response.data.message).toEqual(
"type must be one of 'default', 'custom', 'gift_card'"
)
})
})

it("updates a shipping profile", async () => {
const api = useApi()

const testProducts = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleProductFactory(dbConnection)
})
)

const testShippingOptions = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleShippingOptionFactory(dbConnection)
})
)

const payload = {
name: "test-profile-2023",
type: "custom",
metadata: {
my_key: "my_value",
},
}

const {
data: { shipping_profile: created },
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)

const updatePayload = {
name: "test-profile-2023-updated",
products: testProducts.map((p) => p.id),
shipping_options: testShippingOptions.map((o) => o.id),
metadata: {
my_key: "",
my_new_key: "my_new_value",
},
}

const {
data: { shipping_profile },
status,
} = await api.post(
`/admin/shipping-profiles/${created.id}`,
updatePayload,
adminReqConfig
)

expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
name: "test-profile-2023-updated",
created_at: expect.any(String),
updated_at: expect.any(String),
metadata: {
my_new_key: "my_new_value",
},
deleted_at: null,
type: "custom",
})
)

const {
data: { products },
} = await api.get(`/admin/products`, adminReqConfig)

expect(products.length).toEqual(5)
expect(products).toEqual(
expect.arrayContaining(
testProducts.map((p) => {
return expect.objectContaining({
id: p.id,
profile_id: shipping_profile.id,
})
})
)
)

const {
data: { shipping_options },
} = await api.get(`/admin/shipping-options`, adminReqConfig)

const numberOfShippingOptionsWithProfile = shipping_options.filter(
(so) => so.profile_id === shipping_profile.id
).length

expect(numberOfShippingOptionsWithProfile).toEqual(5)
expect(shipping_options).toEqual(
expect.arrayContaining(
testShippingOptions.map((o) => {
return expect.objectContaining({
id: o.id,
profile_id: shipping_profile.id,
})
})
)
)
})
})

describe("DELETE /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})

afterEach(async () => {
const db = useDb()
await db.teardown()
})

it("deletes a shipping profile", async () => {
expect.assertions(2)

const api = useApi()

const profile = await simpleShippingProfileFactory(dbConnection)

const { status } = await api.delete(
`/admin/shipping-profiles/${profile.id}`,
adminReqConfig
)

expect(status).toEqual(200)
await api
.get(`/admin/shipping-profiles/${profile.id}`, adminReqConfig)
.catch((err) => {
expect(err.response.status).toEqual(404)
})
})
})
})
36 changes: 18 additions & 18 deletions integration-tests/api/factories/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
export * from "./simple-gift-card-factory"
export * from "./simple-payment-factory"
export * from "./simple-batch-job-factory"
export * from "./simple-discount-factory"
export * from "./simple-order-factory"
export * from "./simple-cart-factory"
export * from "./simple-region-factory"
export * from "./simple-custom-shipping-option-factory"
export * from "./simple-customer-factory"
export * from "./simple-discount-factory"
export * from "./simple-gift-card-factory"
export * from "./simple-line-item-factory"
export * from "./simple-order-edit-factory"
export * from "./simple-order-factory"
export * from "./simple-order-item-change-factory"
export * from "./simple-payment-collection-factory"
export * from "./simple-payment-factory"
export * from "./simple-price-list-factory"
export * from "./simple-product-category-factory"
export * from "./simple-product-factory"
export * from "./simple-product-variant-factory"
export * from "./simple-product-tax-rate-factory"
export * from "./simple-shipping-tax-rate-factory"
export * from "./simple-tax-rate-factory"
export * from "./simple-shipping-option-factory"
export * from "./simple-shipping-method-factory"
export * from "./simple-product-type-tax-rate-factory"
export * from "./simple-price-list-factory"
export * from "./simple-batch-job-factory"
export * from "./simple-product-variant-factory"
export * from "./simple-region-factory"
export * from "./simple-sales-channel-factory"
export * from "./simple-custom-shipping-option-factory"
export * from "./simple-payment-collection-factory"
export * from "./simple-order-edit-factory"
export * from "./simple-order-item-change-factory"
export * from "./simple-customer-factory"
export * from "./simple-product-category-factory"
export * from "./simple-shipping-method-factory"
export * from "./simple-shipping-option-factory"
export * from "./simple-shipping-profile-factory"
export * from "./simple-shipping-tax-rate-factory"
export * from "./simple-tax-rate-factory"