@tapcart/mobile-components 0.12.4 → 0.12.6
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-recommendations.d.ts +3 -1
- package/dist/components/hooks/use-recommendations.d.ts.map +1 -1
- package/dist/components/hooks/use-recommendations.js +8 -4
- package/dist/components/ui/product-card.d.ts +1 -0
- package/dist/components/ui/product-card.d.ts.map +1 -1
- package/dist/components/ui/product-card.js +3 -3
- package/package.json +1 -1
- package/dist/lib/utils.wishlist.test.d.ts +0 -2
- package/dist/lib/utils.wishlist.test.d.ts.map +0 -1
- package/dist/lib/utils.wishlist.test.js +0 -108
- package/dist/tests/conditional-rendering.test.d.ts +0 -2
- package/dist/tests/conditional-rendering.test.d.ts.map +0 -1
- package/dist/tests/conditional-rendering.test.js +0 -476
|
@@ -2,6 +2,7 @@ import { Collection, Product, BaseSearchClient } from "app-studio-types";
|
|
|
2
2
|
interface UseRecommendationProps {
|
|
3
3
|
searchClient?: BaseSearchClient<Product>;
|
|
4
4
|
query?: string;
|
|
5
|
+
customSearchConfig?: Record<string, any>;
|
|
5
6
|
queryVariables: Record<string, any>;
|
|
6
7
|
apiURL: string;
|
|
7
8
|
}
|
|
@@ -9,9 +10,10 @@ interface UseRecommendationReturn {
|
|
|
9
10
|
products: Product[];
|
|
10
11
|
collections: Collection[];
|
|
11
12
|
searches: string[];
|
|
13
|
+
facets: any[];
|
|
12
14
|
isLoading: boolean;
|
|
13
15
|
error: any;
|
|
14
16
|
}
|
|
15
|
-
declare const useRecommendations: ({ searchClient, query, queryVariables, apiURL, }: UseRecommendationProps) => UseRecommendationReturn;
|
|
17
|
+
declare const useRecommendations: ({ searchClient, query, customSearchConfig, queryVariables, apiURL, }: UseRecommendationProps) => UseRecommendationReturn;
|
|
16
18
|
export { useRecommendations };
|
|
17
19
|
//# sourceMappingURL=use-recommendations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-recommendations.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-recommendations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAOxE,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"use-recommendations.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-recommendations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAOxE,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGxC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;CACf;AAUD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,EAAE,GAAG,EAAE,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,GAAG,CAAA;CACX;AAiBD,QAAA,MAAM,kBAAkB,yEASrB,sBAAsB,KAAG,uBAkG3B,CAAA;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -24,7 +24,7 @@ const getCollections = (collections) => {
|
|
|
24
24
|
const recommendationsLocalStorage = new RecommendationsLocalStorage();
|
|
25
25
|
const useRecommendations = ({
|
|
26
26
|
// Search client props
|
|
27
|
-
searchClient, query = "",
|
|
27
|
+
searchClient, query = "", customSearchConfig,
|
|
28
28
|
// API props (backwards compatibility)
|
|
29
29
|
queryVariables, apiURL, }) => {
|
|
30
30
|
// When searchClient is provided, use search client approach
|
|
@@ -40,12 +40,13 @@ queryVariables, apiURL, }) => {
|
|
|
40
40
|
const searchClientFetcher = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
41
|
if (!searchClient)
|
|
42
42
|
return null;
|
|
43
|
-
// Call searchClient.getRecommendations
|
|
43
|
+
// Call searchClient.getRecommendations with optional custom config
|
|
44
44
|
const recommendations = yield searchClient.getRecommendations({
|
|
45
45
|
query: recommendation,
|
|
46
|
+
customSearchConfig,
|
|
46
47
|
});
|
|
47
48
|
// Format as expected by the hook
|
|
48
|
-
return Object.assign(
|
|
49
|
+
return Object.assign({ collections: [], facets: [] }, recommendations);
|
|
49
50
|
});
|
|
50
51
|
// API fetcher (backwards compatibility)
|
|
51
52
|
const apiFetcher = (body) => fetch(constructURL(apiURL), {
|
|
@@ -64,6 +65,7 @@ queryVariables, apiURL, }) => {
|
|
|
64
65
|
type: "searchClient",
|
|
65
66
|
query: recommendation,
|
|
66
67
|
language: queryVariables === null || queryVariables === void 0 ? void 0 : queryVariables.language,
|
|
68
|
+
customSearchConfig,
|
|
67
69
|
}
|
|
68
70
|
: {
|
|
69
71
|
appId: queryVariables.appId,
|
|
@@ -84,12 +86,14 @@ queryVariables, apiURL, }) => {
|
|
|
84
86
|
products: data === null || data === void 0 ? void 0 : data.products,
|
|
85
87
|
collections: getCollections(data === null || data === void 0 ? void 0 : data.collections),
|
|
86
88
|
searches: data === null || data === void 0 ? void 0 : data.searches,
|
|
89
|
+
facets: (data === null || data === void 0 ? void 0 : data.facets) || [],
|
|
87
90
|
});
|
|
88
|
-
}, [data]);
|
|
91
|
+
}, [data, recommendation, queryVariables === null || queryVariables === void 0 ? void 0 : queryVariables.language]);
|
|
89
92
|
return {
|
|
90
93
|
products: cachedRecommendation === null || cachedRecommendation === void 0 ? void 0 : cachedRecommendation.products,
|
|
91
94
|
collections: cachedRecommendation === null || cachedRecommendation === void 0 ? void 0 : cachedRecommendation.collections,
|
|
92
95
|
searches: cachedRecommendation === null || cachedRecommendation === void 0 ? void 0 : cachedRecommendation.searches,
|
|
96
|
+
facets: (cachedRecommendation === null || cachedRecommendation === void 0 ? void 0 : cachedRecommendation.facets) || [],
|
|
93
97
|
isLoading: !cachedRecommendation && isLoading,
|
|
94
98
|
error: error,
|
|
95
99
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-card.d.ts","sourceRoot":"","sources":["../../../components/ui/product-card.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAQ1C,KAAK,MAAM,GAAG;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,iBAAiB,EAAE,OAAO,CAAA;KAC3B,CAAA;IACD,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"product-card.d.ts","sourceRoot":"","sources":["../../../components/ui/product-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -135,7 +135,7 @@ const productCardFavoriteVariants = cva("absolute ", {
|
|
|
135
135
|
},
|
|
136
136
|
});
|
|
137
137
|
const ProductCard = ({ config, tapcartData, product, isLoading, favorited, onFavoriteClick, onQuickAdd, openProduct, className, }) => {
|
|
138
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20;
|
|
138
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21;
|
|
139
139
|
const { variants, images, title, tags } = product;
|
|
140
140
|
// Select the variant that has the lowest price that is available or just the lowest price if none are available
|
|
141
141
|
let searchVariants = variants.filter((variant) => variant.available);
|
|
@@ -271,9 +271,9 @@ const ProductCard = ({ config, tapcartData, product, isLoading, favorited, onFav
|
|
|
271
271
|
variant.compareAtPrice &&
|
|
272
272
|
parseFloat((_12 = variant.compareAtPrice) === null || _12 === void 0 ? void 0 : _12.amount) >
|
|
273
273
|
parseFloat(variant.price.amount), compareAtPrice: variant.compareAtPrice &&
|
|
274
|
-
parseFloat((_13 = variant.compareAtPrice) === null || _13 === void 0 ? void 0 : _13.amount), currency: tapcartData.currency.code, locale: tapcartData.currency.locale, fontSize: (_14 = config.price) === null || _14 === void 0 ? void 0 : _14.fontSize })), ((
|
|
274
|
+
parseFloat((_13 = variant.compareAtPrice) === null || _13 === void 0 ? void 0 : _13.amount), currency: tapcartData.currency.code, locale: tapcartData.currency.locale, fontSize: (_14 = config.price) === null || _14 === void 0 ? void 0 : _14.fontSize, hideZeroCents: (_15 = config.price) === null || _15 === void 0 ? void 0 : _15.hideZeroCents })), ((_16 = config.favoritesIcon) === null || _16 === void 0 ? void 0 : _16.enabled) &&
|
|
275
275
|
config.favoritesIcon.layoutType === "below-image-on-right" && (_jsx("div", Object.assign({ className: "w-8 h-8 flex items-center justify-center" }, { children: _jsx(Favorite, { selected: favorited, onClick: (e) => {
|
|
276
276
|
onFavoriteClick === null || onFavoriteClick === void 0 ? void 0 : onFavoriteClick(e, product);
|
|
277
|
-
}, size: "small", iconUrl: (
|
|
277
|
+
}, size: "small", iconUrl: (_18 = (_17 = config.favoritesIcon) === null || _17 === void 0 ? void 0 : _17.icon) === null || _18 === void 0 ? void 0 : _18.url, cornerRadius: (_19 = config.favoritesIcon) === null || _19 === void 0 ? void 0 : _19.cornerRadius, layoutType: (_20 = config.favoritesIcon) === null || _20 === void 0 ? void 0 : _20.layoutType, showBackground: (_21 = config.favoritesIcon) === null || _21 === void 0 ? void 0 : _21.showBackground }) })))] }))] }))] })) })));
|
|
278
278
|
};
|
|
279
279
|
export { ProductCard };
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.wishlist.test.d.ts","sourceRoot":"","sources":["../../lib/utils.wishlist.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { findWishlistEntry, getEnabledWishlistIntegration, supportsMultipleWishlists, } from "./utils";
|
|
2
|
-
describe("getEnabledWishlistIntegration", () => {
|
|
3
|
-
it("returns the first enabled wishlist integration", () => {
|
|
4
|
-
const integrations = [
|
|
5
|
-
{ name: "tapcart-search", enabled: true },
|
|
6
|
-
{ name: "tapcart-wishlist", enabled: true, multiwishlist: true },
|
|
7
|
-
{ name: "swym", enabled: true },
|
|
8
|
-
];
|
|
9
|
-
const result = getEnabledWishlistIntegration(integrations);
|
|
10
|
-
expect(result).toEqual({
|
|
11
|
-
name: "tapcart-wishlist",
|
|
12
|
-
enabled: true,
|
|
13
|
-
multiwishlist: true,
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
it("returns null when no wishlist integration is enabled", () => {
|
|
17
|
-
const integrations = [
|
|
18
|
-
{ name: "tapcart-search", enabled: true },
|
|
19
|
-
{ name: "tapcart-wishlist", enabled: false },
|
|
20
|
-
];
|
|
21
|
-
expect(getEnabledWishlistIntegration(integrations)).toBeNull();
|
|
22
|
-
});
|
|
23
|
-
it("returns null when integrations is not an array", () => {
|
|
24
|
-
expect(getEnabledWishlistIntegration(undefined)).toBeNull();
|
|
25
|
-
expect(getEnabledWishlistIntegration(null)).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
describe("supportsMultipleWishlists", () => {
|
|
29
|
-
it("respects explicit multiwishlist flag", () => {
|
|
30
|
-
expect(supportsMultipleWishlists({
|
|
31
|
-
name: "tapcart-wishlist",
|
|
32
|
-
enabled: true,
|
|
33
|
-
multiwishlist: false,
|
|
34
|
-
})).toBe(false);
|
|
35
|
-
expect(supportsMultipleWishlists({
|
|
36
|
-
name: "tapcart-wishlist",
|
|
37
|
-
enabled: true,
|
|
38
|
-
multiwishlist: true,
|
|
39
|
-
})).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
it("defaults to true for known integrations when flag is omitted", () => {
|
|
42
|
-
expect(supportsMultipleWishlists({
|
|
43
|
-
name: "tapcart-wishlist-v2",
|
|
44
|
-
enabled: true,
|
|
45
|
-
})).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it("returns false for unknown integrations", () => {
|
|
48
|
-
expect(supportsMultipleWishlists({
|
|
49
|
-
name: "not-a-wishlist",
|
|
50
|
-
enabled: true,
|
|
51
|
-
})).toBe(false);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
describe("findWishlistEntry", () => {
|
|
55
|
-
const wishlists = [
|
|
56
|
-
{
|
|
57
|
-
id: "wl-1",
|
|
58
|
-
items: [
|
|
59
|
-
{
|
|
60
|
-
id: "item-1",
|
|
61
|
-
productId: "gid://shopify/Product/123",
|
|
62
|
-
variantId: "gid://shopify/ProductVariant/456",
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
_id: "wl-2",
|
|
68
|
-
items: [
|
|
69
|
-
{
|
|
70
|
-
id: "item-2",
|
|
71
|
-
productId: "789",
|
|
72
|
-
variantId: "654",
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
];
|
|
77
|
-
it("finds an entry when product and variant match across gid representations", () => {
|
|
78
|
-
const match = findWishlistEntry(wishlists, "123", "456");
|
|
79
|
-
expect(match).toEqual({
|
|
80
|
-
wishlistId: "wl-1",
|
|
81
|
-
item: {
|
|
82
|
-
id: "item-1",
|
|
83
|
-
productId: "gid://shopify/Product/123",
|
|
84
|
-
variantId: "gid://shopify/ProductVariant/456",
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
it("falls back to product-only lookup when variant is omitted", () => {
|
|
89
|
-
const match = findWishlistEntry(wishlists, "789");
|
|
90
|
-
expect(match).toEqual({
|
|
91
|
-
wishlistId: "wl-2",
|
|
92
|
-
item: {
|
|
93
|
-
id: "item-2",
|
|
94
|
-
productId: "789",
|
|
95
|
-
variantId: "654",
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
it("returns null when no matching entry is found", () => {
|
|
100
|
-
const match = findWishlistEntry(wishlists, "999", "888");
|
|
101
|
-
expect(match).toBeNull();
|
|
102
|
-
});
|
|
103
|
-
it("handles empty or invalid inputs gracefully", () => {
|
|
104
|
-
expect(findWishlistEntry(undefined, "123")).toBeNull();
|
|
105
|
-
expect(findWishlistEntry([], "123")).toBeNull();
|
|
106
|
-
expect(findWishlistEntry(wishlists, undefined)).toBeNull();
|
|
107
|
-
});
|
|
108
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"conditional-rendering.test.d.ts","sourceRoot":"","sources":["../../tests/conditional-rendering.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
import { shouldShowBlock, evaluateConditions, getEnvState } from "../lib/utils";
|
|
2
|
-
describe("Conditional Rendering - Bug Tests", () => {
|
|
3
|
-
describe("V1 Conditionals (shouldShowBlock)", () => {
|
|
4
|
-
describe("OR logic with customerTag and deviceId", () => {
|
|
5
|
-
it("should show block when customerTag matches and deviceId does not match", () => {
|
|
6
|
-
const envState = getEnvState({
|
|
7
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
8
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
9
|
-
});
|
|
10
|
-
const blockState = {
|
|
11
|
-
customerTag: [{ value: "VIP" }],
|
|
12
|
-
deviceId: [{ value: "device-999" }], // Different device ID
|
|
13
|
-
};
|
|
14
|
-
const result = shouldShowBlock(envState, blockState);
|
|
15
|
-
expect(result).toBe(true); // Should be true because customerTag matches (OR logic)
|
|
16
|
-
});
|
|
17
|
-
it("should show block when deviceId matches and customerTag does not match", () => {
|
|
18
|
-
const envState = getEnvState({
|
|
19
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
20
|
-
customer: { id: "customer-1", tags: ["Regular"] },
|
|
21
|
-
});
|
|
22
|
-
const blockState = {
|
|
23
|
-
customerTag: [{ value: "VIP" }],
|
|
24
|
-
deviceId: [{ value: "device-123" }], // Device ID matches
|
|
25
|
-
};
|
|
26
|
-
const result = shouldShowBlock(envState, blockState);
|
|
27
|
-
expect(result).toBe(true); // Should be true because deviceId matches (OR logic)
|
|
28
|
-
});
|
|
29
|
-
it("should NOT show block when neither customerTag nor deviceId match", () => {
|
|
30
|
-
const envState = getEnvState({
|
|
31
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
32
|
-
customer: { id: "customer-1", tags: ["Regular"] },
|
|
33
|
-
});
|
|
34
|
-
const blockState = {
|
|
35
|
-
customerTag: [{ value: "VIP" }],
|
|
36
|
-
deviceId: [{ value: "device-999" }],
|
|
37
|
-
};
|
|
38
|
-
const result = shouldShowBlock(envState, blockState);
|
|
39
|
-
expect(result).toBe(false); // Neither condition matches
|
|
40
|
-
});
|
|
41
|
-
it("should show block when both customerTag and deviceId match", () => {
|
|
42
|
-
const envState = getEnvState({
|
|
43
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
44
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
45
|
-
});
|
|
46
|
-
const blockState = {
|
|
47
|
-
customerTag: [{ value: "VIP" }],
|
|
48
|
-
deviceId: [{ value: "device-123" }],
|
|
49
|
-
};
|
|
50
|
-
const result = shouldShowBlock(envState, blockState);
|
|
51
|
-
expect(result).toBe(true); // Both match
|
|
52
|
-
});
|
|
53
|
-
it("should handle missing deviceId in environment gracefully", () => {
|
|
54
|
-
const envState = getEnvState({
|
|
55
|
-
location: { country: "US", language: "en" },
|
|
56
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
57
|
-
});
|
|
58
|
-
const blockState = {
|
|
59
|
-
customerTag: [{ value: "VIP" }],
|
|
60
|
-
deviceId: [{ value: "device-123" }],
|
|
61
|
-
};
|
|
62
|
-
const result = shouldShowBlock(envState, blockState);
|
|
63
|
-
expect(result).toBe(true); // Should still show because customerTag matches
|
|
64
|
-
});
|
|
65
|
-
it("should handle missing customer tags gracefully", () => {
|
|
66
|
-
const envState = getEnvState({
|
|
67
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
68
|
-
customer: { id: "customer-1", tags: [] }, // No tags
|
|
69
|
-
});
|
|
70
|
-
const blockState = {
|
|
71
|
-
customerTag: [{ value: "VIP" }],
|
|
72
|
-
deviceId: [{ value: "device-123" }],
|
|
73
|
-
};
|
|
74
|
-
const result = shouldShowBlock(envState, blockState);
|
|
75
|
-
expect(result).toBe(true); // Should show because deviceId matches
|
|
76
|
-
});
|
|
77
|
-
it("should handle no customer (logged out) with deviceId match", () => {
|
|
78
|
-
const envState = getEnvState({
|
|
79
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
80
|
-
customer: undefined, // Not logged in
|
|
81
|
-
});
|
|
82
|
-
const blockState = {
|
|
83
|
-
customerTag: [{ value: "VIP" }],
|
|
84
|
-
deviceId: [{ value: "device-123" }],
|
|
85
|
-
};
|
|
86
|
-
const result = shouldShowBlock(envState, blockState);
|
|
87
|
-
expect(result).toBe(true); // Should show because deviceId matches
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
describe("V2 Conditionals (evaluateConditions)", () => {
|
|
92
|
-
describe("OR logic with customerTag and deviceId", () => {
|
|
93
|
-
it("should show block when customerTag matches and deviceId does not match (OR logic)", () => {
|
|
94
|
-
const envState = getEnvState({
|
|
95
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
96
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
97
|
-
});
|
|
98
|
-
const conditions = {
|
|
99
|
-
logic: "OR",
|
|
100
|
-
conditions: [
|
|
101
|
-
{
|
|
102
|
-
type: "customerTag",
|
|
103
|
-
operator: "equals",
|
|
104
|
-
value: "VIP",
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
type: "deviceId",
|
|
108
|
-
operator: "equals",
|
|
109
|
-
value: "device-999", // Different device ID
|
|
110
|
-
},
|
|
111
|
-
],
|
|
112
|
-
};
|
|
113
|
-
const result = evaluateConditions(conditions, envState);
|
|
114
|
-
expect(result).toBe(true); // Should be true because customerTag matches
|
|
115
|
-
});
|
|
116
|
-
it("should show block when deviceId matches and customerTag does not match (OR logic)", () => {
|
|
117
|
-
const envState = getEnvState({
|
|
118
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
119
|
-
customer: { id: "customer-1", tags: ["Regular"] },
|
|
120
|
-
});
|
|
121
|
-
const conditions = {
|
|
122
|
-
logic: "OR",
|
|
123
|
-
conditions: [
|
|
124
|
-
{
|
|
125
|
-
type: "customerTag",
|
|
126
|
-
operator: "equals",
|
|
127
|
-
value: "VIP", // Customer doesn't have VIP tag
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
type: "deviceId",
|
|
131
|
-
operator: "equals",
|
|
132
|
-
value: "device-123", // Device ID matches
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
};
|
|
136
|
-
const result = evaluateConditions(conditions, envState);
|
|
137
|
-
expect(result).toBe(true); // Should be true because deviceId matches
|
|
138
|
-
});
|
|
139
|
-
it("should NOT show block when neither customerTag nor deviceId match", () => {
|
|
140
|
-
const envState = getEnvState({
|
|
141
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
142
|
-
customer: { id: "customer-1", tags: ["Regular"] },
|
|
143
|
-
});
|
|
144
|
-
const conditions = {
|
|
145
|
-
logic: "OR",
|
|
146
|
-
conditions: [
|
|
147
|
-
{
|
|
148
|
-
type: "customerTag",
|
|
149
|
-
operator: "equals",
|
|
150
|
-
value: "VIP",
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: "deviceId",
|
|
154
|
-
operator: "equals",
|
|
155
|
-
value: "device-999",
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
};
|
|
159
|
-
const result = evaluateConditions(conditions, envState);
|
|
160
|
-
expect(result).toBe(false); // Neither condition matches
|
|
161
|
-
});
|
|
162
|
-
it("should show block when both customerTag and deviceId match", () => {
|
|
163
|
-
const envState = getEnvState({
|
|
164
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
165
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
166
|
-
});
|
|
167
|
-
const conditions = {
|
|
168
|
-
logic: "OR",
|
|
169
|
-
conditions: [
|
|
170
|
-
{
|
|
171
|
-
type: "customerTag",
|
|
172
|
-
operator: "equals",
|
|
173
|
-
value: "VIP",
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
type: "deviceId",
|
|
177
|
-
operator: "equals",
|
|
178
|
-
value: "device-123",
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
};
|
|
182
|
-
const result = evaluateConditions(conditions, envState);
|
|
183
|
-
expect(result).toBe(true); // Both match
|
|
184
|
-
});
|
|
185
|
-
it("should NOT show block when deviceId is undefined in environment but is checked in conditions", () => {
|
|
186
|
-
const envState = getEnvState({
|
|
187
|
-
location: { country: "US", language: "en" },
|
|
188
|
-
customer: { id: "customer-1", tags: ["Regular"] }, // Customer doesn't have VIP tag
|
|
189
|
-
});
|
|
190
|
-
const conditions = {
|
|
191
|
-
logic: "OR",
|
|
192
|
-
conditions: [
|
|
193
|
-
{
|
|
194
|
-
type: "customerTag",
|
|
195
|
-
operator: "equals",
|
|
196
|
-
value: "VIP", // Doesn't match
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
type: "deviceId",
|
|
200
|
-
operator: "equals",
|
|
201
|
-
value: "device-123", // deviceId has value "undefined" in context
|
|
202
|
-
},
|
|
203
|
-
],
|
|
204
|
-
};
|
|
205
|
-
const result = evaluateConditions(conditions, envState);
|
|
206
|
-
// deviceId is present in envState with value "undefined", so it checks and returns false
|
|
207
|
-
expect(result).toBe(false); // Neither condition matches
|
|
208
|
-
});
|
|
209
|
-
it("should NOT show block when customer has no tags and deviceId doesn't match", () => {
|
|
210
|
-
const envState = getEnvState({
|
|
211
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
212
|
-
customer: { id: "customer-1", tags: [] }, // No tags (empty array)
|
|
213
|
-
});
|
|
214
|
-
const conditions = {
|
|
215
|
-
logic: "OR",
|
|
216
|
-
conditions: [
|
|
217
|
-
{
|
|
218
|
-
type: "customerTag",
|
|
219
|
-
operator: "equals",
|
|
220
|
-
value: "VIP", // Customer has no tags (empty array)
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
type: "deviceId",
|
|
224
|
-
operator: "equals",
|
|
225
|
-
value: "device-999", // Device ID doesn't match
|
|
226
|
-
},
|
|
227
|
-
],
|
|
228
|
-
};
|
|
229
|
-
const result = evaluateConditions(conditions, envState);
|
|
230
|
-
expect(result).toBe(false); // Neither condition matches
|
|
231
|
-
});
|
|
232
|
-
it("should NOT show block when customer is undefined and deviceId doesn't match", () => {
|
|
233
|
-
const envState = getEnvState({
|
|
234
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
235
|
-
customer: undefined, // Not logged in - customer is undefined
|
|
236
|
-
});
|
|
237
|
-
const conditions = {
|
|
238
|
-
logic: "OR",
|
|
239
|
-
conditions: [
|
|
240
|
-
{
|
|
241
|
-
type: "customerTag",
|
|
242
|
-
operator: "equals",
|
|
243
|
-
value: "VIP", // Customer is undefined, so customerTag is empty array []
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
type: "deviceId",
|
|
247
|
-
operator: "equals",
|
|
248
|
-
value: "device-999", // Device ID doesn't match
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
};
|
|
252
|
-
const result = evaluateConditions(conditions, envState);
|
|
253
|
-
// customerTag is present as empty array [], deviceId doesn't match
|
|
254
|
-
expect(result).toBe(false); // Neither condition matches
|
|
255
|
-
});
|
|
256
|
-
it("should correctly handle AND logic with customerTag and deviceId", () => {
|
|
257
|
-
const envState = getEnvState({
|
|
258
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
259
|
-
customer: { id: "customer-1", tags: ["VIP"] },
|
|
260
|
-
});
|
|
261
|
-
const conditions = {
|
|
262
|
-
logic: "AND",
|
|
263
|
-
conditions: [
|
|
264
|
-
{
|
|
265
|
-
type: "customerTag",
|
|
266
|
-
operator: "equals",
|
|
267
|
-
value: "VIP",
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
type: "deviceId",
|
|
271
|
-
operator: "equals",
|
|
272
|
-
value: "device-123",
|
|
273
|
-
},
|
|
274
|
-
],
|
|
275
|
-
};
|
|
276
|
-
const result = evaluateConditions(conditions, envState);
|
|
277
|
-
expect(result).toBe(true); // Both conditions must match for AND
|
|
278
|
-
});
|
|
279
|
-
it("should NOT show block with AND logic when only one condition matches", () => {
|
|
280
|
-
const envState = getEnvState({
|
|
281
|
-
location: { country: "US", language: "en", deviceId: "device-123" },
|
|
282
|
-
customer: { id: "customer-1", tags: ["Regular"] },
|
|
283
|
-
});
|
|
284
|
-
const conditions = {
|
|
285
|
-
logic: "AND",
|
|
286
|
-
conditions: [
|
|
287
|
-
{
|
|
288
|
-
type: "customerTag",
|
|
289
|
-
operator: "equals",
|
|
290
|
-
value: "VIP", // Doesn't match
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
type: "deviceId",
|
|
294
|
-
operator: "equals",
|
|
295
|
-
value: "device-123", // Matches
|
|
296
|
-
},
|
|
297
|
-
],
|
|
298
|
-
};
|
|
299
|
-
const result = evaluateConditions(conditions, envState);
|
|
300
|
-
expect(result).toBe(false); // AND requires both to match
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
describe("Edge cases with missing context data", () => {
|
|
304
|
-
it("KNOWN BEHAVIOR: returns true when checking a condition type that doesn't exist in context", () => {
|
|
305
|
-
const envState = {
|
|
306
|
-
// Empty context - no data
|
|
307
|
-
};
|
|
308
|
-
const conditions = {
|
|
309
|
-
logic: "OR",
|
|
310
|
-
conditions: [
|
|
311
|
-
{
|
|
312
|
-
type: "customerTag",
|
|
313
|
-
operator: "equals",
|
|
314
|
-
value: "VIP",
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
};
|
|
318
|
-
const result = evaluateConditions(conditions, envState);
|
|
319
|
-
// This returns TRUE when context is missing (current behavior)
|
|
320
|
-
expect(result).toBe(true);
|
|
321
|
-
});
|
|
322
|
-
it("should return true for empty conditions array", () => {
|
|
323
|
-
const envState = getEnvState({
|
|
324
|
-
location: { country: "US", language: "en" },
|
|
325
|
-
});
|
|
326
|
-
const conditions = {
|
|
327
|
-
logic: "OR",
|
|
328
|
-
conditions: [],
|
|
329
|
-
};
|
|
330
|
-
const result = evaluateConditions(conditions, envState);
|
|
331
|
-
expect(result).toBe(true); // Empty conditions should pass
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
describe("Real-world bug scenario", () => {
|
|
335
|
-
it("KNOWN BEHAVIOR: Block configured with 'VIP customer OR specific device' shows when customerTag context is missing", () => {
|
|
336
|
-
// This simulates what happens in production:
|
|
337
|
-
// - A block is configured to show to VIP customers OR a specific test device
|
|
338
|
-
// - But the customerTag key is completely missing from the context
|
|
339
|
-
// - This could happen due to a data fetching error, API change, or incomplete context setup
|
|
340
|
-
const incompleteEnvState = {
|
|
341
|
-
deviceLanguage: [{ value: "English" }],
|
|
342
|
-
deviceCountry: [{ value: "United States" }],
|
|
343
|
-
deviceId: [{ value: "random-user-device" }], // Not the test device
|
|
344
|
-
// customerTag is MISSING entirely
|
|
345
|
-
};
|
|
346
|
-
const conditions = {
|
|
347
|
-
logic: "OR",
|
|
348
|
-
conditions: [
|
|
349
|
-
{
|
|
350
|
-
type: "customerTag",
|
|
351
|
-
operator: "equals",
|
|
352
|
-
value: "VIP",
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
type: "deviceId",
|
|
356
|
-
operator: "equals",
|
|
357
|
-
value: "test-device-123",
|
|
358
|
-
},
|
|
359
|
-
],
|
|
360
|
-
};
|
|
361
|
-
const result = evaluateConditions(conditions, incompleteEnvState);
|
|
362
|
-
// This returns true (current behavior when context is missing)
|
|
363
|
-
// Not fixing this behavior in this change
|
|
364
|
-
expect(result).toBe(true);
|
|
365
|
-
});
|
|
366
|
-
it("BUG SCENARIO: Block with trailing empty condition shows to all users", () => {
|
|
367
|
-
// This simulates what happens when a user partially deletes a condition in the UI
|
|
368
|
-
// leaving behind an empty condition with type="" and value=""
|
|
369
|
-
// Real-world example from production data
|
|
370
|
-
const envState = getEnvState({
|
|
371
|
-
location: {
|
|
372
|
-
country: "US",
|
|
373
|
-
language: "en",
|
|
374
|
-
deviceId: "67442bf1-7433-443b-8446-2a0ac77dc388", // Real device ID
|
|
375
|
-
},
|
|
376
|
-
});
|
|
377
|
-
const conditions = {
|
|
378
|
-
logic: "OR",
|
|
379
|
-
conditions: [
|
|
380
|
-
{
|
|
381
|
-
logic: "AND",
|
|
382
|
-
conditions: [
|
|
383
|
-
{
|
|
384
|
-
type: "deviceId",
|
|
385
|
-
operator: "equals",
|
|
386
|
-
value: "123", // Doesn't match
|
|
387
|
-
},
|
|
388
|
-
],
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
logic: "OR",
|
|
392
|
-
conditions: [
|
|
393
|
-
{
|
|
394
|
-
type: "deviceId",
|
|
395
|
-
operator: "equals",
|
|
396
|
-
value: "67442bf1-7433-443b-8446-2a0ac77dc388-a", // Doesn't match
|
|
397
|
-
},
|
|
398
|
-
{
|
|
399
|
-
type: "deviceId",
|
|
400
|
-
operator: "equals",
|
|
401
|
-
value: "67442bf1-7433-443b-8446-2a0ac77dc388-b", // Doesn't match
|
|
402
|
-
},
|
|
403
|
-
],
|
|
404
|
-
},
|
|
405
|
-
{
|
|
406
|
-
logic: "AND",
|
|
407
|
-
conditions: [
|
|
408
|
-
{
|
|
409
|
-
type: "",
|
|
410
|
-
operator: "equals",
|
|
411
|
-
value: "", // ← Empty value
|
|
412
|
-
},
|
|
413
|
-
],
|
|
414
|
-
},
|
|
415
|
-
],
|
|
416
|
-
};
|
|
417
|
-
const result = evaluateConditions(conditions, envState);
|
|
418
|
-
// EXPECTED: false (none of the device IDs match)
|
|
419
|
-
// ACTUAL (BUG): true (empty condition returns true, making the OR pass)
|
|
420
|
-
expect(result).toBe(false);
|
|
421
|
-
});
|
|
422
|
-
it("BUG SCENARIO: Empty condition should not pass when used with AND logic", () => {
|
|
423
|
-
const envState = getEnvState({
|
|
424
|
-
location: {
|
|
425
|
-
country: "US",
|
|
426
|
-
language: "en",
|
|
427
|
-
deviceId: "real-device-id",
|
|
428
|
-
},
|
|
429
|
-
});
|
|
430
|
-
const conditions = {
|
|
431
|
-
logic: "AND",
|
|
432
|
-
conditions: [
|
|
433
|
-
{
|
|
434
|
-
type: "deviceId",
|
|
435
|
-
operator: "equals",
|
|
436
|
-
value: "real-device-id", // This matches
|
|
437
|
-
},
|
|
438
|
-
{
|
|
439
|
-
type: "",
|
|
440
|
-
operator: "equals",
|
|
441
|
-
value: "",
|
|
442
|
-
},
|
|
443
|
-
],
|
|
444
|
-
};
|
|
445
|
-
const result = evaluateConditions(conditions, envState);
|
|
446
|
-
// EXPECTED: false (empty condition should fail)
|
|
447
|
-
// ACTUAL (BUG): true (empty condition returns true, AND passes)
|
|
448
|
-
expect(result).toBe(false);
|
|
449
|
-
});
|
|
450
|
-
it("BUG SCENARIO: Multiple empty conditions should not pass", () => {
|
|
451
|
-
const envState = getEnvState({
|
|
452
|
-
location: { country: "US", language: "en" },
|
|
453
|
-
});
|
|
454
|
-
const conditions = {
|
|
455
|
-
logic: "OR",
|
|
456
|
-
conditions: [
|
|
457
|
-
{
|
|
458
|
-
type: "",
|
|
459
|
-
operator: "equals",
|
|
460
|
-
value: "",
|
|
461
|
-
},
|
|
462
|
-
{
|
|
463
|
-
type: "",
|
|
464
|
-
operator: "equals",
|
|
465
|
-
value: "",
|
|
466
|
-
},
|
|
467
|
-
],
|
|
468
|
-
};
|
|
469
|
-
const result = evaluateConditions(conditions, envState);
|
|
470
|
-
// EXPECTED: false (empty conditions should not pass)
|
|
471
|
-
// ACTUAL (BUG): true (all empty conditions return true)
|
|
472
|
-
expect(result).toBe(false);
|
|
473
|
-
});
|
|
474
|
-
});
|
|
475
|
-
});
|
|
476
|
-
});
|