@yoryoboy/bi-mcp 1.10.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.js +398 -8
- package/dist/index.js.map +2 -2
- package/dist/mcp-use.json +2 -2
- package/dist/src/config/__tests__/meta.test.js +35 -0
- package/dist/src/config/__tests__/meta.test.js.map +7 -0
- package/dist/src/config/mercadolibre-profile-store.js +25 -0
- package/dist/src/config/mercadolibre-profile-store.js.map +2 -2
- package/dist/src/config/meta-store.js +109 -0
- package/dist/src/config/meta-store.js.map +7 -0
- package/dist/src/config/meta.js +0 -2
- package/dist/src/config/meta.js.map +2 -2
- package/dist/src/meta/__tests__/meta-utils.test.js +155 -0
- package/dist/src/meta/__tests__/meta-utils.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +265 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js +311 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js.map +7 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +220 -0
- package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +7 -0
- package/dist/src/services/meta/__tests__/meta-ads.test.js +126 -0
- package/dist/src/services/meta/__tests__/meta-ads.test.js.map +7 -0
- package/dist/src/services/meta/__tests__/meta-api.test.js +70 -0
- package/dist/src/services/meta/__tests__/meta-api.test.js.map +7 -0
- package/dist/src/services/meta/meta-ads.js +94 -40
- package/dist/src/services/meta/meta-ads.js.map +2 -2
- package/dist/src/services/meta/meta-api.js +8 -6
- package/dist/src/services/meta/meta-api.js.map +2 -2
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +165 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js +92 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js +41 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog.test.js +80 -0
- package/dist/src/services/vtex/__tests__/vtex-catalog.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js +85 -0
- package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js +251 -0
- package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js.map +7 -0
- package/dist/src/services/vtex/__tests__/vtex-write.test.js +111 -0
- package/dist/src/services/vtex/__tests__/vtex-write.test.js.map +7 -0
- package/dist/src/services/vtex/vtex-catalog-write.js +194 -1
- package/dist/src/services/vtex/vtex-catalog-write.js.map +2 -2
- package/dist/src/services/vtex/vtex-catalog.js +118 -1
- package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
- package/dist/src/services/vtex/vtex-pricing-write.js +5 -0
- package/dist/src/services/vtex/vtex-pricing-write.js.map +2 -2
- package/dist/src/services/vtex/vtex-write.js +67 -1
- package/dist/src/services/vtex/vtex-write.js.map +2 -2
- package/dist/src/tools/config/list-profiles.js +85 -11
- package/dist/src/tools/config/list-profiles.js.map +2 -2
- package/dist/src/tools/index.js.map +2 -2
- package/dist/src/tools/mercadolibre/__tests__/helpers.test.js +37 -0
- package/dist/src/tools/mercadolibre/__tests__/helpers.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js +30 -0
- package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js.map +7 -0
- package/dist/src/tools/mercadolibre/profile-resolution.js +4 -50
- package/dist/src/tools/mercadolibre/profile-resolution.js.map +2 -2
- package/dist/src/tools/meta/__tests__/pagination.test.js +133 -0
- package/dist/src/tools/meta/__tests__/pagination.test.js.map +7 -0
- package/dist/src/tools/meta/__tests__/profile-access.test.js +262 -0
- package/dist/src/tools/meta/__tests__/profile-access.test.js.map +7 -0
- package/dist/src/tools/meta/__tests__/read-tools.test.js +722 -0
- package/dist/src/tools/meta/__tests__/read-tools.test.js.map +7 -0
- package/dist/src/tools/meta/__tests__/schemas.test.js +103 -0
- package/dist/src/tools/meta/__tests__/schemas.test.js.map +7 -0
- package/dist/src/tools/meta/account-overview.js +37 -19
- package/dist/src/tools/meta/account-overview.js.map +2 -2
- package/dist/src/tools/meta/ad-account-info.js +31 -6
- package/dist/src/tools/meta/ad-account-info.js.map +2 -2
- package/dist/src/tools/meta/ads-performance.js +35 -21
- package/dist/src/tools/meta/ads-performance.js.map +2 -2
- package/dist/src/tools/meta/campaign-performance.js +35 -18
- package/dist/src/tools/meta/campaign-performance.js.map +2 -2
- package/dist/src/tools/meta/list-accessible-ad-accounts.js +39 -10
- package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +2 -2
- package/dist/src/tools/meta/list-accessible-businesses.js +37 -13
- package/dist/src/tools/meta/list-accessible-businesses.js.map +2 -2
- package/dist/src/tools/meta/placement-mix.js +37 -22
- package/dist/src/tools/meta/placement-mix.js.map +2 -2
- package/dist/src/tools/meta/profile-access.js +215 -0
- package/dist/src/tools/meta/profile-access.js.map +7 -0
- package/dist/src/tools/meta/schema-helpers.js +19 -0
- package/dist/src/tools/meta/schema-helpers.js.map +7 -0
- package/dist/src/tools/meta/time-series.js +40 -23
- package/dist/src/tools/meta/time-series.js.map +2 -2
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +233 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js +649 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js +339 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js +235 -0
- package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js +372 -0
- package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js +57 -0
- package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js.map +7 -0
- package/dist/src/tools/vtex/__tests__/write-helpers.test.js +97 -0
- package/dist/src/tools/vtex/__tests__/write-helpers.test.js.map +7 -0
- package/dist/src/tools/vtex/activate-sku.js +1 -48
- package/dist/src/tools/vtex/activate-sku.js.map +2 -2
- package/dist/src/tools/vtex/associate-specification.js +3 -54
- package/dist/src/tools/vtex/associate-specification.js.map +2 -2
- package/dist/src/tools/vtex/attach-catalog-image.js +3 -57
- package/dist/src/tools/vtex/attach-catalog-image.js.map +2 -2
- package/dist/src/tools/vtex/catalog-admin-batch.js +298 -0
- package/dist/src/tools/vtex/catalog-admin-batch.js.map +7 -0
- package/dist/src/tools/vtex/catalog-admin-categories.js +542 -0
- package/dist/src/tools/vtex/catalog-admin-categories.js.map +7 -0
- package/dist/src/tools/vtex/catalog-admin-product-specifications.js +275 -0
- package/dist/src/tools/vtex/catalog-admin-product-specifications.js.map +7 -0
- package/dist/src/tools/vtex/catalog-admin-products-skus.js +475 -0
- package/dist/src/tools/vtex/catalog-admin-products-skus.js.map +7 -0
- package/dist/src/tools/vtex/catalog-navigation-reads.js +430 -0
- package/dist/src/tools/vtex/catalog-navigation-reads.js.map +7 -0
- package/dist/src/tools/vtex/create-brand.js +1 -64
- package/dist/src/tools/vtex/create-brand.js.map +2 -2
- package/dist/src/tools/vtex/create-category.js +1 -76
- package/dist/src/tools/vtex/create-category.js.map +2 -2
- package/dist/src/tools/vtex/create-product-with-sku.js +3 -114
- package/dist/src/tools/vtex/create-product-with-sku.js.map +2 -2
- package/dist/src/tools/vtex/create-specification-value.js +3 -47
- package/dist/src/tools/vtex/create-specification-value.js.map +2 -2
- package/dist/src/tools/vtex/create-specification.js +1 -80
- package/dist/src/tools/vtex/create-specification.js.map +2 -2
- package/dist/src/tools/vtex/deactivate-sku.js +1 -48
- package/dist/src/tools/vtex/deactivate-sku.js.map +2 -2
- package/dist/src/tools/vtex/delete-all-product-specifications.js +9 -0
- package/dist/src/tools/vtex/delete-all-product-specifications.js.map +7 -0
- package/dist/src/tools/vtex/delete-all-sku-specifications.js +9 -0
- package/dist/src/tools/vtex/delete-all-sku-specifications.js.map +7 -0
- package/dist/src/tools/vtex/delete-brand.js +9 -0
- package/dist/src/tools/vtex/delete-brand.js.map +7 -0
- package/dist/src/tools/vtex/delete-catalog-image.js +9 -0
- package/dist/src/tools/vtex/delete-catalog-image.js.map +7 -0
- package/dist/src/tools/vtex/delete-product-specification.js +9 -0
- package/dist/src/tools/vtex/delete-product-specification.js.map +7 -0
- package/dist/src/tools/vtex/delete-sku-price.js +55 -0
- package/dist/src/tools/vtex/delete-sku-price.js.map +7 -0
- package/dist/src/tools/vtex/delete-sku-specification.js +9 -0
- package/dist/src/tools/vtex/delete-sku-specification.js.map +7 -0
- package/dist/src/tools/vtex/get-brand.js +6 -0
- package/dist/src/tools/vtex/get-brand.js.map +7 -0
- package/dist/src/tools/vtex/get-category-tree.js +6 -0
- package/dist/src/tools/vtex/get-category-tree.js.map +7 -0
- package/dist/src/tools/vtex/get-category.js +6 -0
- package/dist/src/tools/vtex/get-category.js.map +7 -0
- package/dist/src/tools/vtex/get-product-specifications.js +9 -0
- package/dist/src/tools/vtex/get-product-specifications.js.map +7 -0
- package/dist/src/tools/vtex/get-product.js +6 -0
- package/dist/src/tools/vtex/get-product.js.map +7 -0
- package/dist/src/tools/vtex/get-sku.js +6 -0
- package/dist/src/tools/vtex/get-sku.js.map +7 -0
- package/dist/src/tools/vtex/index.js +23 -1
- package/dist/src/tools/vtex/index.js.map +2 -2
- package/dist/src/tools/vtex/list-brands.js +6 -0
- package/dist/src/tools/vtex/list-brands.js.map +7 -0
- package/dist/src/tools/vtex/list-categories.js +6 -0
- package/dist/src/tools/vtex/list-categories.js.map +7 -0
- package/dist/src/tools/vtex/list-products-by-category.js +6 -0
- package/dist/src/tools/vtex/list-products-by-category.js.map +7 -0
- package/dist/src/tools/vtex/list-products.js +6 -0
- package/dist/src/tools/vtex/list-products.js.map +7 -0
- package/dist/src/tools/vtex/list-skus-by-product.js +6 -0
- package/dist/src/tools/vtex/list-skus-by-product.js.map +7 -0
- package/dist/src/tools/vtex/list-specification-groups.js +9 -0
- package/dist/src/tools/vtex/list-specification-groups.js.map +7 -0
- package/dist/src/tools/vtex/move-category.js +6 -0
- package/dist/src/tools/vtex/move-category.js.map +7 -0
- package/dist/src/tools/vtex/profile-resolution.js +4 -51
- package/dist/src/tools/vtex/profile-resolution.js.map +2 -2
- package/dist/src/tools/vtex/update-brand.js +6 -0
- package/dist/src/tools/vtex/update-brand.js.map +7 -0
- package/dist/src/tools/vtex/update-category.js +6 -0
- package/dist/src/tools/vtex/update-category.js.map +7 -0
- package/dist/src/tools/vtex/update-product-basic-fields.js +3 -65
- package/dist/src/tools/vtex/update-product-basic-fields.js.map +2 -2
- package/dist/src/tools/vtex/update-sku-basic-fields.js +1 -87
- package/dist/src/tools/vtex/update-sku-basic-fields.js.map +2 -2
- package/dist/src/tools/vtex/update-sku-price.js +21 -1
- package/dist/src/tools/vtex/update-sku-price.js.map +2 -2
- package/dist/src/tools/vtex/write-helpers.js +104 -14
- package/dist/src/tools/vtex/write-helpers.js.map +2 -2
- package/dist/src/utils/provider-profile-selection.js +117 -0
- package/dist/src/utils/provider-profile-selection.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js +678 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js +564 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js +387 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js +368 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +626 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +7 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js +480 -0
- package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js.map +7 -0
- package/dist/tests/setup.js +2 -0
- package/dist/tests/setup.js.map +7 -0
- package/dist/tests/smoke/test-harness.test.js +7 -0
- package/dist/tests/smoke/test-harness.test.js.map +7 -0
- package/dist/tests/vtex/read-only-utils.test.js +161 -0
- package/dist/tests/vtex/read-only-utils.test.js.map +7 -0
- package/dist/tests/vtex/vtex-catalog-admin-docs.test.js +24 -0
- package/dist/tests/vtex/vtex-catalog-admin-docs.test.js.map +7 -0
- package/dist/tests/vtex/vtex-catalog-admin-surface.test.js +30 -0
- package/dist/tests/vtex/vtex-catalog-admin-surface.test.js.map +7 -0
- package/dist/tests/vtex/vtex-catalog-write-tools.test.js +712 -0
- package/dist/tests/vtex/vtex-catalog-write-tools.test.js.map +7 -0
- package/dist/tests/vtex/vtex-catalog.service.test.js +51 -0
- package/dist/tests/vtex/vtex-catalog.service.test.js.map +7 -0
- package/dist/tests/vtex/vtex-inventory-tools.test.js +201 -0
- package/dist/tests/vtex/vtex-inventory-tools.test.js.map +7 -0
- package/dist/tests/vtex/vtex-logistics.service.test.js +134 -0
- package/dist/tests/vtex/vtex-logistics.service.test.js.map +7 -0
- package/dist/tests/vtex/vtex-order-details.tool.test.js +141 -0
- package/dist/tests/vtex/vtex-order-details.tool.test.js.map +7 -0
- package/dist/tests/vtex/vtex-order-write-tools.test.js +483 -0
- package/dist/tests/vtex/vtex-order-write-tools.test.js.map +7 -0
- package/dist/tests/vtex/vtex-orders-summary.tool.test.js +185 -0
- package/dist/tests/vtex/vtex-orders-summary.tool.test.js.map +7 -0
- package/dist/tests/vtex/vtex-orders.service.test.js +120 -0
- package/dist/tests/vtex/vtex-orders.service.test.js.map +7 -0
- package/dist/tests/vtex/vtex-pricing-write-tools.test.js +202 -0
- package/dist/tests/vtex/vtex-pricing-write-tools.test.js.map +7 -0
- package/dist/tests/vtex/vtex-pricing-write.service.test.js +106 -0
- package/dist/tests/vtex/vtex-pricing-write.service.test.js.map +7 -0
- package/dist/tests/vtex/vtex-pricing.service.test.js +88 -0
- package/dist/tests/vtex/vtex-pricing.service.test.js.map +7 -0
- package/dist/tests/vtex/vtex-small-tools.test.js +190 -0
- package/dist/tests/vtex/vtex-small-tools.test.js.map +7 -0
- package/dist/tests/vtex/vtex-write-simple-tools.test.js +647 -0
- package/dist/tests/vtex/vtex-write-simple-tools.test.js.map +7 -0
- package/dist/vitest.config.js +15 -0
- package/dist/vitest.config.js.map +7 -0
- package/package.json +6 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../tests/vtex/vtex-catalog-write-tools.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { z } from \"zod\";\n\nimport { associateSpecificationHandler } from \"../../src/tools/vtex/associate-specification.js\";\nimport { createBrandHandler } from \"../../src/tools/vtex/create-brand.js\";\nimport { createCategoryHandler } from \"../../src/tools/vtex/create-category.js\";\nimport { createProductHandler } from \"../../src/tools/vtex/create-product.js\";\nimport { createSkuHandler } from \"../../src/tools/vtex/create-sku.js\";\nimport {\n\tcreateSpecificationHandler,\n\tcreateSpecificationSchema,\n} from \"../../src/tools/vtex/create-specification.js\";\nimport { createSpecificationValueHandler } from \"../../src/tools/vtex/create-specification-value.js\";\nimport {\n\tassociateProductSpecification,\n\tassociateSkuSpecification,\n\tcreateBrand,\n\tcreateCategory,\n\tcreateProduct,\n\tcreateSku,\n\tcreateSkuEan,\n\tcreateSpecification,\n\tcreateSpecificationValue,\n} from \"../../src/services/vtex/vtex-catalog-write.js\";\nimport {\n\tbuildWriteSuccessResponse,\n\thandleVtexWriteError,\n\tresolveVtexWriteProfile,\n} from \"../../src/tools/vtex/write-helpers.js\";\n\nvi.mock(\"../../src/tools/vtex/write-helpers.js\", () => ({\n\tvtexProfileIdSchemaField: z.string().optional(),\n\tconfirmationSchemaField: z.boolean().optional(),\n\tconfirmationNoteSchemaField: z.string().optional(),\n\tresolveVtexWriteProfile: vi.fn(),\n\tbuildWriteSuccessResponse: vi.fn((params: unknown) => ({\n\t\tkind: \"success\",\n\t\tparams,\n\t})),\n\thandleVtexWriteError: vi.fn((err: unknown, fallback: string) => ({\n\t\tkind: \"error\",\n\t\tfallback,\n\t\terr,\n\t})),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-catalog-write.js\", () => ({\n\tcreateBrand: vi.fn(),\n\tcreateCategory: vi.fn(),\n\tcreateProduct: vi.fn(),\n\tcreateSku: vi.fn(),\n\tcreateSkuEan: vi.fn(),\n\tcreateSpecification: vi.fn(),\n\tcreateSpecificationValue: vi.fn(),\n\tassociateProductSpecification: vi.fn(),\n\tassociateSkuSpecification: vi.fn(),\n}));\n\ndescribe(\"VTEX catalog/specification write tools\", () => {\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\tok: true,\n\t\t\tvalue: { profileId: \"profile-1\" },\n\t\t});\n\t});\n\n\tdescribe(\"createBrandHandler\", () => {\n\t\tit(\"applies default payload values before creating a brand\", async () => {\n\t\t\tconst createdBrand = { Id: 10, Name: \"Nike\", Active: true };\n\t\t\tvi.mocked(createBrand).mockResolvedValue(createdBrand as never);\n\n\t\t\tconst result = await createBrandHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tid: 10,\n\t\t\t\tname: \"Nike\",\n\t\t\t\tlinkId: \"nike\",\n\t\t\t});\n\n\t\t\texpect(createBrand).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tId: 10,\n\t\t\t\tName: \"Nike\",\n\t\t\t\tText: \"Nike\",\n\t\t\t\tKeywords: \"\",\n\t\t\t\tSiteTitle: \"Nike\",\n\t\t\t\tActive: true,\n\t\t\t\tMenuHome: false,\n\t\t\t\tLinkId: \"nike\",\n\t\t\t\tScore: null,\n\t\t\t\tAdWordsRemarketingCode: null,\n\t\t\t\tLomadeeCampaignCode: null,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_brand\",\n\t\t\t\tresourceId: \"10\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Brand created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdBrand,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_brand\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createBrandHandler({ id: 10, name: \"Nike\" });\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createBrand).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createBrand).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createBrandHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tid: 10,\n\t\t\t\tname: \"Nike\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create brand in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create brand in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createCategoryHandler\", () => {\n\t\tit(\"forwards the expected VTEX category payload with defaults\", async () => {\n\t\t\tconst createdCategory = { Id: 20, Name: \"Shoes\" };\n\t\t\tvi.mocked(createCategory).mockResolvedValue(createdCategory as never);\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tfatherCategoryId: null,\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(createCategory).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tId: undefined,\n\t\t\t\tName: \"Shoes\",\n\t\t\t\tKeywords: \"\",\n\t\t\t\tTitle: \"Running Shoes\",\n\t\t\t\tDescription: \"Category description\",\n\t\t\t\tAdWordsRemarketingCode: null,\n\t\t\t\tLomadeeCampaignCode: null,\n\t\t\t\tFatherCategoryId: null,\n\t\t\t\tGlobalCategoryId: 123,\n\t\t\t\tShowInStoreFront: true,\n\t\t\t\tIsActive: true,\n\t\t\t\tActiveStoreFrontLink: true,\n\t\t\t\tShowBrandFilter: true,\n\t\t\t\tScore: null,\n\t\t\t\tStockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_category\",\n\t\t\t\tresourceId: \"20\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Category created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdCategory,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_category\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createCategory).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createCategory).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create category in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create category in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createProductHandler\", () => {\n\t\tit(\"forwards the expected VTEX product payload and builds a success response\", async () => {\n\t\t\tconst createdProduct = { Id: 55, Name: \"Running Shoe\" };\n\t\t\tvi.mocked(createProduct).mockResolvedValue(createdProduct as never);\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryPath: \"Mens/Shoes/Running\",\n\t\t\t\tbrandName: \"Acme\",\n\t\t\t\tdepartmentId: 7,\n\t\t\t\trefId: \"RUN-001\",\n\t\t\t\ttitle: \"Running Shoe\",\n\t\t\t\tdescription: \"Main description\",\n\t\t\t\tdescriptionShort: \"Short description\",\n\t\t\t\tlinkId: \"running-shoe\",\n\t\t\t\treleaseDate: \"2026-06-01T00:00:00Z\",\n\t\t\t\tkeyWords: \"running,shoe\",\n\t\t\t\tisVisible: true,\n\t\t\t\tisActive: false,\n\t\t\t\ttaxCode: \"TX-1\",\n\t\t\t\tmetaTagDescription: \"Meta description\",\n\t\t\t\tsupplierId: 91,\n\t\t\t\tshowWithoutStock: true,\n\t\t\t\tscore: 12,\n\t\t\t});\n\n\t\t\texpect(createProduct).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tName: \"Running Shoe\",\n\t\t\t\tCategoryPath: \"Mens/Shoes/Running\",\n\t\t\t\tBrandName: \"Acme\",\n\t\t\t\tDepartmentId: 7,\n\t\t\t\tRefId: \"RUN-001\",\n\t\t\t\tTitle: \"Running Shoe\",\n\t\t\t\tDescription: \"Main description\",\n\t\t\t\tDescriptionShort: \"Short description\",\n\t\t\t\tLinkId: \"running-shoe\",\n\t\t\t\tReleaseDate: \"2026-06-01T00:00:00Z\",\n\t\t\t\tKeyWords: \"running,shoe\",\n\t\t\t\tIsVisible: true,\n\t\t\t\tIsActive: false,\n\t\t\t\tTaxCode: \"TX-1\",\n\t\t\t\tMetaTagDescription: \"Meta description\",\n\t\t\t\tSupplierId: 91,\n\t\t\t\tShowWithoutStock: true,\n\t\t\t\tScore: 12,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_product\",\n\t\t\t\tresourceId: \"55\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Product created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdProduct,\n\t\t\t\tdetails: {\n\t\t\t\t\tproduct_id: \"55\",\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_product\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryId: 10,\n\t\t\t\tbrandId: 20,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createProduct).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createProduct).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryId: 10,\n\t\t\t\tbrandId: 20,\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create product in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create product in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSkuHandler\", () => {\n\t\tconst skuPayload = {\n\t\t\tprofileId: \"custom\",\n\t\t\tproductId: 99,\n\t\t\tname: \"Running Shoe / Black / 42\",\n\t\t\trefId: \"RUN-001-42\",\n\t\t\tpackagedHeight: 10,\n\t\t\tpackagedLength: 20,\n\t\t\tpackagedWidth: 30,\n\t\t\tpackagedWeightKg: 1.5,\n\t\t\theight: 9,\n\t\t\tlength: 19,\n\t\t\twidth: 29,\n\t\t\tweightKg: 1.25,\n\t\t\tmeasurementUnit: \"un\",\n\t\t\tunitMultiplier: 1,\n\t\t\tmanufacturerCode: \"ACME-42\",\n\t\t\tcommercialConditionId: 12,\n\t\t};\n\n\t\tit(\"forwards the expected VTEX SKU payload with default flags\", async () => {\n\t\t\tconst createdSku = { Id: 77, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tconst result = await createSkuHandler(skuPayload);\n\n\t\t\texpect(createSku).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tProductId: 99,\n\t\t\t\tName: \"Running Shoe / Black / 42\",\n\t\t\t\tRefId: \"RUN-001-42\",\n\t\t\t\tPackagedHeight: 10,\n\t\t\t\tPackagedLength: 20,\n\t\t\t\tPackagedWidth: 30,\n\t\t\t\tPackagedWeightKg: 1.5,\n\t\t\t\tActivateIfPossible: true,\n\t\t\t\tIsActive: false,\n\t\t\t\tHeight: 9,\n\t\t\t\tLength: 19,\n\t\t\t\tWidth: 29,\n\t\t\t\tWeightKg: 1.25,\n\t\t\t\tMeasurementUnit: \"un\",\n\t\t\t\tUnitMultiplier: 1,\n\t\t\t\tManufacturerCode: \"ACME-42\",\n\t\t\t\tCommercialConditionId: 12,\n\t\t\t});\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_sku\",\n\t\t\t\tresourceId: \"77\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"SKU created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdSku,\n\t\t\t\tdetails: {\n\t\t\t\t\tproduct_id: 99,\n\t\t\t\t\tsku_id: \"77\",\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_sku\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"creates the sku then attaches the EAN when provided\", async () => {\n\t\t\tconst createdSku = { Id: 78, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tawait createSkuHandler({\n\t\t\t\t...skuPayload,\n\t\t\t\tean: \" 7791234567890 \",\n\t\t\t\tisActive: true,\n\t\t\t\tactivateIfPossible: false,\n\t\t\t});\n\n\t\t\texpect(createSku).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tProductId: 99,\n\t\t\t\tName: \"Running Shoe / Black / 42\",\n\t\t\t\tRefId: \"RUN-001-42\",\n\t\t\t\tPackagedHeight: 10,\n\t\t\t\tPackagedLength: 20,\n\t\t\t\tPackagedWidth: 30,\n\t\t\t\tPackagedWeightKg: 1.5,\n\t\t\t\tActivateIfPossible: false,\n\t\t\t\tIsActive: true,\n\t\t\t\tHeight: 9,\n\t\t\t\tLength: 19,\n\t\t\t\tWidth: 29,\n\t\t\t\tWeightKg: 1.25,\n\t\t\t\tMeasurementUnit: \"un\",\n\t\t\t\tUnitMultiplier: 1,\n\t\t\t\tManufacturerCode: \"ACME-42\",\n\t\t\t\tCommercialConditionId: 12,\n\t\t\t});\n\t\t\texpect(createSkuEan).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"78\",\n\t\t\t\t\"7791234567890\",\n\t\t\t);\n\t\t\texpect(\n\t\t\t\tvi.mocked(createSku).mock.invocationCallOrder[0],\n\t\t\t).toBeLessThan(vi.mocked(createSkuEan).mock.invocationCallOrder[0]);\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tafter: expect.objectContaining({ Eans: [\"7791234567890\"] }),\n\t\t\t\t}),\n\t\t\t);\n\t\t});\n\n\t\tit(\"skips EAN attachment when EAN is missing or blank\", async () => {\n\t\t\tconst createdSku = { Id: 79, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tawait createSkuHandler({\n\t\t\t\t...skuPayload,\n\t\t\t\tean: \" \",\n\t\t\t});\n\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSkuHandler({\n\t\t\t\tproductId: 99,\n\t\t\t\tname: \"Running Shoe / Black / 42\",\n\t\t\t\trefId: \"RUN-001-42\",\n\t\t\t\tpackagedHeight: 10,\n\t\t\t\tpackagedLength: 20,\n\t\t\t\tpackagedWidth: 30,\n\t\t\t\tpackagedWeightKg: 1.5,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSku).not.toHaveBeenCalled();\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSku).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSkuHandler(skuPayload);\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create SKU in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create SKU in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSpecificationHandler\", () => {\n\t\tit(\"schema converts fieldTypeId from string to number\", () => {\n\t\t\tconst parsed = createSpecificationSchema.parse({\n\t\t\t\tfieldTypeId: \"4\",\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(parsed.fieldTypeId).toBe(4);\n\t\t});\n\n\t\tit(\"fills default fields before creating a specification\", async () => {\n\t\t\tconst createdSpecification = { Id: 30, Name: \"Color\" };\n\t\t\tvi.mocked(createSpecification).mockResolvedValue(\n\t\t\t\tcreatedSpecification as never,\n\t\t\t);\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(createSpecification).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tFieldTypeId: 4,\n\t\t\t\tFieldGroupId: 12,\n\t\t\t\tName: \"Color\",\n\t\t\t\tCategoryId: undefined,\n\t\t\t\tDescription: null,\n\t\t\t\tPosition: 0,\n\t\t\t\tIsFilter: false,\n\t\t\t\tIsRequired: false,\n\t\t\t\tIsOnProductDetails: true,\n\t\t\t\tIsStockKeepingUnit: false,\n\t\t\t\tIsWizard: false,\n\t\t\t\tIsActive: true,\n\t\t\t\tIsTopMenuLinkActive: false,\n\t\t\t\tIsSideMenuLinkActive: false,\n\t\t\t\tDefaultValue: \"\",\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_specification\",\n\t\t\t\tresourceId: \"30\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdSpecification,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_specification\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSpecification).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create specification in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create specification in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSpecificationValueHandler\", () => {\n\t\tit(\"fills default fields before creating a specification value\", async () => {\n\t\t\tconst createdValue = { FieldValueId: 40, Name: \"Red\" };\n\t\t\tvi.mocked(createSpecificationValue).mockResolvedValue(\n\t\t\t\tcreatedValue as never,\n\t\t\t);\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(createSpecificationValue).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tFieldId: 30,\n\t\t\t\tName: \"Red\",\n\t\t\t\tIsActive: true,\n\t\t\t\tPosition: 0,\n\t\t\t\tText: null,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_specification_value\",\n\t\t\t\tresourceId: \"40\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification value created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdValue,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({\n\t\t\t\t\toperation: \"create_specification_value\",\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSpecificationValue).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSpecificationValue).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create specification value in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create specification value in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"associateSpecificationHandler\", () => {\n\t\tit(\"routes product associations to the product service and shapes optional payload fields\", async () => {\n\t\t\tconst association = { success: true, id: \"prod-1\" };\n\t\t\tvi.mocked(associateProductSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tfieldValueId: 40,\n\t\t\t});\n\n\t\t\texpect(associateProductSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"prod-1\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 30,\n\t\t\t\t\tFieldValueId: 40,\n\t\t\t\t},\n\t\t\t);\n\t\t\texpect(associateSkuSpecification).not.toHaveBeenCalled();\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"associate_specification\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification associated successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: association,\n\t\t\t\tdetails: { entity_type: \"product\" },\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({\n\t\t\t\t\toperation: \"associate_specification\",\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\n\t\tit(\"routes sku associations to the sku service and keeps free-text payloads\", async () => {\n\t\t\tconst association = { success: true, id: \"sku-1\" };\n\t\t\tvi.mocked(associateSkuSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tawait associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"sku\",\n\t\t\t\tresourceId: \"sku-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t\ttext: \"Blue\",\n\t\t\t});\n\n\t\t\texpect(associateSkuSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"sku-1\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 30,\n\t\t\t\t\tText: \"Blue\",\n\t\t\t\t},\n\t\t\t);\n\t\t\texpect(associateProductSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"keeps both FieldValueId and Text when both are provided\", async () => {\n\t\t\tconst association = { success: true, id: \"sku-2\" };\n\t\t\tvi.mocked(associateSkuSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tawait associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"sku\",\n\t\t\t\tresourceId: \"sku-2\",\n\t\t\t\tfieldId: 31,\n\t\t\t\tfieldValueId: 41,\n\t\t\t\ttext: \"Navy\",\n\t\t\t});\n\n\t\t\texpect(associateSkuSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"sku-2\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 31,\n\t\t\t\t\tFieldValueId: 41,\n\t\t\t\t\tText: \"Navy\",\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(associateProductSpecification).not.toHaveBeenCalled();\n\t\t\texpect(associateSkuSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(associateProductSpecification).mockRejectedValue(\n\t\t\t\tnew Error(\"boom\"),\n\t\t\t);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to associate specification to product prod-1\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to associate specification to product prod-1\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
getProductOffers,
|
|
4
|
+
getSkuOffers
|
|
5
|
+
} from "../../src/services/vtex/vtex-catalog.js";
|
|
6
|
+
import { getVtexApiClients } from "../../src/services/vtex/vtex-api.js";
|
|
7
|
+
vi.mock("../../src/services/vtex/vtex-api.js", () => ({
|
|
8
|
+
getVtexApiClients: vi.fn()
|
|
9
|
+
}));
|
|
10
|
+
describe("vtex-catalog service", () => {
|
|
11
|
+
const catalogGet = vi.fn();
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
vi.mocked(getVtexApiClients).mockResolvedValue({
|
|
15
|
+
config: {
|
|
16
|
+
accountName: "test-account",
|
|
17
|
+
apiKey: "key",
|
|
18
|
+
apiToken: "token",
|
|
19
|
+
baseUrl: "https://example.vtex.com",
|
|
20
|
+
pricingBaseUrl: "https://pricing.example.vtex.com"
|
|
21
|
+
},
|
|
22
|
+
vtexApi: {
|
|
23
|
+
get: catalogGet
|
|
24
|
+
},
|
|
25
|
+
vtexPricingApi: {
|
|
26
|
+
get: vi.fn()
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
it("fetches product offers through the general VTEX client", async () => {
|
|
31
|
+
const payload = [{ seller: "1", price: 1e3 }];
|
|
32
|
+
catalogGet.mockResolvedValue({ data: payload });
|
|
33
|
+
const result = await getProductOffers("profile-1", "product-1");
|
|
34
|
+
expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
|
|
35
|
+
expect(catalogGet).toHaveBeenCalledWith(
|
|
36
|
+
"/api/catalog_system/pub/products/offers/product-1"
|
|
37
|
+
);
|
|
38
|
+
expect(result).toEqual(payload);
|
|
39
|
+
});
|
|
40
|
+
it("fetches SKU offers using both product and sku identifiers", async () => {
|
|
41
|
+
const payload = [{ seller: "1", availableQuantity: 4 }];
|
|
42
|
+
catalogGet.mockResolvedValue({ data: payload });
|
|
43
|
+
const result = await getSkuOffers("profile-1", "product-1", "sku-9");
|
|
44
|
+
expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
|
|
45
|
+
expect(catalogGet).toHaveBeenCalledWith(
|
|
46
|
+
"/api/catalog_system/pub/products/offers/product-1/sku/sku-9"
|
|
47
|
+
);
|
|
48
|
+
expect(result).toEqual(payload);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=vtex-catalog.service.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../tests/vtex/vtex-catalog.service.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n\tgetProductOffers,\n\tgetSkuOffers,\n} from \"../../src/services/vtex/vtex-catalog.js\";\nimport { getVtexApiClients } from \"../../src/services/vtex/vtex-api.js\";\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tgetVtexApiClients: vi.fn(),\n}));\n\ndescribe(\"vtex-catalog service\", () => {\n\tconst catalogGet = vi.fn();\n\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\n\t\tvi.mocked(getVtexApiClients).mockResolvedValue({\n\t\t\tconfig: {\n\t\t\t\taccountName: \"test-account\",\n\t\t\t\tapiKey: \"key\",\n\t\t\t\tapiToken: \"token\",\n\t\t\t\tbaseUrl: \"https://example.vtex.com\",\n\t\t\t\tpricingBaseUrl: \"https://pricing.example.vtex.com\",\n\t\t\t},\n\t\t\tvtexApi: {\n\t\t\t\tget: catalogGet,\n\t\t\t} as never,\n\t\t\tvtexPricingApi: {\n\t\t\t\tget: vi.fn(),\n\t\t\t} as never,\n\t\t});\n\t});\n\n\tit(\"fetches product offers through the general VTEX client\", async () => {\n\t\tconst payload = [{ seller: \"1\", price: 1000 }];\n\t\tcatalogGet.mockResolvedValue({ data: payload });\n\n\t\tconst result = await getProductOffers(\"profile-1\", \"product-1\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(catalogGet).toHaveBeenCalledWith(\n\t\t\t\"/api/catalog_system/pub/products/offers/product-1\",\n\t\t);\n\t\texpect(result).toEqual(payload);\n\t});\n\n\tit(\"fetches SKU offers using both product and sku identifiers\", async () => {\n\t\tconst payload = [{ seller: \"1\", availableQuantity: 4 }];\n\t\tcatalogGet.mockResolvedValue({ data: payload });\n\n\t\tconst result = await getSkuOffers(\"profile-1\", \"product-1\", \"sku-9\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(catalogGet).toHaveBeenCalledWith(\n\t\t\t\"/api/catalog_system/pub/products/offers/product-1/sku/sku-9\",\n\t\t);\n\t\texpect(result).toEqual(payload);\n\t});\n});\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,YAAY,UAAU,QAAQ,IAAI,UAAU;AAErD;AAAA,EACC;AAAA,EACA;AAAA,OACM;AACP,SAAS,yBAAyB;AAElC,GAAG,KAAK,uCAAuC,OAAO;AAAA,EACrD,mBAAmB,GAAG,GAAG;AAC1B,EAAE;AAEF,SAAS,wBAAwB,MAAM;AACtC,QAAM,aAAa,GAAG,GAAG;AAEzB,aAAW,MAAM;AAChB,OAAG,cAAc;AAEjB,OAAG,OAAO,iBAAiB,EAAE,kBAAkB;AAAA,MAC9C,QAAQ;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SAAS;AAAA,QACT,gBAAgB;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,QACR,KAAK;AAAA,MACN;AAAA,MACA,gBAAgB;AAAA,QACf,KAAK,GAAG,GAAG;AAAA,MACZ;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AAED,KAAG,0DAA0D,YAAY;AACxE,UAAM,UAAU,CAAC,EAAE,QAAQ,KAAK,OAAO,IAAK,CAAC;AAC7C,eAAW,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAE9C,UAAM,SAAS,MAAM,iBAAiB,aAAa,WAAW;AAE9D,WAAO,iBAAiB,EAAE,qBAAqB,WAAW;AAC1D,WAAO,UAAU,EAAE;AAAA,MAClB;AAAA,IACD;AACA,WAAO,MAAM,EAAE,QAAQ,OAAO;AAAA,EAC/B,CAAC;AAED,KAAG,6DAA6D,YAAY;AAC3E,UAAM,UAAU,CAAC,EAAE,QAAQ,KAAK,mBAAmB,EAAE,CAAC;AACtD,eAAW,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAE9C,UAAM,SAAS,MAAM,aAAa,aAAa,aAAa,OAAO;AAEnE,WAAO,iBAAiB,EAAE,qBAAqB,WAAW;AAC1D,WAAO,UAAU,EAAE;AAAA,MAClB;AAAA,IACD;AACA,WAAO,MAAM,EAAE,QAAQ,OAAO;AAAA,EAC/B,CAAC;AACF,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { formatVtexError } from "../../src/services/vtex/vtex-api.js";
|
|
3
|
+
import {
|
|
4
|
+
getInventoryBySkuBatch,
|
|
5
|
+
getInventoryByWarehouse
|
|
6
|
+
} from "../../src/services/vtex/vtex-logistics.js";
|
|
7
|
+
import { inventoryCheckHandler } from "../../src/tools/vtex/inventory-check.js";
|
|
8
|
+
import { resolveVtexProfileOrSelection } from "../../src/tools/vtex/profile-resolution.js";
|
|
9
|
+
import { warehouseInventoryHandler } from "../../src/tools/vtex/warehouse-inventory.js";
|
|
10
|
+
vi.mock("mcp-use/server", () => ({
|
|
11
|
+
object: vi.fn((payload) => ({ kind: "object", payload })),
|
|
12
|
+
error: vi.fn((message) => ({ kind: "error", message }))
|
|
13
|
+
}));
|
|
14
|
+
vi.mock("../../src/tools/vtex/profile-resolution.js", () => ({
|
|
15
|
+
resolveVtexProfileOrSelection: vi.fn()
|
|
16
|
+
}));
|
|
17
|
+
vi.mock("../../src/services/vtex/vtex-logistics.js", () => ({
|
|
18
|
+
getInventoryByWarehouse: vi.fn(),
|
|
19
|
+
getInventoryBySkuBatch: vi.fn()
|
|
20
|
+
}));
|
|
21
|
+
vi.mock("../../src/services/vtex/vtex-api.js", () => ({
|
|
22
|
+
formatVtexError: vi.fn(
|
|
23
|
+
(err, fallback) => `formatted:${fallback}:${err instanceof Error ? err.message : String(err)}`
|
|
24
|
+
)
|
|
25
|
+
}));
|
|
26
|
+
describe("heavy VTEX inventory tools", () => {
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
vi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({
|
|
30
|
+
ok: true,
|
|
31
|
+
value: { profileId: "profile-1" }
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
it("formats warehouse inventory output", async () => {
|
|
35
|
+
vi.mocked(getInventoryByWarehouse).mockResolvedValue([
|
|
36
|
+
{
|
|
37
|
+
skuId: "sku-1",
|
|
38
|
+
warehouseId: "wh-1",
|
|
39
|
+
totalQuantity: 10,
|
|
40
|
+
reservedQuantity: 3,
|
|
41
|
+
availableQuantity: 7,
|
|
42
|
+
isUnlimited: false,
|
|
43
|
+
keepSellingAfterExpiration: true
|
|
44
|
+
}
|
|
45
|
+
]);
|
|
46
|
+
const result = await warehouseInventoryHandler({
|
|
47
|
+
profileId: "custom",
|
|
48
|
+
skuId: "sku-1",
|
|
49
|
+
warehouseId: "wh-1"
|
|
50
|
+
});
|
|
51
|
+
expect(getInventoryByWarehouse).toHaveBeenCalledWith(
|
|
52
|
+
"profile-1",
|
|
53
|
+
"sku-1",
|
|
54
|
+
"wh-1"
|
|
55
|
+
);
|
|
56
|
+
expect(result).toEqual({
|
|
57
|
+
kind: "object",
|
|
58
|
+
payload: {
|
|
59
|
+
profile_id: "profile-1",
|
|
60
|
+
sku_id: "sku-1",
|
|
61
|
+
warehouse_id: "wh-1",
|
|
62
|
+
inventory: [
|
|
63
|
+
{
|
|
64
|
+
sku_id: "sku-1",
|
|
65
|
+
warehouse_id: "wh-1",
|
|
66
|
+
total_quantity: 10,
|
|
67
|
+
reserved_quantity: 3,
|
|
68
|
+
available_quantity: 7,
|
|
69
|
+
is_unlimited: false,
|
|
70
|
+
keep_selling_after_expiration: true
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
it("formats inventory batch output with deduped sku ids and dynamic warehouse schema", async () => {
|
|
77
|
+
vi.mocked(getInventoryBySkuBatch).mockResolvedValue({
|
|
78
|
+
successful: [
|
|
79
|
+
{
|
|
80
|
+
skuId: "sku-1",
|
|
81
|
+
document: {
|
|
82
|
+
skuId: "sku-1",
|
|
83
|
+
balance: [
|
|
84
|
+
{
|
|
85
|
+
warehouseName: "Main",
|
|
86
|
+
totalQuantity: 10,
|
|
87
|
+
reservedQuantity: 3,
|
|
88
|
+
hasUnlimitedQuantity: false,
|
|
89
|
+
timeToRefill: "2d",
|
|
90
|
+
dateOfSupplyUtc: "2026-06-01T15:30:00.000Z"
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
skuId: "sku-2",
|
|
97
|
+
document: {
|
|
98
|
+
skuId: "sku-2",
|
|
99
|
+
balance: [
|
|
100
|
+
{
|
|
101
|
+
warehouseId: "WH-2",
|
|
102
|
+
totalQuantity: 2,
|
|
103
|
+
reservedQuantity: 0,
|
|
104
|
+
availableQuantity: 2,
|
|
105
|
+
isUnlimited: false
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
failed: [
|
|
112
|
+
{
|
|
113
|
+
skuId: "sku-3",
|
|
114
|
+
message: "missing",
|
|
115
|
+
statusCode: 404,
|
|
116
|
+
attempts: 1,
|
|
117
|
+
retryable: false
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
});
|
|
121
|
+
const result = await inventoryCheckHandler({
|
|
122
|
+
profileId: "custom",
|
|
123
|
+
skuIds: ["sku-1", "sku-1", "sku-2", "sku-3"]
|
|
124
|
+
});
|
|
125
|
+
expect(getInventoryBySkuBatch).toHaveBeenCalledWith(
|
|
126
|
+
"profile-1",
|
|
127
|
+
["sku-1", "sku-2", "sku-3"],
|
|
128
|
+
{
|
|
129
|
+
maxConcurrency: 10,
|
|
130
|
+
maxRetries: 2
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
expect(result).toEqual({
|
|
134
|
+
kind: "object",
|
|
135
|
+
payload: {
|
|
136
|
+
metadata: {
|
|
137
|
+
profile_id: "profile-1",
|
|
138
|
+
requested_ids: 4,
|
|
139
|
+
unique_ids: 3,
|
|
140
|
+
max_parallel_requests: 10,
|
|
141
|
+
successful_items: 2,
|
|
142
|
+
failed_items: 1,
|
|
143
|
+
has_failures: true
|
|
144
|
+
},
|
|
145
|
+
inventory_schema: {
|
|
146
|
+
sku: ["sku_id", "global_available_quantity", "health_status"],
|
|
147
|
+
warehouse_balance: [
|
|
148
|
+
"warehouseName",
|
|
149
|
+
"totalQuantity",
|
|
150
|
+
"reservedQuantity",
|
|
151
|
+
"hasUnlimitedQuantity",
|
|
152
|
+
"timeToRefill",
|
|
153
|
+
"dateOfSupplyUtc"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
inventory: [
|
|
157
|
+
{
|
|
158
|
+
sku: ["sku-1", 7, "LOW_STOCK"],
|
|
159
|
+
warehouses: [["Main", 10, 3, false, "2d", "2026-06-01 15:30"]]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
sku: ["sku-2", 2, "CRITICAL_LOW_STOCK"],
|
|
163
|
+
warehouses: [["WH-2", 2, 0, false, "", ""]]
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
failures: [
|
|
167
|
+
{
|
|
168
|
+
sku_id: "sku-3",
|
|
169
|
+
message: "missing",
|
|
170
|
+
status_code: 404,
|
|
171
|
+
attempts: 1,
|
|
172
|
+
retryable: false
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
it("returns profile selection payload unchanged when resolution fails", async () => {
|
|
179
|
+
vi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({
|
|
180
|
+
ok: false,
|
|
181
|
+
response: { selection: true }
|
|
182
|
+
});
|
|
183
|
+
const result = await inventoryCheckHandler({ skuIds: ["sku-1"] });
|
|
184
|
+
expect(result).toEqual({ selection: true });
|
|
185
|
+
expect(getInventoryBySkuBatch).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
it("formats heavy tool failures through formatVtexError", async () => {
|
|
188
|
+
vi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error("boom"));
|
|
189
|
+
const result = await warehouseInventoryHandler({
|
|
190
|
+
profileId: "custom",
|
|
191
|
+
skuId: "sku-1",
|
|
192
|
+
warehouseId: "wh-1"
|
|
193
|
+
});
|
|
194
|
+
expect(formatVtexError).toHaveBeenCalled();
|
|
195
|
+
expect(result).toEqual({
|
|
196
|
+
kind: "error",
|
|
197
|
+
message: "formatted:Failed to fetch inventory for SKU sku-1 in warehouse wh-1:boom"
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=vtex-inventory-tools.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../tests/vtex/vtex-inventory-tools.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { formatVtexError } from \"../../src/services/vtex/vtex-api.js\";\nimport {\n\tgetInventoryBySkuBatch,\n\tgetInventoryByWarehouse,\n} from \"../../src/services/vtex/vtex-logistics.js\";\nimport { inventoryCheckHandler } from \"../../src/tools/vtex/inventory-check.js\";\nimport { resolveVtexProfileOrSelection } from \"../../src/tools/vtex/profile-resolution.js\";\nimport { warehouseInventoryHandler } from \"../../src/tools/vtex/warehouse-inventory.js\";\n\nvi.mock(\"mcp-use/server\", () => ({\n\tobject: vi.fn((payload: unknown) => ({ kind: \"object\", payload })),\n\terror: vi.fn((message: string) => ({ kind: \"error\", message })),\n}));\n\nvi.mock(\"../../src/tools/vtex/profile-resolution.js\", () => ({\n\tresolveVtexProfileOrSelection: vi.fn(),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-logistics.js\", () => ({\n\tgetInventoryByWarehouse: vi.fn(),\n\tgetInventoryBySkuBatch: vi.fn(),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tformatVtexError: vi.fn(\n\t\t(err: unknown, fallback: string) =>\n\t\t\t`formatted:${fallback}:${err instanceof Error ? err.message : String(err)}`,\n\t),\n}));\n\ndescribe(\"heavy VTEX inventory tools\", () => {\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\t\tvi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({\n\t\t\tok: true,\n\t\t\tvalue: { profileId: \"profile-1\" },\n\t\t});\n\t});\n\n\tit(\"formats warehouse inventory output\", async () => {\n\t\tvi.mocked(getInventoryByWarehouse).mockResolvedValue([\n\t\t\t{\n\t\t\t\tskuId: \"sku-1\",\n\t\t\t\twarehouseId: \"wh-1\",\n\t\t\t\ttotalQuantity: 10,\n\t\t\t\treservedQuantity: 3,\n\t\t\t\tavailableQuantity: 7,\n\t\t\t\tisUnlimited: false,\n\t\t\t\tkeepSellingAfterExpiration: true,\n\t\t\t},\n\t\t]);\n\n\t\tconst result = await warehouseInventoryHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuId: \"sku-1\",\n\t\t\twarehouseId: \"wh-1\",\n\t\t});\n\n\t\texpect(getInventoryByWarehouse).toHaveBeenCalledWith(\n\t\t\t\"profile-1\",\n\t\t\t\"sku-1\",\n\t\t\t\"wh-1\",\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tkind: \"object\",\n\t\t\tpayload: {\n\t\t\t\tprofile_id: \"profile-1\",\n\t\t\t\tsku_id: \"sku-1\",\n\t\t\t\twarehouse_id: \"wh-1\",\n\t\t\t\tinventory: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku_id: \"sku-1\",\n\t\t\t\t\t\twarehouse_id: \"wh-1\",\n\t\t\t\t\t\ttotal_quantity: 10,\n\t\t\t\t\t\treserved_quantity: 3,\n\t\t\t\t\t\tavailable_quantity: 7,\n\t\t\t\t\t\tis_unlimited: false,\n\t\t\t\t\t\tkeep_selling_after_expiration: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"formats inventory batch output with deduped sku ids and dynamic warehouse schema\", async () => {\n\t\tvi.mocked(getInventoryBySkuBatch).mockResolvedValue({\n\t\t\tsuccessful: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-1\",\n\t\t\t\t\tdocument: {\n\t\t\t\t\t\tskuId: \"sku-1\",\n\t\t\t\t\t\tbalance: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twarehouseName: \"Main\",\n\t\t\t\t\t\t\t\ttotalQuantity: 10,\n\t\t\t\t\t\t\t\treservedQuantity: 3,\n\t\t\t\t\t\t\t\thasUnlimitedQuantity: false,\n\t\t\t\t\t\t\t\ttimeToRefill: \"2d\",\n\t\t\t\t\t\t\t\tdateOfSupplyUtc: \"2026-06-01T15:30:00.000Z\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\tdocument: {\n\t\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\t\tbalance: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twarehouseId: \"WH-2\",\n\t\t\t\t\t\t\t\ttotalQuantity: 2,\n\t\t\t\t\t\t\t\treservedQuantity: 0,\n\t\t\t\t\t\t\t\tavailableQuantity: 2,\n\t\t\t\t\t\t\t\tisUnlimited: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tfailed: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-3\",\n\t\t\t\t\tmessage: \"missing\",\n\t\t\t\t\tstatusCode: 404,\n\t\t\t\t\tattempts: 1,\n\t\t\t\t\tretryable: false,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst result = await inventoryCheckHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuIds: [\"sku-1\", \"sku-1\", \"sku-2\", \"sku-3\"],\n\t\t});\n\n\t\texpect(getInventoryBySkuBatch).toHaveBeenCalledWith(\n\t\t\t\"profile-1\",\n\t\t\t[\"sku-1\", \"sku-2\", \"sku-3\"],\n\t\t\t{\n\t\t\t\tmaxConcurrency: 10,\n\t\t\t\tmaxRetries: 2,\n\t\t\t},\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tkind: \"object\",\n\t\t\tpayload: {\n\t\t\t\tmetadata: {\n\t\t\t\t\tprofile_id: \"profile-1\",\n\t\t\t\t\trequested_ids: 4,\n\t\t\t\t\tunique_ids: 3,\n\t\t\t\t\tmax_parallel_requests: 10,\n\t\t\t\t\tsuccessful_items: 2,\n\t\t\t\t\tfailed_items: 1,\n\t\t\t\t\thas_failures: true,\n\t\t\t\t},\n\t\t\t\tinventory_schema: {\n\t\t\t\t\tsku: [\"sku_id\", \"global_available_quantity\", \"health_status\"],\n\t\t\t\t\twarehouse_balance: [\n\t\t\t\t\t\t\"warehouseName\",\n\t\t\t\t\t\t\"totalQuantity\",\n\t\t\t\t\t\t\"reservedQuantity\",\n\t\t\t\t\t\t\"hasUnlimitedQuantity\",\n\t\t\t\t\t\t\"timeToRefill\",\n\t\t\t\t\t\t\"dateOfSupplyUtc\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tinventory: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku: [\"sku-1\", 7, \"LOW_STOCK\"],\n\t\t\t\t\t\twarehouses: [[\"Main\", 10, 3, false, \"2d\", \"2026-06-01 15:30\"]],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsku: [\"sku-2\", 2, \"CRITICAL_LOW_STOCK\"],\n\t\t\t\t\t\twarehouses: [[\"WH-2\", 2, 0, false, \"\", \"\"]],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tfailures: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku_id: \"sku-3\",\n\t\t\t\t\t\tmessage: \"missing\",\n\t\t\t\t\t\tstatus_code: 404,\n\t\t\t\t\t\tattempts: 1,\n\t\t\t\t\t\tretryable: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns profile selection payload unchanged when resolution fails\", async () => {\n\t\tvi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({\n\t\t\tok: false,\n\t\t\tresponse: { selection: true },\n\t\t} as never);\n\n\t\tconst result = await inventoryCheckHandler({ skuIds: [\"sku-1\"] });\n\n\t\texpect(result).toEqual({ selection: true });\n\t\texpect(getInventoryBySkuBatch).not.toHaveBeenCalled();\n\t});\n\n\tit(\"formats heavy tool failures through formatVtexError\", async () => {\n\t\tvi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error(\"boom\"));\n\n\t\tconst result = await warehouseInventoryHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuId: \"sku-1\",\n\t\t\twarehouseId: \"wh-1\",\n\t\t});\n\n\t\texpect(formatVtexError).toHaveBeenCalled();\n\t\texpect(result).toEqual({\n\t\t\tkind: \"error\",\n\t\t\tmessage:\n\t\t\t\t\"formatted:Failed to fetch inventory for SKU sku-1 in warehouse wh-1:boom\",\n\t\t});\n\t});\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
getInventoryBySku,
|
|
4
|
+
getInventoryBySkuBatch,
|
|
5
|
+
getInventoryByWarehouse
|
|
6
|
+
} from "../../src/services/vtex/vtex-logistics.js";
|
|
7
|
+
import { getVtexApiClients } from "../../src/services/vtex/vtex-api.js";
|
|
8
|
+
vi.mock("../../src/services/vtex/vtex-api.js", () => ({
|
|
9
|
+
getVtexApiClients: vi.fn()
|
|
10
|
+
}));
|
|
11
|
+
function makeAxiosLikeError(message, status, retryAfter) {
|
|
12
|
+
return {
|
|
13
|
+
isAxiosError: true,
|
|
14
|
+
message,
|
|
15
|
+
response: status ? {
|
|
16
|
+
status,
|
|
17
|
+
headers: retryAfter === void 0 ? {} : { "retry-after": retryAfter },
|
|
18
|
+
data: { message }
|
|
19
|
+
} : void 0,
|
|
20
|
+
toJSON: () => ({})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
describe("vtex-logistics service", () => {
|
|
24
|
+
const logisticsGet = vi.fn();
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
vi.mocked(getVtexApiClients).mockResolvedValue({
|
|
28
|
+
config: {
|
|
29
|
+
accountName: "test-account",
|
|
30
|
+
apiKey: "key",
|
|
31
|
+
apiToken: "token",
|
|
32
|
+
baseUrl: "https://example.vtex.com",
|
|
33
|
+
pricingBaseUrl: "https://pricing.example.vtex.com"
|
|
34
|
+
},
|
|
35
|
+
vtexApi: {
|
|
36
|
+
get: logisticsGet,
|
|
37
|
+
patch: vi.fn()
|
|
38
|
+
},
|
|
39
|
+
vtexPricingApi: {
|
|
40
|
+
get: vi.fn()
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
it("fetches inventory by sku", async () => {
|
|
45
|
+
logisticsGet.mockResolvedValue({
|
|
46
|
+
data: {
|
|
47
|
+
skuId: "sku-1",
|
|
48
|
+
balance: [{ warehouseId: "wh-1", availableQuantity: 4 }]
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const result = await getInventoryBySku("profile-1", "sku-1");
|
|
52
|
+
expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
|
|
53
|
+
expect(logisticsGet).toHaveBeenCalledWith(
|
|
54
|
+
"/api/logistics/pvt/inventory/skus/sku-1"
|
|
55
|
+
);
|
|
56
|
+
expect(result).toEqual({
|
|
57
|
+
skuId: "sku-1",
|
|
58
|
+
balance: [{ warehouseId: "wh-1", availableQuantity: 4 }]
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
it("fetches inventory by warehouse for a sku", async () => {
|
|
62
|
+
logisticsGet.mockResolvedValue({
|
|
63
|
+
data: [{ skuId: "sku-1", warehouseId: "wh-1", availableQuantity: 3 }]
|
|
64
|
+
});
|
|
65
|
+
const result = await getInventoryByWarehouse("profile-1", "sku-1", "wh-1");
|
|
66
|
+
expect(logisticsGet).toHaveBeenCalledWith(
|
|
67
|
+
"/api/logistics/pvt/inventory/items/sku-1/warehouses/wh-1"
|
|
68
|
+
);
|
|
69
|
+
expect(result).toEqual([
|
|
70
|
+
{ skuId: "sku-1", warehouseId: "wh-1", availableQuantity: 3 }
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
it("returns successful and failed sku inventory documents in batch mode", async () => {
|
|
74
|
+
logisticsGet.mockImplementation((url) => {
|
|
75
|
+
if (url.endsWith("sku-1")) {
|
|
76
|
+
return Promise.resolve({ data: { skuId: "sku-1", balance: [] } });
|
|
77
|
+
}
|
|
78
|
+
return Promise.reject(makeAxiosLikeError("missing", 404));
|
|
79
|
+
});
|
|
80
|
+
const result = await getInventoryBySkuBatch(
|
|
81
|
+
"profile-1",
|
|
82
|
+
["sku-1", "sku-2"],
|
|
83
|
+
{
|
|
84
|
+
maxConcurrency: 2,
|
|
85
|
+
maxRetries: 0
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
expect(result).toEqual({
|
|
89
|
+
successful: [
|
|
90
|
+
{ skuId: "sku-1", document: { skuId: "sku-1", balance: [] } }
|
|
91
|
+
],
|
|
92
|
+
failed: [
|
|
93
|
+
{
|
|
94
|
+
skuId: "sku-2",
|
|
95
|
+
message: "Unexpected error while fetching inventory details",
|
|
96
|
+
statusCode: 404,
|
|
97
|
+
attempts: 1,
|
|
98
|
+
retryable: false
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
it("retries retryable inventory fetches and then succeeds", async () => {
|
|
104
|
+
let attempts = 0;
|
|
105
|
+
logisticsGet.mockImplementation((url) => {
|
|
106
|
+
if (!url.endsWith("sku-3")) {
|
|
107
|
+
return Promise.resolve({ data: { skuId: "other", balance: [] } });
|
|
108
|
+
}
|
|
109
|
+
attempts += 1;
|
|
110
|
+
if (attempts === 1) {
|
|
111
|
+
return Promise.reject(makeAxiosLikeError("rate limited", 429, 0));
|
|
112
|
+
}
|
|
113
|
+
return Promise.resolve({
|
|
114
|
+
data: { skuId: "sku-3", balance: [{ warehouseId: "wh-1" }] }
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
const result = await getInventoryBySkuBatch("profile-1", ["sku-3"], {
|
|
118
|
+
maxConcurrency: 1,
|
|
119
|
+
maxRetries: 1,
|
|
120
|
+
baseRetryDelayMs: 0
|
|
121
|
+
});
|
|
122
|
+
expect(attempts).toBe(2);
|
|
123
|
+
expect(result).toEqual({
|
|
124
|
+
successful: [
|
|
125
|
+
{
|
|
126
|
+
skuId: "sku-3",
|
|
127
|
+
document: { skuId: "sku-3", balance: [{ warehouseId: "wh-1" }] }
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
failed: []
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=vtex-logistics.service.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../tests/vtex/vtex-logistics.service.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n\tgetInventoryBySku,\n\tgetInventoryBySkuBatch,\n\tgetInventoryByWarehouse,\n} from \"../../src/services/vtex/vtex-logistics.js\";\nimport { getVtexApiClients } from \"../../src/services/vtex/vtex-api.js\";\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tgetVtexApiClients: vi.fn(),\n}));\n\nfunction makeAxiosLikeError(\n\tmessage: string,\n\tstatus?: number,\n\tretryAfter?: string | number,\n) {\n\treturn {\n\t\tisAxiosError: true,\n\t\tmessage,\n\t\tresponse: status\n\t\t\t? {\n\t\t\t\t\tstatus,\n\t\t\t\t\theaders:\n\t\t\t\t\t\tretryAfter === undefined ? {} : { \"retry-after\": retryAfter },\n\t\t\t\t\tdata: { message },\n\t\t\t\t}\n\t\t\t: undefined,\n\t\ttoJSON: () => ({}),\n\t};\n}\n\ndescribe(\"vtex-logistics service\", () => {\n\tconst logisticsGet = vi.fn();\n\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\n\t\tvi.mocked(getVtexApiClients).mockResolvedValue({\n\t\t\tconfig: {\n\t\t\t\taccountName: \"test-account\",\n\t\t\t\tapiKey: \"key\",\n\t\t\t\tapiToken: \"token\",\n\t\t\t\tbaseUrl: \"https://example.vtex.com\",\n\t\t\t\tpricingBaseUrl: \"https://pricing.example.vtex.com\",\n\t\t\t},\n\t\t\tvtexApi: {\n\t\t\t\tget: logisticsGet,\n\t\t\t\tpatch: vi.fn(),\n\t\t\t} as never,\n\t\t\tvtexPricingApi: {\n\t\t\t\tget: vi.fn(),\n\t\t\t} as never,\n\t\t});\n\t});\n\n\tit(\"fetches inventory by sku\", async () => {\n\t\tlogisticsGet.mockResolvedValue({\n\t\t\tdata: {\n\t\t\t\tskuId: \"sku-1\",\n\t\t\t\tbalance: [{ warehouseId: \"wh-1\", availableQuantity: 4 }],\n\t\t\t},\n\t\t});\n\n\t\tconst result = await getInventoryBySku(\"profile-1\", \"sku-1\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(logisticsGet).toHaveBeenCalledWith(\n\t\t\t\"/api/logistics/pvt/inventory/skus/sku-1\",\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tskuId: \"sku-1\",\n\t\t\tbalance: [{ warehouseId: \"wh-1\", availableQuantity: 4 }],\n\t\t});\n\t});\n\n\tit(\"fetches inventory by warehouse for a sku\", async () => {\n\t\tlogisticsGet.mockResolvedValue({\n\t\t\tdata: [{ skuId: \"sku-1\", warehouseId: \"wh-1\", availableQuantity: 3 }],\n\t\t});\n\n\t\tconst result = await getInventoryByWarehouse(\"profile-1\", \"sku-1\", \"wh-1\");\n\n\t\texpect(logisticsGet).toHaveBeenCalledWith(\n\t\t\t\"/api/logistics/pvt/inventory/items/sku-1/warehouses/wh-1\",\n\t\t);\n\t\texpect(result).toEqual([\n\t\t\t{ skuId: \"sku-1\", warehouseId: \"wh-1\", availableQuantity: 3 },\n\t\t]);\n\t});\n\n\tit(\"returns successful and failed sku inventory documents in batch mode\", async () => {\n\t\tlogisticsGet.mockImplementation((url: string) => {\n\t\t\tif (url.endsWith(\"sku-1\")) {\n\t\t\t\treturn Promise.resolve({ data: { skuId: \"sku-1\", balance: [] } });\n\t\t\t}\n\n\t\t\treturn Promise.reject(makeAxiosLikeError(\"missing\", 404));\n\t\t});\n\n\t\tconst result = await getInventoryBySkuBatch(\n\t\t\t\"profile-1\",\n\t\t\t[\"sku-1\", \"sku-2\"],\n\t\t\t{\n\t\t\t\tmaxConcurrency: 2,\n\t\t\t\tmaxRetries: 0,\n\t\t\t},\n\t\t);\n\n\t\texpect(result).toEqual({\n\t\t\tsuccessful: [\n\t\t\t\t{ skuId: \"sku-1\", document: { skuId: \"sku-1\", balance: [] } },\n\t\t\t],\n\t\t\tfailed: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\tmessage: \"Unexpected error while fetching inventory details\",\n\t\t\t\t\tstatusCode: 404,\n\t\t\t\t\tattempts: 1,\n\t\t\t\t\tretryable: false,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t});\n\n\tit(\"retries retryable inventory fetches and then succeeds\", async () => {\n\t\tlet attempts = 0;\n\t\tlogisticsGet.mockImplementation((url: string) => {\n\t\t\tif (!url.endsWith(\"sku-3\")) {\n\t\t\t\treturn Promise.resolve({ data: { skuId: \"other\", balance: [] } });\n\t\t\t}\n\n\t\t\tattempts += 1;\n\t\t\tif (attempts === 1) {\n\t\t\t\treturn Promise.reject(makeAxiosLikeError(\"rate limited\", 429, 0));\n\t\t\t}\n\n\t\t\treturn Promise.resolve({\n\t\t\t\tdata: { skuId: \"sku-3\", balance: [{ warehouseId: \"wh-1\" }] },\n\t\t\t});\n\t\t});\n\n\t\tconst result = await getInventoryBySkuBatch(\"profile-1\", [\"sku-3\"], {\n\t\t\tmaxConcurrency: 1,\n\t\t\tmaxRetries: 1,\n\t\t\tbaseRetryDelayMs: 0,\n\t\t});\n\n\t\texpect(attempts).toBe(2);\n\t\texpect(result).toEqual({\n\t\t\tsuccessful: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-3\",\n\t\t\t\t\tdocument: { skuId: \"sku-3\", balance: [{ warehouseId: \"wh-1\" }] },\n\t\t\t\t},\n\t\t\t],\n\t\t\tfailed: [],\n\t\t});\n\t});\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|