@faststore/core 4.9.0 → 4.9.1
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 +132 -136
- package/@generated/graphql.ts +1 -1
- package/@generated/schema.graphql +1 -1
- package/CHANGELOG.md +6 -0
- package/package.json +6 -6
- package/src/pages/[slug]/p.tsx +7 -6
- package/src/utils/productJsonLd.ts +100 -1
- package/test/utils/productJsonLd.test.ts +101 -1
- package/test/utils/productJsonLdRendering.test.tsx +24 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.9.0
|
|
2
|
+
> @faststore/core@4.9.0 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.9.0
|
|
6
|
+
> @faststore/core@4.9.0 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 @generated/
|
|
20
20
|
[32m[COMPLETED][39m Generate outputs
|
|
21
21
|
|
|
22
|
-
> @faststore/core@4.9.0
|
|
22
|
+
> @faststore/core@4.9.0 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.9.0
|
|
2
|
+
> @faststore/core@4.9.0 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
@@ -7,27 +7,25 @@
|
|
|
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
|
|
11
|
-
Browserslist: browsers data (caniuse-lite) is
|
|
10
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 991[2mms[22m[39m
|
|
11
|
+
Browserslist: browsers data (caniuse-lite) is 8 months old. Please run:
|
|
12
12
|
npx update-browserslist-db@latest
|
|
13
13
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
14
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/
|
|
15
|
-
[33m[2m✓[22m[39m shows
|
|
16
|
-
[33m[2m✓[22m[39m
|
|
17
|
-
[33m[2m✓[22m[39m
|
|
18
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/
|
|
19
|
-
[33m[2m✓[22m[39m shows
|
|
20
|
-
|
|
21
|
-
[33m[2m✓[22m[39m
|
|
22
|
-
[33m[2m✓[22m[39m
|
|
23
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
28
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
29
|
-
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 715[2mms[22m[39m
|
|
30
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
14
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[33m 2974[2mms[22m[39m
|
|
15
|
+
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m 681[2mms[22m[39m
|
|
16
|
+
[33m[2m✓[22m[39m requires selecting a contract before Confirm is enabled, then switches (REQ-03) [33m 370[2mms[22m[39m
|
|
17
|
+
[33m[2m✓[22m[39m keeps Confirm disabled until a different contract is selected [33m 346[2mms[22m[39m
|
|
18
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/cards/MyAccountListCards.browser.test.tsx [2m([22m[2m16 tests[22m[2m)[22m[33m 2099[2mms[22m[39m
|
|
19
|
+
[33m[2m✓[22m[39m shows the tab bar and renders Personal cards by default [33m 966[2mms[22m[39m
|
|
20
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/BuyingPolicyAlert.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 1905[2mms[22m[39m
|
|
21
|
+
[33m[2m✓[22m[39m opens the reject confirmation modal with the default English copy [33m 705[2mms[22m[39m
|
|
22
|
+
[33m[2m✓[22m[39m opens the reject confirmation modal with CMS-provided labels [33m 341[2mms[22m[39m
|
|
23
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartRecommendationShelf/CartRecommendationShelf.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[32m 221[2mms[22m[39m
|
|
24
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/useBindingSelector.browser.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[32m 139[2mms[22m[39m
|
|
25
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[33m 1489[2mms[22m[39m
|
|
26
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 815[2mms[22m[39m
|
|
27
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 90[2mms[22m[39m
|
|
28
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
31
29
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
|
|
32
30
|
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
|
|
33
31
|
[90m at node:internal/deps/undici/undici:16416:13[39m
|
|
@@ -54,16 +52,13 @@ Browserslist: browsers data (caniuse-lite) is 7 months old. Please run:
|
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
55
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 50[2mms[22m[39m
|
|
58
56
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
59
57
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
60
58
|
|
|
61
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
62
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
63
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
64
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDetails.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 129[2mms[22m[39m
|
|
65
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/Navbar.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 77[2mms[22m[39m
|
|
66
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
59
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 139[2mms[22m[39m
|
|
60
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartSidebar/CartSidebar.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 51[2mms[22m[39m
|
|
61
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDetails.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
67
62
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
68
63
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
69
64
|
|
|
@@ -101,6 +96,7 @@ act(() => {
|
|
|
101
96
|
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
|
|
102
97
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
103
98
|
|
|
99
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/Navbar.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 44[2mms[22m[39m
|
|
104
100
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mdefaults returnTo to root and shows API validation errors
|
|
105
101
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
106
102
|
|
|
@@ -293,8 +289,11 @@ act(() => {
|
|
|
293
289
|
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
|
|
294
290
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
295
291
|
|
|
296
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
297
|
-
[33m[2m✓[22m[39m renders the password protection form [33m
|
|
292
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 740[2mms[22m[39m
|
|
293
|
+
[33m[2m✓[22m[39m renders the password protection form [33m 431[2mms[22m[39m
|
|
294
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
295
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
296
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 319[2mms[22m[39m
|
|
298
297
|
[90mstderr[2m | test/components/cms/RenderSections.browser.test.tsx
|
|
299
298
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
300
299
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -303,10 +302,9 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
303
302
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
304
303
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
305
304
|
|
|
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/components/
|
|
309
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarSlider.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
305
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/cms/RenderSections.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
306
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarSlider.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
307
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/Menu.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 234[2mms[22m[39m
|
|
310
308
|
[90mstderr[2m | test/sdk/localization/store-url.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,15 +313,14 @@ 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:357: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/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
319
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
320
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
321
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
322
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
323
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarAccountArea.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
324
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
325
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
326
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
316
|
+
[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
|
|
317
|
+
[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
|
|
318
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
319
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.sessionFallback.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 125[2mms[22m[39m
|
|
320
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListQuotes.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 101[2mms[22m[39m
|
|
321
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarAccountArea.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 57[2mms[22m[39m
|
|
322
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartRecommendationShelf/CartRecommendationProductCard.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 35[2mms[22m[39m
|
|
323
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
327
324
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
328
325
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
329
326
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -332,8 +329,9 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
332
329
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
333
330
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
334
331
|
|
|
335
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
336
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
332
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 20[2mms[22m[39m
|
|
333
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 272[2mms[22m[39m
|
|
334
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/LocalizationButton.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
337
335
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
338
336
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
339
337
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -342,22 +340,21 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
342
340
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
343
341
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
344
342
|
|
|
345
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
346
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
347
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
348
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
349
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/
|
|
350
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/
|
|
351
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
352
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/
|
|
353
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/
|
|
354
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/StatusCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
355
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
356
|
-
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
343
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
344
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDelivery.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 61[2mms[22m[39m
|
|
345
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordion.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 74[2mms[22m[39m
|
|
346
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderStatus.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 90[2mms[22m[39m
|
|
347
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrdersList.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
348
|
+
[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
|
|
349
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/SummaryCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 65[2mms[22m[39m
|
|
350
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionDeliveryInfo.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
351
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationSignInButton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 182[2mms[22m[39m
|
|
352
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/StatusCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 86[2mms[22m[39m
|
|
353
|
+
[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
|
|
357
354
|
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
358
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryCard.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
359
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionProducts.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
360
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
355
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryCard.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
356
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionProducts.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
357
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
361
358
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
362
359
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
363
360
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -366,18 +363,18 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
366
363
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
367
364
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
368
365
|
|
|
369
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
366
|
+
[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
|
|
370
367
|
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
371
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/switch-contract.test.ts [2m([22m[2m25 tests[22m[2m)[22m[32m
|
|
372
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m
|
|
373
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
374
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/FilterFacetPendingApproval.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
375
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m
|
|
376
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m
|
|
377
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
368
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/switch-contract.test.ts [2m([22m[2m25 tests[22m[2m)[22m[32m 67[2mms[22m[39m
|
|
369
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
370
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
371
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/FilterFacetPendingApproval.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 167[2mms[22m[39m
|
|
372
|
+
[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
|
|
373
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 136[2mms[22m[39m
|
|
378
374
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
379
375
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
380
376
|
|
|
377
|
+
[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
|
|
381
378
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx[2m > [22m[2mSearchInput (OES integration)[2m > [22m[2mrenders without crashing
|
|
382
379
|
[22m[39mWarning: React does not recognize the `visibleDropdown` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `visibledropdown` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
|
|
383
380
|
at div
|
|
@@ -438,22 +435,22 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
438
435
|
at Suspense
|
|
439
436
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
440
437
|
|
|
441
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
442
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m15 tests[22m[2m)[22m[33m
|
|
438
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
439
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m15 tests[22m[2m)[22m[33m 350[2mms[22m[39m
|
|
443
440
|
[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
|
|
444
441
|
[22m[39m{ extensions: { status: [33m401[39m } }
|
|
445
442
|
|
|
446
443
|
[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
|
|
447
444
|
[22m[39m{ extensions: { status: [33m502[39m } }
|
|
448
445
|
|
|
449
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
450
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
451
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m
|
|
452
|
-
[33m[2m✓[22m[39m navigates with the search term on blur [33m
|
|
453
|
-
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m
|
|
454
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m26 tests[22m[2m)[22m[32m
|
|
455
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/
|
|
456
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
446
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
447
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
448
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m 798[2mms[22m[39m
|
|
449
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 360[2mms[22m[39m
|
|
450
|
+
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 356[2mms[22m[39m
|
|
451
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m26 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
452
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLd.test.ts [2m([22m[2m36 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
453
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
457
454
|
[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
|
|
458
455
|
[22m[39mGraphql execution returned with error: [
|
|
459
456
|
{
|
|
@@ -505,7 +502,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
505
502
|
|
|
506
503
|
[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
|
|
507
504
|
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
508
|
-
|
|
505
|
+
k [FastStoreError]: malformed
|
|
509
506
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:201:31
|
|
510
507
|
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:207:39
|
|
511
508
|
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
|
|
@@ -563,73 +560,72 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
563
560
|
at trace (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/test.B8ej_ZHS.js:239:21)
|
|
564
561
|
at runTest (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:12)
|
|
565
562
|
|
|
566
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m19 tests[22m[2m)[22m[32m
|
|
567
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
563
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m19 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
564
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
565
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 20[2mms[22m[39m
|
|
568
566
|
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
569
567
|
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
570
568
|
[22m[39mSet password request failed: Bad Request
|
|
571
569
|
|
|
572
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
573
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
574
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m
|
|
575
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
576
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
577
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
578
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
579
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
580
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/redirects/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
581
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
582
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
583
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
584
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
585
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
586
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
587
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
570
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
|
571
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
572
|
+
[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
|
|
573
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 137[2mms[22m[39m
|
|
574
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m14 tests[22m[2m)[22m[32m 130[2mms[22m[39m
|
|
575
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/hreflang.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
576
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
577
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[32m 94[2mms[22m[39m
|
|
578
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/redirects/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 50[2mms[22m[39m
|
|
579
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
580
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
581
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
582
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getDeliveryOptionLabel.test.ts [2m([22m[2m21 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
583
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/graphql/retryPolicy.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
584
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
585
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLdRendering.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
588
586
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/syncSalesChannelFromOrderForm.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
589
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
590
|
-
|
|
591
|
-
[33m[2m✓[22m[39m should handle options and execute [33m
|
|
592
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
593
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
594
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
595
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
596
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/StatusCard.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
|
587
|
+
[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
|
|
588
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 1039[2mms[22m[39m
|
|
589
|
+
[33m[2m✓[22m[39m should handle options and execute [33m 591[2mms[22m[39m
|
|
590
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
591
|
+
[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
|
|
592
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
593
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/StatusCard.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
597
594
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
598
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/cart/waitForSessionValidated.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
599
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
600
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/content/service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
601
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
602
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
603
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
604
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m
|
|
605
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
606
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
607
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
608
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
609
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
610
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
611
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
612
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
613
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
614
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
615
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
616
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
617
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
618
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/
|
|
619
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
620
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/
|
|
621
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getOrderTotalLabel.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
595
|
+
[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
|
|
596
|
+
[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
|
|
597
|
+
[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
|
|
598
|
+
[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
|
|
599
|
+
[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
|
|
600
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 55[2mms[22m[39m
|
|
601
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
602
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
603
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
604
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
605
|
+
[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
|
|
606
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
607
|
+
[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
|
|
608
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
609
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getB2BSessionClaims.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
610
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
611
|
+
[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
|
|
612
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
613
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
614
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
615
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
616
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
617
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/listOrdersLabels.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 2[2mms[22m[39m
|
|
618
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getOrderTotalLabel.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
622
619
|
[32m✓[39m [30m[43m node [49m[39m test/utils/getCookie.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
623
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/listOrdersLabels.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
624
620
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/isSignInAreaResolved.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
625
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
626
621
|
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
627
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
628
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/
|
|
629
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
622
|
+
[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
|
|
623
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
624
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/orderDetailsLabels.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
625
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
630
626
|
|
|
631
627
|
[2m Test Files [22m [1m[32m123 passed[39m[22m[90m (123)[39m
|
|
632
|
-
[2m Tests [22m [1m[
|
|
633
|
-
[2m Start at [22m 14:
|
|
634
|
-
[2m Duration [22m
|
|
628
|
+
[2m Tests [22m [1m[32m985 passed[39m[22m[90m (985)[39m
|
|
629
|
+
[2m Start at [22m 14:08:29
|
|
630
|
+
[2m Duration [22m 46.77s[2m (transform 11.26s, setup 0ms, import 41.54s, tests 17.36s, environment 57.52s)[22m
|
|
635
631
|
|
package/@generated/graphql.ts
CHANGED
|
@@ -1727,7 +1727,7 @@ export type StoreProduct = {
|
|
|
1727
1727
|
otherLocales: Maybe<Array<StoreProductLocale>>;
|
|
1728
1728
|
/** Product ID, such as [ISBN](https://www.isbn-international.org/content/what-isbn) or similar global IDs. */
|
|
1729
1729
|
productID: Scalars['String']['output'];
|
|
1730
|
-
/** The product's release date.
|
|
1730
|
+
/** The product's release date, passed through exactly as the catalog returns it, without validation or normalization. Usually epoch milliseconds (e.g. "1774224000000"), but some accounts store an ISO 8601 string, and the value may be empty. Parse and validate it before use. */
|
|
1731
1731
|
releaseDate: Scalars['String']['output'];
|
|
1732
1732
|
/** Array with review information. */
|
|
1733
1733
|
review: Array<StoreReview>;
|
|
@@ -1730,7 +1730,7 @@ type StoreProduct {
|
|
|
1730
1730
|
"""Array of additional properties."""
|
|
1731
1731
|
additionalProperty: [StorePropertyValue!]!
|
|
1732
1732
|
"""
|
|
1733
|
-
The product's release date.
|
|
1733
|
+
The product's release date, passed through exactly as the catalog returns it, without validation or normalization. Usually epoch milliseconds (e.g. "1774224000000"), but some accounts store an ISO 8601 string, and the value may be empty. Parse and validate it before use.
|
|
1734
1734
|
"""
|
|
1735
1735
|
releaseDate: String!
|
|
1736
1736
|
"""Sku Unit Multiplier"""
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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.9.1](https://github.com/vtex/faststore/compare/v4.9.0...v4.9.1) (2026-10-02)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- restore raw StoreProduct.releaseDate, normalize only in PDP JSON-LD ([#3508](https://github.com/vtex/faststore/issues/3508)) ([fb0112d](https://github.com/vtex/faststore/commit/fb0112df966dc59b8971c335bcb5fd405b715763)), closes [#3465](https://github.com/vtex/faststore/issues/3465) [#3465](https://github.com/vtex/faststore/issues/3465) [#1438](https://github.com/vtex/faststore/issues/1438) [#3437](https://github.com/vtex/faststore/issues/3437)
|
|
11
|
+
|
|
6
12
|
# [4.9.0](https://github.com/vtex/faststore/compare/v4.9.0-dev.8...v4.9.0) (2026-09-30)
|
|
7
13
|
|
|
8
14
|
**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.9.
|
|
3
|
+
"version": "4.9.1",
|
|
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/api": "4.9.
|
|
75
|
-
"@faststore/
|
|
76
|
-
"@faststore/
|
|
77
|
-
"@faststore/
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/api": "4.9.1",
|
|
75
|
+
"@faststore/diagnostics": "4.9.1",
|
|
76
|
+
"@faststore/sdk": "4.9.1",
|
|
77
|
+
"@faststore/lighthouse": "4.9.1",
|
|
78
|
+
"@faststore/ui": "4.9.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
package/src/pages/[slug]/p.tsx
CHANGED
|
@@ -30,7 +30,10 @@ import { execute } from 'src/server'
|
|
|
30
30
|
import { getComponentKey } from 'src/utils/cms'
|
|
31
31
|
import { getChannelForLocale } from 'src/utils/localization/bindingPaths'
|
|
32
32
|
import { buildHreflangLinks } from 'src/utils/localization/hreflang'
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
toProductJsonLdIdentifiers,
|
|
35
|
+
toProductJsonLdOffer,
|
|
36
|
+
} from 'src/utils/productJsonLd'
|
|
34
37
|
|
|
35
38
|
import storeConfig from 'discovery.config'
|
|
36
39
|
import {
|
|
@@ -295,11 +298,9 @@ function Page({
|
|
|
295
298
|
description={description}
|
|
296
299
|
brand={product.brand.name}
|
|
297
300
|
sku={product.sku}
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
{...(product
|
|
301
|
-
{...(product.mpn && { mpn: product.mpn })}
|
|
302
|
-
{...(product.releaseDate && { releaseDate: product.releaseDate })}
|
|
301
|
+
// Omits empty identifiers and normalizes releaseDate to ISO 8601; see
|
|
302
|
+
// toProductJsonLdIdentifiers.
|
|
303
|
+
{...toProductJsonLdIdentifiers(product)}
|
|
303
304
|
images={product.image.map((img) => img.url)} // Somehow, Google does not understand this valid Schema.org schema, so we need to do conversions
|
|
304
305
|
{...(offers && { offers })}
|
|
305
306
|
{...(itemListElements.length !== 0 && {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ServerProductQueryQuery } from '@generated/graphql'
|
|
2
2
|
|
|
3
|
-
type
|
|
3
|
+
type ServerProduct = ServerProductQueryQuery['product']
|
|
4
|
+
type ServerOffers = ServerProduct['offers']
|
|
4
5
|
type ServerOffer = ServerOffers['offers'][number]
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -69,3 +70,101 @@ export const toProductJsonLdOffer = (
|
|
|
69
70
|
|
|
70
71
|
return offer
|
|
71
72
|
}
|
|
73
|
+
|
|
74
|
+
// Epoch values are disambiguated by magnitude, not digit count: anything at or
|
|
75
|
+
// above this is milliseconds (>= 1973-03-03), anything below is seconds. A
|
|
76
|
+
// millisecond value under the threshold is read as seconds — accepted, since no
|
|
77
|
+
// real catalog carries a release date that early, and a digit-count heuristic
|
|
78
|
+
// leaves a strictly larger hole (9-digit seconds and 12-digit milliseconds both
|
|
79
|
+
// fall through to the string parser, which reads them as a year).
|
|
80
|
+
const MILLISECONDS_THRESHOLD = 1e11
|
|
81
|
+
|
|
82
|
+
const isAllDigits = (value: string) => /^\d+$/.test(value)
|
|
83
|
+
|
|
84
|
+
// An ISO date-time with no timezone designator. `new Date()` reads these as
|
|
85
|
+
// host-local time (date-only forms are already read as UTC), which would make
|
|
86
|
+
// the emitted calendar day depend on the build machine's zone.
|
|
87
|
+
const ISO_DATE_TIME_WITHOUT_ZONE =
|
|
88
|
+
/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/
|
|
89
|
+
|
|
90
|
+
const toDate = (value: string): Date => {
|
|
91
|
+
if (!isAllDigits(value)) {
|
|
92
|
+
return new Date(
|
|
93
|
+
ISO_DATE_TIME_WITHOUT_ZONE.test(value) ? `${value}Z` : value
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const epoch = Number(value)
|
|
98
|
+
|
|
99
|
+
return new Date(epoch >= MILLISECONDS_THRESHOLD ? epoch : epoch * 1000)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Normalizes `StoreProduct.releaseDate` to the ISO 8601 calendar date
|
|
104
|
+
* (`YYYY-MM-DD`) Schema.org expects for the PDP's `ProductJsonLd`.
|
|
105
|
+
*
|
|
106
|
+
* The API passes the field through as Intelligent Search delivers it — epoch
|
|
107
|
+
* milliseconds for most accounts, an ISO string for others — because stores
|
|
108
|
+
* read that raw value in their own customizations. Normalizing here, and only
|
|
109
|
+
* here, keeps the structured data valid without changing that contract.
|
|
110
|
+
*
|
|
111
|
+
* Accepts epoch milliseconds, epoch seconds, and date strings. Returns an empty
|
|
112
|
+
* string when the input is absent or unparseable — never throws, and never
|
|
113
|
+
* returns `"Invalid Date"`.
|
|
114
|
+
*
|
|
115
|
+
* The calendar day is always taken in UTC, so a build produces the same markup
|
|
116
|
+
* on any machine. An input carrying a timezone offset is converted first, which
|
|
117
|
+
* means `2026-03-23T21:00:00-05:00` normalizes to `2026-03-24`. That is
|
|
118
|
+
* deliberate: preserving the source calendar day would make the output depend on
|
|
119
|
+
* the offset embedded in each record. An input with no timezone designator is
|
|
120
|
+
* read as UTC rather than as host-local time, for the same reason.
|
|
121
|
+
*/
|
|
122
|
+
export const toProductJsonLdReleaseDate = (
|
|
123
|
+
value: string | number | null | undefined
|
|
124
|
+
): string => {
|
|
125
|
+
if (value === null || value === undefined) {
|
|
126
|
+
return ''
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const raw = String(value).trim()
|
|
130
|
+
|
|
131
|
+
if (raw === '') {
|
|
132
|
+
return ''
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const date = toDate(raw)
|
|
136
|
+
|
|
137
|
+
if (Number.isNaN(date.getTime())) {
|
|
138
|
+
return ''
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return date.toISOString().slice(0, 10)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Builds the identifier props (`gtin`, `mpn`, `releaseDate`) for the PDP's
|
|
146
|
+
* `ProductJsonLd`, ready to spread.
|
|
147
|
+
*
|
|
148
|
+
* Every key is omitted when its value is empty, because next-seo publishes
|
|
149
|
+
* props untouched and an empty string is invalid Schema.org. `releaseDate` is
|
|
150
|
+
* normalized here because `StoreProduct.releaseDate` is the raw upstream value
|
|
151
|
+
* (usually epoch milliseconds), which Schema.org consumers reject.
|
|
152
|
+
*
|
|
153
|
+
* This lives here rather than inline in `p.tsx` so the rendering tests exercise
|
|
154
|
+
* the same code the page runs: passing `product.releaseDate` straight through
|
|
155
|
+
* would publish `"1774224000000"` and still leave a unit test of the
|
|
156
|
+
* normalizer green.
|
|
157
|
+
*/
|
|
158
|
+
export const toProductJsonLdIdentifiers = ({
|
|
159
|
+
gtin,
|
|
160
|
+
mpn,
|
|
161
|
+
releaseDate,
|
|
162
|
+
}: Pick<ServerProduct, 'gtin' | 'mpn' | 'releaseDate'>) => {
|
|
163
|
+
const normalizedReleaseDate = toProductJsonLdReleaseDate(releaseDate)
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
...(gtin && { gtin }),
|
|
167
|
+
...(mpn && { mpn }),
|
|
168
|
+
...(normalizedReleaseDate && { releaseDate: normalizedReleaseDate }),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
toProductJsonLdIdentifiers,
|
|
4
|
+
toProductJsonLdOffer,
|
|
5
|
+
toProductJsonLdReleaseDate,
|
|
6
|
+
} from '../../src/utils/productJsonLd'
|
|
3
7
|
|
|
4
8
|
const OBJECT_LEVEL = { priceCurrency: 'USD', url: 'https://store.example/p' }
|
|
5
9
|
|
|
@@ -124,3 +128,99 @@ describe('toProductJsonLdOffer', () => {
|
|
|
124
128
|
).toBeUndefined()
|
|
125
129
|
})
|
|
126
130
|
})
|
|
131
|
+
|
|
132
|
+
describe('toProductJsonLdReleaseDate', () => {
|
|
133
|
+
const resolve = toProductJsonLdReleaseDate
|
|
134
|
+
|
|
135
|
+
it('converts epoch milliseconds to an ISO calendar date', () => {
|
|
136
|
+
expect(resolve('1774224000000')).toBe('2026-03-23')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('converts epoch seconds to the same date as its millisecond form', () => {
|
|
140
|
+
expect(resolve('1774224000')).toBe(resolve('1774224000000'))
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('reads a value at the millisecond threshold as milliseconds', () => {
|
|
144
|
+
expect(resolve('100000000000')).toBe('1973-03-03')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('reads a value just below the threshold as seconds', () => {
|
|
148
|
+
expect(resolve('99999999999')).toBe('5138-11-16')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('accepts a numeric epoch, not only its string form', () => {
|
|
152
|
+
expect(resolve(1774224000000)).toBe('2026-03-23')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('passes an ISO date through unchanged', () => {
|
|
156
|
+
expect(resolve('2026-03-23')).toBe('2026-03-23')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('truncates an ISO datetime to its calendar date', () => {
|
|
160
|
+
expect(resolve('2026-03-23T14:30:00Z')).toBe('2026-03-23')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// UTC is deliberate: preserving the source calendar day would make the
|
|
164
|
+
// output depend on the offset embedded in each record.
|
|
165
|
+
it('resolves an offset that crosses midnight to the UTC day', () => {
|
|
166
|
+
expect(resolve('2026-03-23T21:00:00-05:00')).toBe('2026-03-24')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// `new Date(...)` reads an ISO date-time with no timezone designator as
|
|
170
|
+
// host-local, so without explicit handling this value resolves to the day
|
|
171
|
+
// before in any zone ahead of UTC. The build machine must not change the
|
|
172
|
+
// markup.
|
|
173
|
+
it('reads an ISO date-time with no timezone as UTC, not host-local', () => {
|
|
174
|
+
expect(resolve('2026-03-23T00:30:00')).toBe('2026-03-23')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('reads an end-of-day ISO date-time with no timezone as UTC', () => {
|
|
178
|
+
expect(resolve('2026-03-23T23:30:00')).toBe('2026-03-23')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it.each([
|
|
182
|
+
['an empty string', ''],
|
|
183
|
+
['whitespace', ' '],
|
|
184
|
+
['an unparseable value', 'not-a-date'],
|
|
185
|
+
['null', null],
|
|
186
|
+
['undefined', undefined],
|
|
187
|
+
])('returns an empty string for %s', (_label, input) => {
|
|
188
|
+
expect(resolve(input)).toBe('')
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('never returns "Invalid Date"', () => {
|
|
192
|
+
expect(resolve('garbage')).not.toContain('Invalid')
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
describe('toProductJsonLdIdentifiers', () => {
|
|
197
|
+
it('normalizes an epoch releaseDate to an ISO calendar date', () => {
|
|
198
|
+
expect(
|
|
199
|
+
toProductJsonLdIdentifiers({
|
|
200
|
+
gtin: '0012345678905',
|
|
201
|
+
mpn: 'MPN-1',
|
|
202
|
+
releaseDate: '1774224000000',
|
|
203
|
+
})
|
|
204
|
+
).toEqual({
|
|
205
|
+
gtin: '0012345678905',
|
|
206
|
+
mpn: 'MPN-1',
|
|
207
|
+
releaseDate: '2026-03-23',
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('omits every identifier that is empty', () => {
|
|
212
|
+
expect(
|
|
213
|
+
toProductJsonLdIdentifiers({ gtin: '', mpn: '', releaseDate: '' })
|
|
214
|
+
).toEqual({})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('omits a releaseDate that cannot be parsed', () => {
|
|
218
|
+
expect(
|
|
219
|
+
toProductJsonLdIdentifiers({
|
|
220
|
+
gtin: '',
|
|
221
|
+
mpn: '',
|
|
222
|
+
releaseDate: 'not-a-date',
|
|
223
|
+
})
|
|
224
|
+
).toEqual({})
|
|
225
|
+
})
|
|
226
|
+
})
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { ProductJsonLd } from 'next-seo'
|
|
2
2
|
import { renderToStaticMarkup } from 'react-dom/server'
|
|
3
3
|
import { describe, expect, it } from 'vitest'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
toProductJsonLdIdentifiers,
|
|
6
|
+
toProductJsonLdOffer,
|
|
7
|
+
} from '../../src/utils/productJsonLd'
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Pins the next-seo behaviour the PDP's JSON-LD depends on.
|
|
8
11
|
*
|
|
9
|
-
* `p.tsx` omits `mpn`, `gtin` and `releaseDate`
|
|
10
|
-
* than passing empty strings, and drops
|
|
11
|
-
* choices only work because of how next-seo builds the script — it forwards
|
|
12
|
+
* `p.tsx` omits empty `mpn`, `gtin` and `releaseDate` (via
|
|
13
|
+
* `toProductJsonLdIdentifiers`) rather than passing empty strings, and drops
|
|
14
|
+
* `seller` from the offer allowlist. Both choices only work because of how next-seo builds the script — it forwards
|
|
12
15
|
* unknown props untouched (so `""` would be published) and turns any truthy
|
|
13
16
|
* `seller` into an `Organization`, even when it has no name. A next-seo upgrade
|
|
14
17
|
* that changed either would silently reintroduce the defects from ticket
|
|
@@ -71,4 +74,21 @@ describe('next-seo ProductJsonLd contract', () => {
|
|
|
71
74
|
url: 'https://store.example/p',
|
|
72
75
|
})
|
|
73
76
|
})
|
|
77
|
+
|
|
78
|
+
// `p.tsx` spreads `toProductJsonLdIdentifiers(product)` into ProductJsonLd,
|
|
79
|
+
// and `StoreProduct.releaseDate` is the raw upstream epoch. This pins what
|
|
80
|
+
// actually lands in the published script for that input.
|
|
81
|
+
it('publishes an epoch releaseDate as an ISO calendar date', () => {
|
|
82
|
+
const jsonLd = renderJsonLd(
|
|
83
|
+
toProductJsonLdIdentifiers({
|
|
84
|
+
gtin: '',
|
|
85
|
+
mpn: '',
|
|
86
|
+
releaseDate: '1774224000000',
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
expect(jsonLd.releaseDate).toBe('2026-03-23')
|
|
91
|
+
expect(jsonLd).not.toHaveProperty('gtin')
|
|
92
|
+
expect(jsonLd).not.toHaveProperty('mpn')
|
|
93
|
+
})
|
|
74
94
|
})
|