@faststore/core 4.7.0-dev.8 → 4.7.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/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +99 -100
- package/@generated/gql.ts +3 -3
- package/@generated/graphql.ts +10 -2
- package/@generated/persisted-documents.json +1 -1
- package/@generated/schema.graphql +8 -0
- package/CHANGELOG.md +10 -0
- package/package.json +6 -6
- package/src/components/ui/LocalizationButton/LocalizationButton.tsx +5 -3
- package/src/pages/[slug]/p.tsx +6 -1
- package/src/sdk/localization/LocalizedProductContext.tsx +14 -2
- package/src/sdk/localization/bindingSelector.ts +38 -0
- package/src/sdk/localization/useBindingSelector.ts +17 -22
- package/test/components/ui/LocalizationButton.browser.test.tsx +87 -0
- package/test/sdk/localization/useBindingSelector.browser.test.tsx +252 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.7.0-dev.
|
|
2
|
+
> @faststore/core@4.7.0-dev.9 generate /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> pnpm run gen-types && pnpm run cache-graphql
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@4.7.0-dev.
|
|
6
|
+
> @faststore/core@4.7.0-dev.9 gen-types /home/runner/work/faststore/faststore/packages/core
|
|
7
7
|
> node ../cli/bin/run generate-types .
|
|
8
8
|
|
|
9
9
|
[33m[STARTED][39m Parse Configuration
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
[32m[COMPLETED][39m Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
|
|
20
20
|
[32m[COMPLETED][39m Generate outputs
|
|
21
21
|
|
|
22
|
-
> @faststore/core@4.7.0-dev.
|
|
22
|
+
> @faststore/core@4.7.0-dev.9 cache-graphql /home/runner/work/faststore/faststore/packages/core
|
|
23
23
|
> node ../cli/bin/run cache-graphql --config=./discovery.config.default.js --queries=./@generated/persisted-documents.json
|
|
24
24
|
|
|
25
25
|
[Info] - Config file location: /home/runner/work/faststore/faststore/packages/core/discovery.config.default.js
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.7.0-dev.
|
|
2
|
+
> @faststore/core@4.7.0-dev.9 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
@@ -7,19 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
Not implemented: navigation to another Document
|
|
9
9
|
Not implemented: navigation to another Document
|
|
10
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 764[2mms[22m[39m
|
|
10
11
|
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
11
12
|
npx update-browserslist-db@latest
|
|
12
13
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
13
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
21
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
|
22
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 226[2mms[22m[39m
|
|
14
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/cards/MyAccountListCards.browser.test.tsx [2m([22m[2m14 tests[22m[2m)[22m[33m 1570[2mms[22m[39m
|
|
15
|
+
[33m[2m✓[22m[39m shows the tab bar and renders Personal cards by default [33m 794[2mms[22m[39m
|
|
16
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 2032[2mms[22m[39m
|
|
17
|
+
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m 520[2mms[22m[39m
|
|
18
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/useBindingSelector.browser.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[32m 126[2mms[22m[39m
|
|
19
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 16[2mms[22m[39m
|
|
20
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 172[2mms[22m[39m
|
|
21
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 107[2mms[22m[39m
|
|
23
22
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
|
|
24
23
|
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
|
|
25
24
|
[90m at node:internal/deps/undici/undici:16416:13[39m
|
|
@@ -49,7 +48,9 @@ Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
|
49
48
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
50
49
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
51
50
|
|
|
52
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
51
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m7 tests[22m[2m)[22m[32m 118[2mms[22m[39m
|
|
52
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 654[2mms[22m[39m
|
|
53
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 420[2mms[22m[39m
|
|
53
54
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
54
55
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
55
56
|
|
|
@@ -135,7 +136,6 @@ act(() => {
|
|
|
135
136
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
136
137
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
137
138
|
|
|
138
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
139
139
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2muses the fallback invalid-password message when API omits an error
|
|
140
140
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
141
141
|
|
|
@@ -280,11 +280,9 @@ act(() => {
|
|
|
280
280
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
281
281
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
282
282
|
|
|
283
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
284
|
-
|
|
285
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
286
|
-
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 715[2mms[22m[39m
|
|
287
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
283
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 774[2mms[22m[39m
|
|
284
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
285
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
288
286
|
[90mstderr[2m | test/sdk/localization/store-url.browser.test.ts
|
|
289
287
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
290
288
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -293,6 +291,7 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
293
291
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
294
292
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
295
293
|
|
|
294
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
296
295
|
[90mstderr[2m | test/components/cms/RenderSections.browser.test.tsx
|
|
297
296
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
298
297
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -301,12 +300,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
301
300
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
302
301
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
303
302
|
|
|
304
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/
|
|
305
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
306
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
307
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
308
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/
|
|
309
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 60[2mms[22m[39m
|
|
303
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
304
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/cms/RenderSections.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 64[2mms[22m[39m
|
|
305
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
306
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.sessionFallback.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 124[2mms[22m[39m
|
|
307
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
|
310
308
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
311
309
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
312
310
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -315,10 +313,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
315
313
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
316
314
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
317
315
|
|
|
318
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
319
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
320
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
321
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/
|
|
316
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
317
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/LocalizationButton.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
318
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListCards.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 71[2mms[22m[39m
|
|
319
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 267[2mms[22m[39m
|
|
320
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 191[2mms[22m[39m
|
|
322
321
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
323
322
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
324
323
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -328,11 +327,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
328
327
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
329
328
|
|
|
330
329
|
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
331
|
-
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
332
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
333
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m
|
|
334
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
335
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m
|
|
330
|
+
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
331
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 2[2mms[22m[39m
|
|
332
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
333
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
334
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
|
336
335
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
337
336
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
338
337
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -341,11 +340,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
341
340
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
342
341
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
343
342
|
|
|
344
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
345
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
346
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
347
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
348
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m
|
|
343
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
344
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
345
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
346
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 125[2mms[22m[39m
|
|
347
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
349
348
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
350
349
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
351
350
|
|
|
@@ -409,19 +408,19 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
409
408
|
at Suspense
|
|
410
409
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
411
410
|
|
|
412
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
413
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
414
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
411
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 65[2mms[22m[39m
|
|
412
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
413
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
415
414
|
[90mstderr[2m | test/pages/pvt/account/cards/index.test.ts[2m > [22m[2mCards page getServerSideProps[2m > [22m[2mredirects to /pvt/account/403 when the query fails with 401/403
|
|
416
415
|
[22m[39m{ extensions: { status: [33m401[39m } }
|
|
417
416
|
|
|
418
417
|
[90mstderr[2m | test/pages/pvt/account/cards/index.test.ts[2m > [22m[2mCards page getServerSideProps[2m > [22m[2mrenders the error state (no redirect) when the query fails with a non-auth status
|
|
419
418
|
[22m[39m{ extensions: { status: [33m502[39m } }
|
|
420
419
|
|
|
421
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
422
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m
|
|
423
|
-
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
424
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[
|
|
420
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
421
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
422
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
423
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 231[2mms[22m[39m
|
|
425
424
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql error status propagation[2m > [22m[2mpropagates the upstream 400 from a wrapped BadRequestError instead of 500
|
|
426
425
|
[22m[39mGraphql execution returned with error: [
|
|
427
426
|
{
|
|
@@ -470,7 +469,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
470
469
|
|
|
471
470
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql request handling[2m > [22m[2mmaps BadRequestError thrown by execute to its status
|
|
472
471
|
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
473
|
-
|
|
472
|
+
T [FastStoreError]: malformed
|
|
474
473
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:190:31
|
|
475
474
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
476
475
|
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1024:60
|
|
@@ -514,66 +513,66 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
514
513
|
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:37
|
|
515
514
|
at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/traces.CCmnQaNT.js:142:27)
|
|
516
515
|
|
|
517
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m
|
|
518
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 836[2mms[22m[39m
|
|
519
|
-
[33m[2m✓[22m[39m navigates with the search term on blur [33m 364[2mms[22m[39m
|
|
520
|
-
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 361[2mms[22m[39m
|
|
516
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m 16[2mms[22m[39m
|
|
521
517
|
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
522
518
|
[22m[39mSet password request failed: Bad Request
|
|
523
519
|
|
|
524
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
525
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m
|
|
526
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
527
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
528
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
532
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
533
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
534
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
535
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
536
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
537
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
538
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
539
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
540
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
541
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
542
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
543
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
544
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
545
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
546
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
547
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
548
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
549
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
550
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
551
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
552
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
553
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
554
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
555
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
556
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
557
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
520
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
521
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
522
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
523
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
524
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 792[2mms[22m[39m
|
|
525
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 361[2mms[22m[39m
|
|
526
|
+
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 357[2mms[22m[39m
|
|
527
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
528
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
529
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
530
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/redirects/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
531
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 102[2mms[22m[39m
|
|
532
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLd.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
533
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
|
534
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
535
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 699[2mms[22m[39m
|
|
536
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/syncSalesChannelFromOrderForm.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
537
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 77[2mms[22m[39m
|
|
538
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/useStartRecommendationSession.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
539
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
540
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
541
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
542
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/cart/waitForSessionValidated.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
543
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
544
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLdRendering.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
545
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
546
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/content/service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
547
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/global.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
548
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
549
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
550
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 100[2mms[22m[39m
|
|
551
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
552
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
553
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
554
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInput.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
555
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 60[2mms[22m[39m
|
|
556
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
558
557
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
559
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
558
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
560
559
|
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
561
560
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getB2BSessionClaims.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
562
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m
|
|
563
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
564
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
565
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
566
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
567
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
561
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
562
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
563
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 182[2mms[22m[39m
|
|
564
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
565
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
566
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 2[2mms[22m[39m
|
|
568
567
|
[32m✓[39m [30m[43m node [49m[39m test/utils/getCookie.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
568
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
569
569
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
570
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
571
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
572
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
[2m
|
|
576
|
-
[2m
|
|
577
|
-
[2m
|
|
578
|
-
[2m Duration [22m 45.26s[2m (transform 14.82s, setup 0ms, import 41.48s, tests 15.63s, environment 54.18s)[22m
|
|
570
|
+
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
571
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
572
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
573
|
+
|
|
574
|
+
[2m Test Files [22m [1m[32m93 passed[39m[22m[90m (93)[39m
|
|
575
|
+
[2m Tests [22m [1m[32m742 passed[39m[22m[90m (742)[39m
|
|
576
|
+
[2m Start at [22m 21:20:36
|
|
577
|
+
[2m Duration [22m 29.99s[2m (transform 8.81s, setup 0ms, import 26.73s, tests 10.47s, environment 36.18s)[22m
|
|
579
578
|
|
package/@generated/gql.ts
CHANGED
|
@@ -30,7 +30,7 @@ type Documents = {
|
|
|
30
30
|
"\n fragment ServerProduct on Query {\n product(locator: $locator) {\n id: productID\n }\n }\n": typeof types.ServerProductFragmentDoc,
|
|
31
31
|
"\n query ServerAccountPageQuery {\n accountProfile {\n name\n }\n }\n": typeof types.ServerAccountPageQueryDocument,
|
|
32
32
|
"\n query ServerCollectionPageQuery($slug: String!) {\n ...ServerCollectionPage\n collection(slug: $slug) {\n seo {\n title\n description\n }\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n meta {\n selectedFacets {\n key\n value\n }\n }\n otherLocales {\n locale\n slug\n }\n }\n }\n": typeof types.ServerCollectionPageQueryDocument,
|
|
33
|
-
"\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n ...ProductDetailsFragment_product\n }\n }\n": typeof types.ServerProductQueryDocument,
|
|
33
|
+
"\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n defaultLocaleSlug\n\n ...ProductDetailsFragment_product\n }\n }\n": typeof types.ServerProductQueryDocument,
|
|
34
34
|
"\n query ServerListCardsQuery {\n listCreditCards {\n list {\n accountId\n bin\n cardNumber\n cardLabel\n paymentSystem\n paymentSystemName\n isDefault\n isActive\n origin\n }\n }\n accountProfile {\n name\n }\n hasAdHocCardAccess\n }\n": typeof types.ServerListCardsQueryDocument,
|
|
35
35
|
"\n fragment UserOrderItemsFragment on UserOrderItems {\n id\n name\n quantity\n sellingPrice\n unitMultiplier\n measurementUnit\n imageUrl\n detailUrl\n refId\n rewardValue\n }\n": typeof types.UserOrderItemsFragmentFragmentDoc,
|
|
36
36
|
"\n query ServerOrderDetailsQuery($orderId: String!) {\n userOrder(orderId: $orderId) {\n orderId\n creationDate\n status\n canProcessOrderAuthorization\n statusDescription\n allowCancellation\n ruleForAuthorization {\n orderAuthorizationId\n dimensionId\n rule {\n id\n name\n status\n doId\n authorizedEmails\n priority\n trigger {\n condition {\n conditionType\n description\n lessThan\n greatherThan\n expression\n }\n effect {\n description\n effectType\n funcPath\n }\n }\n timeout\n notification\n scoreInterval {\n accept\n deny\n }\n authorizationData {\n requireAllApprovals\n authorizers {\n id\n email\n type\n authorizationDate\n }\n }\n isUserAuthorized\n isUserNextAuthorizer\n }\n }\n storePreferencesData {\n currencyCode\n }\n clientProfileData {\n firstName\n lastName\n email\n phone\n corporateName\n isCorporate\n }\n customFields {\n type\n id\n fields {\n name\n value\n refId\n }\n }\n deliveryOptionsData {\n deliveryOptions {\n selectedSla\n deliveryChannel\n deliveryCompany\n deliveryWindow {\n startDateUtc\n endDateUtc\n price\n }\n shippingEstimate\n shippingEstimateDate\n friendlyShippingEstimate\n friendlyDeliveryOptionName\n seller\n address {\n addressType\n receiverName\n addressId\n versionId\n entityId\n postalCode\n city\n state\n country\n street\n number\n neighborhood\n complement\n reference\n geoCoordinates\n }\n pickupStoreInfo {\n additionalInfo\n address {\n addressType\n receiverName\n addressId\n versionId\n entityId\n postalCode\n city\n state\n country\n street\n number\n neighborhood\n complement\n reference\n geoCoordinates\n }\n dockId\n friendlyName\n isPickupStore\n }\n quantityOfDifferentItems\n total\n items {\n id\n uniqueId\n name\n quantity\n price\n sellingPrice\n imageUrl\n tax\n taxPriceTagsTotal\n total\n }\n }\n contact {\n email\n phone\n name\n }\n }\n paymentData {\n transactions {\n isActive\n payments {\n id\n paymentSystemName\n value\n installments\n referenceValue\n lastDigits\n url\n group\n tid\n connectorResponses {\n authId\n }\n bankIssuedInvoiceIdentificationNumber\n redemptionCode\n paymentOrigin\n }\n }\n }\n totals {\n id\n name\n value\n }\n shopper {\n firstName\n lastName\n email\n phone\n }\n budgetData {\n budgets {\n id\n name\n balance {\n remaining\n }\n allocations {\n id\n linkedEntity {\n id\n }\n reservations\n }\n }\n }\n }\n accountProfile {\n name\n }\n }\n": typeof types.ServerOrderDetailsQueryDocument,
|
|
@@ -83,7 +83,7 @@ const documents: Documents = {
|
|
|
83
83
|
"\n fragment ServerProduct on Query {\n product(locator: $locator) {\n id: productID\n }\n }\n": types.ServerProductFragmentDoc,
|
|
84
84
|
"\n query ServerAccountPageQuery {\n accountProfile {\n name\n }\n }\n": types.ServerAccountPageQueryDocument,
|
|
85
85
|
"\n query ServerCollectionPageQuery($slug: String!) {\n ...ServerCollectionPage\n collection(slug: $slug) {\n seo {\n title\n description\n }\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n meta {\n selectedFacets {\n key\n value\n }\n }\n otherLocales {\n locale\n slug\n }\n }\n }\n": types.ServerCollectionPageQueryDocument,
|
|
86
|
-
"\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n ...ProductDetailsFragment_product\n }\n }\n": types.ServerProductQueryDocument,
|
|
86
|
+
"\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n defaultLocaleSlug\n\n ...ProductDetailsFragment_product\n }\n }\n": types.ServerProductQueryDocument,
|
|
87
87
|
"\n query ServerListCardsQuery {\n listCreditCards {\n list {\n accountId\n bin\n cardNumber\n cardLabel\n paymentSystem\n paymentSystemName\n isDefault\n isActive\n origin\n }\n }\n accountProfile {\n name\n }\n hasAdHocCardAccess\n }\n": types.ServerListCardsQueryDocument,
|
|
88
88
|
"\n fragment UserOrderItemsFragment on UserOrderItems {\n id\n name\n quantity\n sellingPrice\n unitMultiplier\n measurementUnit\n imageUrl\n detailUrl\n refId\n rewardValue\n }\n": types.UserOrderItemsFragmentFragmentDoc,
|
|
89
89
|
"\n query ServerOrderDetailsQuery($orderId: String!) {\n userOrder(orderId: $orderId) {\n orderId\n creationDate\n status\n canProcessOrderAuthorization\n statusDescription\n allowCancellation\n ruleForAuthorization {\n orderAuthorizationId\n dimensionId\n rule {\n id\n name\n status\n doId\n authorizedEmails\n priority\n trigger {\n condition {\n conditionType\n description\n lessThan\n greatherThan\n expression\n }\n effect {\n description\n effectType\n funcPath\n }\n }\n timeout\n notification\n scoreInterval {\n accept\n deny\n }\n authorizationData {\n requireAllApprovals\n authorizers {\n id\n email\n type\n authorizationDate\n }\n }\n isUserAuthorized\n isUserNextAuthorizer\n }\n }\n storePreferencesData {\n currencyCode\n }\n clientProfileData {\n firstName\n lastName\n email\n phone\n corporateName\n isCorporate\n }\n customFields {\n type\n id\n fields {\n name\n value\n refId\n }\n }\n deliveryOptionsData {\n deliveryOptions {\n selectedSla\n deliveryChannel\n deliveryCompany\n deliveryWindow {\n startDateUtc\n endDateUtc\n price\n }\n shippingEstimate\n shippingEstimateDate\n friendlyShippingEstimate\n friendlyDeliveryOptionName\n seller\n address {\n addressType\n receiverName\n addressId\n versionId\n entityId\n postalCode\n city\n state\n country\n street\n number\n neighborhood\n complement\n reference\n geoCoordinates\n }\n pickupStoreInfo {\n additionalInfo\n address {\n addressType\n receiverName\n addressId\n versionId\n entityId\n postalCode\n city\n state\n country\n street\n number\n neighborhood\n complement\n reference\n geoCoordinates\n }\n dockId\n friendlyName\n isPickupStore\n }\n quantityOfDifferentItems\n total\n items {\n id\n uniqueId\n name\n quantity\n price\n sellingPrice\n imageUrl\n tax\n taxPriceTagsTotal\n total\n }\n }\n contact {\n email\n phone\n name\n }\n }\n paymentData {\n transactions {\n isActive\n payments {\n id\n paymentSystemName\n value\n installments\n referenceValue\n lastDigits\n url\n group\n tid\n connectorResponses {\n authId\n }\n bankIssuedInvoiceIdentificationNumber\n redemptionCode\n paymentOrigin\n }\n }\n }\n totals {\n id\n name\n value\n }\n shopper {\n firstName\n lastName\n email\n phone\n }\n budgetData {\n budgets {\n id\n name\n balance {\n remaining\n }\n allocations {\n id\n linkedEntity {\n id\n }\n reservations\n }\n }\n }\n }\n accountProfile {\n name\n }\n }\n": types.ServerOrderDetailsQueryDocument,
|
|
@@ -184,7 +184,7 @@ export function gql(source: "\n query ServerCollectionPageQuery($slug: String!)
|
|
|
184
184
|
/**
|
|
185
185
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
186
186
|
*/
|
|
187
|
-
export function gql(source: "\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n ...ProductDetailsFragment_product\n }\n }\n"): typeof import('./graphql').ServerProductQueryDocument;
|
|
187
|
+
export function gql(source: "\n query ServerProductQuery($locator: [IStoreSelectedFacet!]!) {\n ...ServerProduct\n product(locator: $locator) {\n id: productID\n\n seo {\n title\n description\n canonical\n }\n\n brand {\n name\n }\n\n sku\n gtin\n mpn\n name\n description\n releaseDate\n\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n\n image {\n url\n alternateName\n }\n\n offers {\n lowPrice\n highPrice\n lowPriceWithTaxes\n priceCurrency\n offers {\n availability\n price\n priceValidUntil\n priceCurrency\n itemCondition\n priceToken\n seller {\n identifier\n }\n }\n }\n\n isVariantOf {\n productGroupID\n }\n\n otherLocales {\n locale\n slug\n }\n\n defaultLocaleSlug\n\n ...ProductDetailsFragment_product\n }\n }\n"): typeof import('./graphql').ServerProductQueryDocument;
|
|
188
188
|
/**
|
|
189
189
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
190
190
|
*/
|
package/@generated/graphql.ts
CHANGED
|
@@ -1681,6 +1681,14 @@ export type StoreProduct = {
|
|
|
1681
1681
|
brand: StoreBrand;
|
|
1682
1682
|
/** List of items consisting of chain linked web pages, ending with the current page. */
|
|
1683
1683
|
breadcrumbList: StoreBreadcrumbList;
|
|
1684
|
+
/**
|
|
1685
|
+
* Slug for the store's default locale, including the SKU ID suffix.
|
|
1686
|
+
* Navigation fallback for the locale selector when the target locale is absent
|
|
1687
|
+
* from `otherLocales`. Best-effort: it may point at a slug the catalog has not
|
|
1688
|
+
* registered for the default locale, so it must never be used to build hreflang
|
|
1689
|
+
* annotations. Only populated when localization is enabled.
|
|
1690
|
+
*/
|
|
1691
|
+
defaultLocaleSlug: Maybe<Scalars['String']['output']>;
|
|
1684
1692
|
/** Delivery Promise product's badge. */
|
|
1685
1693
|
deliveryPromiseBadges: Maybe<Array<Maybe<DeliveryPromiseBadge>>>;
|
|
1686
1694
|
/** Product description. */
|
|
@@ -2819,7 +2827,7 @@ export type ServerProductQueryQueryVariables = Exact<{
|
|
|
2819
2827
|
}>;
|
|
2820
2828
|
|
|
2821
2829
|
|
|
2822
|
-
export type ServerProductQueryQuery = { product: { sku: string, gtin: string, mpn: string, name: string, description: string, releaseDate: string, unitMultiplier: number | null, id: string, seo: { title: string, description: string, canonical: string }, brand: { name: string }, breadcrumbList: { itemListElement: Array<{ item: string, name: string, position: number }> }, image: Array<{ url: string, alternateName: string }>, offers: { lowPrice: number, highPrice: number, lowPriceWithTaxes: number, priceCurrency: string, offers: Array<{ availability: string, price: number, priceValidUntil: string, priceCurrency: string, itemCondition: string, priceToken: string | null, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, quantity: number, seller: { identifier: string } }> }, isVariantOf: { name: string, productGroupID: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, otherLocales: Array<{ locale: string, slug: string }> | null, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } };
|
|
2830
|
+
export type ServerProductQueryQuery = { product: { sku: string, gtin: string, mpn: string, name: string, description: string, releaseDate: string, defaultLocaleSlug: string | null, unitMultiplier: number | null, id: string, seo: { title: string, description: string, canonical: string }, brand: { name: string }, breadcrumbList: { itemListElement: Array<{ item: string, name: string, position: number }> }, image: Array<{ url: string, alternateName: string }>, offers: { lowPrice: number, highPrice: number, lowPriceWithTaxes: number, priceCurrency: string, offers: Array<{ availability: string, price: number, priceValidUntil: string, priceCurrency: string, itemCondition: string, priceToken: string | null, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, quantity: number, seller: { identifier: string } }> }, isVariantOf: { name: string, productGroupID: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, otherLocales: Array<{ locale: string, slug: string }> | null, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } };
|
|
2823
2831
|
|
|
2824
2832
|
export type ServerListCardsQueryQueryVariables = Exact<{ [key: string]: never; }>;
|
|
2825
2833
|
|
|
@@ -3617,7 +3625,7 @@ export const SearchEvent_MetadataFragmentDoc = new TypedDocumentString(`
|
|
|
3617
3625
|
`, {"fragmentName":"SearchEvent_metadata"}) as unknown as TypedDocumentString<SearchEvent_MetadataFragment, unknown>;
|
|
3618
3626
|
export const ServerAccountPageQueryDocument = {"__meta__":{"operationName":"ServerAccountPageQuery","operationHash":"9baae331b75848a310fecb457e8c971ae27897ff"}} as unknown as TypedDocumentString<ServerAccountPageQueryQuery, ServerAccountPageQueryQueryVariables>;
|
|
3619
3627
|
export const ServerCollectionPageQueryDocument = {"__meta__":{"operationName":"ServerCollectionPageQuery","operationHash":"d46841b30ae1f6350021b5cf02f253d56c848664"}} as unknown as TypedDocumentString<ServerCollectionPageQueryQuery, ServerCollectionPageQueryQueryVariables>;
|
|
3620
|
-
export const ServerProductQueryDocument = {"__meta__":{"operationName":"ServerProductQuery","operationHash":"
|
|
3628
|
+
export const ServerProductQueryDocument = {"__meta__":{"operationName":"ServerProductQuery","operationHash":"13fc9efa8628b91971e3a8aa985e6cdbed70adae"}} as unknown as TypedDocumentString<ServerProductQueryQuery, ServerProductQueryQueryVariables>;
|
|
3621
3629
|
export const ServerListCardsQueryDocument = {"__meta__":{"operationName":"ServerListCardsQuery","operationHash":"392cf85d18d66b94d6ea8d6b2a3c6ffb5c94683d"}} as unknown as TypedDocumentString<ServerListCardsQueryQuery, ServerListCardsQueryQueryVariables>;
|
|
3622
3630
|
export const ServerOrderDetailsQueryDocument = {"__meta__":{"operationName":"ServerOrderDetailsQuery","operationHash":"bdf677bbccce12186a5ef15aebdce46585a99782"}} as unknown as TypedDocumentString<ServerOrderDetailsQueryQuery, ServerOrderDetailsQueryQueryVariables>;
|
|
3623
3631
|
export const ServerListOrdersQueryDocument = {"__meta__":{"operationName":"ServerListOrdersQuery","operationHash":"70d06de1da9c11f10ebde31b66fd74eccd456af5"}} as unknown as TypedDocumentString<ServerListOrdersQueryQuery, ServerListOrdersQueryQueryVariables>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"9baae331b75848a310fecb457e8c971ae27897ff": "query ServerAccountPageQuery { accountProfile { name } }",
|
|
3
3
|
"d46841b30ae1f6350021b5cf02f253d56c848664": "fragment ServerCollectionPage on Query { collection(slug: $slug) { id } } query ServerCollectionPageQuery($slug: String!) { collection(slug: $slug) { breadcrumbList { itemListElement { item name position } } meta { selectedFacets { key value } } otherLocales { locale slug } seo { description title } } ...ServerCollectionPage }",
|
|
4
|
-
"
|
|
4
|
+
"13fc9efa8628b91971e3a8aa985e6cdbed70adae": "fragment CartProductItem on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations availableVariations slugsMap } } name sku unitMultiplier } fragment ProductDetailsFragment_product on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } description gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku unitMultiplier ...CartProductItem } fragment ServerProduct on Query { product(locator: $locator) { id: productID } } query ServerProductQuery($locator: [IStoreSelectedFacet!]!) { product(locator: $locator) { brand { name } breadcrumbList { itemListElement { item name position } } defaultLocaleSlug description gtin image { alternateName url } isVariantOf { productGroupID } mpn name offers { highPrice lowPrice lowPriceWithTaxes offers { availability itemCondition price priceCurrency priceToken priceValidUntil seller { identifier } } priceCurrency } otherLocales { locale slug } id: productID releaseDate seo { canonical description title } sku ...ProductDetailsFragment_product } ...ServerProduct }",
|
|
5
5
|
"392cf85d18d66b94d6ea8d6b2a3c6ffb5c94683d": "query ServerListCardsQuery { accountProfile { name } hasAdHocCardAccess listCreditCards { list { accountId bin cardLabel cardNumber isActive isDefault origin paymentSystem paymentSystemName } } }",
|
|
6
6
|
"bdf677bbccce12186a5ef15aebdce46585a99782": "query ServerOrderDetailsQuery($orderId: String!) { accountProfile { name } userOrder(orderId: $orderId) { allowCancellation budgetData { budgets { allocations { id linkedEntity { id } reservations } balance { remaining } id name } } canProcessOrderAuthorization clientProfileData { corporateName email firstName isCorporate lastName phone } creationDate customFields { fields { name refId value } id type } deliveryOptionsData { contact { email name phone } deliveryOptions { address { addressId addressType city complement country entityId geoCoordinates neighborhood number postalCode receiverName reference state street versionId } deliveryChannel deliveryCompany deliveryWindow { endDateUtc price startDateUtc } friendlyDeliveryOptionName friendlyShippingEstimate items { id imageUrl name price quantity sellingPrice tax taxPriceTagsTotal total uniqueId } pickupStoreInfo { additionalInfo address { addressId addressType city complement country entityId geoCoordinates neighborhood number postalCode receiverName reference state street versionId } dockId friendlyName isPickupStore } quantityOfDifferentItems selectedSla seller shippingEstimate shippingEstimateDate total } } orderId paymentData { transactions { isActive payments { bankIssuedInvoiceIdentificationNumber connectorResponses { authId } group id installments lastDigits paymentOrigin paymentSystemName redemptionCode referenceValue tid url value } } } ruleForAuthorization { dimensionId orderAuthorizationId rule { authorizationData { authorizers { authorizationDate email id type } requireAllApprovals } authorizedEmails doId id isUserAuthorized isUserNextAuthorizer name notification priority scoreInterval { accept deny } status timeout trigger { condition { conditionType description expression greatherThan lessThan } effect { description effectType funcPath } } } } shopper { email firstName lastName phone } status statusDescription storePreferencesData { currencyCode } totals { id name value } } }",
|
|
7
7
|
"70d06de1da9c11f10ebde31b66fd74eccd456af5": "query ServerListOrdersQuery($clientEmail: String, $dateFinal: String, $dateInitial: String, $page: Int, $pendingMyApproval: Boolean, $perPage: Int, $status: [String], $text: String) { accountProfile { name } listUserOrders( page: $page perPage: $perPage status: $status dateInitial: $dateInitial dateFinal: $dateFinal text: $text clientEmail: $clientEmail pendingMyApproval: $pendingMyApproval ) { list { ShippingEstimatedDate clientName creationDate currencyCode customFields { type value } items { description ean id price productId quantity refId seller sellingPrice } orderId status statusDescription totalValue } paging { currentPage pages perPage total } } }",
|
|
@@ -1735,6 +1735,14 @@ type StoreProduct {
|
|
|
1735
1735
|
Only populated when localization is enabled.
|
|
1736
1736
|
"""
|
|
1737
1737
|
otherLocales: [StoreProductLocale!]
|
|
1738
|
+
"""
|
|
1739
|
+
Slug for the store's default locale, including the SKU ID suffix.
|
|
1740
|
+
Navigation fallback for the locale selector when the target locale is absent
|
|
1741
|
+
from `otherLocales`. Best-effort: it may point at a slug the catalog has not
|
|
1742
|
+
registered for the default locale, so it must never be used to build hreflang
|
|
1743
|
+
annotations. Only populated when localization is enabled.
|
|
1744
|
+
"""
|
|
1745
|
+
defaultLocaleSlug: String
|
|
1738
1746
|
}
|
|
1739
1747
|
|
|
1740
1748
|
"""
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.7.0](https://github.com/vtex/faststore/compare/v4.7.0-dev.9...v4.7.0) (2026-08-31)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @faststore/core
|
|
9
|
+
|
|
10
|
+
# [4.7.0-dev.9](https://github.com/vtex/faststore/compare/v4.7.0-dev.8...v4.7.0-dev.9) (2026-08-31)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **api:** separate hreflang slugs from locale-switch navigation ([#3462](https://github.com/vtex/faststore/issues/3462)) ([3091a46](https://github.com/vtex/faststore/commit/3091a46031f387d1e11e5747dd0f4ac6bef358e2))
|
|
15
|
+
|
|
6
16
|
# [4.7.0-dev.8](https://github.com/vtex/faststore/compare/v4.7.0-dev.7...v4.7.0-dev.8) (2026-08-28)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @faststore/core
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.7.0
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -71,11 +71,11 @@
|
|
|
71
71
|
"style-loader": "^3.3.1",
|
|
72
72
|
"swr": "^2.2.5",
|
|
73
73
|
"use-sync-external-store": "^1.6.0",
|
|
74
|
-
"@faststore/
|
|
75
|
-
"@faststore/lighthouse": "4.7.0
|
|
76
|
-
"@faststore/
|
|
77
|
-
"@faststore/ui": "4.7.0
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/diagnostics": "4.7.0",
|
|
75
|
+
"@faststore/lighthouse": "4.7.0",
|
|
76
|
+
"@faststore/sdk": "4.7.0",
|
|
77
|
+
"@faststore/ui": "4.7.0",
|
|
78
|
+
"@faststore/api": "4.7.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
|
@@ -42,8 +42,10 @@ const LocalizationButton = ({
|
|
|
42
42
|
const [isSelectorOpen, setIsSelectorOpen] = useState(false)
|
|
43
43
|
const buttonRef = useRef<HTMLButtonElement>(null)
|
|
44
44
|
|
|
45
|
-
const
|
|
46
|
-
const
|
|
45
|
+
const localizedProduct = useLocalizedProduct()
|
|
46
|
+
const otherLocales = localizedProduct?.otherLocales ?? undefined
|
|
47
|
+
const urlSuffix = localizedProduct?.urlSuffix ?? '/p'
|
|
48
|
+
const defaultLocaleSlug = localizedProduct?.defaultLocaleSlug ?? undefined
|
|
47
49
|
|
|
48
50
|
const {
|
|
49
51
|
languages,
|
|
@@ -56,7 +58,7 @@ const LocalizationButton = ({
|
|
|
56
58
|
reset,
|
|
57
59
|
isSaveEnabled,
|
|
58
60
|
error,
|
|
59
|
-
} = useBindingSelector(otherLocales, urlSuffix)
|
|
61
|
+
} = useBindingSelector(otherLocales, urlSuffix, defaultLocaleSlug)
|
|
60
62
|
|
|
61
63
|
const { locale: sessionLocale, currency: sessionCurrency } = useSession()
|
|
62
64
|
|
package/src/pages/[slug]/p.tsx
CHANGED
|
@@ -352,7 +352,10 @@ function Page({
|
|
|
352
352
|
If needed, wrap your component in a <Section /> component
|
|
353
353
|
(not the HTML tag) before rendering it here.
|
|
354
354
|
*/}
|
|
355
|
-
<LocalizedProductProvider
|
|
355
|
+
<LocalizedProductProvider
|
|
356
|
+
otherLocales={server.product.otherLocales}
|
|
357
|
+
defaultLocaleSlug={server.product.defaultLocaleSlug}
|
|
358
|
+
>
|
|
356
359
|
<PageProvider context={context}>
|
|
357
360
|
<RenderSections
|
|
358
361
|
sections={sections}
|
|
@@ -428,6 +431,8 @@ const query = gql(`
|
|
|
428
431
|
slug
|
|
429
432
|
}
|
|
430
433
|
|
|
434
|
+
defaultLocaleSlug
|
|
435
|
+
|
|
431
436
|
...ProductDetailsFragment_product
|
|
432
437
|
}
|
|
433
438
|
}
|
|
@@ -12,6 +12,12 @@ interface LocalizedProductData {
|
|
|
12
12
|
* Null when localization is disabled or the page type does not support it.
|
|
13
13
|
*/
|
|
14
14
|
otherLocales: LocalizedProductLocale[] | null
|
|
15
|
+
/**
|
|
16
|
+
* Slug for the store's default locale, used to navigate to a locale that is
|
|
17
|
+
* absent from `otherLocales`. Null outside PDPs, where the API does not
|
|
18
|
+
* provide one.
|
|
19
|
+
*/
|
|
20
|
+
defaultLocaleSlug: string | null
|
|
15
21
|
/**
|
|
16
22
|
* Suffix appended after the localized slug when building the redirect URL.
|
|
17
23
|
* Use '/p' for product pages (PDP), '' for collection/PLP pages.
|
|
@@ -24,6 +30,7 @@ const LocalizedProductContext = createContext<LocalizedProductData | null>(null)
|
|
|
24
30
|
type LocalizedProductProviderProps = Readonly<
|
|
25
31
|
PropsWithChildren<{
|
|
26
32
|
otherLocales: LocalizedProductLocale[] | null | undefined
|
|
33
|
+
defaultLocaleSlug?: string | null
|
|
27
34
|
/**
|
|
28
35
|
* Suffix to append to the localized slug when building the redirect URL.
|
|
29
36
|
* Defaults to '/p' (product pages). Pass '' for collection/PLP pages.
|
|
@@ -41,12 +48,17 @@ type LocalizedProductProviderProps = Readonly<
|
|
|
41
48
|
*/
|
|
42
49
|
export function LocalizedProductProvider({
|
|
43
50
|
otherLocales,
|
|
51
|
+
defaultLocaleSlug,
|
|
44
52
|
urlSuffix = '/p',
|
|
45
53
|
children,
|
|
46
54
|
}: LocalizedProductProviderProps) {
|
|
47
55
|
const value = useMemo(
|
|
48
|
-
() => ({
|
|
49
|
-
|
|
56
|
+
() => ({
|
|
57
|
+
otherLocales: otherLocales ?? null,
|
|
58
|
+
defaultLocaleSlug: defaultLocaleSlug ?? null,
|
|
59
|
+
urlSuffix,
|
|
60
|
+
}),
|
|
61
|
+
[otherLocales, defaultLocaleSlug, urlSuffix]
|
|
50
62
|
)
|
|
51
63
|
|
|
52
64
|
return (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LocalizedProductLocale } from './LocalizedProductContext'
|
|
1
2
|
import type { Binding, Locale } from './types'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -74,6 +75,43 @@ export function resolveBinding(
|
|
|
74
75
|
return matches.find((b) => b.isDefault) ?? matches[0]
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Resolves which product slug the locale selector should navigate to.
|
|
80
|
+
*
|
|
81
|
+
* Falls back to the default locale's slug rather than to any other entry, so a
|
|
82
|
+
* translated slug is never carried across locales (e.g. an Italian slug served
|
|
83
|
+
* under an es-ES prefix).
|
|
84
|
+
*
|
|
85
|
+
* `otherLocales` only carries locales the catalog has a registered slug for, so
|
|
86
|
+
* an untranslated product has no entry at all — not even for the default
|
|
87
|
+
* locale. `defaultLocaleSlug` covers that gap: the API resolves it best-effort
|
|
88
|
+
* so navigation lands on the product page instead of the locale root.
|
|
89
|
+
*
|
|
90
|
+
* @param otherLocales - Registered localized slugs for the current product
|
|
91
|
+
* @param targetLocale - Locale the shopper is switching to
|
|
92
|
+
* @param defaultLocale - The store's default locale
|
|
93
|
+
* @param defaultLocaleSlug - Best-effort default-locale slug, PDP only
|
|
94
|
+
* @returns The slug to redirect to, or null when none is available
|
|
95
|
+
*/
|
|
96
|
+
export function resolveTargetSlug({
|
|
97
|
+
otherLocales,
|
|
98
|
+
targetLocale,
|
|
99
|
+
defaultLocale,
|
|
100
|
+
defaultLocaleSlug,
|
|
101
|
+
}: {
|
|
102
|
+
otherLocales: LocalizedProductLocale[] | null | undefined
|
|
103
|
+
targetLocale: string
|
|
104
|
+
defaultLocale: string
|
|
105
|
+
defaultLocaleSlug?: string | null
|
|
106
|
+
}): string | null {
|
|
107
|
+
return (
|
|
108
|
+
otherLocales?.find((e) => e.locale === targetLocale)?.slug ??
|
|
109
|
+
otherLocales?.find((e) => e.locale === defaultLocale)?.slug ??
|
|
110
|
+
defaultLocaleSlug ??
|
|
111
|
+
null
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
77
115
|
/**
|
|
78
116
|
* Validates that a URL is non-empty and appears to be valid.
|
|
79
117
|
*
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getCurrenciesForLocale,
|
|
9
9
|
isValidUrl,
|
|
10
10
|
resolveBinding,
|
|
11
|
+
resolveTargetSlug,
|
|
11
12
|
} from './bindingSelector'
|
|
12
13
|
import type { LocalizedProductLocale } from './LocalizedProductContext'
|
|
13
14
|
import type { BindingSelectorError, Locale } from './types'
|
|
@@ -147,11 +148,14 @@ export interface UseBindingSelectorReturn {
|
|
|
147
148
|
* localized page URL instead of preserving the current page path verbatim.
|
|
148
149
|
* @param urlSuffix - Suffix appended after the slug when building the redirect URL.
|
|
149
150
|
* Use '/p' for product pages (default) and '' for collection/PLP pages.
|
|
151
|
+
* @param defaultLocaleSlug - Slug for the store's default locale, used when the
|
|
152
|
+
* target locale is absent from `otherLocales`. PDP only; PLPs pass nothing.
|
|
150
153
|
* @returns Object with languages, currencies, selections, and actions
|
|
151
154
|
*/
|
|
152
155
|
export function useBindingSelector(
|
|
153
156
|
otherLocales?: Array<{ locale: string; slug: string }> | null,
|
|
154
|
-
urlSuffix = '/p'
|
|
157
|
+
urlSuffix = '/p',
|
|
158
|
+
defaultLocaleSlug?: string | null
|
|
155
159
|
): UseBindingSelectorReturn {
|
|
156
160
|
const { locale: currentLocale, currency: currentCurrency } = useSession()
|
|
157
161
|
const localizationConfig = storeConfig.localization as LocalizationConfig
|
|
@@ -284,27 +288,17 @@ export function useBindingSelector(
|
|
|
284
288
|
? otherLocales
|
|
285
289
|
: recoverOtherLocales()
|
|
286
290
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
(e) => e.locale === localizationConfig.defaultLocale
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
const entry = localizedEntry ?? fallbackEntry
|
|
302
|
-
|
|
303
|
-
if (entry) {
|
|
304
|
-
const baseUrl = binding.url.replace(/\/$/, '')
|
|
305
|
-
globalThis.location.href = `${baseUrl}/${entry.slug}${urlSuffix}${globalThis.location.search}${globalThis.location.hash}`
|
|
306
|
-
return
|
|
307
|
-
}
|
|
291
|
+
const slug = resolveTargetSlug({
|
|
292
|
+
otherLocales: effectiveOtherLocales,
|
|
293
|
+
targetLocale: localeCode,
|
|
294
|
+
defaultLocale: localizationConfig.defaultLocale,
|
|
295
|
+
defaultLocaleSlug,
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
if (slug) {
|
|
299
|
+
const baseUrl = binding.url.replace(/\/$/, '')
|
|
300
|
+
globalThis.location.href = `${baseUrl}/${slug}${urlSuffix}${globalThis.location.search}${globalThis.location.hash}`
|
|
301
|
+
return
|
|
308
302
|
}
|
|
309
303
|
|
|
310
304
|
// otherLocales is empty/null but we're still on a PDP: strip the stale slug.
|
|
@@ -329,6 +323,7 @@ export function useBindingSelector(
|
|
|
329
323
|
localizationConfig.defaultLocale,
|
|
330
324
|
otherLocales,
|
|
331
325
|
urlSuffix,
|
|
326
|
+
defaultLocaleSlug,
|
|
332
327
|
])
|
|
333
328
|
|
|
334
329
|
const isSaveEnabled = Boolean(localeCode && currencyCode && !error)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { cleanup, render } from '@testing-library/react'
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
const mockUseBindingSelector = vi.hoisted(() =>
|
|
5
|
+
vi.fn(() => ({
|
|
6
|
+
languages: { 'en-US': 'English' },
|
|
7
|
+
currencies: { USD: 'USD' },
|
|
8
|
+
localeCode: 'en-US',
|
|
9
|
+
currencyCode: 'USD',
|
|
10
|
+
setLocaleCode: vi.fn(),
|
|
11
|
+
setCurrencyCode: vi.fn(),
|
|
12
|
+
save: vi.fn(),
|
|
13
|
+
reset: vi.fn(),
|
|
14
|
+
isSaveEnabled: true,
|
|
15
|
+
error: null,
|
|
16
|
+
}))
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
vi.mock('src/sdk/localization', () => ({
|
|
20
|
+
useBindingSelector: mockUseBindingSelector,
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
vi.mock('src/sdk/session', () => ({
|
|
24
|
+
useSession: () => ({ locale: 'pt-BR', currency: { code: 'BRL' } }),
|
|
25
|
+
}))
|
|
26
|
+
|
|
27
|
+
vi.mock('discovery.config', async (importOriginal) => {
|
|
28
|
+
const original = await importOriginal<{ default: Record<string, unknown> }>()
|
|
29
|
+
|
|
30
|
+
return { default: { ...original.default, localization: { enabled: true } } }
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
import LocalizationButton from 'src/components/ui/LocalizationButton'
|
|
34
|
+
import { LocalizedProductProvider } from 'src/sdk/localization/LocalizedProductContext'
|
|
35
|
+
|
|
36
|
+
const OTHER_LOCALES = [
|
|
37
|
+
{ locale: 'en-US', slug: 'roshe-tenis-76' },
|
|
38
|
+
{ locale: 'pt-BR', slug: 'tenis-roshe-76' },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
cleanup()
|
|
43
|
+
mockUseBindingSelector.mockClear()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('LocalizationButton', () => {
|
|
47
|
+
it('forwards both slug sources from the product context to the selector', () => {
|
|
48
|
+
render(
|
|
49
|
+
<LocalizedProductProvider
|
|
50
|
+
otherLocales={OTHER_LOCALES}
|
|
51
|
+
defaultLocaleSlug="roshe-tenis-76"
|
|
52
|
+
>
|
|
53
|
+
<LocalizationButton />
|
|
54
|
+
</LocalizedProductProvider>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
expect(mockUseBindingSelector).toHaveBeenCalledWith(
|
|
58
|
+
OTHER_LOCALES,
|
|
59
|
+
'/p',
|
|
60
|
+
'roshe-tenis-76'
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('passes no default-locale slug on collection pages', () => {
|
|
65
|
+
render(
|
|
66
|
+
<LocalizedProductProvider otherLocales={OTHER_LOCALES} urlSuffix="">
|
|
67
|
+
<LocalizationButton />
|
|
68
|
+
</LocalizedProductProvider>
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
expect(mockUseBindingSelector).toHaveBeenCalledWith(
|
|
72
|
+
OTHER_LOCALES,
|
|
73
|
+
'',
|
|
74
|
+
undefined
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('falls back to product-page defaults outside a provider', () => {
|
|
79
|
+
render(<LocalizationButton />)
|
|
80
|
+
|
|
81
|
+
expect(mockUseBindingSelector).toHaveBeenCalledWith(
|
|
82
|
+
undefined,
|
|
83
|
+
'/p',
|
|
84
|
+
undefined
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react'
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
vi.mock(import('../../../discovery.config.js'), async (original) => ({
|
|
5
|
+
default: {
|
|
6
|
+
...((await original()).default ?? (await original())),
|
|
7
|
+
localization: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
defaultLocale: 'en-US',
|
|
10
|
+
regions: {
|
|
11
|
+
US: {
|
|
12
|
+
code: 'US',
|
|
13
|
+
name: 'United States',
|
|
14
|
+
dateFormat: 'MM/DD/YYYY',
|
|
15
|
+
timeFormat: '12h',
|
|
16
|
+
timeFormatMask: 'hh:mm a',
|
|
17
|
+
unitSystem: 'imperial',
|
|
18
|
+
defaultTimezone: 'GMT-5',
|
|
19
|
+
},
|
|
20
|
+
BR: {
|
|
21
|
+
code: 'BR',
|
|
22
|
+
name: 'Brazil',
|
|
23
|
+
dateFormat: 'DD/MM/YYYY',
|
|
24
|
+
timeFormat: '24h',
|
|
25
|
+
timeFormatMask: 'HH:mm',
|
|
26
|
+
unitSystem: 'metric',
|
|
27
|
+
defaultTimezone: 'GMT-3',
|
|
28
|
+
},
|
|
29
|
+
IT: {
|
|
30
|
+
code: 'IT',
|
|
31
|
+
name: 'Italy',
|
|
32
|
+
dateFormat: 'DD/MM/YYYY',
|
|
33
|
+
timeFormat: '24h',
|
|
34
|
+
timeFormatMask: 'HH:mm',
|
|
35
|
+
unitSystem: 'metric',
|
|
36
|
+
defaultTimezone: 'GMT+1',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
locales: {
|
|
40
|
+
'en-US': {
|
|
41
|
+
code: 'en-US',
|
|
42
|
+
name: 'English',
|
|
43
|
+
languageCode: 'en',
|
|
44
|
+
languageName: 'English',
|
|
45
|
+
script: 'Latn',
|
|
46
|
+
textDirection: 'ltr',
|
|
47
|
+
regionCode: 'US',
|
|
48
|
+
bindings: [
|
|
49
|
+
{
|
|
50
|
+
currencyCode: 'USD',
|
|
51
|
+
url: 'https://store.example.com',
|
|
52
|
+
salesChannel: '1',
|
|
53
|
+
isDefault: true,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
'pt-BR': {
|
|
58
|
+
code: 'pt-BR',
|
|
59
|
+
name: 'português',
|
|
60
|
+
languageCode: 'pt',
|
|
61
|
+
languageName: 'Portuguese',
|
|
62
|
+
script: 'Latn',
|
|
63
|
+
textDirection: 'ltr',
|
|
64
|
+
regionCode: 'BR',
|
|
65
|
+
bindings: [
|
|
66
|
+
{
|
|
67
|
+
currencyCode: 'BRL',
|
|
68
|
+
url: 'https://store.example.com/pt-BR',
|
|
69
|
+
salesChannel: '2',
|
|
70
|
+
isDefault: true,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
'it-IT': {
|
|
75
|
+
code: 'it-IT',
|
|
76
|
+
name: 'italiano',
|
|
77
|
+
languageCode: 'it',
|
|
78
|
+
languageName: 'Italian',
|
|
79
|
+
script: 'Latn',
|
|
80
|
+
textDirection: 'ltr',
|
|
81
|
+
regionCode: 'IT',
|
|
82
|
+
bindings: [
|
|
83
|
+
{
|
|
84
|
+
currencyCode: 'EUR',
|
|
85
|
+
url: 'https://store.example.com/it-IT',
|
|
86
|
+
salesChannel: '3',
|
|
87
|
+
isDefault: true,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
currencies: {
|
|
93
|
+
USD: { code: 'USD', name: 'US Dollar', symbol: '$' },
|
|
94
|
+
BRL: { code: 'BRL', name: 'Brazilian Real', symbol: 'R$' },
|
|
95
|
+
EUR: { code: 'EUR', name: 'Euro', symbol: '€' },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
}))
|
|
100
|
+
|
|
101
|
+
vi.mock('../../../src/sdk/session', () => ({
|
|
102
|
+
useSession: () => ({
|
|
103
|
+
locale: 'en-US',
|
|
104
|
+
currency: { code: 'USD', symbol: '$' },
|
|
105
|
+
}),
|
|
106
|
+
}))
|
|
107
|
+
|
|
108
|
+
import { useBindingSelector } from '../../../src/sdk/localization/useBindingSelector'
|
|
109
|
+
|
|
110
|
+
const TRANSLATED = [
|
|
111
|
+
{ locale: 'en-US', slug: 'roshe-tenis-76' },
|
|
112
|
+
{ locale: 'pt-BR', slug: 'tenis-roshe-76' },
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Replaces `globalThis.location` with a plain object so the redirect can be
|
|
117
|
+
* asserted. jsdom throws on a real `href` assignment.
|
|
118
|
+
*/
|
|
119
|
+
function stubLocation(pathname: string, search = '', hash = '') {
|
|
120
|
+
const location = { pathname, search, hash, href: '' }
|
|
121
|
+
vi.stubGlobal('location', location)
|
|
122
|
+
|
|
123
|
+
return location
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Drives the selector to a locale/currency pair and triggers the redirect. */
|
|
127
|
+
function switchTo(
|
|
128
|
+
locale: string,
|
|
129
|
+
currency: string,
|
|
130
|
+
otherLocales?: Array<{ locale: string; slug: string }> | null,
|
|
131
|
+
defaultLocaleSlug?: string | null,
|
|
132
|
+
urlSuffix = '/p'
|
|
133
|
+
) {
|
|
134
|
+
const { result } = renderHook(() =>
|
|
135
|
+
useBindingSelector(otherLocales, urlSuffix, defaultLocaleSlug)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
act(() => result.current.setLocaleCode(locale))
|
|
139
|
+
act(() => result.current.setCurrencyCode(currency))
|
|
140
|
+
act(() => result.current.save())
|
|
141
|
+
|
|
142
|
+
return result
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
describe('useBindingSelector redirect', () => {
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
globalThis.sessionStorage.clear()
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
afterEach(() => {
|
|
151
|
+
vi.unstubAllGlobals()
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('navigates to the slug the catalog registered for the target locale', () => {
|
|
155
|
+
const location = stubLocation('/roshe-tenis-76/p')
|
|
156
|
+
|
|
157
|
+
switchTo('pt-BR', 'BRL', TRANSLATED)
|
|
158
|
+
|
|
159
|
+
expect(location.href).toBe(
|
|
160
|
+
'https://store.example.com/pt-BR/tenis-roshe-76/p'
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('falls back to the default locale slug registered in the map when the target has none', () => {
|
|
165
|
+
const location = stubLocation('/tenis-roshe-76/p')
|
|
166
|
+
|
|
167
|
+
switchTo('it-IT', 'EUR', TRANSLATED)
|
|
168
|
+
|
|
169
|
+
expect(location.href).toBe(
|
|
170
|
+
'https://store.example.com/it-IT/roshe-tenis-76/p'
|
|
171
|
+
)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('navigates to the product page via defaultLocaleSlug when the target locale has no registered slug', () => {
|
|
175
|
+
const location = stubLocation('/roshe-tenis-76/p')
|
|
176
|
+
|
|
177
|
+
switchTo(
|
|
178
|
+
'it-IT',
|
|
179
|
+
'EUR',
|
|
180
|
+
[{ locale: 'pt-BR', slug: 'tenis-roshe-76' }],
|
|
181
|
+
'roshe-tenis-76'
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
// The Italian binding with the default-locale slug: an untranslated product
|
|
185
|
+
// page, which the agreed behavior prefers over the locale root.
|
|
186
|
+
expect(location.href).toBe(
|
|
187
|
+
'https://store.example.com/it-IT/roshe-tenis-76/p'
|
|
188
|
+
)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('uses defaultLocaleSlug for a product with no registered translations at all', () => {
|
|
192
|
+
const location = stubLocation('/side-by-side-refrigerator-14/p')
|
|
193
|
+
|
|
194
|
+
switchTo('pt-BR', 'BRL', [], 'side-by-side-refrigerator-14')
|
|
195
|
+
|
|
196
|
+
expect(location.href).toBe(
|
|
197
|
+
'https://store.example.com/pt-BR/side-by-side-refrigerator-14/p'
|
|
198
|
+
)
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('never carries a slug registered for a third locale into the target locale', () => {
|
|
202
|
+
const location = stubLocation('/roshe-tenis-76/p')
|
|
203
|
+
|
|
204
|
+
switchTo(
|
|
205
|
+
'it-IT',
|
|
206
|
+
'EUR',
|
|
207
|
+
[{ locale: 'pt-BR', slug: 'tenis-roshe-76' }],
|
|
208
|
+
'roshe-tenis-76'
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
expect(location.href).not.toContain('tenis-roshe-76')
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('falls back to the binding root on a PDP with no slug available', () => {
|
|
215
|
+
const location = stubLocation('/roshe-tenis-76/p')
|
|
216
|
+
|
|
217
|
+
switchTo('pt-BR', 'BRL', [], null)
|
|
218
|
+
|
|
219
|
+
expect(location.href).toBe('https://store.example.com/pt-BR')
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('preserves the query string and hash across the switch', () => {
|
|
223
|
+
const location = stubLocation('/roshe-tenis-76/p', '?skuId=76', '#reviews')
|
|
224
|
+
|
|
225
|
+
switchTo('pt-BR', 'BRL', TRANSLATED)
|
|
226
|
+
|
|
227
|
+
expect(location.href).toBe(
|
|
228
|
+
'https://store.example.com/pt-BR/tenis-roshe-76/p?skuId=76#reviews'
|
|
229
|
+
)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('omits the /p suffix for collection pages', () => {
|
|
233
|
+
const location = stubLocation('/apparel')
|
|
234
|
+
|
|
235
|
+
switchTo('pt-BR', 'BRL', [{ locale: 'pt-BR', slug: 'vestuario' }], null, '')
|
|
236
|
+
|
|
237
|
+
expect(location.href).toBe('https://store.example.com/pt-BR/vestuario')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('reports an error instead of redirecting when the locale has no binding for the currency', () => {
|
|
241
|
+
const location = stubLocation('/roshe-tenis-76/p')
|
|
242
|
+
|
|
243
|
+
const result = switchTo('pt-BR', 'JPY', TRANSLATED)
|
|
244
|
+
|
|
245
|
+
expect(result.current.error).toEqual({
|
|
246
|
+
type: 'no-binding-found',
|
|
247
|
+
locale: 'pt-BR',
|
|
248
|
+
currency: 'JPY',
|
|
249
|
+
})
|
|
250
|
+
expect(location.href).toBe('')
|
|
251
|
+
})
|
|
252
|
+
})
|