@salesforce/retail-react-app 6.1.0 → 7.0.0-nightly-20250526080400
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/CHANGELOG.md +5 -0
- package/app/components/nested-accordion/index.jsx +2 -2
- package/app/components/product-scroller/index.jsx +1 -1
- package/app/components/product-tile/index.test.js +6 -6
- package/app/components/product-view/index.test.js +23 -0
- package/app/components/quantity-picker/index.test.jsx +27 -3
- package/app/constants.js +3 -3
- package/app/hooks/use-auth-modal.test.js +1 -1
- package/app/hooks/use-multi-site.js +1 -1
- package/app/mocks/product-search-hit-data.js +18 -18
- package/app/pages/account/index.test.js +1 -1
- package/app/pages/cart/index.test.js +146 -0
- package/app/pages/checkout/partials/checkout-footer.test.js +7 -0
- package/app/pages/login/index.test.js +33 -0
- package/app/pages/product-list/index.jsx +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## v7.0.0-dev.0 (May 20, 2025)
|
|
2
|
+
|
|
3
|
+
- Improved the layout of product tiles in product scroll and product list [#2446](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2446)
|
|
4
|
+
|
|
1
5
|
## v6.1.0 (May 22, 2025)
|
|
2
6
|
|
|
3
7
|
- Fix hreflang alternate links [#2269](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2269)
|
|
@@ -101,6 +105,7 @@
|
|
|
101
105
|
- Add aria-label for Checkout's action buttons [#1906](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1906)
|
|
102
106
|
- Avoid forced focus changes that are not user-initiated [#1940](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1940)
|
|
103
107
|
|
|
108
|
+
|
|
104
109
|
## v3.0.2 (Jul 11, 2024)
|
|
105
110
|
|
|
106
111
|
### Bug Fixes
|
|
@@ -141,14 +141,14 @@ NestedAccordion.propTypes = {
|
|
|
141
141
|
item: PropTypes.object.isRequired,
|
|
142
142
|
/**
|
|
143
143
|
* An array of `AccordionItem` components that will be displayed after all
|
|
144
|
-
* of the child items. Alternatively you can pass a function that will
|
|
144
|
+
* of the child items. Alternatively you can pass a function that will receive
|
|
145
145
|
* the current item and it's depth, your should return an `AccordionItem` or
|
|
146
146
|
* array of `AccordionItem`'s.
|
|
147
147
|
*/
|
|
148
148
|
itemsAfter: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
|
|
149
149
|
/**
|
|
150
150
|
* An array of `AccordionItem` components that will be displayed before all
|
|
151
|
-
* of the child items. Alternatively you can pass a function that will
|
|
151
|
+
* of the child items. Alternatively you can pass a function that will receive
|
|
152
152
|
* the current item and it's depth, your should return an `AccordionItem` or
|
|
153
153
|
* array of `AccordionItem`'s.
|
|
154
154
|
*/
|
|
@@ -86,7 +86,7 @@ test('Renders variant details based on the selected swatch', async () => {
|
|
|
86
86
|
// Initial render will show swatched and the image will be the represented product variation
|
|
87
87
|
expect(swatches).toHaveLength(2)
|
|
88
88
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
89
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
89
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg'
|
|
90
90
|
)
|
|
91
91
|
const currentPriceTag = productTile.querySelectorAll('b')
|
|
92
92
|
const strikethroughPriceTag = productTile.querySelectorAll('s')
|
|
@@ -100,7 +100,7 @@ test('Renders variant details based on the selected swatch', async () => {
|
|
|
100
100
|
fireEvent.mouseOver(swatches[0])
|
|
101
101
|
await waitFor(() => screen.getByTestId('product-tile-image'))
|
|
102
102
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
103
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
103
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed78c6fc/images/medium/PG.52002RUBN4Q.NAVYWL.PZ.jpg'
|
|
104
104
|
)
|
|
105
105
|
expect(currentPriceTag).toHaveLength(1)
|
|
106
106
|
expect(within(currentPriceTag[0]).getByText(/£143\.99/i)).toBeDefined()
|
|
@@ -122,7 +122,7 @@ test('Renders variant details based on the selected swatch on mobile', async ()
|
|
|
122
122
|
// Initial render will show swatched and the image will be the represented product variation
|
|
123
123
|
expect(swatches).toHaveLength(2)
|
|
124
124
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
125
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
125
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg'
|
|
126
126
|
)
|
|
127
127
|
const currentPriceTag = productTile.querySelectorAll('b')
|
|
128
128
|
const strikethroughPriceTag = productTile.querySelectorAll('s')
|
|
@@ -136,7 +136,7 @@ test('Renders variant details based on the selected swatch on mobile', async ()
|
|
|
136
136
|
fireEvent.click(swatches[0])
|
|
137
137
|
await waitFor(() => screen.getByTestId('product-tile-image'))
|
|
138
138
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
139
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
139
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed78c6fc/images/medium/PG.52002RUBN4Q.NAVYWL.PZ.jpg'
|
|
140
140
|
)
|
|
141
141
|
expect(currentPriceTag).toHaveLength(1)
|
|
142
142
|
expect(within(currentPriceTag[0]).getByText(/£143\.99/i)).toBeDefined()
|
|
@@ -154,7 +154,7 @@ test('Renders price range with starting price and strikethrough price for master
|
|
|
154
154
|
expect(getByText(/Long Sleeve Embellished Boat Neck Top/i)).toBeInTheDocument()
|
|
155
155
|
const productImage = getByTestId('product-tile-image')
|
|
156
156
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
157
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
157
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwc9ce7da9/images/medium/PG.10217069.JJ908XX.PZ.jpg'
|
|
158
158
|
)
|
|
159
159
|
|
|
160
160
|
const currentPriceTag = container.querySelectorAll('b')
|
|
@@ -171,7 +171,7 @@ test('Renders price range with starting price and strikethrough price for master
|
|
|
171
171
|
fireEvent.mouseOver(swatches[0])
|
|
172
172
|
await waitFor(() => screen.getByTestId('product-tile-image'))
|
|
173
173
|
expect(productImage.firstChild.getAttribute('src')).toBe(
|
|
174
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
174
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed56b2da/images/medium/PG.10217069.JJ5QZXX.PZ.jpg'
|
|
175
175
|
)
|
|
176
176
|
expect(currentPriceTag).toHaveLength(1)
|
|
177
177
|
expect(within(currentPriceTag[0]).getByText(/From £18\.55/i)).toBeDefined()
|
|
@@ -128,6 +128,29 @@ test('Product View can update quantity', async () => {
|
|
|
128
128
|
})
|
|
129
129
|
})
|
|
130
130
|
|
|
131
|
+
describe('ProductView Component', () => {
|
|
132
|
+
test('increases quantity when increment button is clicked', async () => {
|
|
133
|
+
const user = userEvent.setup()
|
|
134
|
+
renderWithProviders(<ProductView product={mockProductDetail} />)
|
|
135
|
+
|
|
136
|
+
const quantityInput = await screen.findByRole('spinbutton')
|
|
137
|
+
const incrementButton = screen.getByTestId('quantity-increment')
|
|
138
|
+
const decrementButton = screen.getByTestId('quantity-decrement')
|
|
139
|
+
|
|
140
|
+
// Click increment
|
|
141
|
+
await user.click(incrementButton)
|
|
142
|
+
await waitFor(() => {
|
|
143
|
+
expect(quantityInput).toHaveValue('2')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Click decrement
|
|
147
|
+
await user.click(decrementButton)
|
|
148
|
+
await waitFor(() => {
|
|
149
|
+
expect(quantityInput).toHaveValue('1')
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
131
154
|
test('renders a product set properly - parent item', () => {
|
|
132
155
|
const parent = mockProductSet
|
|
133
156
|
renderWithProviders(
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
6
|
*/
|
|
7
7
|
import React, {useState} from 'react'
|
|
8
|
-
import {screen} from '@testing-library/react'
|
|
8
|
+
import {screen, fireEvent} from '@testing-library/react'
|
|
9
9
|
import userEvent from '@testing-library/user-event'
|
|
10
10
|
import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
|
|
11
11
|
import QuantityPicker from '@salesforce/retail-react-app/app/components/quantity-picker/index'
|
|
@@ -34,7 +34,7 @@ describe('QuantityPicker', () => {
|
|
|
34
34
|
await user.click(button)
|
|
35
35
|
expect(input.value).toBe('4')
|
|
36
36
|
})
|
|
37
|
-
test('
|
|
37
|
+
test('typing enter/space on plus increments value', async () => {
|
|
38
38
|
const user = userEvent.setup()
|
|
39
39
|
renderWithProviders(<MockComponent />)
|
|
40
40
|
const input = screen.getByRole('spinbutton')
|
|
@@ -44,7 +44,19 @@ describe('QuantityPicker', () => {
|
|
|
44
44
|
await user.type(button, '{space}')
|
|
45
45
|
expect(input.value).toBe('7')
|
|
46
46
|
})
|
|
47
|
-
|
|
47
|
+
|
|
48
|
+
test('keydown enter/space on plus increments value', async () => {
|
|
49
|
+
const user = userEvent.setup()
|
|
50
|
+
renderWithProviders(<MockComponent />)
|
|
51
|
+
const input = screen.getByRole('spinbutton')
|
|
52
|
+
const button = screen.getByText('+')
|
|
53
|
+
fireEvent.keyDown(button, {key: 'Enter'})
|
|
54
|
+
expect(input.value).toBe('6')
|
|
55
|
+
fireEvent.keyDown(button, {key: ' '})
|
|
56
|
+
expect(input.value).toBe('7')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('typing space on minus decrements value', async () => {
|
|
48
60
|
const user = userEvent.setup()
|
|
49
61
|
renderWithProviders(<MockComponent />)
|
|
50
62
|
const input = screen.getByRole('spinbutton')
|
|
@@ -54,6 +66,18 @@ describe('QuantityPicker', () => {
|
|
|
54
66
|
await user.type(button, '{space}')
|
|
55
67
|
expect(input.value).toBe('3')
|
|
56
68
|
})
|
|
69
|
+
|
|
70
|
+
test('keydown enter/space on minus decrements value', async () => {
|
|
71
|
+
const user = userEvent.setup()
|
|
72
|
+
renderWithProviders(<MockComponent />)
|
|
73
|
+
const input = screen.getByRole('spinbutton')
|
|
74
|
+
const button = screen.getByText(MINUS)
|
|
75
|
+
fireEvent.keyDown(button, {key: 'Enter'})
|
|
76
|
+
expect(input.value).toBe('4')
|
|
77
|
+
fireEvent.keyDown(button, {key: ' '})
|
|
78
|
+
expect(input.value).toBe('3')
|
|
79
|
+
})
|
|
80
|
+
|
|
57
81
|
test('plus button is tabbable', async () => {
|
|
58
82
|
const user = userEvent.setup()
|
|
59
83
|
renderWithProviders(<MockComponent />)
|
package/app/constants.js
CHANGED
|
@@ -18,7 +18,7 @@ export const STALE_WHILE_REVALIDATE = 60 * 15 // 15 min
|
|
|
18
18
|
export const DEFAULT_SEARCH_PARAMS = {limit: 25, offset: 0, sort: 'best-matches', refine: []}
|
|
19
19
|
export const DEFAULT_LIMIT_VALUES = [25, 50, 100] // Page sizes
|
|
20
20
|
|
|
21
|
-
//Constants for customer orders searching.
|
|
21
|
+
// Constants for customer orders searching.
|
|
22
22
|
export const DEFAULT_ORDERS_SEARCH_PARAMS = {limit: 10, offset: 0, sort: 'best-matches', refine: []}
|
|
23
23
|
|
|
24
24
|
// Constants for Search Component
|
|
@@ -27,11 +27,11 @@ export const RECENT_SEARCH_KEY = 'recent-search-key'
|
|
|
27
27
|
export const RECENT_SEARCH_MIN_LENGTH = 3
|
|
28
28
|
|
|
29
29
|
// Constants for product list page
|
|
30
|
-
export const PRODUCT_LIST_IMAGE_VIEW_TYPE = '
|
|
30
|
+
export const PRODUCT_LIST_IMAGE_VIEW_TYPE = 'medium'
|
|
31
31
|
export const PRODUCT_LIST_SELECTABLE_ATTRIBUTE_ID = 'color'
|
|
32
32
|
|
|
33
33
|
// Constants for product tile page
|
|
34
|
-
export const PRODUCT_TILE_IMAGE_VIEW_TYPE = '
|
|
34
|
+
export const PRODUCT_TILE_IMAGE_VIEW_TYPE = 'medium'
|
|
35
35
|
export const PRODUCT_TILE_SELECTABLE_ATTRIBUTE_ID = 'color'
|
|
36
36
|
|
|
37
37
|
// Constants for the Homepage's Shop Products section.
|
|
@@ -357,7 +357,7 @@ test('Allows customer to create an account', async () => {
|
|
|
357
357
|
)
|
|
358
358
|
})
|
|
359
359
|
|
|
360
|
-
// TODO:
|
|
360
|
+
// TODO: investigate why this test is failing when running with other tests
|
|
361
361
|
// eslint-disable-next-line jest/no-disabled-tests
|
|
362
362
|
test.skip('Allows customer to sign in to their account', async () => {
|
|
363
363
|
const user = userEvent.setup()
|
|
@@ -10,7 +10,7 @@ import {MultiSiteContext} from '@salesforce/retail-react-app/app/contexts'
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Custom React hook to get the function that returns usefule multi-site values, the site, the locale and
|
|
13
|
-
* the
|
|
13
|
+
* the function used to build URLs following the App configuration.
|
|
14
14
|
* @returns {{site, locale, buildUrl: (function(*, *, *): *)}}
|
|
15
15
|
*/
|
|
16
16
|
const useMultiSite = () => {
|
|
@@ -17,10 +17,10 @@ const mockProductSearchItem = {
|
|
|
17
17
|
{
|
|
18
18
|
images: [
|
|
19
19
|
{
|
|
20
|
-
alt: 'Charcoal Single Pleat Wool Suit, ,
|
|
20
|
+
alt: 'Charcoal Single Pleat Wool Suit, , medium',
|
|
21
21
|
disBaseLink:
|
|
22
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
23
|
-
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
22
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg',
|
|
23
|
+
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg',
|
|
24
24
|
title: 'Charcoal Single Pleat Wool Suit, '
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -36,10 +36,10 @@ const mockProductSearchItem = {
|
|
|
36
36
|
{
|
|
37
37
|
images: [
|
|
38
38
|
{
|
|
39
|
-
alt: 'Charcoal Single Pleat Wool Suit, Charcoal,
|
|
39
|
+
alt: 'Charcoal Single Pleat Wool Suit, Charcoal, medium',
|
|
40
40
|
disBaseLink:
|
|
41
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
42
|
-
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
41
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg',
|
|
42
|
+
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw23283a20/images/medium/PG.33698RUBN4Q.CHARCWL.PZ.jpg',
|
|
43
43
|
title: 'Charcoal Single Pleat Wool Suit, Charcoal'
|
|
44
44
|
},
|
|
45
45
|
{
|
|
@@ -535,9 +535,9 @@ const mockStandardProductHit = {
|
|
|
535
535
|
currency: 'GBP',
|
|
536
536
|
hitType: 'product',
|
|
537
537
|
image: {
|
|
538
|
-
alt: 'Laptop Briefcase with wheels (37L), ,
|
|
538
|
+
alt: 'Laptop Briefcase with wheels (37L), , medium',
|
|
539
539
|
disBaseLink:
|
|
540
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
540
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwcc8912f4/images/medium/P0048_001.jpg?sw=768&q=60',
|
|
541
541
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw7cb2d401/images/large/P0048_001.jpg',
|
|
542
542
|
title: 'Laptop Briefcase with wheels (37L), '
|
|
543
543
|
},
|
|
@@ -578,9 +578,9 @@ const mockMasterProductHitWithOneVariant = {
|
|
|
578
578
|
currency: 'GBP',
|
|
579
579
|
hitType: 'master',
|
|
580
580
|
image: {
|
|
581
|
-
alt: 'Black Flat Front Wool Suit, ,
|
|
581
|
+
alt: 'Black Flat Front Wool Suit, , medium',
|
|
582
582
|
disBaseLink:
|
|
583
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
583
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dw5aa46219/images/medium/PG.52001DAN84Q.BLACKWL.PZ.jpg',
|
|
584
584
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw3d8972fe/images/large/PG.52001DAN84Q.BLACKWL.PZ.jpg',
|
|
585
585
|
title: 'Black Flat Front Wool Suit, '
|
|
586
586
|
},
|
|
@@ -704,9 +704,9 @@ const mockMasterProductHitWithMultipleVariants = {
|
|
|
704
704
|
currency: 'GBP',
|
|
705
705
|
hitType: 'master',
|
|
706
706
|
image: {
|
|
707
|
-
alt: 'Long Sleeve Embellished Boat Neck Top, ,
|
|
707
|
+
alt: 'Long Sleeve Embellished Boat Neck Top, , medium',
|
|
708
708
|
disBaseLink:
|
|
709
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
709
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed56b2da/images/medium/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
710
710
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw7e4c00a0/images/large/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
711
711
|
title: 'Long Sleeve Embellished Boat Neck Top, '
|
|
712
712
|
},
|
|
@@ -714,9 +714,9 @@ const mockMasterProductHitWithMultipleVariants = {
|
|
|
714
714
|
{
|
|
715
715
|
images: [
|
|
716
716
|
{
|
|
717
|
-
alt: 'Long Sleeve Embellished Boat Neck Top, ,
|
|
717
|
+
alt: 'Long Sleeve Embellished Boat Neck Top, , medium',
|
|
718
718
|
disBaseLink:
|
|
719
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
719
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed56b2da/images/medium/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
720
720
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw7e4c00a0/images/large/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
721
721
|
title: 'Long Sleeve Embellished Boat Neck Top, '
|
|
722
722
|
},
|
|
@@ -733,9 +733,9 @@ const mockMasterProductHitWithMultipleVariants = {
|
|
|
733
733
|
{
|
|
734
734
|
images: [
|
|
735
735
|
{
|
|
736
|
-
alt: 'Long Sleeve Embellished Boat Neck Top, Begonia Pink,
|
|
736
|
+
alt: 'Long Sleeve Embellished Boat Neck Top, Begonia Pink, medium',
|
|
737
737
|
disBaseLink:
|
|
738
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
738
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwed56b2da/images/medium/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
739
739
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw7e4c00a0/images/large/PG.10217069.JJ5QZXX.PZ.jpg',
|
|
740
740
|
title: 'Long Sleeve Embellished Boat Neck Top, Begonia Pink'
|
|
741
741
|
},
|
|
@@ -762,9 +762,9 @@ const mockMasterProductHitWithMultipleVariants = {
|
|
|
762
762
|
{
|
|
763
763
|
images: [
|
|
764
764
|
{
|
|
765
|
-
alt: 'Long Sleeve Embellished Boat Neck Top, Grey Heather,
|
|
765
|
+
alt: 'Long Sleeve Embellished Boat Neck Top, Grey Heather, medium',
|
|
766
766
|
disBaseLink:
|
|
767
|
-
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/
|
|
767
|
+
'https://edge.disstg.commercecloud.salesforce.com/dw/image/v2/ZZRF_001/on/demandware.static/-/Sites-apparel-m-catalog/default/dwc9ce7da9/images/medium/PG.10217069.JJ908XX.PZ.jpg',
|
|
768
768
|
link: 'https://zzrf-001.dx.commercecloud.salesforce.com/on/demandware.static/-/Sites-apparel-m-catalog/default/dw3255ea4c/images/large/PG.10217069.JJ908XX.PZ.jpg',
|
|
769
769
|
title: 'Long Sleeve Embellished Boat Neck Top, Grey Heather'
|
|
770
770
|
},
|
|
@@ -140,8 +140,8 @@ describe('Render and logs out', function () {
|
|
|
140
140
|
expect(logOutIcons[1]).toHaveAttribute('aria-hidden', 'true')
|
|
141
141
|
})
|
|
142
142
|
|
|
143
|
-
await user.click(screen.getAllByText(/Log Out/)[0])
|
|
144
143
|
useCustomerType.mockReturnValue({isRegistered: false, isGuest: true})
|
|
144
|
+
await user.click(screen.getAllByText(/Log Out/)[0])
|
|
145
145
|
|
|
146
146
|
await waitFor(() => {
|
|
147
147
|
expect(window.location.pathname).toBe(`${expectedBasePath}/login`)
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
baskets as mockBaskets,
|
|
29
29
|
products as mockProducts
|
|
30
30
|
} from '@salesforce/retail-react-app/app/pages/cart/cart.mock'
|
|
31
|
+
import userEvent from '@testing-library/user-event'
|
|
31
32
|
|
|
32
33
|
const mockProduct = {
|
|
33
34
|
...mockVariant,
|
|
@@ -549,6 +550,128 @@ describe('Update this is a gift option', function () {
|
|
|
549
550
|
})
|
|
550
551
|
})
|
|
551
552
|
})
|
|
553
|
+
describe('Update this is not a gift option', function () {
|
|
554
|
+
beforeEach(() => {
|
|
555
|
+
global.server.use(
|
|
556
|
+
rest.patch('*/baskets/:basketId/items/:itemId', (req, res, ctx) => {
|
|
557
|
+
const basket = mockCustomerBaskets.baskets[0]
|
|
558
|
+
const updatedBasket = {
|
|
559
|
+
...basket,
|
|
560
|
+
productItems: [
|
|
561
|
+
{
|
|
562
|
+
adjustedTax: 2.93,
|
|
563
|
+
basePrice: 61.43,
|
|
564
|
+
bonusProductLineItem: false,
|
|
565
|
+
gift: false,
|
|
566
|
+
itemId: '4a9af0a24fe46c3f6d8721b371',
|
|
567
|
+
itemText: 'Belted Cardigan With Studs',
|
|
568
|
+
price: 61.43,
|
|
569
|
+
priceAfterItemDiscount: 61.43,
|
|
570
|
+
priceAfterOrderDiscount: 61.43,
|
|
571
|
+
productId: '701642889830M',
|
|
572
|
+
productName: 'Belted Cardigan With Studs',
|
|
573
|
+
quantity: 2,
|
|
574
|
+
shipmentId: 'me',
|
|
575
|
+
tax: 2.93,
|
|
576
|
+
taxBasis: 61.43,
|
|
577
|
+
taxClassId: 'standard',
|
|
578
|
+
taxRate: 0.05
|
|
579
|
+
}
|
|
580
|
+
]
|
|
581
|
+
}
|
|
582
|
+
return res(ctx.json(updatedBasket))
|
|
583
|
+
}),
|
|
584
|
+
rest.get('*/customers/:customerId/baskets', (req, res, ctx) => {
|
|
585
|
+
return res(
|
|
586
|
+
ctx.delay(0),
|
|
587
|
+
ctx.json({
|
|
588
|
+
baskets: [
|
|
589
|
+
{
|
|
590
|
+
...mockCustomerBaskets.baskets[0],
|
|
591
|
+
productItems: [
|
|
592
|
+
{
|
|
593
|
+
adjustedTax: 2.93,
|
|
594
|
+
basePrice: 61.43,
|
|
595
|
+
bonusProductLineItem: false,
|
|
596
|
+
gift: true,
|
|
597
|
+
itemId: '4a9af0a24fe46c3f6d8721b371',
|
|
598
|
+
itemText: 'Belted Cardigan With Studs',
|
|
599
|
+
price: 61.43,
|
|
600
|
+
priceAfterItemDiscount: 61.43,
|
|
601
|
+
priceAfterOrderDiscount: 61.43,
|
|
602
|
+
productId: '701642889830M',
|
|
603
|
+
productName: 'Belted Cardigan With Studs',
|
|
604
|
+
quantity: 2,
|
|
605
|
+
shipmentId: 'me',
|
|
606
|
+
tax: 2.93,
|
|
607
|
+
taxBasis: 61.43,
|
|
608
|
+
taxClassId: 'standard',
|
|
609
|
+
taxRate: 0.05
|
|
610
|
+
}
|
|
611
|
+
]
|
|
612
|
+
}
|
|
613
|
+
],
|
|
614
|
+
total: 1
|
|
615
|
+
})
|
|
616
|
+
)
|
|
617
|
+
})
|
|
618
|
+
)
|
|
619
|
+
})
|
|
620
|
+
test('can update cart item when user unchecks the gift checkbox', async () => {
|
|
621
|
+
const {user} = renderWithProviders(<Cart />)
|
|
622
|
+
await waitFor(() => {
|
|
623
|
+
expect(screen.getByTestId('sf-cart-container')).toBeInTheDocument()
|
|
624
|
+
expect(screen.getByText(/Belted Cardigan With Studs/i)).toBeInTheDocument()
|
|
625
|
+
|
|
626
|
+
const cartItem = screen.getByTestId('sf-cart-item-701642889830M')
|
|
627
|
+
expect(cartItem).toBeInTheDocument()
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
const giftCheckbox = screen.getByRole('checkbox')
|
|
631
|
+
expect(giftCheckbox).toBeChecked()
|
|
632
|
+
await user.click(giftCheckbox)
|
|
633
|
+
global.server.use(
|
|
634
|
+
rest.get('*/customers/:customerId/baskets', (req, res, ctx) => {
|
|
635
|
+
return res.once(
|
|
636
|
+
ctx.delay(0),
|
|
637
|
+
ctx.json({
|
|
638
|
+
baskets: [
|
|
639
|
+
{
|
|
640
|
+
...mockCustomerBaskets.baskets[0],
|
|
641
|
+
productItems: [
|
|
642
|
+
{
|
|
643
|
+
adjustedTax: 2.93,
|
|
644
|
+
basePrice: 61.43,
|
|
645
|
+
bonusProductLineItem: false,
|
|
646
|
+
gift: false,
|
|
647
|
+
itemId: '4a9af0a24fe46c3f6d8721b371',
|
|
648
|
+
itemText: 'Belted Cardigan With Studs',
|
|
649
|
+
price: 61.43,
|
|
650
|
+
priceAfterItemDiscount: 61.43,
|
|
651
|
+
priceAfterOrderDiscount: 61.43,
|
|
652
|
+
productId: '701642889830M',
|
|
653
|
+
productName: 'Belted Cardigan With Studs',
|
|
654
|
+
quantity: 2,
|
|
655
|
+
shipmentId: 'me',
|
|
656
|
+
tax: 2.93,
|
|
657
|
+
taxBasis: 61.43,
|
|
658
|
+
taxClassId: 'standard',
|
|
659
|
+
taxRate: 0.05
|
|
660
|
+
}
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
],
|
|
664
|
+
total: 1
|
|
665
|
+
})
|
|
666
|
+
)
|
|
667
|
+
})
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
await waitFor(() => {
|
|
671
|
+
expect(giftCheckbox).not.toBeChecked()
|
|
672
|
+
})
|
|
673
|
+
})
|
|
674
|
+
})
|
|
552
675
|
|
|
553
676
|
describe('Product bundles', () => {
|
|
554
677
|
beforeEach(() => {
|
|
@@ -796,3 +919,26 @@ describe('Unavailable products tests', function () {
|
|
|
796
919
|
})
|
|
797
920
|
})
|
|
798
921
|
})
|
|
922
|
+
|
|
923
|
+
test('shows error toast when updating cart item fails', async () => {
|
|
924
|
+
// Mock the update item API to fail
|
|
925
|
+
global.server.use(
|
|
926
|
+
rest.patch('*/baskets/:basketId/items/:itemId', (req, res, ctx) => {
|
|
927
|
+
return res(ctx.status(500))
|
|
928
|
+
})
|
|
929
|
+
)
|
|
930
|
+
|
|
931
|
+
renderWithProviders(<Cart />)
|
|
932
|
+
await waitFor(() => expect(screen.getByTestId('sf-cart-container')).toBeInTheDocument())
|
|
933
|
+
|
|
934
|
+
// Find the first "Edit" button and click it to open the edit modal
|
|
935
|
+
const editButtons = await screen.findAllByRole('button', {name: /edit/i})
|
|
936
|
+
await userEvent.click(editButtons[0])
|
|
937
|
+
|
|
938
|
+
// In the modal, find and click the "Update" or "Save" button (adjust selector as needed)
|
|
939
|
+
const updateButton = await screen.findByRole('button', {name: /update|save/i})
|
|
940
|
+
await userEvent.click(updateButton)
|
|
941
|
+
|
|
942
|
+
// Wait for the error toast to appear
|
|
943
|
+
await waitFor(() => expect(screen.getByText(/something went wrong/i)).toBeInTheDocument())
|
|
944
|
+
})
|
|
@@ -14,3 +14,10 @@ test('renders component', () => {
|
|
|
14
14
|
renderWithProviders(<CheckoutFooter />)
|
|
15
15
|
expect(screen.getByRole('link', {name: 'Shipping'})).toBeInTheDocument()
|
|
16
16
|
})
|
|
17
|
+
|
|
18
|
+
test('displays copyright message with current year', () => {
|
|
19
|
+
renderWithProviders(<CheckoutFooter />)
|
|
20
|
+
const currentYear = new Date().getFullYear()
|
|
21
|
+
const copyrightText = `© ${currentYear} Salesforce or its affiliates. All rights reserved. This is a demo store only. Orders made WILL NOT be processed.`
|
|
22
|
+
expect(screen.getByText(copyrightText)).toBeInTheDocument()
|
|
23
|
+
})
|
|
@@ -99,6 +99,39 @@ describe('Logging in tests', function () {
|
|
|
99
99
|
)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
+
test('Shows inline error when email is empty', async () => {
|
|
103
|
+
const {user} = renderWithProviders(<MockedComponent />, {
|
|
104
|
+
wrapperProps: {
|
|
105
|
+
siteAlias: 'uk',
|
|
106
|
+
locale: {id: 'en-GB'},
|
|
107
|
+
appConfig: mockConfig.app,
|
|
108
|
+
bypassAuth: false
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// Only fill password, leave email empty
|
|
113
|
+
await user.type(screen.getByLabelText('Password'), 'Password!1')
|
|
114
|
+
// Try to submit the form
|
|
115
|
+
await user.click(screen.getByText(/sign in/i))
|
|
116
|
+
expect(await screen.findByText(/Please enter your email address\./i)).toBeInTheDocument()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
test('Shows inline error when password is empty', async () => {
|
|
120
|
+
const {user} = renderWithProviders(<MockedComponent />, {
|
|
121
|
+
wrapperProps: {
|
|
122
|
+
siteAlias: 'uk',
|
|
123
|
+
locale: {id: 'en-GB'},
|
|
124
|
+
appConfig: mockConfig.app,
|
|
125
|
+
bypassAuth: false
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
// Only fill email, leave password empty
|
|
129
|
+
await user.type(screen.getByLabelText('Email'), 'customer@test.com')
|
|
130
|
+
// Try to submit the form
|
|
131
|
+
await user.click(screen.getByText(/sign in/i))
|
|
132
|
+
expect(await screen.findByText(/Please enter your password\./i)).toBeInTheDocument()
|
|
133
|
+
})
|
|
134
|
+
|
|
102
135
|
test('Allows customer to sign in to their account', async () => {
|
|
103
136
|
const {user} = renderWithProviders(<MockedComponent />, {
|
|
104
137
|
wrapperProps: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/retail-react-app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-nightly-20250526080400",
|
|
4
4
|
"license": "See license in LICENSE",
|
|
5
5
|
"author": "cc-pwa-kit@salesforce.com",
|
|
6
6
|
"ccExtensibility": {
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"@loadable/component": "^5.15.3",
|
|
47
47
|
"@peculiar/webcrypto": "^1.4.2",
|
|
48
48
|
"@salesforce/cc-datacloud-typescript": "1.1.2",
|
|
49
|
-
"@salesforce/commerce-sdk-react": "3.
|
|
50
|
-
"@salesforce/pwa-kit-dev": "3.
|
|
51
|
-
"@salesforce/pwa-kit-react-sdk": "3.
|
|
52
|
-
"@salesforce/pwa-kit-runtime": "3.
|
|
49
|
+
"@salesforce/commerce-sdk-react": "3.4.0-nightly-20250526080400",
|
|
50
|
+
"@salesforce/pwa-kit-dev": "3.11.0-nightly-20250526080400",
|
|
51
|
+
"@salesforce/pwa-kit-react-sdk": "3.11.0-nightly-20250526080400",
|
|
52
|
+
"@salesforce/pwa-kit-runtime": "3.11.0-nightly-20250526080400",
|
|
53
53
|
"@tanstack/react-query": "^4.28.0",
|
|
54
54
|
"@tanstack/react-query-devtools": "^4.29.1",
|
|
55
55
|
"@testing-library/dom": "^9.0.1",
|
|
@@ -107,5 +107,5 @@
|
|
|
107
107
|
"maxSize": "328 kB"
|
|
108
108
|
}
|
|
109
109
|
],
|
|
110
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "f7cdce47d5702c370abf36a0a639bd6e7fee89c6"
|
|
111
111
|
}
|