@akinon/pz-theme 2.0.152-rc.3 → 2.0.153-beta.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.
@@ -0,0 +1,673 @@
1
+ import React from 'react';
2
+ import { act, fireEvent, render, screen } from '@testing-library/react';
3
+
4
+ import AddToCartBlock from '../add-to-cart-block';
5
+ import VariantSelectorBlock from '../variant-selector-block';
6
+ import { ThemePageContextProvider } from '../../theme-page-context';
7
+ import {
8
+ __resetStockAlertPickForTests,
9
+ setStockAlertPick
10
+ } from '../stock-alert-pick';
11
+
12
+ /**
13
+ * ZERO-5233: the PDP button says "notify me" for a sold-out product or a
14
+ * sold-out size the shopper picked, and "sold out" only for a product with
15
+ * nothing left to come back.
16
+ */
17
+
18
+ let currentPath = '/p/s';
19
+
20
+ jest.mock('next/navigation', () => ({
21
+ useRouter: () => ({ push: jest.fn() }),
22
+ usePathname: () => currentPath,
23
+ useSearchParams: () => new URLSearchParams('')
24
+ }));
25
+
26
+ let sessionStatus: 'authenticated' | 'unauthenticated' = 'authenticated';
27
+ let sessionEmail = 'shopper@example.com';
28
+
29
+ jest.mock('next-auth/react', () => ({
30
+ useSession: () => ({
31
+ status: sessionStatus,
32
+ data:
33
+ sessionStatus === 'authenticated'
34
+ ? { user: { email: sessionEmail } }
35
+ : null
36
+ })
37
+ }));
38
+
39
+ const mockAddProduct = jest.fn();
40
+ const mockAddStockAlert = jest.fn();
41
+
42
+ jest.mock('@akinon/next/data/client/product', () => ({
43
+ __esModule: true,
44
+ useAddProductMutation: () => [
45
+ (payload: unknown) => mockAddProduct(payload),
46
+ { isLoading: false }
47
+ ],
48
+ useAddStockAlertMutation: () => [
49
+ (payload: unknown) => mockAddStockAlert(payload),
50
+ { isLoading: false }
51
+ ],
52
+ basketApi: {
53
+ util: { invalidateTags: () => ({ type: 'basket/invalidateTags' }) }
54
+ }
55
+ }));
56
+
57
+ jest.mock('@akinon/next/redux/hooks', () => ({
58
+ __esModule: true,
59
+ useAppSelector: () => undefined,
60
+ useAppDispatch: () => () => undefined
61
+ }));
62
+
63
+ const SIZES = {
64
+ attribute_key: 'integration_beden',
65
+ attribute_name: 'Beden',
66
+ options: [
67
+ {
68
+ label: 'S',
69
+ value: 's',
70
+ in_stock: true,
71
+ is_selectable: true,
72
+ product: { pk: 101, absolute_url: '/p/s', stock: 9 }
73
+ },
74
+ {
75
+ label: 'M',
76
+ value: 'm',
77
+ in_stock: false,
78
+ is_selectable: false,
79
+ product: { pk: 102, absolute_url: '/p/m', stock: 0 }
80
+ }
81
+ ]
82
+ };
83
+
84
+ const SOLD_OUT_SIZES = {
85
+ ...SIZES,
86
+ options: SIZES.options.map((option) => ({
87
+ ...option,
88
+ in_stock: false,
89
+ is_selectable: false,
90
+ product: { ...option.product, stock: 0 }
91
+ }))
92
+ };
93
+
94
+ const IN_STOCK = { pk: 101, name: 'Polo', in_stock: true, variants: [SIZES] };
95
+ // The page's own size is gone, another size of the colour is not.
96
+ const SOLD_OUT = { pk: 101, name: 'Polo', in_stock: false, variants: [SIZES] };
97
+ // Every size of the colour is gone.
98
+ const COLOUR_GONE = {
99
+ pk: 101,
100
+ name: 'Polo',
101
+ in_stock: false,
102
+ variants: [SOLD_OUT_SIZES]
103
+ };
104
+ const DELISTED = { pk: 101, name: 'Polo', in_stock: false, variants: [] };
105
+
106
+ const LABELS = {
107
+ label: 'Sepete Ekle',
108
+ outOfStockLabel: 'Tükendi',
109
+ stockAlertLabel: 'Stok Gelince Haber Ver',
110
+ stockAlertTitle: 'Stok alarmı',
111
+ stockAlertMessage: 'Ürün stoğa girdiğinde {email} adresine haber vereceğiz.',
112
+ stockAlertMessageNoEmail: 'Ürün stoğa girdiğinde haber vereceğiz.',
113
+ stockAlertErrorMessage: 'Bir hata oluştu.',
114
+ stockAlertCloseLabel: 'Kapat'
115
+ };
116
+
117
+ const block = (type: string, properties: Record<string, unknown>) =>
118
+ ({
119
+ id: type,
120
+ type,
121
+ label: type,
122
+ value: '',
123
+ order: 0,
124
+ hidden: false,
125
+ properties,
126
+ styles: {}
127
+ } as never);
128
+
129
+ const renderPdp = (
130
+ product: Record<string, unknown>,
131
+ {
132
+ alert = true,
133
+ selector = false,
134
+ extra = {}
135
+ }: {
136
+ alert?: boolean;
137
+ selector?: boolean;
138
+ extra?: Record<string, unknown>;
139
+ } = {}
140
+ ) =>
141
+ render(
142
+ <ThemePageContextProvider value={{ product } as never}>
143
+ {selector && (
144
+ <VariantSelectorBlock
145
+ {...({
146
+ block: block('variant-selector', {
147
+ stockAlert: true,
148
+ stockAlertPresentation: 'add-to-cart'
149
+ }),
150
+ currentBreakpoint: 'desktop'
151
+ } as never)}
152
+ />
153
+ )}
154
+ <AddToCartBlock
155
+ {...({
156
+ block: block('add-to-cart', {
157
+ ...LABELS,
158
+ stockAlert: alert,
159
+ ...extra
160
+ }),
161
+ currentBreakpoint: 'desktop'
162
+ } as never)}
163
+ />
164
+ </ThemePageContextProvider>
165
+ );
166
+
167
+ const button = (container: HTMLElement) =>
168
+ container.querySelector('[data-add-to-cart]') as HTMLButtonElement;
169
+
170
+ const dialog = () => document.querySelector('[role="dialog"]') as HTMLElement;
171
+
172
+ const press = async (container: HTMLElement) => {
173
+ await act(async () => {
174
+ fireEvent.click(button(container));
175
+ });
176
+ };
177
+
178
+ const withLocation = async (run: (assign: jest.Mock) => Promise<void>) => {
179
+ const assign = jest.fn();
180
+ const original = window.location;
181
+ Object.defineProperty(window, 'location', {
182
+ configurable: true,
183
+ value: { ...original, pathname: '/polo-101/', search: '?a=1', assign }
184
+ });
185
+
186
+ try {
187
+ await run(assign);
188
+ } finally {
189
+ Object.defineProperty(window, 'location', {
190
+ configurable: true,
191
+ value: original
192
+ });
193
+ }
194
+ };
195
+
196
+ beforeEach(() => {
197
+ sessionStatus = 'authenticated';
198
+ sessionEmail = 'shopper@example.com';
199
+ currentPath = '/p/s';
200
+ mockAddProduct.mockReset();
201
+ mockAddStockAlert.mockReset();
202
+ mockAddStockAlert.mockReturnValue({ unwrap: () => Promise.resolve({}) });
203
+ __resetStockAlertPickForTests();
204
+ });
205
+
206
+ describe('add-to-cart stock alert', () => {
207
+ it('keeps the disabled out-of-stock button while the switch is off', () => {
208
+ const { container } = renderPdp(SOLD_OUT, { alert: false });
209
+
210
+ expect(button(container).textContent).toBe('Tükendi');
211
+ expect(button(container).disabled).toBe(true);
212
+ });
213
+
214
+ it('adds to cart as before while the product is in stock', () => {
215
+ const { container } = renderPdp(IN_STOCK);
216
+
217
+ expect(button(container).textContent).toBe('Sepete Ekle');
218
+ expect(button(container).getAttribute('data-add-to-cart-state')).toBe(
219
+ 'idle'
220
+ );
221
+ });
222
+
223
+ it('offers the alert while another size of the colour is in stock', () => {
224
+ const { container } = renderPdp(SOLD_OUT);
225
+
226
+ expect(button(container).textContent).toBe('Stok Gelince Haber Ver');
227
+ expect(button(container).disabled).toBe(false);
228
+ expect(button(container).getAttribute('data-state')).toBe('unavailable');
229
+ });
230
+
231
+ it('says sold out when every size of the colour is gone', () => {
232
+ const { container } = renderPdp(COLOUR_GONE);
233
+
234
+ expect(button(container).textContent).toBe('Tükendi');
235
+ expect(button(container).disabled).toBe(true);
236
+ });
237
+
238
+ it('says sold out for a product with no variants left', () => {
239
+ const { container } = renderPdp(DELISTED);
240
+
241
+ expect(button(container).textContent).toBe('Tükendi');
242
+ expect(button(container).disabled).toBe(true);
243
+ });
244
+
245
+ it('registers a signed-in shopper and names their email in a dialog', async () => {
246
+ const { container } = renderPdp(SOLD_OUT);
247
+
248
+ expect(dialog()).toBeNull();
249
+
250
+ await press(container);
251
+
252
+ expect(mockAddStockAlert).toHaveBeenCalledWith({
253
+ productPk: 101,
254
+ email: 'shopper@example.com'
255
+ });
256
+ expect(mockAddProduct).not.toHaveBeenCalled();
257
+ expect(dialog().textContent).toContain('Stok alarmı');
258
+ expect(dialog().textContent).toContain(
259
+ 'Ürün stoğa girdiğinde shopper@example.com adresine haber vereceğiz.'
260
+ );
261
+
262
+ // Only the × closes it: no second close button under the message.
263
+ expect(dialog().querySelectorAll('button')).toHaveLength(1);
264
+ expect(dialog().querySelector('[data-part="title"]')?.textContent).toBe(
265
+ 'Stok alarmı'
266
+ );
267
+
268
+ act(() => {
269
+ fireEvent.click(screen.getByRole('button', { name: 'Kapat' }));
270
+ });
271
+
272
+ expect(dialog()).toBeNull();
273
+
274
+ // Already on the list: the dialog again, no second request.
275
+ await press(container);
276
+
277
+ expect(mockAddStockAlert).toHaveBeenCalledTimes(1);
278
+ expect(dialog()).not.toBeNull();
279
+ });
280
+
281
+ it('opens as a drawer on the side the author picked', async () => {
282
+ const { container } = renderPdp(SOLD_OUT, {
283
+ extra: { stockAlertPresentation: 'drawer', stockAlertWidth: 420 }
284
+ });
285
+
286
+ await press(container);
287
+
288
+ // jsdom drops `min()`, so the side and the full height stand in for it.
289
+ expect(dialog().style.position).toBe('absolute');
290
+ expect(dialog().style.right).toBe('0px');
291
+ expect(dialog().style.top).toBe('0px');
292
+ expect(dialog().style.bottom).toBe('0px');
293
+ });
294
+
295
+ it('opens as a bottom sheet with the backdrop the author picked', async () => {
296
+ const { container } = renderPdp(SOLD_OUT, {
297
+ extra: {
298
+ stockAlertPresentation: 'sheet',
299
+ stockAlertSheetHeight: 87,
300
+ stockAlertBackdropColor: '#00321B',
301
+ stockAlertBackdropOpacity: 85
302
+ }
303
+ });
304
+
305
+ await press(container);
306
+
307
+ expect(dialog().style.bottom).toBe('0px');
308
+ expect(dialog().style.maxHeight).toBe('87vh');
309
+ expect(
310
+ (document.querySelector('[data-part="overlay"]') as HTMLElement).style
311
+ .background
312
+ ).toBe('rgba(0, 50, 27, 0.85)');
313
+ });
314
+
315
+ it('closes with the brand icon glyph when one is set', async () => {
316
+ const { container } = renderPdp(SOLD_OUT, {
317
+ extra: {
318
+ stockAlertCloseIcon: 'pz-icon-close"><script>',
319
+ stockAlertCloseIconSize: 12
320
+ }
321
+ });
322
+
323
+ await press(container);
324
+
325
+ const close = screen.getByRole('button', { name: 'Kapat' });
326
+ const glyph = close.querySelector('i') as HTMLElement;
327
+
328
+ expect(close.querySelector('svg')).toBeNull();
329
+ // Only class-name characters reach `className`.
330
+ expect(glyph.className).toBe('flex pz-icon-closescript');
331
+ expect(glyph.style.fontSize).toBe('12px');
332
+ });
333
+
334
+ it('tells the shopper when commerce refuses the alert', async () => {
335
+ mockAddStockAlert.mockReturnValue({
336
+ unwrap: () => Promise.reject({ status: 400 })
337
+ });
338
+ const { container } = renderPdp(SOLD_OUT);
339
+
340
+ await press(container);
341
+
342
+ expect(dialog().textContent).toContain('Bir hata oluştu.');
343
+ expect(dialog().textContent).not.toContain('shopper@example.com');
344
+ });
345
+
346
+ it('sends a guest to sign in with the page as the way back', async () => {
347
+ sessionStatus = 'unauthenticated';
348
+
349
+ await withLocation(async (assign) => {
350
+ const { container } = renderPdp(SOLD_OUT);
351
+
352
+ await press(container);
353
+
354
+ expect(mockAddStockAlert).not.toHaveBeenCalled();
355
+ expect(assign).toHaveBeenCalledWith(
356
+ `/auth?callbackUrl=${encodeURIComponent('/polo-101/?a=1')}`
357
+ );
358
+ });
359
+ });
360
+
361
+ it('sends a shopper whose session lapsed to sign in too', async () => {
362
+ mockAddStockAlert.mockReturnValue({
363
+ unwrap: () => Promise.reject({ status: 401 })
364
+ });
365
+
366
+ await withLocation(async (assign) => {
367
+ const { container } = renderPdp(SOLD_OUT, {
368
+ extra: { stockAlertReturnParam: 'next' }
369
+ });
370
+
371
+ await press(container);
372
+
373
+ expect(assign).toHaveBeenCalledWith(
374
+ `/auth?next=${encodeURIComponent('/polo-101/?a=1')}`
375
+ );
376
+ expect(dialog()).toBeNull();
377
+ });
378
+ });
379
+
380
+ it('leaves the email out of the message for an account without one', async () => {
381
+ sessionEmail = '';
382
+ const { container } = renderPdp(SOLD_OUT);
383
+
384
+ await press(container);
385
+
386
+ expect(mockAddStockAlert).toHaveBeenCalledWith({
387
+ productPk: 101,
388
+ email: ''
389
+ });
390
+ expect(dialog().textContent).toContain(
391
+ 'Ürün stoğa girdiğinde haber vereceğiz.'
392
+ );
393
+ });
394
+
395
+ it('carries the picked size on the way back from sign-in', async () => {
396
+ sessionStatus = 'unauthenticated';
397
+ act(() => {
398
+ setStockAlertPick({
399
+ pagePk: 101,
400
+ productPk: 102,
401
+ optionLabel: 'M',
402
+ attributeKey: 'integration_beden'
403
+ });
404
+ });
405
+
406
+ await withLocation(async (assign) => {
407
+ const { container } = renderPdp(IN_STOCK);
408
+
409
+ await press(container);
410
+
411
+ expect(assign).toHaveBeenCalledWith(
412
+ `/auth?callbackUrl=${encodeURIComponent(
413
+ '/polo-101/?a=1&stock_alert=102'
414
+ )}`
415
+ );
416
+ });
417
+ });
418
+
419
+ it('ignores a pick made on another page', () => {
420
+ act(() => {
421
+ setStockAlertPick({
422
+ pagePk: 999,
423
+ productPk: 102,
424
+ optionLabel: 'M',
425
+ attributeKey: 'integration_beden'
426
+ });
427
+ });
428
+
429
+ const { container } = renderPdp(IN_STOCK);
430
+
431
+ expect(button(container).textContent).toBe('Sepete Ekle');
432
+ });
433
+ });
434
+
435
+ describe('variant selector handing a sold-out size to the button', () => {
436
+ const sizeOption = (container: HTMLElement, label: string) =>
437
+ Array.from(
438
+ container.querySelectorAll('[data-variant-option]')
439
+ ).find((node) => node.textContent === label) as HTMLElement;
440
+
441
+ it('turns the button into the alert for the picked size, and back', async () => {
442
+ const { container } = renderPdp(IN_STOCK, { selector: true });
443
+ const m = sizeOption(container, 'M');
444
+
445
+ expect(m.tagName).toBe('BUTTON');
446
+ expect(m.getAttribute('aria-pressed')).toBe('false');
447
+
448
+ act(() => {
449
+ fireEvent.click(m);
450
+ });
451
+
452
+ expect(m.getAttribute('aria-pressed')).toBe('true');
453
+ expect(m.getAttribute('data-state')).toBe('disabled selected');
454
+ expect(button(container).textContent).toBe('Stok Gelince Haber Ver');
455
+
456
+ await act(async () => {
457
+ fireEvent.click(button(container));
458
+ });
459
+
460
+ expect(mockAddStockAlert).toHaveBeenCalledWith({
461
+ productPk: 102,
462
+ email: 'shopper@example.com'
463
+ });
464
+
465
+ act(() => {
466
+ fireEvent.click(sizeOption(container, 'M'));
467
+ });
468
+
469
+ expect(button(container).textContent).toBe('Sepete Ekle');
470
+ });
471
+
472
+ it('drops the pick when an in-stock size is picked, even the one on the page', () => {
473
+ const { container } = renderPdp(IN_STOCK, { selector: true });
474
+
475
+ act(() => {
476
+ fireEvent.click(sizeOption(container, 'M'));
477
+ });
478
+ expect(button(container).textContent).toBe('Stok Gelince Haber Ver');
479
+
480
+ act(() => {
481
+ fireEvent.click(sizeOption(container, 'S'));
482
+ });
483
+
484
+ expect(button(container).textContent).toBe('Sepete Ekle');
485
+ expect(sizeOption(container, 'M').getAttribute('aria-pressed')).toBe(
486
+ 'false'
487
+ );
488
+ });
489
+
490
+ it('drops the pick on navigation, so coming back does not restore it', () => {
491
+ const view = renderPdp(IN_STOCK, { selector: true });
492
+
493
+ act(() => {
494
+ fireEvent.click(sizeOption(view.container, 'M'));
495
+ });
496
+ expect(button(view.container).textContent).toBe('Stok Gelince Haber Ver');
497
+
498
+ // Another colour (the blocks remount on the new page), then back.
499
+ view.unmount();
500
+ currentPath = '/p/other';
501
+ renderPdp({ ...IN_STOCK, pk: 301 }, { selector: true }).unmount();
502
+ currentPath = '/p/s';
503
+
504
+ const back = renderPdp(IN_STOCK, { selector: true });
505
+
506
+ expect(button(back.container).textContent).toBe('Sepete Ekle');
507
+ });
508
+
509
+ it('picks the size again when sign-in hands the shopper back', () => {
510
+ window.history.replaceState(null, '', '/p/s?a=1&stock_alert=102');
511
+
512
+ const { container } = renderPdp(IN_STOCK, { selector: true });
513
+
514
+ expect(button(container).textContent).toBe('Stok Gelince Haber Ver');
515
+ expect(sizeOption(container, 'M').getAttribute('aria-pressed')).toBe(
516
+ 'true'
517
+ );
518
+ expect(window.location.search).toBe('?a=1');
519
+
520
+ window.history.replaceState(null, '', '/');
521
+ });
522
+
523
+ it('only lets the size row hand a pick over, never an outer one', () => {
524
+ const product = {
525
+ ...IN_STOCK,
526
+ variants: [
527
+ {
528
+ attribute_key: 'integration_renk',
529
+ attribute_name: 'Renk',
530
+ options: [
531
+ {
532
+ label: 'Mavi',
533
+ value: 'mavi',
534
+ in_stock: true,
535
+ is_selected: true,
536
+ is_selectable: true,
537
+ product: { pk: 101, absolute_url: '/p/s', stock: 9 }
538
+ },
539
+ {
540
+ label: 'Kırmızı',
541
+ value: 'kirmizi',
542
+ in_stock: false,
543
+ is_selectable: false,
544
+ product: { pk: 201, absolute_url: '/p/red', stock: 0 }
545
+ }
546
+ ]
547
+ },
548
+ SIZES
549
+ ]
550
+ };
551
+ const { container } = renderPdp(product, { selector: true });
552
+
553
+ expect(sizeOption(container, 'Kırmızı').tagName).toBe('SPAN');
554
+ expect(sizeOption(container, 'M').tagName).toBe('BUTTON');
555
+ });
556
+
557
+ it('leaves a sold-out size inert when the colour has no size left', () => {
558
+ const { container } = renderPdp(COLOUR_GONE, { selector: true });
559
+
560
+ expect(sizeOption(container, 'M').tagName).toBe('SPAN');
561
+ expect(container.querySelector('form')).toBeNull();
562
+ });
563
+
564
+ it('leaves a sold-out size inert while the switch is off', () => {
565
+ const { container } = render(
566
+ <ThemePageContextProvider value={{ product: IN_STOCK } as never}>
567
+ <VariantSelectorBlock
568
+ {...({
569
+ block: block('variant-selector', { stockAlert: false }),
570
+ currentBreakpoint: 'desktop'
571
+ } as never)}
572
+ />
573
+ </ThemePageContextProvider>
574
+ );
575
+
576
+ expect(sizeOption(container, 'M').tagName).toBe('SPAN');
577
+ });
578
+ });
579
+
580
+ /**
581
+ * Commerce's real shape: a size the colour does not have is filled with that
582
+ * size of ANOTHER colour, and a colour that is sold out altogether has every
583
+ * size filled that way — in stock.
584
+ */
585
+ describe('only the colour on the page counts', () => {
586
+ const size = (
587
+ label: string,
588
+ pk: number,
589
+ renk: string,
590
+ inStock: boolean
591
+ ) => ({
592
+ label,
593
+ value: label.toLowerCase(),
594
+ in_stock: inStock,
595
+ is_selectable: inStock,
596
+ product: {
597
+ pk,
598
+ absolute_url: `/p/${pk}`,
599
+ stock: inStock ? 9 : 0,
600
+ attributes: { integration_renk: renk }
601
+ }
602
+ });
603
+
604
+ const page = (renk: string, sizes: ReturnType<typeof size>[]) => ({
605
+ pk: 500,
606
+ name: 'Polo',
607
+ in_stock: false,
608
+ attributesKeyed: { integration_renk: renk },
609
+ variants: [
610
+ {
611
+ attribute_key: 'integration_renk',
612
+ options: [{ label: renk, value: renk, in_stock: false }]
613
+ },
614
+ { attribute_key: 'integration_beden', options: sizes }
615
+ ]
616
+ });
617
+
618
+ it('says sold out on a colour whose every size is gone, whatever the row lists', () => {
619
+ // The yellow page: S and M are the green and the brown ones.
620
+ const yellow = page('714', [
621
+ size('XS', 501, '714', false),
622
+ size('S', 502, '308', true),
623
+ size('M', 503, '284', true)
624
+ ]);
625
+ const { container } = renderPdp(yellow, { selector: true });
626
+
627
+ expect(button(container).textContent).toBe('Tükendi');
628
+ expect(
629
+ Array.from(container.querySelectorAll('[data-variant-option]')).find(
630
+ (node) => node.textContent === 'XS'
631
+ )?.tagName
632
+ ).toBe('SPAN');
633
+ });
634
+
635
+ it('offers the alert while one of the colour own sizes is in stock', () => {
636
+ const { container } = renderPdp(
637
+ page('714', [size('XS', 501, '714', false), size('S', 502, '714', true)])
638
+ );
639
+
640
+ expect(button(container).textContent).toBe('Stok Gelince Haber Ver');
641
+ });
642
+
643
+ it('lets another colour stand-in size be picked, as gant_zero did', async () => {
644
+ const white = {
645
+ ...page('110', [
646
+ // XS of grey stands in for the white XS that does not exist.
647
+ size('XS', 601, '95', false),
648
+ size('M', 602, '110', false),
649
+ size('L', 603, '110', true)
650
+ ]),
651
+ in_stock: true
652
+ };
653
+ const { container } = renderPdp(white, { selector: true });
654
+ const option = (label: string) =>
655
+ Array.from(container.querySelectorAll('[data-variant-option]')).find(
656
+ (node) => node.textContent === label
657
+ ) as HTMLElement;
658
+
659
+ expect(option('XS').tagName).toBe('BUTTON');
660
+ expect(option('M').tagName).toBe('BUTTON');
661
+
662
+ act(() => {
663
+ fireEvent.click(option('XS'));
664
+ });
665
+ await press(container);
666
+
667
+ // The alert goes to the product commerce sent for the size.
668
+ expect(mockAddStockAlert).toHaveBeenCalledWith({
669
+ productPk: 601,
670
+ email: 'shopper@example.com'
671
+ });
672
+ });
673
+ });