@ominity/api-typescript 1.4.8 → 1.6.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/dist/commonjs/funcs/commerce/cartItemsCreate.js +1 -1
- package/dist/commonjs/funcs/commerce/cartItemsCreate.js.map +1 -1
- package/dist/commonjs/funcs/commerce/customerSubscriptions.d.ts +6 -0
- package/dist/commonjs/funcs/commerce/customerSubscriptions.d.ts.map +1 -1
- package/dist/commonjs/funcs/commerce/customerSubscriptions.js +13 -1
- package/dist/commonjs/funcs/commerce/customerSubscriptions.js.map +1 -1
- package/dist/commonjs/lib/config.d.ts +3 -3
- package/dist/commonjs/lib/config.js +1 -1
- package/dist/commonjs/models/commerce/cart-item.d.ts +19 -14
- package/dist/commonjs/models/commerce/cart-item.d.ts.map +1 -1
- package/dist/commonjs/models/commerce/cart-item.js +28 -23
- package/dist/commonjs/models/commerce/cart-item.js.map +1 -1
- package/dist/commonjs/models/commerce/index.d.ts +1 -0
- package/dist/commonjs/models/commerce/index.d.ts.map +1 -1
- package/dist/commonjs/models/commerce/index.js +1 -0
- package/dist/commonjs/models/commerce/index.js.map +1 -1
- package/dist/commonjs/models/commerce/product.d.ts +3 -0
- package/dist/commonjs/models/commerce/product.d.ts.map +1 -1
- package/dist/commonjs/models/commerce/product.js +2 -0
- package/dist/commonjs/models/commerce/product.js.map +1 -1
- package/dist/commonjs/models/commerce/subscription-change.d.ts +72 -0
- package/dist/commonjs/models/commerce/subscription-change.d.ts.map +1 -0
- package/dist/commonjs/models/commerce/subscription-change.js +96 -0
- package/dist/commonjs/models/commerce/subscription-change.js.map +1 -0
- package/dist/commonjs/models/commerce/subscription.d.ts +2 -0
- package/dist/commonjs/models/commerce/subscription.d.ts.map +1 -1
- package/dist/commonjs/models/commerce/subscription.js +1 -0
- package/dist/commonjs/models/commerce/subscription.js.map +1 -1
- package/dist/commonjs/models/errors/error-response.d.ts +6 -0
- package/dist/commonjs/models/errors/error-response.d.ts.map +1 -1
- package/dist/commonjs/models/errors/error-response.js +8 -1
- package/dist/commonjs/models/errors/error-response.js.map +1 -1
- package/dist/commonjs/models/operations/commerce-customer-subscriptions.d.ts +61 -0
- package/dist/commonjs/models/operations/commerce-customer-subscriptions.d.ts.map +1 -1
- package/dist/commonjs/models/operations/commerce-customer-subscriptions.js +17 -1
- package/dist/commonjs/models/operations/commerce-customer-subscriptions.js.map +1 -1
- package/dist/commonjs/sdk/commerce/customer-subscriptions.d.ts +15 -0
- package/dist/commonjs/sdk/commerce/customer-subscriptions.d.ts.map +1 -1
- package/dist/commonjs/sdk/commerce/customer-subscriptions.js +15 -0
- package/dist/commonjs/sdk/commerce/customer-subscriptions.js.map +1 -1
- package/dist/esm/funcs/commerce/cartItemsCreate.js +1 -1
- package/dist/esm/funcs/commerce/cartItemsCreate.js.map +1 -1
- package/dist/esm/funcs/commerce/customerSubscriptions.d.ts +6 -0
- package/dist/esm/funcs/commerce/customerSubscriptions.d.ts.map +1 -1
- package/dist/esm/funcs/commerce/customerSubscriptions.js +6 -0
- package/dist/esm/funcs/commerce/customerSubscriptions.js.map +1 -1
- package/dist/esm/lib/config.d.ts +3 -3
- package/dist/esm/lib/config.js +1 -1
- package/dist/esm/models/commerce/cart-item.d.ts +19 -14
- package/dist/esm/models/commerce/cart-item.d.ts.map +1 -1
- package/dist/esm/models/commerce/cart-item.js +27 -22
- package/dist/esm/models/commerce/cart-item.js.map +1 -1
- package/dist/esm/models/commerce/index.d.ts +1 -0
- package/dist/esm/models/commerce/index.d.ts.map +1 -1
- package/dist/esm/models/commerce/index.js +1 -0
- package/dist/esm/models/commerce/index.js.map +1 -1
- package/dist/esm/models/commerce/product.d.ts +3 -0
- package/dist/esm/models/commerce/product.d.ts.map +1 -1
- package/dist/esm/models/commerce/product.js +2 -0
- package/dist/esm/models/commerce/product.js.map +1 -1
- package/dist/esm/models/commerce/subscription-change.d.ts +72 -0
- package/dist/esm/models/commerce/subscription-change.d.ts.map +1 -0
- package/dist/esm/models/commerce/subscription-change.js +60 -0
- package/dist/esm/models/commerce/subscription-change.js.map +1 -0
- package/dist/esm/models/commerce/subscription.d.ts +2 -0
- package/dist/esm/models/commerce/subscription.d.ts.map +1 -1
- package/dist/esm/models/commerce/subscription.js +1 -0
- package/dist/esm/models/commerce/subscription.js.map +1 -1
- package/dist/esm/models/errors/error-response.d.ts +6 -0
- package/dist/esm/models/errors/error-response.d.ts.map +1 -1
- package/dist/esm/models/errors/error-response.js +8 -1
- package/dist/esm/models/errors/error-response.js.map +1 -1
- package/dist/esm/models/operations/commerce-customer-subscriptions.d.ts +61 -0
- package/dist/esm/models/operations/commerce-customer-subscriptions.d.ts.map +1 -1
- package/dist/esm/models/operations/commerce-customer-subscriptions.js +16 -0
- package/dist/esm/models/operations/commerce-customer-subscriptions.js.map +1 -1
- package/dist/esm/sdk/commerce/customer-subscriptions.d.ts +15 -0
- package/dist/esm/sdk/commerce/customer-subscriptions.d.ts.map +1 -1
- package/dist/esm/sdk/commerce/customer-subscriptions.js +16 -1
- package/dist/esm/sdk/commerce/customer-subscriptions.js.map +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/funcs/commerce/cartItemsCreate.ts +1 -1
- package/src/funcs/commerce/customerSubscriptions.ts +6 -0
- package/src/lib/config.ts +1 -1
- package/src/models/commerce/cart-item.ts +42 -27
- package/src/models/commerce/index.ts +1 -0
- package/src/models/commerce/product.ts +4 -0
- package/src/models/commerce/subscription-change.ts +137 -0
- package/src/models/commerce/subscription.ts +3 -0
- package/src/models/errors/error-response.ts +13 -1
- package/src/models/operations/commerce-customer-subscriptions.ts +37 -0
- package/src/sdk/commerce/customer-subscriptions.ts +16 -1
- package/tests/core-operations.test.mjs +187 -3
|
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import * as api from "../dist/esm/index.js";
|
|
4
4
|
import { ErrorResponse } from "../dist/esm/models/errors/index.js";
|
|
5
|
-
import { Subscription$inboundSchema } from "../dist/esm/models/index.js";
|
|
5
|
+
import { CartItem$inboundSchema, Product$inboundSchema, Subscription$inboundSchema } from "../dist/esm/models/index.js";
|
|
6
6
|
|
|
7
7
|
const noRetries = { retries: { strategy: "none" } };
|
|
8
8
|
|
|
@@ -43,6 +43,12 @@ const operationCases = [
|
|
|
43
43
|
["customerSubscriptionsRenew", { customerId: 1, id: 2 }, "POST", "/commerce/customers/1/subscriptions/2/renew"],
|
|
44
44
|
["customerSubscriptionsListTransitionProducts", { customerId: 1, subscriptionId: 2 }, "GET", "/commerce/customers/1/subscriptions/2/transition"],
|
|
45
45
|
["customerSubscriptionsGetTransitionProduct", { customerId: 1, subscriptionId: 2, productId: 3 }, "GET", "/commerce/customers/1/subscriptions/2/transition/3"],
|
|
46
|
+
["customerSubscriptionsListTransitions", { customerId: 1, subscriptionId: 2 }, "GET", "/commerce/customers/1/subscriptions/2/transitions"],
|
|
47
|
+
["customerSubscriptionsQuoteChange", { customerId: 1, subscriptionId: 2, data: { toOfferId: 12 } }, "POST", "/commerce/customers/1/subscriptions/2/changes/quote"],
|
|
48
|
+
["customerSubscriptionsConfirmChange", { customerId: 1, subscriptionId: 2, data: { quoteId: "change-id" } }, "POST", "/commerce/customers/1/subscriptions/2/changes"],
|
|
49
|
+
["customerSubscriptionsCancelChange", { customerId: 1, subscriptionId: 2, changeId: "change-id" }, "DELETE", "/commerce/customers/1/subscriptions/2/changes/change-id"],
|
|
50
|
+
["customerSubscriptionsCancel", { customerId: 1, subscriptionId: 2 }, "POST", "/commerce/customers/1/subscriptions/2/cancellation"],
|
|
51
|
+
["customerSubscriptionsRevokeCancellation", { customerId: 1, subscriptionId: 2 }, "DELETE", "/commerce/customers/1/subscriptions/2/cancellation"],
|
|
46
52
|
["shippingClassesList", {}, "GET", "/commerce/shipping-classes"],
|
|
47
53
|
["shippingClassesGet", { id: 1 }, "GET", "/commerce/shipping-classes/1"],
|
|
48
54
|
["invoicesCreate", { data: {} }, "POST", "/commerce/invoices"],
|
|
@@ -100,7 +106,7 @@ test("all added core operations construct the registered API method and path", a
|
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
assert.equal(seen.length, operationCases.length);
|
|
103
|
-
assert.equal(operationCases.length,
|
|
109
|
+
assert.equal(operationCases.length, 75);
|
|
104
110
|
});
|
|
105
111
|
|
|
106
112
|
test("new operations encode deep filters, parse pagination, JSON bodies, and bytes", async () => {
|
|
@@ -137,6 +143,13 @@ test("new operations encode deep filters, parse pagination, JSON bodies, and byt
|
|
|
137
143
|
assert.deepEqual(JSON.parse(seen[3].body), { source_language: "en", target_languages: ["nl"], fields: [{ key: "title", source: "Hello" }] });
|
|
138
144
|
});
|
|
139
145
|
|
|
146
|
+
const amount = (value) => ({ value, currency: "EUR" });
|
|
147
|
+
const cartItemPayload = (extra = {}) => ({
|
|
148
|
+
resource: "cartitem", id: "item-1", cartId: "cart-1", productId: 6, productOfferId: 9, quantity: 1,
|
|
149
|
+
unitAmount: amount("19.99"), discountAmount: amount("0.00"), taxAmount: amount("3.47"), totalAmount: amount("19.99"),
|
|
150
|
+
isShippingRequired: true, updatedAt: "2026-10-29T00:00:00Z", createdAt: "2026-10-29T00:00:00Z", ...extra,
|
|
151
|
+
});
|
|
152
|
+
|
|
140
153
|
test("cart item creation sends only the camelCase request body", async () => {
|
|
141
154
|
let forwardedRequest;
|
|
142
155
|
const sdk = new api.Ominity({
|
|
@@ -144,7 +157,7 @@ test("cart item creation sends only the camelCase request body", async () => {
|
|
|
144
157
|
httpClient: new api.HTTPClient({
|
|
145
158
|
fetcher: async (request) => {
|
|
146
159
|
forwardedRequest = request.clone();
|
|
147
|
-
return new Response(JSON.stringify(
|
|
160
|
+
return new Response(JSON.stringify(cartItemPayload()), {
|
|
148
161
|
status: 201,
|
|
149
162
|
headers: { "content-type": "application/hal+json" },
|
|
150
163
|
});
|
|
@@ -163,6 +176,21 @@ test("cart item creation sends only the camelCase request body", async () => {
|
|
|
163
176
|
});
|
|
164
177
|
});
|
|
165
178
|
|
|
179
|
+
test("adding a product already in the cart accepts the 200 merge response", async () => {
|
|
180
|
+
const sdk = new api.Ominity({
|
|
181
|
+
serverURL: "https://example.test/api",
|
|
182
|
+
httpClient: new api.HTTPClient({
|
|
183
|
+
fetcher: async () => new Response(JSON.stringify(cartItemPayload({ quantity: 2 })), {
|
|
184
|
+
status: 200,
|
|
185
|
+
headers: { "content-type": "application/hal+json" },
|
|
186
|
+
}),
|
|
187
|
+
}),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const item = await sdk.commerce.cartItems.create("cart-1", "6", 1, noRetries);
|
|
191
|
+
assert.equal(item.quantity, 2);
|
|
192
|
+
});
|
|
193
|
+
|
|
166
194
|
test("Subscription parses the corrected productId field", () => {
|
|
167
195
|
const parsed = Subscription$inboundSchema.parse({
|
|
168
196
|
resource: "subscription", id: 1, customerId: 2, productId: 3, intervalId: 4, status: "active",
|
|
@@ -171,6 +199,124 @@ test("Subscription parses the corrected productId field", () => {
|
|
|
171
199
|
updatedAt: "2026-09-13T00:00:00Z", createdAt: "2026-09-13T00:00:00Z",
|
|
172
200
|
});
|
|
173
201
|
assert.equal(parsed.productId, 3);
|
|
202
|
+
assert.equal(parsed.reference, undefined);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const subscriptionChange = (overrides = {}) => ({
|
|
206
|
+
resource: "subscription_change",
|
|
207
|
+
id: "9d3c6a1e-0000-4000-8000-000000000001",
|
|
208
|
+
subscriptionId: 2,
|
|
209
|
+
type: "change",
|
|
210
|
+
direction: "upgrade",
|
|
211
|
+
status: "quoted",
|
|
212
|
+
timing: "immediate",
|
|
213
|
+
effectiveAt: "2026-10-28T00:00:00+00:00",
|
|
214
|
+
from: { productId: 3, offerId: 10, intervalId: 1, recurringAmount: { value: "10.00", currency: "EUR" }, quantity: 1 },
|
|
215
|
+
to: { productId: 4, offerId: 12, intervalId: 1, recurringAmount: { value: "20.00", currency: "EUR" }, quantity: 1 },
|
|
216
|
+
quote: {
|
|
217
|
+
lines: [
|
|
218
|
+
{ type: "charge", description: "rest_of_period", amount: { value: "6.45", currency: "EUR" }, tax: { value: "1.35", currency: "EUR" }, taxRate: 21 },
|
|
219
|
+
{ type: "credit", description: "unused_current_period", amount: { value: "3.23", currency: "EUR" }, tax: { value: "0.68", currency: "EUR" }, taxRate: 21 },
|
|
220
|
+
],
|
|
221
|
+
charge: { value: "6.45", currency: "EUR" },
|
|
222
|
+
credit: { value: "3.23", currency: "EUR" },
|
|
223
|
+
settlement: "next_invoice",
|
|
224
|
+
},
|
|
225
|
+
warnings: [],
|
|
226
|
+
quoteExpiresAt: "2026-10-28T01:00:00+00:00",
|
|
227
|
+
orderId: null,
|
|
228
|
+
createdAt: "2026-10-28T00:00:00+00:00",
|
|
229
|
+
_links: { subscription: { href: "https://example.test/api/v1/commerce/customers/1/subscriptions/2", type: "application/hal+json" } },
|
|
230
|
+
...overrides,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("subscription plan changes and cancellation follow the quote/confirm flow", async () => {
|
|
234
|
+
const seen = [];
|
|
235
|
+
const product = {
|
|
236
|
+
resource: "product", id: 4, sku: "PRO", ean: null, mpn: null, asin: null, title: "Pro", shortTitle: null,
|
|
237
|
+
coverImage: null, additionalImages: [], shortDescription: null, description: null, bulletpoints: [], boxContent: null,
|
|
238
|
+
type: "virtual", condition: "new", categoryId: 1, stock: null, isBackorderAllowed: false, routes: {}, searches: [],
|
|
239
|
+
customFields: [], publishedAt: null, updatedAt: "2026-10-28T00:00:00Z", createdAt: "2026-10-28T00:00:00Z",
|
|
240
|
+
};
|
|
241
|
+
const json = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
242
|
+
const responses = [
|
|
243
|
+
json(200, { count: 1, _embedded: { transitions: [{
|
|
244
|
+
productId: 4, offerId: 12, direction: "upgrade", timing: "immediate", effectiveAt: "2026-10-28T00:00:00+00:00",
|
|
245
|
+
allowed: true, reasons: [], charge: { value: "6.45", currency: "EUR" }, product,
|
|
246
|
+
}] } }),
|
|
247
|
+
json(201, subscriptionChange()),
|
|
248
|
+
json(200, subscriptionChange({
|
|
249
|
+
status: "awaiting_payment",
|
|
250
|
+
orderId: 55,
|
|
251
|
+
_links: { checkout: { href: "https://example.test/api/v1/commerce/customers/1/orders/55", type: "application/hal+json" } },
|
|
252
|
+
})),
|
|
253
|
+
new Response(null, { status: 204 }),
|
|
254
|
+
json(201, subscriptionChange({ type: "cancel", direction: "cancel", timing: "period_end", to: { productId: null, offerId: null, intervalId: null, recurringAmount: null, quantity: null }, warnings: ["notice_period_applies"] })),
|
|
255
|
+
json(200, subscriptionChange({ type: "cancel", status: "pending" })),
|
|
256
|
+
new Response(null, { status: 204 }),
|
|
257
|
+
];
|
|
258
|
+
const sdk = new api.Ominity({
|
|
259
|
+
serverURL: "https://example.test/api",
|
|
260
|
+
httpClient: new api.HTTPClient({ fetcher: async (request) => {
|
|
261
|
+
seen.push({ path: new URL(request.url).pathname, method: request.method, body: await request.clone().text() });
|
|
262
|
+
return responses.shift();
|
|
263
|
+
} }),
|
|
264
|
+
});
|
|
265
|
+
const subscriptions = sdk.commerce.customerSubscriptions;
|
|
266
|
+
|
|
267
|
+
const transitions = await subscriptions.listTransitions({ customerId: 1, subscriptionId: 2 });
|
|
268
|
+
assert.equal(transitions.count, 1);
|
|
269
|
+
assert.equal(transitions.items[0].offerId, 12);
|
|
270
|
+
assert.equal(transitions.items[0].product.id, 4);
|
|
271
|
+
|
|
272
|
+
const quote = await subscriptions.quoteChange({ customerId: 1, subscriptionId: 2, data: { toOfferId: 12, timing: "immediate" } });
|
|
273
|
+
assert.equal(quote.status, "quoted");
|
|
274
|
+
assert.equal(quote.quote.lines.length, 2);
|
|
275
|
+
assert.equal(quote.links?.subscription?.href, "https://example.test/api/v1/commerce/customers/1/subscriptions/2");
|
|
276
|
+
assert.deepEqual(JSON.parse(seen[1].body), { toOfferId: 12, timing: "immediate" });
|
|
277
|
+
|
|
278
|
+
const confirmed = await subscriptions.confirmChange({ customerId: 1, subscriptionId: 2, data: { quoteId: quote.id } });
|
|
279
|
+
assert.equal(confirmed.orderId, 55);
|
|
280
|
+
assert.equal(confirmed.links?.checkout?.href, "https://example.test/api/v1/commerce/customers/1/orders/55");
|
|
281
|
+
assert.deepEqual(JSON.parse(seen[2].body), { quoteId: quote.id });
|
|
282
|
+
|
|
283
|
+
await subscriptions.cancelChange({ customerId: 1, subscriptionId: 2, changeId: quote.id });
|
|
284
|
+
assert.equal(seen[3].path, `/api/v1/commerce/customers/1/subscriptions/2/changes/${quote.id}`);
|
|
285
|
+
|
|
286
|
+
const cancellation = await subscriptions.cancel({ customerId: 1, subscriptionId: 2 });
|
|
287
|
+
assert.equal(cancellation.type, "cancel");
|
|
288
|
+
assert.equal(cancellation.to.recurringAmount, null);
|
|
289
|
+
assert.deepEqual(JSON.parse(seen[4].body), {});
|
|
290
|
+
|
|
291
|
+
await subscriptions.cancel({ customerId: 1, subscriptionId: 2, data: { quoteId: cancellation.id } });
|
|
292
|
+
assert.deepEqual(JSON.parse(seen[5].body), { quoteId: cancellation.id });
|
|
293
|
+
|
|
294
|
+
await subscriptions.revokeCancellation({ customerId: 1, subscriptionId: 2 });
|
|
295
|
+
assert.deepEqual(seen.map((request) => request.method), ["GET", "POST", "POST", "DELETE", "POST", "POST", "DELETE"]);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("a refused subscription change exposes the reason code and field messages", async () => {
|
|
299
|
+
const sdk = new api.Ominity({
|
|
300
|
+
serverURL: "https://example.test/api",
|
|
301
|
+
httpClient: new api.HTTPClient({
|
|
302
|
+
fetcher: async () => new Response(JSON.stringify({
|
|
303
|
+
status: 422,
|
|
304
|
+
title: "Unprocessable Content",
|
|
305
|
+
detail: "Validation failed for the request",
|
|
306
|
+
code: "subscription.next_period_locked",
|
|
307
|
+
errors: { change: ["The next period is already being prepared."] },
|
|
308
|
+
_links: { documentation: { href: "https://docs.ominity.com/overview/handling-errors", type: "text/html" } },
|
|
309
|
+
}), { status: 422, headers: { "content-type": "application/json" } }),
|
|
310
|
+
}),
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
await assert.rejects(
|
|
314
|
+
sdk.commerce.customerSubscriptions.confirmChange({ customerId: 1, subscriptionId: 2, data: { quoteId: "change-id" } }, noRetries),
|
|
315
|
+
(error) => error instanceof ErrorResponse
|
|
316
|
+
&& error.status === 422
|
|
317
|
+
&& error.code === "subscription.next_period_locked"
|
|
318
|
+
&& error.fields?.change?.[0] === "The next period is already being prepared.",
|
|
319
|
+
);
|
|
174
320
|
});
|
|
175
321
|
|
|
176
322
|
test("user action endpoints parse application/json responses and errors", async () => {
|
|
@@ -308,3 +454,41 @@ test("user customer membership failures preserve the API status and detail", asy
|
|
|
308
454
|
&& error.detail === "Could not authorize request",
|
|
309
455
|
);
|
|
310
456
|
});
|
|
457
|
+
|
|
458
|
+
test("Product keeps the offers requested with include=offers", () => {
|
|
459
|
+
const product = {
|
|
460
|
+
resource: "product", id: 4, sku: "PRO", ean: null, mpn: null, asin: null, title: "Pro", shortTitle: null,
|
|
461
|
+
coverImage: null, additionalImages: [], shortDescription: null, description: null, bulletpoints: [], boxContent: null,
|
|
462
|
+
type: "virtual", condition: "new", categoryId: 1, stock: null, isBackorderAllowed: false, routes: {}, searches: [],
|
|
463
|
+
customFields: [], publishedAt: null, updatedAt: "2026-10-28T00:00:00Z", createdAt: "2026-10-28T00:00:00Z",
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
assert.equal(Product$inboundSchema.parse(product).offers, undefined);
|
|
467
|
+
const parsed = Product$inboundSchema.parse({
|
|
468
|
+
...product,
|
|
469
|
+
offers: [{
|
|
470
|
+
resource: "product_offer", id: 9, productId: 4, type: "once", intervalId: null, quantity: 1,
|
|
471
|
+
prices: { EUR: { amount: 19.99, formatted: "€ 19,99" } },
|
|
472
|
+
_links: { self: { href: "https://example.test/api/v1/commerce/products/4/offers/9", type: "application/hal+json" } },
|
|
473
|
+
}],
|
|
474
|
+
});
|
|
475
|
+
assert.equal(parsed.offers?.[0]?.id, 9);
|
|
476
|
+
assert.equal(parsed.offers?.[0]?.links?.self?.href, "https://example.test/api/v1/commerce/products/4/offers/9");
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("CartItem is typed and keeps the embedded product", () => {
|
|
480
|
+
const item = CartItem$inboundSchema.parse(cartItemPayload({
|
|
481
|
+
_embedded: { product: {
|
|
482
|
+
resource: "product", id: 6, sku: "PRO", ean: null, mpn: null, asin: null, title: "Pro", shortTitle: null,
|
|
483
|
+
coverImage: null, additionalImages: [], shortDescription: null, description: null, bulletpoints: [], boxContent: null,
|
|
484
|
+
type: "physical", condition: "new", categoryId: 1, stock: null, isBackorderAllowed: false, routes: {}, searches: [],
|
|
485
|
+
customFields: [], publishedAt: null, updatedAt: "2026-10-29T00:00:00Z", createdAt: "2026-10-29T00:00:00Z",
|
|
486
|
+
} },
|
|
487
|
+
_links: { cart: { href: "https://example.test/api/v1/commerce/carts/cart-1", type: "application/hal+json" } },
|
|
488
|
+
}));
|
|
489
|
+
|
|
490
|
+
assert.equal(item.product?.title, "Pro");
|
|
491
|
+
assert.equal(item.totalAmount.value, "19.99");
|
|
492
|
+
assert.equal(item.links?.cart?.href, "https://example.test/api/v1/commerce/carts/cart-1");
|
|
493
|
+
assert.equal("_embedded" in item, false);
|
|
494
|
+
});
|