@salesforce/retail-react-app 7.1.0-preview.1 → 8.0.0-dev
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 +8 -2
- package/app/components/_app/index.jsx +9 -7
- package/app/components/_app/index.test.js +2 -2
- package/app/components/_app-config/index.jsx +9 -3
- package/app/components/drawer-menu/drawer-menu.jsx +3 -1
- package/app/components/footer/index.jsx +3 -1
- package/app/components/header/index.jsx +3 -1
- package/app/components/header/index.test.js +2 -2
- package/app/components/island/README.md +1 -1
- package/app/components/island/index.jsx +3 -1
- package/app/components/island/index.test.js +94 -5
- package/app/components/item-variant/item-attributes.jsx +12 -3
- package/app/components/multiship/multiship-order-summary.jsx +137 -0
- package/app/components/multiship/multiship-order-summary.test.js +121 -0
- package/app/components/order-summary/index.jsx +2 -4
- package/app/components/pickup-or-delivery/index.jsx +80 -0
- package/app/components/pickup-or-delivery/index.test.jsx +182 -0
- package/app/components/product-item/index.jsx +26 -16
- package/app/components/product-item/index.test.js +29 -2
- package/app/components/product-item-list/index.jsx +10 -0
- package/app/components/product-item-list/index.test.jsx +14 -0
- package/app/components/product-view/index.jsx +9 -6
- package/app/components/product-view/index.test.js +25 -21
- package/app/components/quantity-picker/index.test.jsx +12 -12
- package/app/components/reset-password/index.test.js +1 -1
- package/app/components/shared/ui/AlertDescription/index.jsx +8 -0
- package/app/components/shared/ui/index.jsx +1 -0
- package/app/components/store-display/index.jsx +28 -4
- package/app/components/store-display/index.test.js +71 -0
- package/app/components/store-locator/form.test.jsx +16 -4
- package/app/components/store-locator/list.jsx +9 -4
- package/app/components/toggle-card/index.jsx +14 -0
- package/app/components/unavailable-product-confirmation-modal/index.jsx +19 -5
- package/app/components/unavailable-product-confirmation-modal/index.test.js +122 -1
- package/app/constants.js +20 -6
- package/app/contexts/store-locator-provider.jsx +7 -1
- package/app/contexts/store-locator-provider.test.jsx +36 -1
- package/app/hooks/use-address-form.js +155 -0
- package/app/hooks/use-address-form.test.js +501 -0
- package/app/hooks/use-auth-modal.js +2 -6
- package/app/hooks/use-current-basket.js +71 -2
- package/app/hooks/use-current-basket.test.js +37 -1
- package/app/hooks/use-dnt-notification.js +4 -4
- package/app/hooks/use-dnt-notification.test.js +5 -5
- package/app/hooks/use-item-shipment-management.js +233 -0
- package/app/hooks/use-item-shipment-management.test.js +696 -0
- package/app/hooks/use-multiship.js +589 -0
- package/app/hooks/use-multiship.test.js +776 -0
- package/app/hooks/use-pickup-shipment.js +70 -106
- package/app/hooks/use-pickup-shipment.test.js +345 -209
- package/app/hooks/use-product-address-assignment.js +280 -0
- package/app/hooks/use-product-address-assignment.test.js +414 -0
- package/app/hooks/use-product-inventory.js +100 -0
- package/app/hooks/use-product-inventory.test.js +254 -0
- package/app/hooks/use-shipment-operations.js +168 -0
- package/app/hooks/use-shipment-operations.test.js +385 -0
- package/app/hooks/use-store-locator.js +24 -2
- package/app/hooks/use-store-locator.test.jsx +109 -1
- package/app/pages/account/index.test.js +1 -1
- package/app/pages/account/profile.test.js +0 -2
- package/app/pages/cart/index.jsx +397 -157
- package/app/pages/cart/index.test.js +353 -2
- package/app/pages/cart/partials/bonus-products-title.jsx +10 -8
- package/app/pages/cart/partials/cart-secondary-button-group.test.js +1 -1
- package/app/pages/cart/partials/order-type-display.jsx +68 -0
- package/app/pages/cart/partials/order-type-display.test.js +241 -0
- package/app/pages/checkout/confirmation.jsx +79 -158
- package/app/pages/checkout/index.jsx +34 -9
- package/app/pages/checkout/index.test.js +245 -118
- package/app/pages/checkout/partials/contact-info.jsx +2 -6
- package/app/pages/checkout/partials/contact-info.test.js +93 -7
- package/app/pages/checkout/partials/payment.jsx +19 -5
- package/app/pages/checkout/partials/pickup-address.jsx +340 -70
- package/app/pages/checkout/partials/pickup-address.test.js +1075 -82
- package/app/pages/checkout/partials/product-shipping-address-card.jsx +382 -0
- package/app/pages/checkout/partials/shipment-details.jsx +209 -0
- package/app/pages/checkout/partials/shipment-details.test.js +246 -0
- package/app/pages/checkout/partials/shipping-address.jsx +156 -68
- package/app/pages/checkout/partials/shipping-address.test.js +673 -0
- package/app/pages/checkout/partials/shipping-method-options.jsx +180 -0
- package/app/pages/checkout/partials/shipping-methods.jsx +403 -0
- package/app/pages/checkout/partials/shipping-methods.test.js +472 -0
- package/app/pages/checkout/partials/shipping-multi-address.jsx +259 -0
- package/app/pages/checkout/partials/shipping-multi-address.test.js +2088 -0
- package/app/pages/checkout/partials/shipping-product-cards.jsx +101 -0
- package/app/pages/checkout/util/checkout-context.js +25 -18
- package/app/pages/login/index.jsx +2 -6
- package/app/pages/product-detail/index.jsx +96 -81
- package/app/pages/product-detail/index.test.js +103 -19
- package/app/pages/product-list/index.jsx +3 -1
- package/app/pages/product-list/partials/inventory-filter.jsx +18 -21
- package/app/pages/product-list/partials/inventory-filter.test.js +15 -17
- package/app/pages/product-list/partials/selected-refinements.jsx +3 -1
- package/app/ssr.js +1 -1
- package/app/static/translations/compiled/en-GB.json +316 -30
- package/app/static/translations/compiled/en-US.json +316 -30
- package/app/static/translations/compiled/en-XA.json +673 -75
- package/app/utils/address-utils.js +112 -0
- package/app/utils/address-utils.test.js +484 -0
- package/app/utils/product-utils.js +17 -5
- package/app/utils/product-utils.test.js +17 -8
- package/app/utils/sfdc-user-agent-utils.js +32 -0
- package/app/utils/sfdc-user-agent-utils.test.js +82 -0
- package/app/utils/shipment-utils.js +196 -0
- package/app/utils/shipment-utils.test.js +458 -0
- package/app/utils/test-utils.js +4 -4
- package/app/utils/utils.js +6 -1
- package/config/default.js +4 -1
- package/config/mocks/default.js +3 -1
- package/package.json +9 -9
- package/translations/en-GB.json +127 -10
- package/translations/en-US.json +127 -10
- package/app/pages/checkout/partials/shipping-options.jsx +0 -269
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react'
|
|
8
|
+
import {render, screen, waitFor} from '@testing-library/react'
|
|
9
|
+
import {IntlProvider} from 'react-intl'
|
|
10
|
+
import {CurrencyProvider} from '@salesforce/retail-react-app/app/contexts'
|
|
11
|
+
import ShippingMethods from '@salesforce/retail-react-app/app/pages/checkout/partials/shipping-methods'
|
|
12
|
+
import {useCheckout} from '@salesforce/retail-react-app/app/pages/checkout/util/checkout-context'
|
|
13
|
+
import {useCurrentBasket} from '@salesforce/retail-react-app/app/hooks/use-current-basket'
|
|
14
|
+
import {useCurrency} from '@salesforce/retail-react-app/app/hooks'
|
|
15
|
+
import {useShippingMethodsForShipment, useProducts} from '@salesforce/commerce-sdk-react'
|
|
16
|
+
|
|
17
|
+
// Mock the hooks
|
|
18
|
+
jest.mock('@salesforce/retail-react-app/app/pages/checkout/util/checkout-context')
|
|
19
|
+
jest.mock('@salesforce/retail-react-app/app/hooks/use-current-basket')
|
|
20
|
+
jest.mock('@salesforce/retail-react-app/app/hooks')
|
|
21
|
+
jest.mock('@salesforce/commerce-sdk-react')
|
|
22
|
+
|
|
23
|
+
const mockUseCheckout = useCheckout
|
|
24
|
+
const mockUseCurrentBasket = useCurrentBasket
|
|
25
|
+
const mockUseCurrency = useCurrency
|
|
26
|
+
const mockUseShippingMethodsForShipment = useShippingMethodsForShipment
|
|
27
|
+
const mockUseProducts = useProducts
|
|
28
|
+
|
|
29
|
+
// Mock data
|
|
30
|
+
const mockBasket = {
|
|
31
|
+
basketId: 'basket-1',
|
|
32
|
+
shipments: [
|
|
33
|
+
{
|
|
34
|
+
shipmentId: 'shipment-1',
|
|
35
|
+
shippingAddress: {
|
|
36
|
+
firstName: 'John',
|
|
37
|
+
lastName: 'Doe',
|
|
38
|
+
address1: '123 Main St',
|
|
39
|
+
city: 'Anytown',
|
|
40
|
+
stateCode: 'CA',
|
|
41
|
+
postalCode: '12345'
|
|
42
|
+
},
|
|
43
|
+
shippingMethod: {
|
|
44
|
+
id: 'shipping-method-1',
|
|
45
|
+
name: 'Standard Shipping',
|
|
46
|
+
description: '5-7 business days'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
productItems: [
|
|
51
|
+
{
|
|
52
|
+
itemId: 'item-1',
|
|
53
|
+
productId: 'product-1',
|
|
54
|
+
productName: 'Test Product 1',
|
|
55
|
+
quantity: 2,
|
|
56
|
+
price: 29.99,
|
|
57
|
+
variationValues: {
|
|
58
|
+
color: 'Red',
|
|
59
|
+
size: 'Medium'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
itemId: 'item-2',
|
|
64
|
+
productId: 'product-2',
|
|
65
|
+
productName: 'Test Product 2',
|
|
66
|
+
quantity: 1,
|
|
67
|
+
price: 19.99,
|
|
68
|
+
variationValues: {
|
|
69
|
+
color: 'Blue',
|
|
70
|
+
size: 'Large'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
shippingItems: [
|
|
75
|
+
{
|
|
76
|
+
shipmentId: 'shipment-1',
|
|
77
|
+
price: 5.99,
|
|
78
|
+
priceAfterItemDiscount: 5.99
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const mockShippingMethods = {
|
|
84
|
+
applicableShippingMethods: [
|
|
85
|
+
{
|
|
86
|
+
id: 'shipping-method-1',
|
|
87
|
+
name: 'Standard Shipping',
|
|
88
|
+
description: '5-7 business days',
|
|
89
|
+
price: 5.99
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'shipping-method-2',
|
|
93
|
+
name: 'Express Shipping',
|
|
94
|
+
description: '2-3 business days',
|
|
95
|
+
price: 12.99
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
defaultShippingMethodId: 'shipping-method-1'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const mockProductsMap = {
|
|
102
|
+
'product-1': {
|
|
103
|
+
id: 'product-1',
|
|
104
|
+
name: 'Test Product 1',
|
|
105
|
+
imageGroups: [
|
|
106
|
+
{
|
|
107
|
+
viewType: 'small',
|
|
108
|
+
images: [
|
|
109
|
+
{
|
|
110
|
+
link: 'https://test-image-1.jpg',
|
|
111
|
+
disBaseLink: 'https://test-image-1.jpg'
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
'product-2': {
|
|
118
|
+
id: 'product-2',
|
|
119
|
+
name: 'Test Product 2',
|
|
120
|
+
imageGroups: [
|
|
121
|
+
{
|
|
122
|
+
viewType: 'small',
|
|
123
|
+
images: [
|
|
124
|
+
{
|
|
125
|
+
link: 'https://test-image-2.jpg',
|
|
126
|
+
disBaseLink: 'https://test-image-2.jpg'
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const defaultProps = {
|
|
135
|
+
step: 'SHIPPING_OPTIONS',
|
|
136
|
+
STEPS: {
|
|
137
|
+
SHIPPING_OPTIONS: 'SHIPPING_OPTIONS'
|
|
138
|
+
},
|
|
139
|
+
goToStep: jest.fn(),
|
|
140
|
+
goToNextStep: jest.fn()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const renderWithIntl = (component) => {
|
|
144
|
+
return render(
|
|
145
|
+
<CurrencyProvider currency="USD">
|
|
146
|
+
<IntlProvider locale="en">{component}</IntlProvider>
|
|
147
|
+
</CurrencyProvider>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
describe('ShippingMethods', () => {
|
|
152
|
+
beforeEach(() => {
|
|
153
|
+
mockUseCheckout.mockReturnValue(defaultProps)
|
|
154
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
155
|
+
data: mockBasket,
|
|
156
|
+
derivedData: {
|
|
157
|
+
totalShippingCost: 5.99
|
|
158
|
+
},
|
|
159
|
+
isLoading: false
|
|
160
|
+
})
|
|
161
|
+
mockUseCurrency.mockReturnValue({
|
|
162
|
+
currency: 'USD'
|
|
163
|
+
})
|
|
164
|
+
mockUseShippingMethodsForShipment.mockReturnValue({
|
|
165
|
+
data: mockShippingMethods,
|
|
166
|
+
isLoading: false
|
|
167
|
+
})
|
|
168
|
+
mockUseProducts.mockReturnValue({
|
|
169
|
+
data: mockProductsMap,
|
|
170
|
+
isLoading: false
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
afterEach(() => {
|
|
175
|
+
jest.clearAllMocks()
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('Loading States', () => {
|
|
179
|
+
test('should show loading spinner when basket is loading', () => {
|
|
180
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
181
|
+
data: null,
|
|
182
|
+
derivedData: {
|
|
183
|
+
totalShippingCost: undefined
|
|
184
|
+
},
|
|
185
|
+
isLoading: true
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
renderWithIntl(<ShippingMethods />)
|
|
189
|
+
|
|
190
|
+
expect(screen.getAllByTestId('loading').length).toBeGreaterThan(0)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('should show loading spinner for shipping methods when shipping methods are loading', async () => {
|
|
194
|
+
mockUseShippingMethodsForShipment.mockReturnValue({
|
|
195
|
+
data: null,
|
|
196
|
+
isLoading: true
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
renderWithIntl(<ShippingMethods />)
|
|
200
|
+
|
|
201
|
+
// Wait for the loading spinner to appear
|
|
202
|
+
await waitFor(() => {
|
|
203
|
+
expect(screen.getAllByTestId('loading').length).toBeGreaterThan(0)
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test('should show loading spinner when multiple data sources are loading', () => {
|
|
208
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
209
|
+
data: null,
|
|
210
|
+
derivedData: {
|
|
211
|
+
totalShippingCost: undefined
|
|
212
|
+
},
|
|
213
|
+
isLoading: true
|
|
214
|
+
})
|
|
215
|
+
mockUseProducts.mockReturnValue({
|
|
216
|
+
data: {},
|
|
217
|
+
isLoading: true
|
|
218
|
+
})
|
|
219
|
+
mockUseShippingMethodsForShipment.mockReturnValue({
|
|
220
|
+
data: null,
|
|
221
|
+
isLoading: true
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
renderWithIntl(<ShippingMethods />)
|
|
225
|
+
|
|
226
|
+
expect(screen.getAllByTestId('loading').length).toBeGreaterThan(0)
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
describe('Component Rendering', () => {
|
|
231
|
+
test('should render shipping options when all data is loaded', () => {
|
|
232
|
+
renderWithIntl(<ShippingMethods />)
|
|
233
|
+
|
|
234
|
+
expect(screen.getByText('Shipping & Gift Options')).toBeInTheDocument()
|
|
235
|
+
expect(screen.getByText('Standard Shipping')).toBeInTheDocument()
|
|
236
|
+
expect(screen.getByText('Express Shipping')).toBeInTheDocument()
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
test('should render shipping methods correctly', () => {
|
|
240
|
+
renderWithIntl(<ShippingMethods />)
|
|
241
|
+
|
|
242
|
+
expect(screen.getByText('Standard Shipping')).toBeInTheDocument()
|
|
243
|
+
expect(screen.getByText('Express Shipping')).toBeInTheDocument()
|
|
244
|
+
expect(screen.getByText('5-7 business days')).toBeInTheDocument()
|
|
245
|
+
expect(screen.getByText('2-3 business days')).toBeInTheDocument()
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
test('should render shipping methods when shipping methods are loaded', () => {
|
|
249
|
+
renderWithIntl(<ShippingMethods />)
|
|
250
|
+
|
|
251
|
+
expect(screen.getByText('Standard Shipping')).toBeInTheDocument()
|
|
252
|
+
expect(screen.getByText('Express Shipping')).toBeInTheDocument()
|
|
253
|
+
expect(screen.getByText('5-7 business days')).toBeInTheDocument()
|
|
254
|
+
expect(screen.getByText('2-3 business days')).toBeInTheDocument()
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test('should display shipping cost from derivedData correctly', () => {
|
|
258
|
+
renderWithIntl(<ShippingMethods />)
|
|
259
|
+
expect(screen.getByText('$5.99')).toBeInTheDocument()
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
describe('Form Functionality', () => {
|
|
264
|
+
test('should render continue button when shipping method is selected', () => {
|
|
265
|
+
renderWithIntl(<ShippingMethods />)
|
|
266
|
+
|
|
267
|
+
const continueButton = screen.getByText('Continue to Payment')
|
|
268
|
+
expect(continueButton).toBeInTheDocument()
|
|
269
|
+
expect(continueButton).not.toBeDisabled()
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
test('should disable continue button when no shipping method is selected', () => {
|
|
273
|
+
// Mock basket without shipping method
|
|
274
|
+
const basketWithoutShippingMethod = {
|
|
275
|
+
...mockBasket,
|
|
276
|
+
shipments: [
|
|
277
|
+
{
|
|
278
|
+
...mockBasket.shipments[0],
|
|
279
|
+
shippingMethod: null
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
285
|
+
data: basketWithoutShippingMethod,
|
|
286
|
+
derivedData: {
|
|
287
|
+
totalShippingCost: 5.99
|
|
288
|
+
},
|
|
289
|
+
isLoading: false
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
renderWithIntl(<ShippingMethods />)
|
|
293
|
+
|
|
294
|
+
const continueButton = screen.getByText('Continue to Payment')
|
|
295
|
+
expect(continueButton).toBeDisabled()
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
describe('Multiple Shipments', () => {
|
|
300
|
+
test('should render multiple shipments correctly', () => {
|
|
301
|
+
const multiShipmentBasket = {
|
|
302
|
+
...mockBasket,
|
|
303
|
+
shipments: [
|
|
304
|
+
{
|
|
305
|
+
shipmentId: 'shipment-1',
|
|
306
|
+
shippingAddress: {
|
|
307
|
+
firstName: 'John',
|
|
308
|
+
lastName: 'Doe',
|
|
309
|
+
address1: '123 Main St',
|
|
310
|
+
city: 'Anytown',
|
|
311
|
+
stateCode: 'CA',
|
|
312
|
+
postalCode: '12345'
|
|
313
|
+
},
|
|
314
|
+
shippingMethod: {
|
|
315
|
+
id: 'shipping-method-1',
|
|
316
|
+
name: 'Standard Shipping',
|
|
317
|
+
description: '5-7 business days'
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
shipmentId: 'shipment-2',
|
|
322
|
+
shippingAddress: {
|
|
323
|
+
firstName: 'Jane',
|
|
324
|
+
lastName: 'Smith',
|
|
325
|
+
address1: '456 Oak Ave',
|
|
326
|
+
city: 'Somewhere',
|
|
327
|
+
stateCode: 'NY',
|
|
328
|
+
postalCode: '67890'
|
|
329
|
+
},
|
|
330
|
+
shippingMethod: {
|
|
331
|
+
id: 'shipping-method-2',
|
|
332
|
+
name: 'Express Shipping',
|
|
333
|
+
description: '2-3 business days'
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
340
|
+
data: multiShipmentBasket,
|
|
341
|
+
derivedData: {
|
|
342
|
+
totalShippingCost: 18.98
|
|
343
|
+
},
|
|
344
|
+
isLoading: false
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
renderWithIntl(<ShippingMethods />)
|
|
348
|
+
|
|
349
|
+
expect(screen.getAllByText('Standard Shipping').length).toBeGreaterThan(0)
|
|
350
|
+
expect(screen.getAllByText('Express Shipping').length).toBeGreaterThan(0)
|
|
351
|
+
})
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
describe('Error Handling', () => {
|
|
355
|
+
test('should handle missing basket data gracefully', () => {
|
|
356
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
357
|
+
data: null,
|
|
358
|
+
derivedData: {
|
|
359
|
+
totalShippingCost: undefined
|
|
360
|
+
},
|
|
361
|
+
isLoading: false
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
renderWithIntl(<ShippingMethods />)
|
|
365
|
+
|
|
366
|
+
// Should not crash and should show appropriate state
|
|
367
|
+
expect(screen.getByText('Shipping & Gift Options')).toBeInTheDocument()
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
test('should handle missing shipping address gracefully', () => {
|
|
371
|
+
const basketWithoutAddress = {
|
|
372
|
+
...mockBasket,
|
|
373
|
+
shipments: [
|
|
374
|
+
{
|
|
375
|
+
...mockBasket.shipments[0],
|
|
376
|
+
shippingAddress: null
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
382
|
+
data: basketWithoutAddress,
|
|
383
|
+
derivedData: {
|
|
384
|
+
totalShippingCost: 5.99
|
|
385
|
+
},
|
|
386
|
+
isLoading: false
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
renderWithIntl(<ShippingMethods />)
|
|
390
|
+
|
|
391
|
+
// Should not crash and should show appropriate state
|
|
392
|
+
expect(screen.getByText('Shipping & Gift Options')).toBeInTheDocument()
|
|
393
|
+
})
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
describe('Product Display', () => {
|
|
397
|
+
test('should render shipping options component with basic structure', () => {
|
|
398
|
+
renderWithIntl(<ShippingMethods />)
|
|
399
|
+
|
|
400
|
+
// Check that the main component structure is rendered
|
|
401
|
+
expect(screen.getByText('Shipping & Gift Options')).toBeInTheDocument()
|
|
402
|
+
expect(screen.getByText('Continue to Payment')).toBeInTheDocument()
|
|
403
|
+
})
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
describe('Shipping Promotions', () => {
|
|
407
|
+
test('should display shipping promotions when available', () => {
|
|
408
|
+
const shippingMethodsWithPromotions = {
|
|
409
|
+
...mockShippingMethods,
|
|
410
|
+
applicableShippingMethods: [
|
|
411
|
+
{
|
|
412
|
+
...mockShippingMethods.applicableShippingMethods[0],
|
|
413
|
+
shippingPromotions: [
|
|
414
|
+
{
|
|
415
|
+
promotionId: 'promo-1',
|
|
416
|
+
calloutMsg: 'Free shipping on orders over $50'
|
|
417
|
+
}
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
mockUseShippingMethodsForShipment.mockReturnValue({
|
|
424
|
+
data: shippingMethodsWithPromotions,
|
|
425
|
+
isLoading: false
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
renderWithIntl(<ShippingMethods />)
|
|
429
|
+
|
|
430
|
+
expect(screen.getByText('Free shipping on orders over $50')).toBeInTheDocument()
|
|
431
|
+
})
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
describe('Loading State Transitions', () => {
|
|
435
|
+
test('should transition from loading to loaded state smoothly', async () => {
|
|
436
|
+
// Start with loading state
|
|
437
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
438
|
+
data: null,
|
|
439
|
+
derivedData: {
|
|
440
|
+
totalShippingCost: undefined
|
|
441
|
+
},
|
|
442
|
+
isLoading: true
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
const {rerender} = renderWithIntl(<ShippingMethods />)
|
|
446
|
+
expect(screen.getAllByTestId('loading').length).toBeGreaterThan(0)
|
|
447
|
+
|
|
448
|
+
// Transition to loaded state
|
|
449
|
+
mockUseCurrentBasket.mockReturnValue({
|
|
450
|
+
data: mockBasket,
|
|
451
|
+
derivedData: {
|
|
452
|
+
totalShippingCost: 5.99
|
|
453
|
+
},
|
|
454
|
+
isLoading: false
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
rerender(
|
|
458
|
+
<CurrencyProvider currency="USD">
|
|
459
|
+
<IntlProvider locale="en">
|
|
460
|
+
<ShippingMethods />
|
|
461
|
+
</IntlProvider>
|
|
462
|
+
</CurrencyProvider>
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
await waitFor(() => {
|
|
466
|
+
expect(screen.queryAllByTestId('loading')).toHaveLength(0)
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
expect(screen.getByText('Standard Shipping')).toBeInTheDocument()
|
|
470
|
+
})
|
|
471
|
+
})
|
|
472
|
+
})
|