@salesforce/retail-react-app 9.1.0 → 9.1.1-preview.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.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,7 @@
1
+ ## v9.1.1-preview.0 (Mar 12, 2026)
2
+ - Add base path prefix to support multiple MRT environments under 1 domain [#3614](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3614)
3
+
1
4
  ## v9.1.0 (Mar 12, 2026)
2
- - [Bugfix] Fix edirect payment methods status value to pascal [#3734](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3734)
3
- - [Bugfix] Fix in checkout and cart page: LoadingSpinner to have full screen overlay [#3730](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3730)
4
- - [Bugfix] Fix adding to cart from a master product in the wishlist [#3732](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3732)
5
5
  - Add Page Designer Support [#3727](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3727)
6
6
  - [Feature] Add Salesforce Payments support in checkout [#3725](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3725)
7
7
  - One Click Checkout removed from Developer Preview. When shoppers use passwordless OTP login with one-click checkout, the system saves their shipping and payment information for faster checkout in the future. Security safeguards required: (1) Captcha - Protects the passwordless login from bots. (2) OTP for Email Changes - Verifies identity before an email update, prevents accidental account lockouts from typos, and prevents unauthorized access to saved payment methods.
@@ -12,6 +12,9 @@
12
12
  - [Bugfix] Fix for custom billing address as returning shoppers in 1CC [#3693](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3693)
13
13
  - [Feature] Add translations for text in 1CC [#3703](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3703)
14
14
  - [Bugfix] Fix lost custom billing address after OTP registration [#3741](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3741)
15
+ - [Bugfix] Fix edirect payment methods status value to pascal [#3734](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3734)
16
+ - [Bugfix] Fix in checkout and cart page: LoadingSpinner to have full screen overlay [#3730](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3730)
17
+ - [Bugfix] Fix adding to cart from a master product in the wishlist [#3732](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3732)
15
18
 
16
19
  ## v9.0.0 (Feb 12, 2026)
17
20
  - [Feature] One Click Checkout (in Developer Preview) [#3552](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3552)
@@ -5,23 +5,23 @@
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
 
8
+ import React, {useState, useEffect, useMemo} from 'react'
9
+ import PropTypes from 'prop-types'
10
+ import {useHistory, useLocation} from 'react-router-dom'
11
+ import {StorefrontPreview} from '@salesforce/commerce-sdk-react/components'
12
+ import {getAssetUrl, getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
13
+ import useActiveData from '@salesforce/retail-react-app/app/hooks/use-active-data'
14
+ import {useQuery} from '@tanstack/react-query'
8
15
  import {
9
16
  useAccessToken,
10
17
  useCategory,
11
18
  useShopperBasketsMutation,
12
19
  useUsid
13
20
  } from '@salesforce/commerce-sdk-react'
14
- import {StorefrontPreview} from '@salesforce/commerce-sdk-react/components'
15
- import {getAssetUrl} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
16
21
  import {useServerContext} from '@salesforce/pwa-kit-react-sdk/ssr/universal/hooks'
17
22
  import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
18
- import useActiveData from '@salesforce/retail-react-app/app/hooks/use-active-data'
19
23
  import {useAppOrigin} from '@salesforce/retail-react-app/app/hooks/use-app-origin'
20
24
  import logger from '@salesforce/retail-react-app/app/utils/logger-instance'
21
- import {useQuery} from '@tanstack/react-query'
22
- import PropTypes from 'prop-types'
23
- import React, {useEffect, useMemo, useState} from 'react'
24
- import {useHistory, useLocation} from 'react-router-dom'
25
25
 
26
26
  // Chakra
27
27
  import {SkipNavContent, SkipNavLink} from '@chakra-ui/skip-nav'
@@ -315,9 +315,14 @@ const App = (props) => {
315
315
  trackPage()
316
316
  }, [location])
317
317
 
318
+ const getHrefForLocale = (localeId) =>
319
+ `${appOrigin}${getRouterBasePath()}${getPathWithLocale(localeId, buildUrl, {
320
+ location: {...location, search: ''}
321
+ })}`
322
+
318
323
  return (
319
324
  <Box className="sf-app" {...styles.container}>
320
- <StorefrontPreview getToken={getTokenWhenReady}>
325
+ <StorefrontPreview getToken={getTokenWhenReady} getBasePath={getRouterBasePath}>
321
326
  <IntlProvider
322
327
  onError={(err) => {
323
328
  if (!messages) {
@@ -362,12 +367,7 @@ const App = (props) => {
362
367
  <link
363
368
  rel="alternate"
364
369
  hrefLang={locale.id.toLowerCase()}
365
- href={`${appOrigin}${getPathWithLocale(locale.id, buildUrl, {
366
- location: {
367
- ...location,
368
- search: ''
369
- }
370
- })}`}
370
+ href={getHrefForLocale(locale.id)}
371
371
  key={locale.id}
372
372
  />
373
373
  ))}
@@ -375,12 +375,7 @@ const App = (props) => {
375
375
  <link
376
376
  rel="alternate"
377
377
  hrefLang={site.l10n.defaultLocale.slice(0, 2)}
378
- href={`${appOrigin}${getPathWithLocale(locale.id, buildUrl, {
379
- location: {
380
- ...location,
381
- search: ''
382
- }
383
- })}`}
378
+ href={getHrefForLocale(locale.id)}
384
379
  />
385
380
  {/* A wider fallback for user locales that the app does not support */}
386
381
  <link rel="alternate" hrefLang="x-default" href={`${appOrigin}/`} />
@@ -18,6 +18,7 @@ import {
18
18
  } from '@salesforce/retail-react-app/app/components/shared/ui'
19
19
 
20
20
  import {BrandLogo, FileIcon} from '@salesforce/retail-react-app/app/components/icons'
21
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
21
22
 
22
23
  // <Error> is rendered when:
23
24
  //
@@ -53,7 +54,11 @@ const Error = (props) => {
53
54
  // We need to use window.location.href here rather than history
54
55
  // as the application is in an error state. We need to force a
55
56
  // hard navigation to get back to the normal state.
56
- onClick={() => (window.location.href = '/')}
57
+ // Include base path since this bypasses React Router
58
+ onClick={() => {
59
+ const basePath = getRouterBasePath()
60
+ window.location.href = basePath ? `${basePath}/` : '/'
61
+ }}
57
62
  />
58
63
  </Box>
59
64
  </Box>
@@ -6,11 +6,17 @@
6
6
  */
7
7
  import React from 'react'
8
8
  import Error from '@salesforce/retail-react-app/app/components/_error/index'
9
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
9
10
  // !!! ----- WARNING ----- WARNING ----- WARNING ----- !!!
10
11
  // Tests use render instead of renderWithProviders because
11
12
  // error component is rendered outside provider tree
12
13
  // !!! ----------------------------------------------- !!!
13
14
  import {screen, render} from '@testing-library/react'
15
+
16
+ jest.mock('@salesforce/pwa-kit-react-sdk/ssr/universal/utils', () => ({
17
+ getRouterBasePath: jest.fn(() => '')
18
+ }))
19
+
14
20
  const originalLocation = window.location
15
21
 
16
22
  afterEach(() => {
@@ -68,3 +74,13 @@ test('renders custom error message', () => {
68
74
  render(<Error message="Custom error occurred" />)
69
75
  expect(screen.getByText('Custom error occurred')).toBeInTheDocument()
70
76
  })
77
+
78
+ test('clicking logo navigates to base path when set', () => {
79
+ delete window.location
80
+ window.location = {href: ''}
81
+ getRouterBasePath.mockReturnValueOnce('/my-base')
82
+ render(<Error />)
83
+ const logoBtn = screen.getByLabelText('logo')
84
+ logoBtn.click()
85
+ expect(window.location.href).toBe('/my-base/')
86
+ })
@@ -54,6 +54,7 @@ import {
54
54
  // Others
55
55
  import {noop} from '@salesforce/retail-react-app/app/utils/utils'
56
56
  import {getPathWithLocale, categoryUrlBuilder} from '@salesforce/retail-react-app/app/utils/url'
57
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
57
58
  import LoadingSpinner from '@salesforce/retail-react-app/app/components/loading-spinner'
58
59
 
59
60
  import useNavigation from '@salesforce/retail-react-app/app/hooks/use-navigation'
@@ -317,7 +318,10 @@ const DrawerMenu = ({
317
318
  const newUrl = getPathWithLocale(newLocale, buildUrl, {
318
319
  disallowParams: ['refine']
319
320
  })
320
- window.location = newUrl
321
+ const basePath = getRouterBasePath()
322
+ window.location = basePath
323
+ ? `${basePath}${newUrl}`
324
+ : newUrl
321
325
  }}
322
326
  />
323
327
  </Box>
@@ -22,6 +22,7 @@ import LinksList from '@salesforce/retail-react-app/app/components/links-list'
22
22
  import SubscribeMarketingConsent from '@salesforce/retail-react-app/app/components/subscription'
23
23
  import {HideOnDesktop, HideOnMobile} from '@salesforce/retail-react-app/app/components/responsive'
24
24
  import {getPathWithLocale} from '@salesforce/retail-react-app/app/utils/url'
25
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
25
26
  import LocaleText from '@salesforce/retail-react-app/app/components/locale-text'
26
27
  import useMultiSite from '@salesforce/retail-react-app/app/hooks/use-multi-site'
27
28
  import styled from '@emotion/styled'
@@ -151,8 +152,8 @@ const Footer = ({...otherProps}) => {
151
152
  const newUrl = getPathWithLocale(target.value, buildUrl, {
152
153
  disallowParams: ['refine']
153
154
  })
154
-
155
- window.location = newUrl
155
+ const basePath = getRouterBasePath()
156
+ window.location = basePath ? `${basePath}${newUrl}` : newUrl
156
157
  }}
157
158
  variant="filled"
158
159
  aria-label={intl.formatMessage({
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
9
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
9
10
 
10
11
  /**
11
12
  * This functions takes an url and returns a site object,
@@ -94,6 +95,20 @@ export const getSiteByReference = (siteRef) => {
94
95
  )
95
96
  }
96
97
 
98
+ /**
99
+ * Remove the base path from a path string only when path equals basePath or path starts with basePath + '/'.
100
+ * @param {string} path - the path to strip
101
+ * @param {string} basePath - the base path to remove
102
+ * @returns {string} the path with base path removed, or the original path
103
+ */
104
+ export const removeBasePathFromPath = (path, basePath) => {
105
+ if (!basePath) return path
106
+ if (path.startsWith(basePath + '/') || path === basePath) {
107
+ return path.substring(basePath.length) || '/'
108
+ }
109
+ return path
110
+ }
111
+
97
112
  /**
98
113
  * This function return the identifiers (site and locale) from the given url
99
114
  * The site will always go before locale if both of them are presented in the pathname
@@ -101,7 +116,12 @@ export const getSiteByReference = (siteRef) => {
101
116
  * @returns {{siteRef: string, localeRef: string}} - site and locale reference (it could either be id or alias)
102
117
  */
103
118
  export const getParamsFromPath = (path) => {
104
- const {pathname, search} = getPathnameAndSearch(path)
119
+ let {pathname, search} = getPathnameAndSearch(path)
120
+
121
+ // Remove the base path from the pathname if present since
122
+ // it shifts the location of the site and locale in the pathname
123
+ const basePath = getRouterBasePath()
124
+ pathname = removeBasePathFromPath(pathname, basePath)
105
125
 
106
126
  const config = getConfig()
107
127
  const {pathMatcher, searchMatcherForSite, searchMatcherForLocale} = getConfigMatcher(config)
@@ -11,11 +11,13 @@ import {
11
11
  resolveSiteFromUrl
12
12
  } from '@salesforce/retail-react-app/app/utils/site-utils'
13
13
  import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
14
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
14
15
 
15
16
  import mockConfig from '@salesforce/retail-react-app/config/mocks/default'
16
17
  import {
17
18
  getParamsFromPath,
18
19
  resolveLocaleFromUrl,
20
+ removeBasePathFromPath,
19
21
  resolvePageDesignerParamsFromUrl
20
22
  } from '@salesforce/retail-react-app/app/utils/site-utils'
21
23
  jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => {
@@ -26,8 +28,18 @@ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => {
26
28
  }
27
29
  })
28
30
 
31
+ jest.mock('@salesforce/pwa-kit-react-sdk/ssr/universal/utils', () => {
32
+ const original = jest.requireActual('@salesforce/pwa-kit-react-sdk/ssr/universal/utils')
33
+ return {
34
+ ...original,
35
+ getRouterBasePath: jest.fn(() => '')
36
+ }
37
+ })
38
+
29
39
  beforeEach(() => {
30
40
  jest.resetModules()
41
+ // Reset the mock after resetModules
42
+ getRouterBasePath.mockReturnValue('')
31
43
  })
32
44
 
33
45
  afterEach(() => {
@@ -311,6 +323,64 @@ describe('getParamsFromPath', function () {
311
323
  expect(getParamsFromPath(path)).toEqual(expectedRes)
312
324
  })
313
325
  })
326
+
327
+ describe('getParamsFromPath with base path', () => {
328
+ test('should remove base path from path when showBasePath is true', () => {
329
+ const basePath = '/test-base'
330
+ getRouterBasePath.mockReturnValue(basePath)
331
+ getConfig.mockImplementation(() => ({
332
+ ...mockConfig,
333
+ app: {
334
+ ...mockConfig.app,
335
+ url: {
336
+ ...mockConfig.app.url,
337
+ showBasePath: true
338
+ }
339
+ }
340
+ }))
341
+
342
+ const path = `${basePath}/us/en-US/category/womens`
343
+ const result = getParamsFromPath(path)
344
+ expect(result).toEqual({siteRef: 'us', localeRef: 'en-US'})
345
+ })
346
+
347
+ test('should not strip when path has basePath only as substring (e.g. /shop vs /shopping/cart)', () => {
348
+ const basePath = '/shop'
349
+ getRouterBasePath.mockReturnValue(basePath)
350
+ getConfig.mockImplementation(() => ({
351
+ ...mockConfig,
352
+ app: {
353
+ ...mockConfig.app,
354
+ url: {
355
+ ...mockConfig.app.url,
356
+ showBasePath: true
357
+ }
358
+ }
359
+ }))
360
+
361
+ const result = getParamsFromPath('/shopping/cart')
362
+ expect(result).toBeDefined()
363
+ })
364
+ })
365
+ })
366
+
367
+ describe('removeBasePathFromPath', () => {
368
+ test('removes when path starts with basePath + "/"', () => {
369
+ expect(removeBasePathFromPath('/shop/cart', '/shop')).toBe('/cart')
370
+ expect(removeBasePathFromPath('/test-base/uk/en-GB/foo', '/test-base')).toBe(
371
+ '/uk/en-GB/foo'
372
+ )
373
+ })
374
+ test('removes to "/" when path exactly equals basePath', () => {
375
+ expect(removeBasePathFromPath('/shop', '/shop')).toBe('/')
376
+ })
377
+ test('does not remove when basePath is only a substring (e.g. /shop vs /shopping/cart)', () => {
378
+ expect(removeBasePathFromPath('/shopping/cart', '/shop')).toBe('/shopping/cart')
379
+ expect(removeBasePathFromPath('/shopping', '/shop')).toBe('/shopping')
380
+ })
381
+ test('returns path unchanged when basePath is empty', () => {
382
+ expect(removeBasePathFromPath('/any/path', '')).toBe('/any/path')
383
+ })
314
384
  })
315
385
 
316
386
  describe('resolveLocaleFromUrl', function () {
package/app/utils/url.js CHANGED
@@ -9,9 +9,11 @@ import {
9
9
  getLocaleByReference,
10
10
  getParamsFromPath,
11
11
  getDefaultSite,
12
- getSiteByReference
12
+ getSiteByReference,
13
+ removeBasePathFromPath
13
14
  } from '@salesforce/retail-react-app/app/utils/site-utils'
14
15
  import {HOME_HREF, urlPartPositions} from '@salesforce/retail-react-app/app/constants'
16
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
15
17
 
16
18
  /**
17
19
  * Modifies a given url by adding/updating query parameters.
@@ -105,19 +107,23 @@ export const searchUrlBuilder = (searchTerm) => '/search?q=' + encodeURIComponen
105
107
 
106
108
  /**
107
109
  * Returns a relative URL for a locale short code.
108
- * Based on your app configuration, this function will replace your current locale shortCode with a new one
110
+ * Based on your app configuration, this function will replace your current locale shortCode with a new one.
109
111
  *
110
112
  * @param {String} shortCode - The locale short code.
111
113
  * @param {function(*, *, *, *=): string} - Generates a site URL from the provided path, site and locale.
112
114
  * @param {string[]} opts.disallowParams - URL parameters to remove
113
115
  * @param {Object} opts.location - location object to replace the default `window.location`
114
- * @returns {String} url - The relative URL for the specific locale.
116
+ * @returns {String} url - The relative URL for the specific locale (without base path).
115
117
  */
116
118
  export const getPathWithLocale = (shortCode, buildUrl, opts = {}) => {
117
119
  const location = opts.location ? opts.location : window.location
118
120
  let {siteRef, localeRef} = getParamsFromPath(`${location.pathname}${location.search}`)
119
121
  let {pathname, search} = location
120
122
 
123
+ // sanitize the base path from current url if existing
124
+ const basePath = getRouterBasePath()
125
+ pathname = removeBasePathFromPath(pathname, basePath)
126
+
121
127
  // sanitize the site from current url if existing
122
128
  if (siteRef) {
123
129
  pathname = pathname.replace(`/${siteRef}`, '')
@@ -153,6 +159,7 @@ export const getPathWithLocale = (shortCode, buildUrl, opts = {}) => {
153
159
  site.alias || site.id,
154
160
  locale?.alias || locale?.id
155
161
  )
162
+
156
163
  return newUrl
157
164
  }
158
165
 
@@ -210,6 +217,7 @@ export const createUrlTemplate = (appConfig, siteRef, localeRef) => {
210
217
  queryLocale && locale && searchParams.append('locale', locale)
211
218
  queryString = `?${searchParams.toString()}`
212
219
  }
220
+
213
221
  return `${sitePath}${localePath}${path}${queryString}`
214
222
  }
215
223
  }
@@ -259,6 +267,9 @@ export const removeQueryParamsFromPath = (path, keys) => {
259
267
  export const removeSiteLocaleFromPath = (pathName = '') => {
260
268
  let {siteRef, localeRef} = getParamsFromPath(pathName)
261
269
 
270
+ const basePath = getRouterBasePath()
271
+ pathName = removeBasePathFromPath(pathName, basePath)
272
+
262
273
  // remove the site alias from the current pathName
263
274
  if (siteRef) {
264
275
  pathName = pathName.replace(new RegExp(`/${siteRef}`, 'g'), '')
@@ -17,27 +17,20 @@ import {
17
17
  removeSiteLocaleFromPath,
18
18
  serverSafeEncode
19
19
  } from '@salesforce/retail-react-app/app/utils/url'
20
- import {getUrlConfig} from '@salesforce/retail-react-app/app/utils/site-utils'
21
20
  import mockConfig from '@salesforce/retail-react-app/config/mocks/default'
21
+ import {getRouterBasePath} from '@salesforce/pwa-kit-react-sdk/ssr/universal/utils'
22
+ import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
22
23
 
23
24
  afterEach(() => {
24
25
  jest.clearAllMocks()
25
26
  })
26
27
 
27
- jest.mock('./utils', () => {
28
- const original = jest.requireActual('./utils')
29
- return {
30
- ...original,
31
- getConfig: jest.fn(() => mockConfig)
32
- }
33
- })
28
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => ({
29
+ getConfig: jest.fn()
30
+ }))
34
31
 
35
- jest.mock('./site-utils', () => {
36
- const original = jest.requireActual('./site-utils')
37
- return {
38
- ...original,
39
- getUrlConfig: jest.fn()
40
- }
32
+ beforeEach(() => {
33
+ getConfig.mockReturnValue(mockConfig)
41
34
  })
42
35
  jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths', () => {
43
36
  const original = jest.requireActual('@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths')
@@ -47,6 +40,14 @@ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths', () => {
47
40
  }
48
41
  })
49
42
 
43
+ jest.mock('@salesforce/pwa-kit-react-sdk/ssr/universal/utils', () => {
44
+ const original = jest.requireActual('@salesforce/pwa-kit-react-sdk/ssr/universal/utils')
45
+ return {
46
+ ...original,
47
+ getRouterBasePath: jest.fn(() => '')
48
+ }
49
+ })
50
+
50
51
  describe('buildUrlSet returns the expected set of urls', () => {
51
52
  test('when no values are passed in', () => {
52
53
  const set = buildUrlSet()
@@ -138,8 +139,6 @@ describe('url builder test', () => {
138
139
  })
139
140
 
140
141
  describe('getPathWithLocale', () => {
141
- getUrlConfig.mockImplementation(() => mockConfig.app.url)
142
-
143
142
  test('getPathWithLocale returns expected for PLP', () => {
144
143
  const location = new URL('http://localhost:3000/uk/it-IT/category/newarrivals-womens')
145
144
  const buildUrl = createUrlTemplate(mockConfig.app, 'uk', 'it-IT')
@@ -186,6 +185,34 @@ describe('getPathWithLocale', () => {
186
185
  const relativeUrl = getPathWithLocale('en-GB', buildUrl, {location})
187
186
  expect(relativeUrl).toBe(`/`)
188
187
  })
188
+
189
+ test('getPathWithLocale returns path without base path if base path is present', () => {
190
+ const basePath = '/test-base'
191
+ getRouterBasePath.mockReturnValue(basePath)
192
+
193
+ const location = new URL(
194
+ `http://localhost:3000${basePath}/uk/it-IT/category/newarrivals-womens`
195
+ )
196
+ const buildUrl = createUrlTemplate(mockConfig.app, 'uk', 'it-IT')
197
+
198
+ const path = getPathWithLocale('fr-FR', buildUrl, {location})
199
+ expect(path).toBe('/uk/fr/category/newarrivals-womens')
200
+ expect(path).not.toContain(basePath)
201
+ // Caller uses basePath + path for window.location or full href
202
+ expect(`${basePath}${path}`).toBe(`${basePath}/uk/fr/category/newarrivals-womens`)
203
+ })
204
+
205
+ test('getPathWithLocale does not strip when path has basePath only as substring (e.g. /shop vs /shopping/cart)', () => {
206
+ const basePath = '/shop'
207
+ getRouterBasePath.mockReturnValue(basePath)
208
+
209
+ const location = new URL('http://localhost:3000/shopping/cart')
210
+ const buildUrl = createUrlTemplate(mockConfig.app, 'uk', 'en-GB')
211
+
212
+ const path = getPathWithLocale('en-GB', buildUrl, {location})
213
+ expect(path).toContain('/shopping')
214
+ expect(path).not.toBe('/cart')
215
+ })
189
216
  })
190
217
 
191
218
  describe('createUrlTemplate tests', () => {
package/config/default.js CHANGED
@@ -27,6 +27,7 @@ module.exports = {
27
27
  site: 'path',
28
28
  locale: 'path',
29
29
  showDefaults: true,
30
+ showBasePath: false,
30
31
  interpretPlusSignAsSpace: false
31
32
  },
32
33
  login: {
@@ -106,7 +107,6 @@ module.exports = {
106
107
  apiKey: process.env.GOOGLE_CLOUD_API_KEY
107
108
  }
108
109
  },
109
- envBasePath: '/',
110
110
  externals: [],
111
111
  pageNotFoundURL: '/page-not-found',
112
112
  ssrEnabled: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/retail-react-app",
3
- "version": "9.1.0",
3
+ "version": "9.1.1-preview.0",
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": "5.1.0",
50
- "@salesforce/pwa-kit-dev": "3.17.0",
51
- "@salesforce/pwa-kit-react-sdk": "3.17.0",
52
- "@salesforce/pwa-kit-runtime": "3.17.0",
49
+ "@salesforce/commerce-sdk-react": "5.1.1-preview.0",
50
+ "@salesforce/pwa-kit-dev": "3.17.1-preview.0",
51
+ "@salesforce/pwa-kit-react-sdk": "3.17.1-preview.0",
52
+ "@salesforce/pwa-kit-runtime": "3.17.1-preview.0",
53
53
  "@salesforce/storefront-next-runtime": "0.1.1",
54
54
  "@tanstack/react-query": "^4.28.0",
55
55
  "@tanstack/react-query-devtools": "^4.29.1",
@@ -113,5 +113,5 @@
113
113
  "maxSize": "391 kB"
114
114
  }
115
115
  ],
116
- "gitHead": "6d0cfd2308b9f25d8badd722469074889bd3b891"
116
+ "gitHead": "beabe8a971b6170bddfe08ae3f5ca2f1bfe66aa7"
117
117
  }