@tapcart/mobile-components 0.8.58 → 0.8.59
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/components/hooks/use-scroll-direction.js +2 -2
- package/dist/components/ui/virtual-grid.d.ts +3 -2
- package/dist/components/ui/virtual-grid.d.ts.map +1 -1
- package/dist/components/ui/virtual-grid.js +2 -2
- package/dist/lib/utils.js +2 -2
- package/dist/lib/variablesCart.util.d.ts.map +1 -1
- package/dist/lib/variablesCart.util.js +9 -8
- package/dist/lib/variablesCart.util.test.js +327 -75
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useState, useEffect, useRef, useTransition } from "react";
|
|
2
|
+
import React, { useState, useEffect, useRef, useTransition } from "react";
|
|
3
3
|
function useScrollDirection(threshold = 100) {
|
|
4
4
|
const [scrollData, setScrollData] = useState({
|
|
5
5
|
direction: null,
|
|
@@ -12,7 +12,7 @@ function useScrollDirection(threshold = 100) {
|
|
|
12
12
|
const isBouncing = useRef(false);
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
var _a;
|
|
15
|
-
if (typeof window === "undefined") {
|
|
15
|
+
if (typeof window === "undefined" || React.version === "17.0.2") {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
const updateScrollDirection = () => {
|
|
@@ -4,7 +4,8 @@ interface GridType {
|
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
isLoadingMore: boolean;
|
|
6
6
|
isReachingEnd: boolean;
|
|
7
|
-
LoaderItem: React.
|
|
7
|
+
LoaderItem: React.ComponentType;
|
|
8
|
+
loaderItemProps?: Record<string, any>;
|
|
8
9
|
overscan?: number;
|
|
9
10
|
estimatedHeight?: number;
|
|
10
11
|
spacing?: {
|
|
@@ -18,6 +19,6 @@ declare const virtualGridVariants: (props?: ({
|
|
|
18
19
|
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
|
19
20
|
export interface VirtualGridProps extends GridType, VariantProps<typeof virtualGridVariants> {
|
|
20
21
|
}
|
|
21
|
-
declare function VirtualGrid({ columns, children, overscan, estimatedHeight, isReachingEnd, LoaderItem, spacing, style, }: VirtualGridProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
declare function VirtualGrid({ columns, children, overscan, estimatedHeight, isReachingEnd, LoaderItem, spacing, loaderItemProps, style, }: VirtualGridProps): import("react/jsx-runtime").JSX.Element;
|
|
22
23
|
export { VirtualGrid, virtualGridVariants };
|
|
23
24
|
//# sourceMappingURL=virtual-grid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-grid.d.ts","sourceRoot":"","sources":["../../../components/ui/virtual-grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAMjE,UAAU,QAAQ;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,aAAa,EAAE,OAAO,CAAA;IACtB,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"virtual-grid.d.ts","sourceRoot":"","sources":["../../../components/ui/virtual-grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAMjE,UAAU,QAAQ;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,aAAa,EAAE,OAAO,CAAA;IACtB,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,KAAK,CAAC,aAAa,CAAA;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE;QACR,aAAa,EAAE,MAAM,CAAA;QACrB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAC5B;AAED,QAAA,MAAM,mBAAmB;;mFAYvB,CAAA;AAEF,MAAM,WAAW,gBACf,SAAQ,QAAQ,EACd,YAAY,CAAC,OAAO,mBAAmB,CAAC;CAAG;AAE/C,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,QAAQ,EACR,QAAY,EACZ,eAAqB,EACrB,aAAa,EACb,UAAU,EACV,OAGC,EACD,eAAoB,EACpB,KAAK,GACN,EAAE,gBAAgB,2CAoElB;AAED,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAA"}
|
|
@@ -21,7 +21,7 @@ const virtualGridVariants = cva("grid", {
|
|
|
21
21
|
function VirtualGrid({ columns, children, overscan = 4, estimatedHeight = 375, isReachingEnd, LoaderItem, spacing = {
|
|
22
22
|
horizontalGap: 7,
|
|
23
23
|
verticalGap: 16,
|
|
24
|
-
}, style, }) {
|
|
24
|
+
}, loaderItemProps = {}, style, }) {
|
|
25
25
|
const col = columns || 2;
|
|
26
26
|
const parentRef = React.useRef(document.getElementById("tc-vgsl"));
|
|
27
27
|
const childrenArray = React.Children.toArray(children);
|
|
@@ -51,7 +51,7 @@ function VirtualGrid({ columns, children, overscan = 4, estimatedHeight = 375, i
|
|
|
51
51
|
} }, { children: Array.from({ length: col }).map((_, colIndex) => {
|
|
52
52
|
const index = rowStartIndex + colIndex;
|
|
53
53
|
if (index >= childrenArray.length && !isReachingEnd)
|
|
54
|
-
return (_jsx("div", { children: _jsx(LoaderItem, {}) }, index));
|
|
54
|
+
return (_jsx("div", { children: _jsx(LoaderItem, Object.assign({}, loaderItemProps)) }, index));
|
|
55
55
|
if (!childrenArray[index])
|
|
56
56
|
return null;
|
|
57
57
|
return (_jsx("div", Object.assign({ style: { height: "100%" } }, { children: childrenArray[index] }), index));
|
package/dist/lib/utils.js
CHANGED
|
@@ -575,9 +575,9 @@ const evaluateSingleCondition = (condition, context) => {
|
|
|
575
575
|
// For regular values (like collection names, customer auth, etc)
|
|
576
576
|
switch (operator) {
|
|
577
577
|
case "equals":
|
|
578
|
-
return contextValues.some((contextValue) => (contextValue === null || contextValue === void 0 ? void 0 : contextValue.value.toLowerCase()) === value.toLowerCase());
|
|
578
|
+
return contextValues.some((contextValue) => { var _a; return ((_a = contextValue === null || contextValue === void 0 ? void 0 : contextValue.value) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (value === null || value === void 0 ? void 0 : value.toLowerCase()); });
|
|
579
579
|
case "does not equal":
|
|
580
|
-
return !contextValues.some((contextValue) => (contextValue === null || contextValue === void 0 ? void 0 : contextValue.value.toLowerCase()) === value.toLowerCase());
|
|
580
|
+
return !contextValues.some((contextValue) => { var _a; return ((_a = contextValue === null || contextValue === void 0 ? void 0 : contextValue.value) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (value === null || value === void 0 ? void 0 : value.toLowerCase()); });
|
|
581
581
|
case "contains":
|
|
582
582
|
return contextValues.some((contextValue) => { var _a; return (_a = contextValue === null || contextValue === void 0 ? void 0 : contextValue.value) === null || _a === void 0 ? void 0 : _a.includes(value); });
|
|
583
583
|
default:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variablesCart.util.d.ts","sourceRoot":"","sources":["../../lib/variablesCart.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6BAA6B,EAO9B,MAAM,kBAAkB,CAAA;AAEzB,eAAO,MAAM,2BAA2B;;cAM5B,MAAM;;0BAEI;YAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;YACzB,KAAK,EAAE,MAAM,CAAA;YACb,cAAc,CAAC,EAAE,MAAM,CAAA;SACxB,EAAE;;;;;;CAyBN,CAAA;AAyED,eAAO,MAAM,6BAA6B,SAClC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;AAED,eAAO,MAAM,2BAA2B,SAChC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;
|
|
1
|
+
{"version":3,"file":"variablesCart.util.d.ts","sourceRoot":"","sources":["../../lib/variablesCart.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,6BAA6B,EAO9B,MAAM,kBAAkB,CAAA;AAEzB,eAAO,MAAM,2BAA2B;;cAM5B,MAAM;;0BAEI;YAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;YACzB,KAAK,EAAE,MAAM,CAAA;YACb,cAAc,CAAC,EAAE,MAAM,CAAA;SACxB,EAAE;;;;;;CAyBN,CAAA;AAyED,eAAO,MAAM,6BAA6B,SAClC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;AAED,eAAO,MAAM,2BAA2B,SAChC,MAAM,QACN,SAAS,GAAG,IAAI,YAUvB,CAAA;AAoLD,MAAM,MAAM,uBAAuB,GAAG;IACpC,yBAAyB,EAAE,sBAAsB,EAAE,CAAA;IACnD,gBAAgB,EAAE,6BAA6B,EAAE,CAAA;IACjD,cAAc,EAAE,OAAO,CAAA;IACvB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,iCAAiC,EAAE,uBAU/C,CAAA;AAED,eAAO,MAAM,8BAA8B,SACnC,SAAS,GAAG,IAAI,KACrB,uBAmCF,CAAA"}
|
|
@@ -159,25 +159,26 @@ const getLineItemDiscounts = (cart) => {
|
|
|
159
159
|
const discountMap = ((cart === null || cart === void 0 ? void 0 : cart.items) || []).reduce((acc, item) => {
|
|
160
160
|
var _a;
|
|
161
161
|
(_a = item === null || item === void 0 ? void 0 : item.discounts) === null || _a === void 0 ? void 0 : _a.forEach((discount) => {
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
// Use code if available, otherwise fall back to title, otherwise use a default identifier
|
|
163
|
+
const identifier = (discount === null || discount === void 0 ? void 0 : discount.code) || (discount === null || discount === void 0 ? void 0 : discount.title) || "unknown-discount";
|
|
164
|
+
if (!identifier)
|
|
164
165
|
return;
|
|
165
|
-
if (!acc[
|
|
166
|
-
acc[
|
|
166
|
+
if (!acc[identifier]) {
|
|
167
|
+
acc[identifier] = {
|
|
167
168
|
amount: 0,
|
|
168
169
|
type: discount.type,
|
|
169
170
|
readOnly: discount.readOnly,
|
|
170
171
|
};
|
|
171
172
|
}
|
|
172
|
-
acc[
|
|
173
|
+
acc[identifier].amount += discount.amount;
|
|
173
174
|
});
|
|
174
175
|
return acc;
|
|
175
176
|
}, {});
|
|
176
177
|
if (!discountMap)
|
|
177
178
|
return [];
|
|
178
|
-
return (_a = Object.entries(discountMap)) === null || _a === void 0 ? void 0 : _a.map(([
|
|
179
|
-
id:
|
|
180
|
-
name: `Discount - ${
|
|
179
|
+
return (_a = Object.entries(discountMap)) === null || _a === void 0 ? void 0 : _a.map(([identifier, { amount, type, readOnly }]) => ({
|
|
180
|
+
id: identifier,
|
|
181
|
+
name: `Discount - ${identifier}`,
|
|
181
182
|
amount,
|
|
182
183
|
type,
|
|
183
184
|
readOnly,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-env jest */
|
|
1
2
|
import { getVariablesCalculatedCartData } from "./variablesCart.util";
|
|
2
3
|
import { DiscountApplicationTargetType, } from "app-studio-types";
|
|
3
4
|
const baseCartData = {
|
|
@@ -294,94 +295,345 @@ describe("cart-provider.util", () => {
|
|
|
294
295
|
attributes: [],
|
|
295
296
|
featuredImage: "https://cdn.shopify.com/s/files/1/0656/7939/2959/files/Screenshot2024-08-22at9.44.04AM.png?v=1726022527",
|
|
296
297
|
compareAtPrice: 0,
|
|
297
|
-
quantity: 1,
|
|
298
|
-
totalAmount: 220,
|
|
299
298
|
currencyCode: "USD",
|
|
299
|
+
totalAmount: 220,
|
|
300
300
|
price: 220,
|
|
301
|
-
quantityAvailable: 99,
|
|
302
|
-
variantSku: "",
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
featuredImage: "https://cdn.shopify.com/s/files/1/0656/7939/2959/files/Screenshot2024-08-22at9.44.04AM.png?v=1726022527",
|
|
306
|
-
quantityAvailable: 99,
|
|
307
|
-
variantSku: "",
|
|
308
|
-
title: "Fall Fancy Rug",
|
|
309
|
-
productId: "7954296832191",
|
|
310
|
-
compareAtPrice: 0,
|
|
311
|
-
discounts: [
|
|
312
|
-
{
|
|
313
|
-
type: "manual",
|
|
314
|
-
code: "FALLRUG10",
|
|
315
|
-
amount: 22,
|
|
316
|
-
},
|
|
317
|
-
],
|
|
318
|
-
id: "gid://shopify/CartLine/b642de72-78c4-4998-92da-5d4c4146057b?cart=Z2NwLXVzLXdlc3QxOjAxSlJYUDZRUk1CS1pSRllDSlNTNUgxWFQz",
|
|
319
|
-
attributes: [],
|
|
320
|
-
productVendor: "Emmys Tapcart Boutique",
|
|
321
|
-
image: "https://cdn.shopify.com/s/files/1/0656/7939/2959/files/Screenshot2024-08-22at9.43.44AM_x500.png?v=1726022527",
|
|
322
301
|
quantity: 1,
|
|
323
|
-
totalAmount: 198,
|
|
324
|
-
currencyCode: "USD",
|
|
325
|
-
selectedOptions: [
|
|
326
|
-
{
|
|
327
|
-
name: "Rug Padding",
|
|
328
|
-
value: "With Padding",
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
value: "2 x 3",
|
|
332
|
-
name: "Size",
|
|
333
|
-
},
|
|
334
|
-
],
|
|
335
|
-
price: 220,
|
|
336
|
-
variantId: "43668884029631",
|
|
337
|
-
cost: {
|
|
338
|
-
totalAmount: {
|
|
339
|
-
amount: "198",
|
|
340
|
-
currencyCode: "USD",
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
302
|
},
|
|
344
303
|
],
|
|
345
|
-
subtotal: 679.96,
|
|
346
|
-
discounts: ["Order10", "Fallrug10"],
|
|
347
|
-
// Added discountAllocations for testing
|
|
348
304
|
discountAllocations: [
|
|
349
305
|
{
|
|
350
306
|
targetType: DiscountApplicationTargetType.LineItem,
|
|
351
|
-
discountedAmount: { amount: "
|
|
352
|
-
code: "
|
|
353
|
-
},
|
|
354
|
-
],
|
|
355
|
-
// Added appliedGiftCards using the provided format
|
|
356
|
-
appliedGiftCards: [
|
|
357
|
-
{
|
|
358
|
-
id: "gid://shopify/AppliedGiftCard/3c208423-e985-46c7-bb34-656c59dc29b1",
|
|
359
|
-
lastCharacters: "oney",
|
|
360
|
-
amountUsed: { amount: "10.00", currencyCode: "USD" },
|
|
361
|
-
presentmentAmountUsed: { amount: "10.00", currencyCode: "USD" },
|
|
307
|
+
discountedAmount: { amount: "22.00", currencyCode: "USD" },
|
|
308
|
+
code: "FALLRUG10",
|
|
362
309
|
},
|
|
363
310
|
],
|
|
364
311
|
};
|
|
365
312
|
const result = getVariablesCalculatedCartData(realWorldCart);
|
|
366
|
-
|
|
367
|
-
// Test that the calculated data is correct
|
|
368
|
-
expect(result.orderAndLineItemDiscounts).toHaveLength(2);
|
|
369
|
-
expect(result.orderAndLineItemDiscounts[0].id).toBe("ORDER10");
|
|
370
|
-
expect(result.orderAndLineItemDiscounts[0].amount).toBe(10);
|
|
371
|
-
// Test applied gift cards
|
|
372
|
-
expect(result.appliedGiftCards).toHaveLength(1);
|
|
373
|
-
expect(result.appliedGiftCards[0].id).toBe("gid://shopify/AppliedGiftCard/3c208423-e985-46c7-bb34-656c59dc29b1");
|
|
374
|
-
expect(result.appliedGiftCards[0].amount).toBe(10);
|
|
375
|
-
expect(result.appliedGiftCards[0].name).toBe("Gift Card - oney");
|
|
376
|
-
// Test other calculated values
|
|
377
|
-
expect(result.discountsTotalAmount).toBe(32); // 22 + 10
|
|
378
|
-
expect(result.giftCardsTotalAmount).toBe(10);
|
|
379
|
-
// Test sales amount calculation - should be 4 * (99.99 - 59.99) = 4 * 40 = 160
|
|
380
|
-
expect(result.salesAmount).toBe(160);
|
|
381
|
-
// Total compare at price should include all items pricing
|
|
313
|
+
expect(result).toBeDefined();
|
|
382
314
|
expect(result.totalCompareAtPrice).toBeGreaterThan(0);
|
|
383
|
-
|
|
384
|
-
|
|
315
|
+
expect(isNaN(result.totalDiscountedPrice)).toBe(false);
|
|
316
|
+
});
|
|
317
|
+
it("should handle null cart gracefully", () => {
|
|
318
|
+
const result = getVariablesCalculatedCartData(null);
|
|
319
|
+
expect(result).toEqual({
|
|
320
|
+
orderAndLineItemDiscounts: [],
|
|
321
|
+
appliedGiftCards: [],
|
|
322
|
+
isFreeShipping: false,
|
|
323
|
+
discountsTotalAmount: 0,
|
|
324
|
+
salesAmount: 0,
|
|
325
|
+
giftCardsTotalAmount: 0,
|
|
326
|
+
totalCompareAtPrice: 0,
|
|
327
|
+
totalDiscountedPrice: 0,
|
|
328
|
+
totalSavedAmount: 0,
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
it("should handle empty cart", () => {
|
|
332
|
+
const emptyCart = Object.assign(Object.assign({}, baseCartData), { items: [] });
|
|
333
|
+
const result = getVariablesCalculatedCartData(emptyCart);
|
|
334
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(0);
|
|
335
|
+
expect(result.totalCompareAtPrice).toBe(0);
|
|
336
|
+
expect(result.totalDiscountedPrice).toBe(0);
|
|
337
|
+
});
|
|
338
|
+
// BOGO Discount Tests - Testing the main fix
|
|
339
|
+
describe("BOGO Discount Functionality", () => {
|
|
340
|
+
it("should handle BOGO discounts with only title (no code)", () => {
|
|
341
|
+
// This is the exact scenario from the user's cart data
|
|
342
|
+
const bogoCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
343
|
+
{
|
|
344
|
+
id: "line1",
|
|
345
|
+
quantity: 1,
|
|
346
|
+
productId: "8675202302202",
|
|
347
|
+
variantId: "46921128968442",
|
|
348
|
+
price: 699.95,
|
|
349
|
+
compareAtPrice: 0,
|
|
350
|
+
currencyCode: "USD",
|
|
351
|
+
totalAmount: 699.95,
|
|
352
|
+
title: "The Complete Snowboard",
|
|
353
|
+
discounts: [
|
|
354
|
+
{
|
|
355
|
+
amount: 0,
|
|
356
|
+
title: "Buy 1 get 1 of same",
|
|
357
|
+
type: "automatic",
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
cost: { totalAmount: { amount: "699.95", currencyCode: "USD" } },
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
id: "line2",
|
|
364
|
+
quantity: 1,
|
|
365
|
+
productId: "8675202302202",
|
|
366
|
+
variantId: "46921128968442",
|
|
367
|
+
price: 699.95,
|
|
368
|
+
compareAtPrice: 0,
|
|
369
|
+
currencyCode: "USD",
|
|
370
|
+
totalAmount: 0,
|
|
371
|
+
title: "The Complete Snowboard",
|
|
372
|
+
discounts: [
|
|
373
|
+
{
|
|
374
|
+
amount: 699.95,
|
|
375
|
+
title: "Buy 1 get 1 of same",
|
|
376
|
+
type: "automatic",
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
cost: { totalAmount: { amount: "0", currencyCode: "USD" } },
|
|
380
|
+
},
|
|
381
|
+
] });
|
|
382
|
+
const result = getVariablesCalculatedCartData(bogoCart);
|
|
383
|
+
// Should find the BOGO discount using title as identifier
|
|
384
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(1);
|
|
385
|
+
expect(result.orderAndLineItemDiscounts[0]).toEqual({
|
|
386
|
+
id: "Buy 1 get 1 of same",
|
|
387
|
+
amount: 699.95,
|
|
388
|
+
name: "Discount - Buy 1 get 1 of same",
|
|
389
|
+
type: "automatic",
|
|
390
|
+
readOnly: undefined,
|
|
391
|
+
});
|
|
392
|
+
// Should include BOGO discount in total calculations
|
|
393
|
+
expect(result.discountsTotalAmount).toBe(699.95);
|
|
394
|
+
expect(result.totalCompareAtPrice).toBe(1399.9); // 699.95 * 2
|
|
395
|
+
expect(result.totalDiscountedPrice).toBe(699.95); // 1399.9 - 699.95
|
|
396
|
+
});
|
|
397
|
+
it("should handle discounts with code but no title", () => {
|
|
398
|
+
const codeOnlyCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
399
|
+
{
|
|
400
|
+
id: "line1",
|
|
401
|
+
quantity: 1,
|
|
402
|
+
productId: "prod1",
|
|
403
|
+
variantId: "var1",
|
|
404
|
+
price: 100,
|
|
405
|
+
compareAtPrice: 0,
|
|
406
|
+
currencyCode: "USD",
|
|
407
|
+
discounts: [
|
|
408
|
+
{
|
|
409
|
+
amount: 20,
|
|
410
|
+
code: "SAVE20",
|
|
411
|
+
type: "manual",
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
cost: { totalAmount: { amount: "80", currencyCode: "USD" } },
|
|
415
|
+
},
|
|
416
|
+
] });
|
|
417
|
+
const result = getVariablesCalculatedCartData(codeOnlyCart);
|
|
418
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(1);
|
|
419
|
+
expect(result.orderAndLineItemDiscounts[0].id).toBe("SAVE20");
|
|
420
|
+
expect(result.discountsTotalAmount).toBe(20);
|
|
421
|
+
});
|
|
422
|
+
it("should prefer code over title when both exist", () => {
|
|
423
|
+
const bothCodeAndTitleCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
424
|
+
{
|
|
425
|
+
id: "line1",
|
|
426
|
+
quantity: 1,
|
|
427
|
+
productId: "prod1",
|
|
428
|
+
variantId: "var1",
|
|
429
|
+
price: 100,
|
|
430
|
+
compareAtPrice: 0,
|
|
431
|
+
currencyCode: "USD",
|
|
432
|
+
discounts: [
|
|
433
|
+
{
|
|
434
|
+
amount: 15,
|
|
435
|
+
code: "PROMO15",
|
|
436
|
+
title: "15% Off Promo",
|
|
437
|
+
type: "manual",
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
cost: { totalAmount: { amount: "85", currencyCode: "USD" } },
|
|
441
|
+
},
|
|
442
|
+
] });
|
|
443
|
+
const result = getVariablesCalculatedCartData(bothCodeAndTitleCart);
|
|
444
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(1);
|
|
445
|
+
expect(result.orderAndLineItemDiscounts[0].id).toBe("PROMO15"); // Should use code
|
|
446
|
+
expect(result.orderAndLineItemDiscounts[0].name).toBe("Discount - PROMO15");
|
|
447
|
+
});
|
|
448
|
+
it("should use fallback identifier when neither code nor title exist", () => {
|
|
449
|
+
const noIdentifierCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
450
|
+
{
|
|
451
|
+
id: "line1",
|
|
452
|
+
quantity: 1,
|
|
453
|
+
productId: "prod1",
|
|
454
|
+
variantId: "var1",
|
|
455
|
+
price: 100,
|
|
456
|
+
compareAtPrice: 0,
|
|
457
|
+
currencyCode: "USD",
|
|
458
|
+
discounts: [
|
|
459
|
+
{
|
|
460
|
+
amount: 10,
|
|
461
|
+
type: "automatic",
|
|
462
|
+
// No code or title
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
cost: { totalAmount: { amount: "90", currencyCode: "USD" } },
|
|
466
|
+
},
|
|
467
|
+
] });
|
|
468
|
+
const result = getVariablesCalculatedCartData(noIdentifierCart);
|
|
469
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(1);
|
|
470
|
+
expect(result.orderAndLineItemDiscounts[0].id).toBe("unknown-discount");
|
|
471
|
+
});
|
|
472
|
+
it("should aggregate multiple line items with same discount identifier", () => {
|
|
473
|
+
const multipleItemsSameDiscountCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
474
|
+
{
|
|
475
|
+
id: "line1",
|
|
476
|
+
quantity: 1,
|
|
477
|
+
productId: "prod1",
|
|
478
|
+
variantId: "var1",
|
|
479
|
+
price: 50,
|
|
480
|
+
compareAtPrice: 0,
|
|
481
|
+
currencyCode: "USD",
|
|
482
|
+
discounts: [
|
|
483
|
+
{
|
|
484
|
+
amount: 5,
|
|
485
|
+
title: "10% Off Sale",
|
|
486
|
+
type: "automatic",
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
cost: { totalAmount: { amount: "45", currencyCode: "USD" } },
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
id: "line2",
|
|
493
|
+
quantity: 1,
|
|
494
|
+
productId: "prod2",
|
|
495
|
+
variantId: "var2",
|
|
496
|
+
price: 30,
|
|
497
|
+
compareAtPrice: 0,
|
|
498
|
+
currencyCode: "USD",
|
|
499
|
+
discounts: [
|
|
500
|
+
{
|
|
501
|
+
amount: 3,
|
|
502
|
+
title: "10% Off Sale",
|
|
503
|
+
type: "automatic",
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
cost: { totalAmount: { amount: "27", currencyCode: "USD" } },
|
|
507
|
+
},
|
|
508
|
+
] });
|
|
509
|
+
const result = getVariablesCalculatedCartData(multipleItemsSameDiscountCart);
|
|
510
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(1);
|
|
511
|
+
expect(result.orderAndLineItemDiscounts[0]).toEqual({
|
|
512
|
+
id: "10% Off Sale",
|
|
513
|
+
amount: 8,
|
|
514
|
+
name: "Discount - 10% Off Sale",
|
|
515
|
+
type: "automatic",
|
|
516
|
+
readOnly: undefined,
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
// Edge Case Tests
|
|
521
|
+
describe("Edge Cases", () => {
|
|
522
|
+
it("should handle subscription pricing", () => {
|
|
523
|
+
const subscriptionCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
524
|
+
{
|
|
525
|
+
attributes: {},
|
|
526
|
+
compareAtPrice: 15,
|
|
527
|
+
cost: {
|
|
528
|
+
totalAmount: {
|
|
529
|
+
amount: 8.5,
|
|
530
|
+
currencyCode: "USD",
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
currencyCode: "USD",
|
|
534
|
+
discounts: [],
|
|
535
|
+
featuredImage: "https://cdn.shopify.com/s/files/1/0733/5179/0842/files/snowboard_wax.png?v=1733258904",
|
|
536
|
+
id: "gid://shopify/CartLine/5e1a02e3-5aa0-4244-8653-8adb8205f590?cart=Z2NwLXVzLWVhc3QxOjAxSllFTjRXTTJHQzVYVENBWUVOQjExS0pC",
|
|
537
|
+
price: 10,
|
|
538
|
+
productId: "8746326294778",
|
|
539
|
+
productVendor: "Eric Dixon's Tapcart Boutique",
|
|
540
|
+
quantity: 1,
|
|
541
|
+
quantityAvailable: 13,
|
|
542
|
+
selectedOptions: [
|
|
543
|
+
{
|
|
544
|
+
name: "Color",
|
|
545
|
+
value: "Yellow",
|
|
546
|
+
},
|
|
547
|
+
],
|
|
548
|
+
sellingPlanAllocation: {
|
|
549
|
+
id: "4139745530",
|
|
550
|
+
name: "Ski wax subscription, billed and delivered weekly",
|
|
551
|
+
priceAdjustments: [
|
|
552
|
+
{
|
|
553
|
+
compareAtPrice: 10,
|
|
554
|
+
perDeliveryPrice: 8.5,
|
|
555
|
+
price: 8.5,
|
|
556
|
+
},
|
|
557
|
+
],
|
|
558
|
+
},
|
|
559
|
+
sellingPlanId: "4139745530",
|
|
560
|
+
title: "Subscription Wax",
|
|
561
|
+
totalAmount: 8.5,
|
|
562
|
+
variantId: "47197277683962",
|
|
563
|
+
variantSku: "",
|
|
564
|
+
},
|
|
565
|
+
] });
|
|
566
|
+
const result = getVariablesCalculatedCartData(subscriptionCart);
|
|
567
|
+
expect(result.totalCompareAtPrice).toBe(10); // Using actual item price * quantity since subscription logic uses price as compareAtPrice when no compareAtPrice exists
|
|
568
|
+
expect(result.salesAmount).toBe(1.5); // (10-8.5) * 1 = 1.5 for subscription pricing
|
|
569
|
+
});
|
|
570
|
+
it("should handle mixed discounts and gift cards", () => {
|
|
571
|
+
const mixedCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
572
|
+
{
|
|
573
|
+
id: "line1",
|
|
574
|
+
quantity: 1,
|
|
575
|
+
productId: "prod1",
|
|
576
|
+
variantId: "var1",
|
|
577
|
+
price: 100,
|
|
578
|
+
compareAtPrice: 120,
|
|
579
|
+
currencyCode: "USD",
|
|
580
|
+
discounts: [
|
|
581
|
+
{
|
|
582
|
+
amount: 15,
|
|
583
|
+
title: "Flash Sale",
|
|
584
|
+
type: "automatic",
|
|
585
|
+
},
|
|
586
|
+
],
|
|
587
|
+
cost: { totalAmount: { amount: "85", currencyCode: "USD" } },
|
|
588
|
+
},
|
|
589
|
+
], discountAllocations: [
|
|
590
|
+
{
|
|
591
|
+
targetType: DiscountApplicationTargetType.LineItem,
|
|
592
|
+
discountedAmount: { amount: "10.00", currencyCode: "USD" },
|
|
593
|
+
code: "EXTRA10",
|
|
594
|
+
},
|
|
595
|
+
], appliedGiftCards: [
|
|
596
|
+
{
|
|
597
|
+
id: "gift1",
|
|
598
|
+
lastCharacters: "5678",
|
|
599
|
+
amountUsed: { amount: "20.00", currencyCode: "USD" },
|
|
600
|
+
presentmentAmountUsed: { amount: "20.00", currencyCode: "USD" },
|
|
601
|
+
},
|
|
602
|
+
] });
|
|
603
|
+
const result = getVariablesCalculatedCartData(mixedCart);
|
|
604
|
+
expect(result.orderAndLineItemDiscounts).toHaveLength(2); // Line item + order level
|
|
605
|
+
expect(result.appliedGiftCards).toHaveLength(1);
|
|
606
|
+
expect(result.discountsTotalAmount).toBe(25); // 15 + 10
|
|
607
|
+
expect(result.giftCardsTotalAmount).toBe(20);
|
|
608
|
+
expect(result.salesAmount).toBe(20); // (120-100) * 1
|
|
609
|
+
expect(result.totalDiscountedPrice).toBe(55); // 120 - 25 - 20 - 20
|
|
610
|
+
});
|
|
611
|
+
it("should handle zero amounts and negative scenarios", () => {
|
|
612
|
+
const zeroAmountCart = Object.assign(Object.assign({}, baseCartData), { items: [
|
|
613
|
+
{
|
|
614
|
+
id: "line1",
|
|
615
|
+
quantity: 1,
|
|
616
|
+
productId: "prod1",
|
|
617
|
+
variantId: "var1",
|
|
618
|
+
price: 0,
|
|
619
|
+
compareAtPrice: 0,
|
|
620
|
+
currencyCode: "USD",
|
|
621
|
+
discounts: [
|
|
622
|
+
{
|
|
623
|
+
amount: 0,
|
|
624
|
+
title: "Zero Discount",
|
|
625
|
+
type: "automatic",
|
|
626
|
+
},
|
|
627
|
+
],
|
|
628
|
+
cost: { totalAmount: { amount: "0", currencyCode: "USD" } },
|
|
629
|
+
},
|
|
630
|
+
] });
|
|
631
|
+
const result = getVariablesCalculatedCartData(zeroAmountCart);
|
|
632
|
+
expect(result.totalCompareAtPrice).toBe(0);
|
|
633
|
+
expect(result.discountsTotalAmount).toBe(0);
|
|
634
|
+
expect(result.totalDiscountedPrice).toBe(0);
|
|
635
|
+
expect(result.totalDiscountedPrice).not.toBeLessThan(0);
|
|
636
|
+
});
|
|
385
637
|
});
|
|
386
638
|
});
|
|
387
639
|
});
|