fix(core-flows, medusa): Prevent cart addresses duplication on update (#13841)

* Allow id field in addresses properties for cart update validator

* Update cart addresses in update step where id is provided, both reference and nested fields

* Add tests

* Add changeset

* Remove unnecessary map step

* Review changes
This commit is contained in:
Nicolas Gorga
2025-12-09 21:49:16 -03:00
committed by GitHub
parent 4dbf46f2cb
commit fdc2b722d9
4 changed files with 337 additions and 5 deletions

View File

@@ -1444,6 +1444,290 @@ medusaIntegrationTestRunner({
)
expect(cart.items?.length).toEqual(1)
})
it("should update cart shipping address fields", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
const regions = await regionModuleService.createRegions([
{
name: "US",
currency_code: "usd",
countries: ["us"],
},
])
let cart = await cartModuleService.createCarts({
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: regions[0].id,
shipping_address: {
first_name: "John",
last_name: "Doe",
address_1: "123 Main St",
city: "New York",
country_code: "us",
postal_code: "10001",
},
})
const shippingAddressId = cart.shipping_address?.id
await updateCartWorkflow(appContainer).run({
input: {
id: cart.id,
shipping_address: {
id: shippingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
},
},
})
cart = await cartModuleService.retrieveCart(cart.id, {
relations: ["shipping_address"],
})
expect(cart.shipping_address).toEqual(
expect.objectContaining({
id: shippingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
})
)
})
it("should update cart billing address fields", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
const regions = await regionModuleService.createRegions([
{
name: "US",
currency_code: "usd",
countries: ["us"],
},
])
let cart = await cartModuleService.createCarts({
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: regions[0].id,
billing_address: {
first_name: "John",
last_name: "Doe",
address_1: "123 Main St",
city: "New York",
country_code: "us",
postal_code: "10001",
},
})
const billingAddressId = cart.billing_address?.id
await updateCartWorkflow(appContainer).run({
input: {
id: cart.id,
billing_address: {
id: billingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
},
},
})
cart = await cartModuleService.retrieveCart(cart.id, {
relations: ["billing_address"],
})
expect(cart.billing_address).toEqual(
expect.objectContaining({
id: billingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
})
)
})
it("should update both shipping and billing addresses simultaneously", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
const regions = await regionModuleService.createRegions([
{
name: "US",
currency_code: "usd",
countries: ["us"],
},
])
let cart = await cartModuleService.createCarts({
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: regions[0].id,
shipping_address: {
first_name: "John",
last_name: "Doe",
address_1: "123 Main St",
city: "New York",
country_code: "us",
postal_code: "10001",
},
billing_address: {
first_name: "John",
last_name: "Doe",
address_1: "789 Business Blvd",
city: "Chicago",
country_code: "us",
postal_code: "60601",
},
})
const shippingAddressId = cart.shipping_address?.id
const billingAddressId = cart.billing_address?.id
await updateCartWorkflow(appContainer).run({
input: {
id: cart.id,
shipping_address: {
id: shippingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
},
billing_address: {
id: billingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "321 Corporate Dr",
city: "San Francisco",
country_code: "us",
postal_code: "94102",
},
},
})
cart = await cartModuleService.retrieveCart(cart.id, {
relations: ["shipping_address", "billing_address"],
})
expect(cart.shipping_address).toEqual(
expect.objectContaining({
id: shippingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
postal_code: "90001",
})
)
expect(cart.billing_address).toEqual(
expect.objectContaining({
id: billingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "321 Corporate Dr",
city: "San Francisco",
postal_code: "94102",
})
)
})
it("should rollback address updates on workflow failure", async () => {
const salesChannel = await scModuleService.createSalesChannels({
name: "Webshop",
})
const regions = await regionModuleService.createRegions([
{
name: "US",
currency_code: "usd",
countries: ["us"],
},
])
let cart = await cartModuleService.createCarts({
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: regions[0].id,
shipping_address: {
first_name: "John",
last_name: "Doe",
address_1: "123 Main St",
city: "New York",
country_code: "us",
postal_code: "10001",
},
})
const originalShippingAddress = { ...cart.shipping_address }
const shippingAddressId = cart.shipping_address?.id
const workflow = updateCartWorkflow(appContainer)
workflow.appendAction("throw", "update-carts", {
invoke: async function failStep() {
throw new Error("Simulated failure")
},
})
const { errors } = await workflow.run({
input: {
id: cart.id,
shipping_address: {
id: shippingAddressId,
first_name: "Jane",
last_name: "Smith",
address_1: "456 Oak Ave",
city: "Los Angeles",
country_code: "us",
postal_code: "90001",
},
},
throwOnError: false,
})
expect(errors).toBeDefined()
expect(errors?.length).toBeGreaterThan(0)
cart = await cartModuleService.retrieveCart(cart.id, {
relations: ["shipping_address"],
})
expect(cart.shipping_address).toEqual(
expect.objectContaining({
id: shippingAddressId,
first_name: originalShippingAddress.first_name,
last_name: originalShippingAddress.last_name,
address_1: originalShippingAddress.address_1,
city: originalShippingAddress.city,
postal_code: originalShippingAddress.postal_code,
})
)
})
})
describe("AddToCartWorkflow", () => {