Skip to content

Commit 2987814

Browse files
ZSnakeViktor Zavala
andauthored
[CDX-169] Support Sale pricing (#169)
* Add logic to handle sale_price, add custom itemFieldGetter to define where to get sale price from, add storybook example and test cases * Fix getSalePrice function type * Add missing test cases, fix default behaviour on getPrice for useProductInfo hook * [CDX-169] Fix mock object data, refactor test to check all properties on products with and without sale price, refactor salePrice assignment on useProducts hook, update RenderProps tabel on product card documentation --------- Co-authored-by: Viktor Zavala <viktor.zavala@constructor.io>
1 parent 5886751 commit 2987814

File tree

12 files changed

+333
-54
lines changed

12 files changed

+333
-54
lines changed

spec/hooks/useProductInfo/useProductInfo.test.js

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { renderHook, waitFor } from '@testing-library/react';
33
import useProductInfo from '../../../src/hooks/useProduct';
44
import { transformResultItem } from '../../../src/utils/transformers';
55
import mockItem from '../../local_examples/item.json';
6+
import mockItemWithSalePrice from '../../local_examples/itemWithSalePrice.json';
67
import { renderHookWithCioPlp } from '../../test-utils';
78

89
describe('Testing Hook: useProductInfo', () => {
@@ -21,6 +22,7 @@ describe('Testing Hook: useProductInfo', () => {
2122
});
2223

2324
const transformedItem = transformResultItem(mockItem);
25+
const transformedItemWithSalePrice = transformResultItem(mockItemWithSalePrice);
2426

2527
it('Should return productSwatch, itemId, itemName, itemImageUrl, itemUrl, itemPrice', async () => {
2628
const { result } = renderHookWithCioPlp(() => useProductInfo({ item: transformedItem }));
@@ -39,27 +41,28 @@ describe('Testing Hook: useProductInfo', () => {
3941
});
4042
});
4143

42-
it('Should return nothing properly with getters that return nothing', async () => {
43-
const { result } = renderHookWithCioPlp(() => useProductInfo({ item: transformedItem }), {
44-
initialProps: {
45-
itemFieldGetters: {
46-
getPrice: () => {},
47-
getSwatches: () => {},
48-
getSwatchPreview: () => {},
49-
},
50-
},
51-
});
52-
53-
await waitFor(() => {
54-
const {
55-
current: { productSwatch, itemName, itemImageUrl, itemUrl, itemPrice },
56-
} = result;
57-
58-
expect(productSwatch).not.toBeNull();
59-
expect(itemName).toEqual(transformedItem.itemName);
60-
expect(itemImageUrl).toEqual(transformedItem.imageUrl);
61-
expect(itemUrl).toEqual(transformedItem.url);
62-
expect(itemPrice).toBeUndefined();
44+
describe.each([
45+
{
46+
item: transformedItem,
47+
itemDescription: 'a standard item',
48+
},
49+
{
50+
item: transformedItemWithSalePrice,
51+
itemDescription: 'an item on sale',
52+
},
53+
])('With $itemDescription', ({ item }) => {
54+
it.each([
55+
['itemId', item.itemId],
56+
['itemName', item.itemName],
57+
['itemImageUrl', item.imageUrl],
58+
['itemUrl', item.url],
59+
['itemPrice', item.data.price],
60+
['salePrice', item.data.sale_price],
61+
])('Should return the correct value for "%s"', async (property, expectedValue) => {
62+
const { result } = renderHookWithCioPlp(() => useProductInfo({ item }));
63+
await waitFor(() => {
64+
expect(result.current[property]).toEqual(expectedValue);
65+
});
6366
});
6467
});
6568

@@ -68,7 +71,7 @@ describe('Testing Hook: useProductInfo', () => {
6871

6972
await waitFor(() => {
7073
const {
71-
current: { productSwatch, itemName, itemImageUrl, itemUrl, itemPrice },
74+
current: { productSwatch, itemName, itemImageUrl, itemUrl, itemPrice, itemSalePrice },
7275
} = result;
7376
const { selectVariation, swatchList } = productSwatch;
7477
selectVariation(swatchList[1]);
@@ -77,36 +80,44 @@ describe('Testing Hook: useProductInfo', () => {
7780
expect(itemImageUrl).toEqual(swatchList[1].imageUrl || transformedItem.imageUrl);
7881
expect(itemUrl).toEqual(swatchList[1].url || transformedItem.url);
7982
expect(itemPrice).toEqual(swatchList[1].price || transformedItem.data.price);
83+
expect(itemSalePrice).toEqual(swatchList[1].salePrice || transformedItem.data.salePrice);
8084
});
8185
});
8286

8387
it('Should return nothing properly with getters that throw errors', async () => {
84-
const { result } = renderHookWithCioPlp(() => useProductInfo({ item: transformedItem }), {
85-
initialProps: {
86-
itemFieldGetters: {
87-
getPrice: () => {
88-
throw new Error();
89-
},
90-
getSwatches: () => {
91-
throw new Error();
92-
},
93-
getSwatchPreview: () => {
94-
throw new Error();
88+
const { result } = renderHookWithCioPlp(
89+
() => useProductInfo({ item: transformedItemWithSalePrice }),
90+
{
91+
initialProps: {
92+
itemFieldGetters: {
93+
getPrice: () => {
94+
throw new Error();
95+
},
96+
getSwatches: () => {
97+
throw new Error();
98+
},
99+
getSwatchPreview: () => {
100+
throw new Error();
101+
},
102+
getSalePrice: () => {
103+
throw new Error();
104+
},
95105
},
96106
},
97107
},
98-
});
108+
);
99109

100110
await waitFor(() => {
101111
const {
102-
current: { productSwatch, itemName, itemImageUrl, itemUrl, itemPrice },
112+
current: { productSwatch, itemName, itemImageUrl, itemUrl, itemPrice, itemSalePrice },
103113
} = result;
104114

105115
expect(productSwatch).not.toBeNull();
106116
expect(itemName).toEqual(transformedItem.itemName);
107117
expect(itemImageUrl).toEqual(transformedItem.imageUrl);
108118
expect(itemUrl).toEqual(transformedItem.url);
109119
expect(itemPrice).toBeUndefined();
120+
expect(itemSalePrice).toBeUndefined();
110121
});
111122
});
112123
});

spec/hooks/useProductSwatch/useProductSwatch.test.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import useProductSwatch from '../../../src/hooks/useProductSwatch';
44
import { transformResultItem } from '../../../src/utils/transformers';
55
import mockItem from '../../local_examples/item.json';
66
import { renderHookWithCioPlp } from '../../test-utils';
7-
import { getSwatchPreview, getPrice, getSwatches } from '../../../src/utils/itemFieldGetters';
7+
import {
8+
getSwatchPreview,
9+
getPrice,
10+
getSwatches,
11+
getSalePrice,
12+
} from '../../../src/utils/itemFieldGetters';
813

914
describe('Testing Hook: useProductSwatch', () => {
1015
beforeEach(() => {
@@ -18,7 +23,7 @@ describe('Testing Hook: useProductSwatch', () => {
1823
});
1924

2025
const transformedItem = transformResultItem(mockItem);
21-
const expectedSwatch = getSwatches(transformedItem, getPrice, getSwatchPreview);
26+
const expectedSwatch = getSwatches(transformedItem, getPrice, getSwatchPreview, getSalePrice);
2227

2328
it('Should throw error if called outside of PlpContext', () => {
2429
expect(() => renderHook(() => useProductSwatch())).toThrow();
@@ -63,6 +68,7 @@ describe('Testing Hook: useProductSwatch', () => {
6368
getPrice: () => {},
6469
getSwatches: () => {},
6570
getSwatchPreview: () => {},
71+
getSalePrice: () => {},
6672
},
6773
},
6874
});
@@ -91,6 +97,9 @@ describe('Testing Hook: useProductSwatch', () => {
9197
getSwatchPreview: () => {
9298
throw new Error();
9399
},
100+
getSalePrice: () => {
101+
throw new Error();
102+
},
94103
},
95104
},
96105
});

spec/local_examples/item.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"url": "https://constructorio-integrations.s3.amazonaws.com/tikus-threads/2022-06-29/KNIT-CASUAL-SHIRT_BUTTON-DOWN-KNIT-SHIRT_BKT00110SG1733_3_category.jpg",
88
"price": 90,
99
"altPrice": 69,
10-
"sale_price": 23,
1110
"image_url": "https://constructorio-integrations.s3.amazonaws.com/tikus-threads/2022-06-29/KNIT-CASUAL-SHIRT_BUTTON-DOWN-KNIT-SHIRT_BKT00110SG1733_3_category.jpg",
1211
"group_ids": [
1312
"1111"
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
{
2+
"matched_terms": [
3+
"shirts"
4+
],
5+
"data": {
6+
"id": "KNITS00423-park bench dot",
7+
"url": "https://constructorio-integrations.s3.amazonaws.com/tikus-threads/2022-06-29/KNIT-CASUAL-SHIRT_BUTTON-DOWN-KNIT-SHIRT_BKT00110SG1733_3_category.jpg",
8+
"price": 90,
9+
"altPrice": 69,
10+
"sale_price": 21,
11+
"image_url": "https://constructorio-integrations.s3.amazonaws.com/tikus-threads/2022-06-29/KNIT-CASUAL-SHIRT_BUTTON-DOWN-KNIT-SHIRT_BKT00110SG1733_3_category.jpg",
12+
"group_ids": [
13+
"1111"
14+
],
15+
"description": "Cotton jersey fabric that feels like a tee & looks like a button-down.",
16+
"facets": [
17+
{
18+
"name": "Color",
19+
"values": [
20+
"Park Bench Dot"
21+
]
22+
}
23+
],
24+
"variation_id": "BKT00110DG1733LR"
25+
},
26+
"value": "Jersey Riviera Shirt (Red Park Bench Dot)",
27+
"is_slotted": false,
28+
"labels": {},
29+
"variations": [
30+
{
31+
"data": {
32+
"variation_id": "BKT00110DG1733LR",
33+
"swatchPreview": "#e04062",
34+
"price": 90,
35+
"sale_price": 21,
36+
"facets": [
37+
{
38+
"name": "Color",
39+
"values": [
40+
"Park Bench Dot"
41+
]
42+
}
43+
]
44+
},
45+
"value": "Jersey Riviera Shirt (Red Park Bench Dot)"
46+
},
47+
{
48+
"data": {
49+
"variation_id": "BKT00110DG1733MR",
50+
"swatchPreview": "#a3c43b",
51+
"price": 99,
52+
"sale_price": 22,
53+
"facets": [
54+
{
55+
"name": "Color",
56+
"values": [
57+
"Red Park Bench Dot"
58+
]
59+
}
60+
]
61+
},
62+
"value": "Jersey Riviera Shirt (Green Park Bench Dot)"
63+
},
64+
{
65+
"data": {
66+
"variation_id": "BKT00110DG1733SR",
67+
"swatchPreview": "#253d37",
68+
"price": 100,
69+
"sale_price": 23,
70+
"facets": [
71+
{
72+
"name": "Color",
73+
"values": [
74+
"Green Park Bench Dot"
75+
]
76+
}
77+
]
78+
},
79+
"value": "Jersey Riviera Shirt (Black Park Bench Dot)"
80+
},
81+
{
82+
"data": {
83+
"variation_id": "BKT00110DG1733XLR",
84+
"swatchPreview": "#bfc1bc",
85+
"price": 105,
86+
"facets": [
87+
{
88+
"name": "Color",
89+
"values": [
90+
"Black Park Bench Dot"
91+
]
92+
}
93+
]
94+
},
95+
"value": "Jersey Riviera Shirt (Silver Park Bench Dot)"
96+
},
97+
{
98+
"data": {
99+
"variation_id": "BKT00110DG1733XSR",
100+
"facets": [
101+
{
102+
"name": "Color",
103+
"values": [
104+
"Silver Park Bench Dot"
105+
]
106+
}
107+
]
108+
},
109+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
110+
},
111+
{
112+
"data": {
113+
"variation_id": "BKT00110DG1733XXLR",
114+
"facets": [
115+
{
116+
"name": "Color",
117+
"values": [
118+
"Park Bench Dot"
119+
]
120+
}
121+
]
122+
},
123+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
124+
},
125+
{
126+
"data": {
127+
"variation_id": "BKT00110SG1733LR",
128+
"facets": [
129+
{
130+
"name": "Color",
131+
"values": [
132+
"Park Bench Dot"
133+
]
134+
}
135+
]
136+
},
137+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
138+
},
139+
{
140+
"data": {
141+
"variation_id": "BKT00110SG1733MR",
142+
"facets": [
143+
{
144+
"name": "Color",
145+
"values": [
146+
"Park Bench Dot"
147+
]
148+
}
149+
]
150+
},
151+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
152+
},
153+
{
154+
"data": {
155+
"variation_id": "BKT00110SG1733SR",
156+
"facets": [
157+
{
158+
"name": "Color",
159+
"values": [
160+
"Park Bench Dot"
161+
]
162+
}
163+
]
164+
},
165+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
166+
},
167+
{
168+
"data": {
169+
"variation_id": "BKT00110SG1733XLR",
170+
"facets": [
171+
{
172+
"name": "Color",
173+
"values": [
174+
"Park Bench Dot"
175+
]
176+
}
177+
]
178+
},
179+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
180+
},
181+
{
182+
"data": {
183+
"variation_id": "BKT00110SG1733XSR",
184+
"facets": [
185+
{
186+
"name": "Color",
187+
"values": [
188+
"Park Bench Dot"
189+
]
190+
}
191+
]
192+
},
193+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
194+
},
195+
{
196+
"data": {
197+
"variation_id": "BKT00110SG1733XXLR",
198+
"facets": [
199+
{
200+
"name": "Color",
201+
"values": [
202+
"Park Bench Dot"
203+
]
204+
}
205+
]
206+
},
207+
"value": "Jersey Riviera Shirt (Park Bench Dot)"
208+
}
209+
]
210+
}

0 commit comments

Comments
 (0)