@faststore/core 4.6.0-dev.1 → 4.6.0-dev.2
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 +102 -99
- package/@generated/gql.ts +3 -3
- package/@generated/graphql.ts +8 -2
- package/@generated/persisted-documents.json +1 -1
- package/@generated/schema.graphql +6 -0
- package/CHANGELOG.md +9 -0
- package/package.json +6 -6
- package/src/sdk/cart/index.ts +15 -1
- package/src/sdk/cart/waitForSessionValidated.ts +43 -0
- package/src/sdk/session/index.ts +14 -0
- package/src/sdk/session/syncSalesChannelFromOrderForm.ts +68 -0
- package/test/sdk/cart/waitForSessionValidated.test.ts +96 -0
- package/test/sdk/session/syncSalesChannelFromOrderForm.test.ts +125 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.6.0-dev.
|
|
2
|
+
> @faststore/core@4.6.0-dev.1 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.6.0-dev.
|
|
6
|
+
> @faststore/core@4.6.0-dev.1 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.6.0-dev.
|
|
22
|
+
> @faststore/core@4.6.0-dev.1 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.6.0-dev.
|
|
2
|
+
> @faststore/core@4.6.0-dev.1 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
@@ -7,14 +7,15 @@
|
|
|
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 763[2mms[22m[39m
|
|
10
11
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
|
|
11
|
-
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=
|
|
12
|
+
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
|
|
12
13
|
[90m at node:internal/deps/undici/undici:16416:13[39m
|
|
13
14
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
14
15
|
at baseRequest [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/graphql/request.ts:42:20[90m)[39m
|
|
15
16
|
at GraphqlRequest [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/graphql/request.ts:130:20[90m)[39m
|
|
16
17
|
at request [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/graphql/request.ts:154:5[90m)[39m
|
|
17
|
-
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:
|
|
18
|
+
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:122:46[90m)[39m
|
|
18
19
|
at onValidate [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/useStore.ts:18:14[90m)[39m
|
|
19
20
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:17) {
|
|
20
21
|
[cause]: TypeError: Invalid URL
|
|
@@ -29,25 +30,21 @@ Not implemented: navigation to another Document
|
|
|
29
30
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
30
31
|
at GraphqlRequest [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/graphql/request.ts:130:20[90m)[39m {
|
|
31
32
|
code: [32m'ERR_INVALID_URL'[39m,
|
|
32
|
-
input: [32m'/api/graphql?operationName=ValidateCartMutation&operationHash=
|
|
33
|
+
input: [32m'/api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12'[39m
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
37
38
|
npx update-browserslist-db@latest
|
|
38
39
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
39
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
40
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 1389[2mms[22m[39m
|
|
40
41
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
41
42
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
42
43
|
|
|
43
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
44
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
[33m[2m✓[22m[39m does not reload when the switch returns false [33m 308[2mms[22m[39m
|
|
48
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
49
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 252[2mms[22m[39m
|
|
50
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
44
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 169[2mms[22m[39m
|
|
45
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 112[2mms[22m[39m
|
|
46
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
47
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
51
48
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
52
49
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
53
50
|
|
|
@@ -277,57 +274,61 @@ act(() => {
|
|
|
277
274
|
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
|
|
278
275
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
279
276
|
|
|
280
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
281
|
-
[33m[2m✓[22m[39m renders the password protection form [33m
|
|
282
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
283
|
-
|
|
284
|
-
|
|
277
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 1159[2mms[22m[39m
|
|
278
|
+
[33m[2m✓[22m[39m renders the password protection form [33m 515[2mms[22m[39m
|
|
279
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
280
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1172[2mms[22m[39m
|
|
281
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 744[2mms[22m[39m
|
|
285
282
|
[90mstderr[2m | test/sdk/localization/store-url.browser.test.ts
|
|
286
283
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
287
|
-
at
|
|
284
|
+
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
285
|
+
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:120:9[90m)[39m
|
|
288
286
|
at onValidate [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/useStore.ts:18:20[90m)[39m
|
|
289
287
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
290
288
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
291
289
|
|
|
292
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
293
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
294
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
295
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
290
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
291
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
292
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
293
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
296
294
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
297
295
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
298
|
-
at
|
|
296
|
+
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
297
|
+
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:120:9[90m)[39m
|
|
299
298
|
at onValidate [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/useStore.ts:18:20[90m)[39m
|
|
300
299
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
301
300
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
302
301
|
|
|
303
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
304
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
302
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
303
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 186[2mms[22m[39m
|
|
305
304
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
306
305
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
307
|
-
at
|
|
306
|
+
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
307
|
+
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:120:9[90m)[39m
|
|
308
308
|
at onValidate [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/useStore.ts:18:20[90m)[39m
|
|
309
309
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
310
310
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
311
311
|
|
|
312
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
313
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
314
|
-
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
315
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
316
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m
|
|
312
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
313
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 239[2mms[22m[39m
|
|
314
|
+
[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
|
|
315
|
+
[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
|
|
316
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
317
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
318
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
317
319
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
318
320
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
319
|
-
at
|
|
321
|
+
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
322
|
+
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:120:9[90m)[39m
|
|
320
323
|
at onValidate [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/useStore.ts:18:20[90m)[39m
|
|
321
324
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
322
325
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
323
326
|
|
|
327
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
324
328
|
[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
|
|
325
|
-
[32m✓[39m [30m[
|
|
326
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
327
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
328
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
329
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 284[2mms[22m[39m
|
|
330
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
329
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
330
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 118[2mms[22m[39m
|
|
331
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
331
332
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
332
333
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
333
334
|
|
|
@@ -391,11 +392,11 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
391
392
|
at Suspense
|
|
392
393
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
393
394
|
|
|
394
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
395
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
396
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
397
|
-
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
398
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m
|
|
395
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 58[2mms[22m[39m
|
|
396
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
397
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 44[2mms[22m[39m
|
|
398
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
399
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
399
400
|
[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
|
|
400
401
|
[22m[39mGraphql execution returned with error: [
|
|
401
402
|
{
|
|
@@ -444,7 +445,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
444
445
|
|
|
445
446
|
[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
|
|
446
447
|
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
447
|
-
|
|
448
|
+
T [FastStoreError]: malformed
|
|
448
449
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:190:31
|
|
449
450
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
450
451
|
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
|
|
@@ -460,7 +461,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
460
461
|
|
|
461
462
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql request handling[2m > [22m[2mmaps UnauthorizedError thrown by execute to its status
|
|
462
463
|
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
463
|
-
|
|
464
|
+
re [FastStoreError]: expired
|
|
464
465
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:191:33
|
|
465
466
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
466
467
|
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
|
|
@@ -488,62 +489,64 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
488
489
|
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
|
|
489
490
|
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)
|
|
490
491
|
|
|
491
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m
|
|
492
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m
|
|
493
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 847[2mms[22m[39m
|
|
494
|
-
[33m[2m✓[22m[39m navigates with the search term on blur [33m 363[2mms[22m[39m
|
|
495
|
-
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 357[2mms[22m[39m
|
|
492
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
493
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 323[2mms[22m[39m
|
|
496
494
|
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
497
495
|
[22m[39mSet password request failed: Bad Request
|
|
498
496
|
|
|
499
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
500
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
501
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
505
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
506
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
507
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
508
|
-
|
|
509
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
510
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
511
|
-
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
512
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
513
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
514
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
515
|
-
|
|
516
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
517
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
518
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
519
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
520
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
497
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 20[2mms[22m[39m
|
|
498
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
499
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 795[2mms[22m[39m
|
|
500
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 360[2mms[22m[39m
|
|
501
|
+
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 358[2mms[22m[39m
|
|
502
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
503
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
504
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
505
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
506
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 103[2mms[22m[39m
|
|
507
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/useStartRecommendationSession.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
508
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
509
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
510
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
511
|
+
[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
|
|
512
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 946[2mms[22m[39m
|
|
513
|
+
[33m[2m✓[22m[39m should handle options and execute [33m 513[2mms[22m[39m
|
|
514
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
515
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
516
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 89[2mms[22m[39m
|
|
517
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
518
|
+
[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
|
|
519
|
+
[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
|
|
520
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
521
|
+
[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
|
|
522
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 2[2mms[22m[39m
|
|
523
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
521
524
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/hasEnabledRecommendationShelf.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
522
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
523
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m
|
|
524
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
525
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
526
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
527
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
528
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
529
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
525
530
|
[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
|
|
526
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
527
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
528
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
529
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
530
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
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/components/
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
[2m
|
|
546
|
-
[2m
|
|
547
|
-
[2m Start at [22m 23:16:25
|
|
548
|
-
[2m Duration [22m 41.03s[2m (transform 8.89s, setup 0ms, import 34.03s, tests 12.55s, environment 53.93s)[22m
|
|
531
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
532
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
533
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
534
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
535
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 185[2mms[22m[39m
|
|
536
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
537
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
538
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
539
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
540
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
541
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
|
542
|
+
[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
|
|
543
|
+
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
544
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 32[2mms[22m[39m
|
|
545
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
546
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
547
|
+
|
|
548
|
+
[2m Test Files [22m [1m[32m81 passed[39m[22m[90m (81)[39m
|
|
549
|
+
[2m Tests [22m [1m[32m651 passed[39m[22m[90m (651)[39m
|
|
550
|
+
[2m Start at [22m 02:49:36
|
|
551
|
+
[2m Duration [22m 29.47s[2m (transform 7.03s, setup 0ms, import 25.03s, tests 8.86s, environment 38.42s)[22m
|
|
549
552
|
|
package/@generated/gql.ts
CHANGED
|
@@ -45,7 +45,7 @@ type Documents = {
|
|
|
45
45
|
"\n mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) {\n processOrderAuthorization(data: $data) {\n isPendingForOtherAuthorizer\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 }\n }\n": typeof types.ProcessOrderAuthorizationMutationDocument,
|
|
46
46
|
"\n query ValidateUser {\n validateUser {\n isValid\n }\n }\n": typeof types.ValidateUserDocument,
|
|
47
47
|
"\n mutation StartRecommendationSession {\n startRecommendationSession\n }\n": typeof types.StartRecommendationSessionDocument,
|
|
48
|
-
"\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": typeof types.ValidateCartMutationDocument,
|
|
48
|
+
"\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": typeof types.ValidateCartMutationDocument,
|
|
49
49
|
"\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates) {\n pickupPointDistances {\n pickupId\n distance\n pickupName\n isActive\n address {\n city\n state\n number\n postalCode\n street\n }\n }\n }\n }\n": typeof types.ClientPickupPointsQueryDocument,
|
|
50
50
|
"\n mutation SubscribeToNewsletter($data: IPersonNewsletter!) {\n subscribeToNewsletter(data: $data) {\n id\n }\n }\n": typeof types.SubscribeToNewsletterDocument,
|
|
51
51
|
"\n mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) {\n startOrderEntryOperation(data: $data) {\n operationId\n }\n }\n": typeof types.StartOrderEntryOperationMutationDocument,
|
|
@@ -97,7 +97,7 @@ const documents: Documents = {
|
|
|
97
97
|
"\n mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) {\n processOrderAuthorization(data: $data) {\n isPendingForOtherAuthorizer\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 }\n }\n": types.ProcessOrderAuthorizationMutationDocument,
|
|
98
98
|
"\n query ValidateUser {\n validateUser {\n isValid\n }\n }\n": types.ValidateUserDocument,
|
|
99
99
|
"\n mutation StartRecommendationSession {\n startRecommendationSession\n }\n": types.StartRecommendationSessionDocument,
|
|
100
|
-
"\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": types.ValidateCartMutationDocument,
|
|
100
|
+
"\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": types.ValidateCartMutationDocument,
|
|
101
101
|
"\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates) {\n pickupPointDistances {\n pickupId\n distance\n pickupName\n isActive\n address {\n city\n state\n number\n postalCode\n street\n }\n }\n }\n }\n": types.ClientPickupPointsQueryDocument,
|
|
102
102
|
"\n mutation SubscribeToNewsletter($data: IPersonNewsletter!) {\n subscribeToNewsletter(data: $data) {\n id\n }\n }\n": types.SubscribeToNewsletterDocument,
|
|
103
103
|
"\n mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) {\n startOrderEntryOperation(data: $data) {\n operationId\n }\n }\n": types.StartOrderEntryOperationMutationDocument,
|
|
@@ -242,7 +242,7 @@ export function gql(source: "\n mutation StartRecommendationSession {\n star
|
|
|
242
242
|
/**
|
|
243
243
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
244
244
|
*/
|
|
245
|
-
export function gql(source: "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n"): typeof import('./graphql').ValidateCartMutationDocument;
|
|
245
|
+
export function gql(source: "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n"): typeof import('./graphql').ValidateCartMutationDocument;
|
|
246
246
|
/**
|
|
247
247
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
248
248
|
*/
|
package/@generated/graphql.ts
CHANGED
|
@@ -1538,6 +1538,12 @@ export type StoreOrder = {
|
|
|
1538
1538
|
acceptedOffer: Array<StoreOffer>;
|
|
1539
1539
|
/** ID of the order in [VTEX order management](https://help.vtex.com/en/tutorial/license-manager-resources-oms--60QcBsvWeum02cFi3GjBzg#). */
|
|
1540
1540
|
orderNumber: Scalars['String']['output'];
|
|
1541
|
+
/**
|
|
1542
|
+
* Sales channel of the underlying orderForm when FastStore adopted it because
|
|
1543
|
+
* the browser session was stale (e.g. after Quick Order). Clients should align
|
|
1544
|
+
* `session.channel` to this value. Null when no SC adoption happened.
|
|
1545
|
+
*/
|
|
1546
|
+
salesChannel: Maybe<Scalars['String']['output']>;
|
|
1541
1547
|
/** Indicates whether or not items with attachments should be split. */
|
|
1542
1548
|
shouldSplitItem: Maybe<Scalars['Boolean']['output']>;
|
|
1543
1549
|
};
|
|
@@ -2863,7 +2869,7 @@ export type ValidateCartMutationMutationVariables = Exact<{
|
|
|
2863
2869
|
}>;
|
|
2864
2870
|
|
|
2865
2871
|
|
|
2866
|
-
export type ValidateCartMutationMutation = { validateCart: { order: { orderNumber: string, shouldSplitItem: boolean | null, acceptedOffer: Array<{ quantity: number, price: number, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, isGift: boolean | null, priceToken: string | null, seller: { identifier: string }, itemOffered: { sku: string, name: string, unitMultiplier: number | null, gtin: string, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null } | null }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } }> }, messages: Array<{ text: string, status: StoreStatus }> } | null };
|
|
2872
|
+
export type ValidateCartMutationMutation = { validateCart: { order: { orderNumber: string, salesChannel: string | null, shouldSplitItem: boolean | null, acceptedOffer: Array<{ quantity: number, price: number, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, isGift: boolean | null, priceToken: string | null, seller: { identifier: string }, itemOffered: { sku: string, name: string, unitMultiplier: number | null, gtin: string, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null } | null }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } }> }, messages: Array<{ text: string, status: StoreStatus }> } | null };
|
|
2867
2873
|
|
|
2868
2874
|
export type CartMessageFragment = { text: string, status: StoreStatus };
|
|
2869
2875
|
|
|
@@ -3565,7 +3571,7 @@ export const CancelOrderMutationDocument = {"__meta__":{"operationName":"CancelO
|
|
|
3565
3571
|
export const ProcessOrderAuthorizationMutationDocument = {"__meta__":{"operationName":"ProcessOrderAuthorizationMutation","operationHash":"8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d"}} as unknown as TypedDocumentString<ProcessOrderAuthorizationMutationMutation, ProcessOrderAuthorizationMutationMutationVariables>;
|
|
3566
3572
|
export const ValidateUserDocument = {"__meta__":{"operationName":"ValidateUser","operationHash":"32f99c73c3de958b64d6bece1afe800469f54548"}} as unknown as TypedDocumentString<ValidateUserQuery, ValidateUserQueryVariables>;
|
|
3567
3573
|
export const StartRecommendationSessionDocument = {"__meta__":{"operationName":"StartRecommendationSession","operationHash":"1def6438c0cd87b85002411ac7326c221f192583"}} as unknown as TypedDocumentString<StartRecommendationSessionMutation, StartRecommendationSessionMutationVariables>;
|
|
3568
|
-
export const ValidateCartMutationDocument = {"__meta__":{"operationName":"ValidateCartMutation","operationHash":"
|
|
3574
|
+
export const ValidateCartMutationDocument = {"__meta__":{"operationName":"ValidateCartMutation","operationHash":"3c71b0d3fc2bade14df68abfa271858beb361b12"}} as unknown as TypedDocumentString<ValidateCartMutationMutation, ValidateCartMutationMutationVariables>;
|
|
3569
3575
|
export const ClientPickupPointsQueryDocument = {"__meta__":{"operationName":"ClientPickupPointsQuery","operationHash":"3fa04e88c811fcb5ece7206fd5aa745bdbc143a8"}} as unknown as TypedDocumentString<ClientPickupPointsQueryQuery, ClientPickupPointsQueryQueryVariables>;
|
|
3570
3576
|
export const SubscribeToNewsletterDocument = {"__meta__":{"operationName":"SubscribeToNewsletter","operationHash":"feb7005103a859e2bc8cf2360d568806fd88deba"}} as unknown as TypedDocumentString<SubscribeToNewsletterMutation, SubscribeToNewsletterMutationVariables>;
|
|
3571
3577
|
export const StartOrderEntryOperationMutationDocument = {"__meta__":{"operationName":"StartOrderEntryOperationMutation","operationHash":"78c50fbf9b85d03dbeac9b05b06405217f2ec440"}} as unknown as TypedDocumentString<StartOrderEntryOperationMutationMutation, StartOrderEntryOperationMutationMutationVariables>;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d": "mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) { processOrderAuthorization(data: $data) { isPendingForOtherAuthorizer 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 } } } } } }",
|
|
16
16
|
"32f99c73c3de958b64d6bece1afe800469f54548": "query ValidateUser { validateUser { isValid } }",
|
|
17
17
|
"1def6438c0cd87b85002411ac7326c221f192583": "mutation StartRecommendationSession { startRecommendationSession }",
|
|
18
|
-
"
|
|
18
|
+
"3c71b0d3fc2bade14df68abfa271858beb361b12": "fragment CartItem on StoreOffer { isGift itemOffered { ...CartProductItem } listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } fragment CartMessage on StoreCartMessage { status text } 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 } mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) { validateCart(cart: $cart, session: $session) { messages { ...CartMessage } order { acceptedOffer { ...CartItem } orderNumber salesChannel shouldSplitItem } } }",
|
|
19
19
|
"3fa04e88c811fcb5ece7206fd5aa745bdbc143a8": "query ClientPickupPointsQuery($geoCoordinates: IStoreGeoCoordinates) { pickupPoints(geoCoordinates: $geoCoordinates) { pickupPointDistances { address { city number postalCode state street } distance isActive pickupId pickupName } } }",
|
|
20
20
|
"feb7005103a859e2bc8cf2360d568806fd88deba": "mutation SubscribeToNewsletter($data: IPersonNewsletter!) { subscribeToNewsletter(data: $data) { id } }",
|
|
21
21
|
"78c50fbf9b85d03dbeac9b05b06405217f2ec440": "mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) { startOrderEntryOperation(data: $data) { operationId } }",
|
|
@@ -1538,6 +1538,12 @@ type StoreOrder {
|
|
|
1538
1538
|
acceptedOffer: [StoreOffer!]!
|
|
1539
1539
|
"""Indicates whether or not items with attachments should be split."""
|
|
1540
1540
|
shouldSplitItem: Boolean
|
|
1541
|
+
"""
|
|
1542
|
+
Sales channel of the underlying orderForm when FastStore adopted it because
|
|
1543
|
+
the browser session was stale (e.g. after Quick Order). Clients should align
|
|
1544
|
+
`session.channel` to this value. Null when no SC adoption happened.
|
|
1545
|
+
"""
|
|
1546
|
+
salesChannel: String
|
|
1541
1547
|
}
|
|
1542
1548
|
|
|
1543
1549
|
type StoreOrderEntryMissingItem {
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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.6.0-dev.2](https://github.com/vtex/faststore/compare/v4.6.0-dev.1...v4.6.0-dev.2) (2026-08-12)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **api:** address Sonar and harden session sales-channel sync ([5f6e8e9](https://github.com/vtex/faststore/commit/5f6e8e909def75f60c24cdaffae9303ed2c0a052))
|
|
11
|
+
- **api:** keep orderForm sales channel after stale validateCart sync ([09b051b](https://github.com/vtex/faststore/commit/09b051b80aaff7183adf7f5e86aece438bcd38f0))
|
|
12
|
+
- **api:** preserve orderForm sales channel in validateCart ([2336cda](https://github.com/vtex/faststore/commit/2336cda2c95970850dd0d29c1c18043ca8c9078a))
|
|
13
|
+
- **api:** sync adopted orderForm sales channel into session ([8943da7](https://github.com/vtex/faststore/commit/8943da7821f8abec08a39b7907a258bf156b05ee))
|
|
14
|
+
|
|
6
15
|
# [4.6.0-dev.1](https://github.com/vtex/faststore/compare/v4.6.0-dev.0...v4.6.0-dev.1) (2026-08-11)
|
|
7
16
|
|
|
8
17
|
## [4.5.1](https://github.com/vtex/faststore/compare/v4.5.1-dev.4...v4.5.1) (2026-08-11)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.6.0-dev.
|
|
3
|
+
"version": "4.6.0-dev.2",
|
|
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/
|
|
76
|
-
"@faststore/lighthouse": "4.6.0-dev.
|
|
77
|
-
"@faststore/
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/diagnostics": "4.6.0-dev.2",
|
|
75
|
+
"@faststore/api": "4.6.0-dev.2",
|
|
76
|
+
"@faststore/lighthouse": "4.6.0-dev.2",
|
|
77
|
+
"@faststore/sdk": "4.6.0-dev.2",
|
|
78
|
+
"@faststore/ui": "4.6.0-dev.2"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
package/src/sdk/cart/index.ts
CHANGED
|
@@ -13,8 +13,10 @@ import type {
|
|
|
13
13
|
|
|
14
14
|
import storeConfig from '../../../discovery.config'
|
|
15
15
|
import { request } from '../graphql/request'
|
|
16
|
-
import { sessionStore } from '../session'
|
|
16
|
+
import { hasValidatedSessionStore, sessionStore } from '../session'
|
|
17
|
+
import { syncSalesChannelFromOrderForm } from '../session/syncSalesChannelFromOrderForm'
|
|
17
18
|
import { createValidationStore, useStore } from '../useStore'
|
|
19
|
+
import { waitForSessionValidated } from './waitForSessionValidated'
|
|
18
20
|
|
|
19
21
|
export interface CartItem
|
|
20
22
|
extends SDKCartItem,
|
|
@@ -33,6 +35,7 @@ export const ValidateCartMutation = gql(`
|
|
|
33
35
|
validateCart(cart: $cart, session: $session) {
|
|
34
36
|
order {
|
|
35
37
|
orderNumber
|
|
38
|
+
salesChannel
|
|
36
39
|
acceptedOffer {
|
|
37
40
|
...CartItem
|
|
38
41
|
}
|
|
@@ -114,6 +117,8 @@ const getItemId = (item: Pick<CartItem, 'itemOffered' | 'seller' | 'price'>) =>
|
|
|
114
117
|
.join('::')
|
|
115
118
|
|
|
116
119
|
const validateCart = async (cart: Cart): Promise<Cart | null> => {
|
|
120
|
+
await waitForSessionValidated(hasValidatedSessionStore)
|
|
121
|
+
|
|
117
122
|
const { validateCart: validated = null } = await request<
|
|
118
123
|
ValidateCartMutationMutation,
|
|
119
124
|
ValidateCartMutationMutationVariables
|
|
@@ -151,6 +156,15 @@ const validateCart = async (cart: Cart): Promise<Cart | null> => {
|
|
|
151
156
|
},
|
|
152
157
|
})
|
|
153
158
|
|
|
159
|
+
const adoptedSalesChannel = validated?.order?.salesChannel
|
|
160
|
+
if (adoptedSalesChannel) {
|
|
161
|
+
syncSalesChannelFromOrderForm(
|
|
162
|
+
adoptedSalesChannel,
|
|
163
|
+
() => sessionStore.read(),
|
|
164
|
+
(session) => sessionStore.setSilent(session)
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
154
168
|
return (
|
|
155
169
|
validated && {
|
|
156
170
|
id: validated.order.orderNumber,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Store } from '@faststore/sdk'
|
|
2
|
+
|
|
3
|
+
/** Max time to wait for the first validateSession before validating the cart. */
|
|
4
|
+
export const SESSION_VALIDATION_WAIT_MS = 3_000
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Defers cart validation until session has been validated at least once.
|
|
8
|
+
* This reduces first-paint races between Session and Cart; sales-channel
|
|
9
|
+
* correctness after external flows (e.g. Quick Order) is enforced in the API
|
|
10
|
+
* by preserving/adopting the orderForm SC.
|
|
11
|
+
*/
|
|
12
|
+
export const waitForSessionValidated = async (
|
|
13
|
+
hasValidatedSessionStore: Store<boolean>,
|
|
14
|
+
waitMs = SESSION_VALIDATION_WAIT_MS
|
|
15
|
+
): Promise<void> => {
|
|
16
|
+
if (hasValidatedSessionStore.read()) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
await new Promise<void>((resolve) => {
|
|
21
|
+
const timeoutId = setTimeout(() => {
|
|
22
|
+
unsubscribe()
|
|
23
|
+
resolve()
|
|
24
|
+
}, waitMs)
|
|
25
|
+
|
|
26
|
+
const unsubscribe = hasValidatedSessionStore.subscribe((validated) => {
|
|
27
|
+
if (!validated) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
clearTimeout(timeoutId)
|
|
32
|
+
unsubscribe()
|
|
33
|
+
resolve()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Race: validation may have finished between read() and subscribe()
|
|
37
|
+
if (hasValidatedSessionStore.read()) {
|
|
38
|
+
clearTimeout(timeoutId)
|
|
39
|
+
unsubscribe()
|
|
40
|
+
resolve()
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
package/src/sdk/session/index.ts
CHANGED
|
@@ -194,6 +194,9 @@ export const validateSession = async (session: Session) => {
|
|
|
194
194
|
const [validationStore, onValidate, hasValidatedStore] =
|
|
195
195
|
createValidationStore(validateSession)
|
|
196
196
|
|
|
197
|
+
/** True after at least one validateSession cycle finished (success or failure). */
|
|
198
|
+
export const hasValidatedSessionStore = hasValidatedStore
|
|
199
|
+
|
|
197
200
|
const urlAwareInitialSession = getInitialSession()
|
|
198
201
|
const defaultStore = createSessionStore(
|
|
199
202
|
urlAwareInitialSession,
|
|
@@ -214,6 +217,17 @@ export const sessionStore = {
|
|
|
214
217
|
// Trigger cart revalidation when session changes
|
|
215
218
|
cartStore.set(cartStore.read())
|
|
216
219
|
},
|
|
220
|
+
/**
|
|
221
|
+
* Updates session without revalidating the cart. Used when aligning
|
|
222
|
+
* `channel.salesChannel` to an orderForm SC adopted by `validateCart`.
|
|
223
|
+
* Still runs `validateSession` via the store's optimistic validator; that
|
|
224
|
+
* path keeps an explicit (non-default) client SC.
|
|
225
|
+
*/
|
|
226
|
+
setSilent: (val: Session) => {
|
|
227
|
+
if (deepEqual(val, defaultStore.read()) === true) return
|
|
228
|
+
|
|
229
|
+
defaultStore.set(val)
|
|
230
|
+
},
|
|
217
231
|
}
|
|
218
232
|
|
|
219
233
|
export async function logoutAndClearSession(session: Session) {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Session } from '@faststore/sdk'
|
|
2
|
+
|
|
3
|
+
function parseChannelRecord(
|
|
4
|
+
raw: string | null | undefined
|
|
5
|
+
): Record<string, unknown> {
|
|
6
|
+
try {
|
|
7
|
+
const parsed: unknown = JSON.parse(raw || '{}')
|
|
8
|
+
|
|
9
|
+
if (
|
|
10
|
+
parsed !== null &&
|
|
11
|
+
typeof parsed === 'object' &&
|
|
12
|
+
!Array.isArray(parsed)
|
|
13
|
+
) {
|
|
14
|
+
return parsed as Record<string, unknown>
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
// Malformed channel — reset below.
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readSalesChannel(channel: Record<string, unknown>): string {
|
|
24
|
+
const value = channel.salesChannel
|
|
25
|
+
|
|
26
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
27
|
+
return String(value)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Aligns `fs::session.channel` with a sales channel adopted from the orderForm
|
|
35
|
+
* (e.g. after Quick Order) without revalidating the cart.
|
|
36
|
+
*
|
|
37
|
+
* Uses `sessionStore.setSilent` so we do not trigger `cartStore.set` mid-flight
|
|
38
|
+
* (that race previously wiped SC-exclusive items). Marks the channel as
|
|
39
|
+
* explicit (`hasOnlyDefaultSalesChannel: false`) so `validateSession` keeps it.
|
|
40
|
+
*/
|
|
41
|
+
export function syncSalesChannelFromOrderForm(
|
|
42
|
+
salesChannel: string | null | undefined,
|
|
43
|
+
readSession: () => Session,
|
|
44
|
+
setSilent: (session: Session) => void
|
|
45
|
+
): boolean {
|
|
46
|
+
if (salesChannel == null || salesChannel === '') {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const session = readSession()
|
|
51
|
+
const channel = parseChannelRecord(session.channel)
|
|
52
|
+
const nextSalesChannel = String(salesChannel)
|
|
53
|
+
|
|
54
|
+
if (readSalesChannel(channel) === nextSalesChannel) {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setSilent({
|
|
59
|
+
...session,
|
|
60
|
+
channel: JSON.stringify({
|
|
61
|
+
...channel,
|
|
62
|
+
salesChannel: nextSalesChannel,
|
|
63
|
+
hasOnlyDefaultSalesChannel: false,
|
|
64
|
+
}),
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createBaseStore } from '@faststore/sdk'
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import {
|
|
4
|
+
SESSION_VALIDATION_WAIT_MS,
|
|
5
|
+
waitForSessionValidated,
|
|
6
|
+
} from '../../../src/sdk/cart/waitForSessionValidated'
|
|
7
|
+
|
|
8
|
+
describe('waitForSessionValidated', () => {
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
vi.useRealTimers()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('resolves immediately when session was already validated', async () => {
|
|
14
|
+
const store = createBaseStore(true)
|
|
15
|
+
|
|
16
|
+
await expect(waitForSessionValidated(store)).resolves.toBeUndefined()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('resolves when session becomes validated after subscribe', async () => {
|
|
20
|
+
const store = createBaseStore(false)
|
|
21
|
+
|
|
22
|
+
const pending = waitForSessionValidated(store, 5_000)
|
|
23
|
+
store.set(true)
|
|
24
|
+
|
|
25
|
+
await expect(pending).resolves.toBeUndefined()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('ignores subscribe callbacks while validated is still false', async () => {
|
|
29
|
+
vi.useFakeTimers()
|
|
30
|
+
const listeners: Array<(value: boolean) => void> = []
|
|
31
|
+
const store = {
|
|
32
|
+
read: vi.fn(() => false),
|
|
33
|
+
readInitial: vi.fn(() => false),
|
|
34
|
+
subscribe: vi.fn((listener: (value: boolean) => void) => {
|
|
35
|
+
listeners.push(listener)
|
|
36
|
+
return () => {
|
|
37
|
+
const index = listeners.indexOf(listener)
|
|
38
|
+
if (index >= 0) {
|
|
39
|
+
listeners.splice(index, 1)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}),
|
|
43
|
+
set: vi.fn(),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const pending = waitForSessionValidated(store, SESSION_VALIDATION_WAIT_MS)
|
|
47
|
+
|
|
48
|
+
// Emit false — should not resolve yet
|
|
49
|
+
for (const listener of listeners) {
|
|
50
|
+
listener(false)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await vi.advanceTimersByTimeAsync(SESSION_VALIDATION_WAIT_MS)
|
|
54
|
+
await expect(pending).resolves.toBeUndefined()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('resolves on timeout when session never validates', async () => {
|
|
58
|
+
vi.useFakeTimers()
|
|
59
|
+
const store = createBaseStore(false)
|
|
60
|
+
|
|
61
|
+
const pending = waitForSessionValidated(store, SESSION_VALIDATION_WAIT_MS)
|
|
62
|
+
|
|
63
|
+
await vi.advanceTimersByTimeAsync(SESSION_VALIDATION_WAIT_MS)
|
|
64
|
+
|
|
65
|
+
await expect(pending).resolves.toBeUndefined()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('resolves the race when validation finishes between read and subscribe', async () => {
|
|
69
|
+
let current = false
|
|
70
|
+
const listeners: Array<(value: boolean) => void> = []
|
|
71
|
+
|
|
72
|
+
const store = {
|
|
73
|
+
read: vi.fn(() => {
|
|
74
|
+
// First read: not validated. Second read (post-subscribe): validated.
|
|
75
|
+
const value = current
|
|
76
|
+
current = true
|
|
77
|
+
return value
|
|
78
|
+
}),
|
|
79
|
+
readInitial: vi.fn(() => false),
|
|
80
|
+
subscribe: vi.fn((listener: (value: boolean) => void) => {
|
|
81
|
+
listeners.push(listener)
|
|
82
|
+
return () => {
|
|
83
|
+
const index = listeners.indexOf(listener)
|
|
84
|
+
if (index >= 0) {
|
|
85
|
+
listeners.splice(index, 1)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
89
|
+
set: vi.fn(),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await expect(waitForSessionValidated(store, 5_000)).resolves.toBeUndefined()
|
|
93
|
+
expect(store.subscribe).toHaveBeenCalledTimes(1)
|
|
94
|
+
expect(store.read).toHaveBeenCalledTimes(2)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import type { Session } from '@faststore/sdk'
|
|
3
|
+
import { syncSalesChannelFromOrderForm } from '../../../src/sdk/session/syncSalesChannelFromOrderForm'
|
|
4
|
+
|
|
5
|
+
const baseSession = (
|
|
6
|
+
salesChannel: string,
|
|
7
|
+
explicit = true,
|
|
8
|
+
channelOverride?: string | null
|
|
9
|
+
): Session => ({
|
|
10
|
+
currency: { code: 'BRL', symbol: 'R$' },
|
|
11
|
+
locale: 'pt-BR',
|
|
12
|
+
country: 'BRA',
|
|
13
|
+
channel:
|
|
14
|
+
channelOverride !== undefined
|
|
15
|
+
? channelOverride
|
|
16
|
+
: JSON.stringify({
|
|
17
|
+
salesChannel,
|
|
18
|
+
regionId: '',
|
|
19
|
+
hasOnlyDefaultSalesChannel: !explicit,
|
|
20
|
+
}),
|
|
21
|
+
deliveryMode: null,
|
|
22
|
+
addressType: null,
|
|
23
|
+
city: null,
|
|
24
|
+
postalCode: null,
|
|
25
|
+
geoCoordinates: null,
|
|
26
|
+
person: null,
|
|
27
|
+
b2b: null,
|
|
28
|
+
marketingData: null,
|
|
29
|
+
refreshAfter: null,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('syncSalesChannelFromOrderForm', () => {
|
|
33
|
+
it('updates session channel silently when SC diverges', () => {
|
|
34
|
+
const setSilent = vi.fn()
|
|
35
|
+
const synced = syncSalesChannelFromOrderForm(
|
|
36
|
+
'2',
|
|
37
|
+
() => baseSession('1', false),
|
|
38
|
+
setSilent
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
expect(synced).toBe(true)
|
|
42
|
+
expect(setSilent).toHaveBeenCalledTimes(1)
|
|
43
|
+
const next = setSilent.mock.calls[0][0] as Session
|
|
44
|
+
expect(JSON.parse(next.channel ?? '{}')).toMatchObject({
|
|
45
|
+
salesChannel: '2',
|
|
46
|
+
hasOnlyDefaultSalesChannel: false,
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('is a no-op when SC already matches', () => {
|
|
51
|
+
const setSilent = vi.fn()
|
|
52
|
+
const synced = syncSalesChannelFromOrderForm(
|
|
53
|
+
'2',
|
|
54
|
+
() => baseSession('2'),
|
|
55
|
+
setSilent
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
expect(synced).toBe(false)
|
|
59
|
+
expect(setSilent).not.toHaveBeenCalled()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('is a no-op when adopted SC is missing', () => {
|
|
63
|
+
const setSilent = vi.fn()
|
|
64
|
+
expect(
|
|
65
|
+
syncSalesChannelFromOrderForm(null, () => baseSession('1'), setSilent)
|
|
66
|
+
).toBe(false)
|
|
67
|
+
expect(
|
|
68
|
+
syncSalesChannelFromOrderForm('', () => baseSession('1'), setSilent)
|
|
69
|
+
).toBe(false)
|
|
70
|
+
expect(setSilent).not.toHaveBeenCalled()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('resets non-object channel JSON before adopting SC', () => {
|
|
74
|
+
const setSilent = vi.fn()
|
|
75
|
+
|
|
76
|
+
for (const invalid of ['null', '[]', '"text"', '0', 'false']) {
|
|
77
|
+
setSilent.mockClear()
|
|
78
|
+
const synced = syncSalesChannelFromOrderForm(
|
|
79
|
+
'2',
|
|
80
|
+
() => baseSession('1', true, invalid),
|
|
81
|
+
setSilent
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
expect(synced).toBe(true)
|
|
85
|
+
expect(JSON.parse(setSilent.mock.calls[0][0].channel)).toMatchObject({
|
|
86
|
+
salesChannel: '2',
|
|
87
|
+
hasOnlyDefaultSalesChannel: false,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('resets malformed channel JSON before adopting SC', () => {
|
|
93
|
+
const setSilent = vi.fn()
|
|
94
|
+
const synced = syncSalesChannelFromOrderForm(
|
|
95
|
+
'2',
|
|
96
|
+
() => baseSession('1', true, '{'),
|
|
97
|
+
setSilent
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
expect(synced).toBe(true)
|
|
101
|
+
expect(JSON.parse(setSilent.mock.calls[0][0].channel)).toMatchObject({
|
|
102
|
+
salesChannel: '2',
|
|
103
|
+
hasOnlyDefaultSalesChannel: false,
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('ignores object-valued salesChannel when comparing', () => {
|
|
108
|
+
const setSilent = vi.fn()
|
|
109
|
+
const synced = syncSalesChannelFromOrderForm(
|
|
110
|
+
'2',
|
|
111
|
+
() =>
|
|
112
|
+
baseSession(
|
|
113
|
+
'1',
|
|
114
|
+
true,
|
|
115
|
+
JSON.stringify({ salesChannel: { nested: true } })
|
|
116
|
+
),
|
|
117
|
+
setSilent
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
expect(synced).toBe(true)
|
|
121
|
+
expect(JSON.parse(setSilent.mock.calls[0][0].channel).salesChannel).toBe(
|
|
122
|
+
'2'
|
|
123
|
+
)
|
|
124
|
+
})
|
|
125
|
+
})
|