1 | import {
|
2 | flattenList,
|
3 | getVariantFromProductDetails,
|
4 | getProductDetailForFlattenedProductList,
|
5 | normalizeServerList
|
6 | } from './list-transforms';
|
7 |
|
8 | const MOCK_LIST = {
|
9 | '6952315': {
|
10 | options: { quantity: 1 },
|
11 | variants: {
|
12 | '6952315-170-white': {
|
13 | options: {
|
14 | quantity: 1
|
15 | },
|
16 | parentArticleNumber: '6952315'
|
17 | }
|
18 | }
|
19 | },
|
20 | '502935480': {
|
21 | variants: null,
|
22 | options: {
|
23 | quantity: 1
|
24 | }
|
25 | },
|
26 | '441922-Classic-16': {
|
27 | variants: null,
|
28 | options: {
|
29 | quantity: 1
|
30 | }
|
31 | },
|
32 | 'without-base': {
|
33 | options: null,
|
34 | variants: {
|
35 | 'with-variant': {
|
36 | options: {
|
37 | quantity: 1
|
38 | },
|
39 | parentArticleNumber: 'without-base'
|
40 | }
|
41 | }
|
42 | }
|
43 | };
|
44 |
|
45 | const MOCK_PRODUCT_WITH_VARIANTS = {
|
46 | variants: {
|
47 | options: [
|
48 | {
|
49 | name: 'Size',
|
50 | values: ['36', '37', '38'],
|
51 | __typename: 'ProductVariantOption'
|
52 | }
|
53 | ],
|
54 | values: [
|
55 | {
|
56 | id: '441728-36',
|
57 | articleNumber: '441728-36',
|
58 | values: ['36'],
|
59 | stockStatus: {
|
60 | buyable: true,
|
61 | text: 'In stock',
|
62 | __typename: 'StockStatus'
|
63 | },
|
64 | images: [
|
65 | {
|
66 | alt: '441728',
|
67 | title: 'Belt Light',
|
68 | url: 'https://www.demostore.se/pub_images/original/441728.jpg',
|
69 | __typename: 'ProductImage'
|
70 | }
|
71 | ],
|
72 | __typename: 'ProductVariant'
|
73 | },
|
74 | {
|
75 | id: '441728-37',
|
76 | articleNumber: '441728-37',
|
77 | values: ['37'],
|
78 | stockStatus: {
|
79 | buyable: true,
|
80 | text: 'In stock',
|
81 | __typename: 'StockStatus'
|
82 | },
|
83 | images: [
|
84 | {
|
85 | alt: 'Belt Light',
|
86 | title: 'Belt Light',
|
87 | url: 'https://www.demostore.se/pub_images/original/441728.jpg',
|
88 | __typename: 'ProductImage'
|
89 | }
|
90 | ],
|
91 | __typename: 'ProductVariant'
|
92 | },
|
93 | {
|
94 | id: '441728-38',
|
95 | articleNumber: '441728-38',
|
96 | values: ['38'],
|
97 | stockStatus: {
|
98 | buyable: true,
|
99 | text: 'In stock',
|
100 | __typename: 'StockStatus'
|
101 | },
|
102 | images: [
|
103 | {
|
104 | alt: 'Belt Light',
|
105 | title: 'Belt Light',
|
106 | url: 'https://www.demostore.se/pub_images/original/441728.jpg',
|
107 | __typename: 'ProductImage'
|
108 | }
|
109 | ],
|
110 | __typename: 'ProductVariant'
|
111 | }
|
112 | ],
|
113 | __typename: 'ProductVariants'
|
114 | },
|
115 | id: 483,
|
116 | articleNumber: '441728',
|
117 | name: 'Belt Light',
|
118 | hasConfigurations: false,
|
119 | hasVariants: true,
|
120 | isPreOrder: false,
|
121 | stockStatus: {
|
122 | buyable: true,
|
123 | text: 'In stock',
|
124 | __typename: 'StockStatus'
|
125 | },
|
126 | __typename: 'Product',
|
127 | images: [
|
128 | {
|
129 | alt: '441728',
|
130 | title: 'Belt Light',
|
131 | url: 'https://www.demostore.se/pub_images/original/441728.jpg',
|
132 | __typename: 'ProductImage'
|
133 | }
|
134 | ]
|
135 | };
|
136 |
|
137 | const MOCK_PRODUCT_QUERY_RESULT = {
|
138 | loading: false,
|
139 | data: {
|
140 | products: [
|
141 | {
|
142 | variants: {
|
143 | options: [
|
144 | {
|
145 | name: 'Size',
|
146 | values: ['36', '37', '38'],
|
147 | __typename: 'ProductVariantOption'
|
148 | }
|
149 | ],
|
150 | values: [
|
151 | {
|
152 | id: '441728-36',
|
153 | articleNumber: '441728-36',
|
154 | values: ['36'],
|
155 | stockStatus: {
|
156 | buyable: true,
|
157 | text: 'In stock',
|
158 | __typename: 'StockStatus'
|
159 | },
|
160 | images: [
|
161 | {
|
162 | alt: '441728',
|
163 | title: 'Belt Light',
|
164 | url:
|
165 | 'https://www.demostore.se/pub_images/original/VARIANTIMAGE.jpg',
|
166 | __typename: 'ProductImage'
|
167 | }
|
168 | ],
|
169 | __typename: 'ProductVariant'
|
170 | },
|
171 | {
|
172 | id: '441728-37',
|
173 | articleNumber: '441728-37',
|
174 | values: ['37'],
|
175 | stockStatus: {
|
176 | buyable: true,
|
177 | text: 'In stock',
|
178 | __typename: 'StockStatus'
|
179 | },
|
180 | images: [
|
181 | {
|
182 | alt: 'Belt Light',
|
183 | title: 'Belt Light',
|
184 | url:
|
185 | 'https://www.demostore.se/pub_images/original/441728.jpg',
|
186 | __typename: 'ProductImage'
|
187 | }
|
188 | ],
|
189 | __typename: 'ProductVariant'
|
190 | },
|
191 | {
|
192 | id: '441728-38',
|
193 | articleNumber: '441728-38',
|
194 | values: ['38'],
|
195 | stockStatus: {
|
196 | buyable: true,
|
197 | text: 'In stock',
|
198 | __typename: 'StockStatus'
|
199 | },
|
200 | images: [
|
201 | {
|
202 | alt: 'Belt Light',
|
203 | title: 'Belt Light',
|
204 | url:
|
205 | 'https://www.demostore.se/pub_images/original/441728.jpg',
|
206 | __typename: 'ProductImage'
|
207 | }
|
208 | ],
|
209 | __typename: 'ProductVariant'
|
210 | }
|
211 | ],
|
212 | __typename: 'ProductVariants'
|
213 | },
|
214 | id: 483,
|
215 | articleNumber: '441728',
|
216 | name: 'Belt Light',
|
217 | subName: 'PantsUp',
|
218 | hasConfigurations: false,
|
219 | hasVariants: true,
|
220 | isPreOrder: false,
|
221 | stockStatus: {
|
222 | buyable: true,
|
223 | text: 'In stock',
|
224 | __typename: 'StockStatus'
|
225 | },
|
226 | primaryRoute: {
|
227 | id: 'accessories/belts/belt-light',
|
228 | path: '/accessories/belts/belt-light',
|
229 | slug: 'belt-light',
|
230 | __typename: 'Route'
|
231 | },
|
232 | price: {
|
233 | incVat: 500,
|
234 | exVat: 400,
|
235 | vat: 100,
|
236 | __typename: 'Price'
|
237 | },
|
238 | previousPrice: {
|
239 | incVat: 1375,
|
240 | exVat: 1100,
|
241 | vat: 275,
|
242 | __typename: 'Price'
|
243 | },
|
244 | __typename: 'Product',
|
245 | badges: [
|
246 | {
|
247 | name: 'SALE Top Left',
|
248 | url:
|
249 | 'https://www.demostore.se/M1/production/images/overlay/overlay8_en-GB.png',
|
250 | location: 'TOP_LEFT',
|
251 | style: '',
|
252 | text: '',
|
253 | __typename: 'ProductBadge'
|
254 | }
|
255 | ],
|
256 | images: [
|
257 | {
|
258 | alt: '441728',
|
259 | title: 'Belt Light',
|
260 | url: 'https://www.demostore.se/pub_images/original/441728.jpg',
|
261 | __typename: 'ProductImage'
|
262 | }
|
263 | ]
|
264 | }
|
265 | ]
|
266 | }
|
267 | };
|
268 |
|
269 | describe('flattenList', () => {
|
270 | it('takes a normalized list and returns an array of items', () => {
|
271 | const flattened = flattenList(MOCK_LIST);
|
272 |
|
273 | expect(flattened).toMatchSnapshot();
|
274 | });
|
275 |
|
276 | it('creates a unique entry for each variant', () => {
|
277 | const options = { quantity: 1 };
|
278 |
|
279 | const list = {
|
280 | baseProduct: {
|
281 | options: null,
|
282 | variants: {
|
283 | 'variant-one': {
|
284 | options,
|
285 | parentArticleNumber: 'baseProduct'
|
286 | },
|
287 | 'variant-two': {
|
288 | options,
|
289 | parentArticleNumber: 'baseProduct'
|
290 | }
|
291 | }
|
292 | }
|
293 | };
|
294 |
|
295 | const flattened = flattenList(list);
|
296 | expect(flattened).toHaveLength(2);
|
297 | expect(flattened[0].articleNumber).toBe('variant-one');
|
298 | expect(flattened[1].articleNumber).toBe('variant-two');
|
299 | });
|
300 | it('creates unique entries for variants and the base product', () => {
|
301 | const options = { quantity: 1 };
|
302 |
|
303 | const list = {
|
304 | baseProduct: {
|
305 | options: options,
|
306 | variants: {
|
307 | 'variant-one': {
|
308 | options,
|
309 | parentArticleNumber: 'baseProduct'
|
310 | },
|
311 | 'variant-two': {
|
312 | options,
|
313 | parentArticleNumber: 'baseProduct'
|
314 | }
|
315 | }
|
316 | }
|
317 | };
|
318 |
|
319 | const flattened = flattenList(list);
|
320 | expect(flattened).toHaveLength(3);
|
321 | expect(flattened[0].articleNumber).toBe('variant-one');
|
322 | expect(flattened[1].articleNumber).toBe('variant-two');
|
323 | expect(flattened[2].articleNumber).toBe('baseProduct');
|
324 | });
|
325 | });
|
326 |
|
327 | describe('getVariantFromProductDetails', () => {
|
328 | it('returns null when no variant is given', () => {
|
329 | const result = getVariantFromProductDetails(
|
330 | undefined,
|
331 | MOCK_PRODUCT_WITH_VARIANTS
|
332 | );
|
333 |
|
334 | expect(result).toBe(null);
|
335 | });
|
336 | it('returns the correct variant when a variant article number is given', () => {
|
337 | const result = getVariantFromProductDetails(
|
338 | '441728-37',
|
339 | MOCK_PRODUCT_WITH_VARIANTS
|
340 | );
|
341 |
|
342 | expect(result).toBe(
|
343 | MOCK_PRODUCT_WITH_VARIANTS.variants.values.find(
|
344 | variant => variant.articleNumber === '441728-37'
|
345 | )
|
346 | );
|
347 | });
|
348 | it('returns null when a variant cannot be found', () => {
|
349 | const result = getVariantFromProductDetails(
|
350 | 'fgdgdfg',
|
351 | MOCK_PRODUCT_WITH_VARIANTS
|
352 | );
|
353 |
|
354 | expect(result).toBe(null);
|
355 | });
|
356 | });
|
357 |
|
358 | describe('getProductDetailForFlattenedProductList', () => {
|
359 | let result;
|
360 | let baseProduct;
|
361 | let variant;
|
362 | beforeEach(() => {
|
363 | const options = { quantity: 2 };
|
364 | const list = [
|
365 | {
|
366 | articleNumber: '441728',
|
367 | options
|
368 | },
|
369 | {
|
370 | articleNumber: '441728-36',
|
371 | options,
|
372 | parentArticleNumber: '441728'
|
373 | }
|
374 | ];
|
375 | const queryResult = MOCK_PRODUCT_QUERY_RESULT;
|
376 |
|
377 | result = getProductDetailForFlattenedProductList(list, queryResult);
|
378 | baseProduct = result[0];
|
379 | variant = result[1];
|
380 | });
|
381 | it(`gets product detail for each item in a flattened list`, () => {
|
382 | expect(result.length).toBe(2);
|
383 | });
|
384 | it(`returns validation messages for products that can't be added to the cart`, () => {
|
385 | expect(baseProduct.validation.status).toBe(`missingVariant`);
|
386 | });
|
387 | it(`appends variant detail to variant key and sets isVariant`, () => {
|
388 | expect(variant.variant.articleNumber).toBe('441728-36');
|
389 | expect(variant.isVariant).toBe(true);
|
390 | expect(baseProduct.variant).toBe(null);
|
391 | expect(baseProduct.isVariant).toBe(false);
|
392 | });
|
393 | });
|
394 |
|
395 | describe('normalizeServerList', () => {
|
396 | let serverList;
|
397 | beforeEach(() => {
|
398 | serverList = {
|
399 | customerProductList: {
|
400 | items: [
|
401 | {
|
402 | quantity: 1,
|
403 | description: 'hello',
|
404 | product: {
|
405 | articleNumber: 'without-variants'
|
406 | },
|
407 | variant: null
|
408 | },
|
409 | {
|
410 | quantity: 1,
|
411 | description: 'hello',
|
412 | product: {
|
413 | articleNumber: 'with-variants'
|
414 | },
|
415 | variant: {
|
416 | articleNumber: 'the-variant'
|
417 | }
|
418 | },
|
419 | {
|
420 | quantity: 1,
|
421 | description: 'hello',
|
422 | product: {
|
423 | articleNumber: 'with-many-variants'
|
424 | },
|
425 | variant: {
|
426 | articleNumber: 'variant-one'
|
427 | }
|
428 | },
|
429 | {
|
430 | quantity: 1,
|
431 | description: 'hello',
|
432 | product: {
|
433 | articleNumber: 'with-many-variants'
|
434 | },
|
435 | variant: {
|
436 | articleNumber: 'variant-two'
|
437 | }
|
438 | },
|
439 | {
|
440 | quantity: 1,
|
441 | description: 'hello',
|
442 | product: {
|
443 | articleNumber: 'with-base-and-variants'
|
444 | },
|
445 | variant: null
|
446 | },
|
447 | {
|
448 | quantity: 1,
|
449 | description: 'hello',
|
450 | product: {
|
451 | articleNumber: 'with-base-and-variants'
|
452 | },
|
453 | variant: {
|
454 | articleNumber: 'variant-one'
|
455 | }
|
456 | }
|
457 | ]
|
458 | }
|
459 | };
|
460 | });
|
461 | it('returns an empty object if an invalid list if passed in', () => {
|
462 | const result = normalizeServerList({ not: 'a list' });
|
463 |
|
464 | expect(result).toEqual({});
|
465 | });
|
466 | it('creates the expected shape', () => {
|
467 | const result = normalizeServerList(serverList);
|
468 |
|
469 | expect(result['without-variants'].variants).toBe(null);
|
470 | expect(result['without-variants'].options.quantity).toBe(1);
|
471 |
|
472 | expect(result['with-variants'].options).toBe(null);
|
473 | expect(
|
474 | result['with-variants'].variants['the-variant'].options.quantity
|
475 | ).toBe(1);
|
476 |
|
477 | expect(result['with-many-variants'].options).toBe(null);
|
478 | expect(result['with-many-variants'].variants['variant-one']).toBeDefined();
|
479 | expect(result['with-many-variants'].variants['variant-two']).toBeDefined();
|
480 |
|
481 | expect(result['with-base-and-variants'].options).toBeDefined();
|
482 | expect(
|
483 | result['with-base-and-variants'].variants['variant-one']
|
484 | ).toBeDefined();
|
485 | });
|
486 | });
|