@faststore/core 4.5.1-dev.4 → 4.6.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
 
2
- > @faststore/core@4.5.1-dev.3 generate /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.5.1-dev.4 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.5.1-dev.3 gen-types /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@4.5.1-dev.4 gen-types /home/runner/work/faststore/faststore/packages/core
7
7
  > node ../cli/bin/run generate-types .
8
8
 
9
9
  [STARTED] Parse Configuration
@@ -19,7 +19,7 @@
19
19
  [COMPLETED] Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
20
20
  [COMPLETED] Generate outputs
21
21
 
22
- > @faststore/core@4.5.1-dev.3 cache-graphql /home/runner/work/faststore/faststore/packages/core
22
+ > @faststore/core@4.5.1-dev.4 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
@@ -1,11 +1,11 @@
1
1
 
2
- > @faststore/core@4.5.1-dev.3 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.5.1-dev.4 test /home/runner/work/faststore/faststore/packages/core
3
3
  > vitest run
4
4
 
5
5
 
6
-  RUN  v4.0.7 /home/runner/work/faststore/faststore/packages/core
6
+  RUN  v4.0.18 /home/runner/work/faststore/faststore/packages/core
7
7
 
8
- ✓  browser  test/sdk/session/reconcileSessionLocale.browser.test.ts (5 tests) 25ms
8
+ ✓  browser  test/sdk/session/reconcileSessionLocale.browser.test.ts (5 tests) 36ms
9
9
  stderr | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
10
10
  Error in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=8199d03debb0a6751ec53d8ee8987b78d0292acb
11
11
   at node:internal/deps/undici/undici:16416:13
@@ -18,7 +18,7 @@
18
18
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:17) {
19
19
  [cause]: TypeError: Invalid URL
20
20
   at new URL (node:internal/url:828:25)
21
- at new URL$1 (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/vitest@4.0.7_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sass@1.97.3_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vitest/dist/chunks/index.CWIFvlX5.js:469:9)
21
+ at new URL$1 (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/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/vitest/dist/chunks/index.CyBMJtT7.js:556:9)
22
22
   at new Request (node:internal/deps/undici/undici:10971:25)
23
23
   at fetch (node:internal/deps/undici/undici:11891:25)
24
24
   at fetch (node:internal/deps/undici/undici:16414:10)
@@ -35,12 +35,12 @@
35
35
  Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
36
36
  npx update-browserslist-db@latest
37
37
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
38
- ✓  browser  test/components/account/ContractSwitcher.browser.test.tsx (13 tests) 1958ms
39
- ✓ shows an error state when the list fails to load  633ms
40
38
  stderr | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx > RecommendationShelf > renders nothing when there is an error
41
39
  Error fetching recommendations undefined boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
42
40
 
43
- ✓  browser  test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx (8 tests) 186ms
41
+ ✓  browser  test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx (8 tests) 283ms
42
+ ✓  browser  test/components/account/ContractSwitcher.browser.test.tsx (13 tests) 2139ms
43
+ ✓ shows an error state when the list fails to load  585ms
44
44
  stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > posts the password and redirects to the requested return path
45
45
  Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
46
46
 
@@ -270,13 +270,12 @@ act(() => {
270
270
  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
271
271
  at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
272
272
 
273
- ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1405ms
274
- ✓ renders the password protection form  561ms
275
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 32ms
273
+ ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1851ms
274
+ ✓ renders the password protection form  789ms
275
+ ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 29ms
276
276
  ✓  browser  test/sdk/account/changeContractToken.browser.test.ts (9 tests) 80ms
277
- ✓  browser  test/components/account/OrganizationDrawer.browser.test.tsx (5 tests) 2162ms
278
- ✓ renders the menu view with contract details and manage footer  1261ms
279
- ✓ opens the contract switcher and returns to the menu on back  397ms
277
+ ✓  browser  test/components/account/OrganizationDrawer.browser.test.tsx (5 tests) 1109ms
278
+ ✓ renders the menu view with contract details and manage footer  577ms
280
279
  stderr | test/sdk/localization/store-url.browser.test.ts
281
280
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
282
281
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
@@ -284,9 +283,9 @@ This ensures that you're testing the behavior the user would see in the browser.
284
283
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
285
284
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
286
285
 
287
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 12ms
288
- ✓  browser  test/sdk/account/useAvailableContracts.browser.test.ts (6 tests) 91ms
289
- ✓  browser  test/sdk/account/useSwitchContract.browser.test.ts (4 tests) 132ms
286
+ ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 17ms
287
+ ✓  browser  test/sdk/account/useSwitchContract.browser.test.ts (4 tests) 119ms
288
+ ✓  browser  test/sdk/account/useAvailableContracts.browser.test.ts (6 tests) 74ms
290
289
  stderr | test/components/account/doLogout.browser.test.ts
291
290
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
292
291
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
@@ -294,9 +293,9 @@ This ensures that you're testing the behavior the user would see in the browser.
294
293
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
295
294
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
296
295
 
297
- ✓  browser  test/components/account/doLogout.browser.test.ts (1 test) 71ms
298
- ✓  browser  test/components/account/OrganizationDrawerHeader.browser.test.tsx (3 tests) 265ms
299
- ✓  browser  test/components/account/OrganizationDrawerFooter.browser.test.tsx (3 tests) 255ms
296
+ ✓  browser  test/components/account/doLogout.browser.test.ts (1 test) 31ms
297
+ ✓  browser  test/components/account/OrganizationDrawerHeader.browser.test.tsx (3 tests) 251ms
298
+ ✓  browser  test/components/account/OrganizationDrawerFooter.browser.test.tsx (3 tests) 306ms
300
299
  stderr | test/sdk/account/clearPersistedSessionState.browser.test.ts
301
300
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
302
301
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
@@ -304,11 +303,12 @@ This ensures that you're testing the behavior the user would see in the browser.
304
303
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
305
304
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
306
305
 
307
- ✓  browser  test/sdk/account/clearPersistedSessionState.browser.test.ts (1 test) 9ms
308
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 3ms
309
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 19ms
306
+ ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 5ms
307
+ ✓  browser  test/sdk/account/clearPersistedSessionState.browser.test.ts (1 test) 7ms
310
308
  ✓  browser  test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts (1 test) 3ms
311
- ✓  node  test/server/password-protection-service.test.ts (22 tests) 31ms
309
+ ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 27ms
310
+ ✓  node  test/server/password-protection-service.test.ts (22 tests) 35ms
311
+ ✓  node  test/utils/match-url.test.ts (10 tests) 9ms
312
312
  stderr | test/sdk/account/refreshToken.browser.test.ts
313
313
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
314
314
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
@@ -316,11 +316,10 @@ This ensures that you're testing the behavior the user would see in the browser.
316
316
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
317
317
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
318
318
 
319
- ✓  node  test/utils/match-url.test.ts (10 tests) 10ms
320
- ✓  browser  test/sdk/account/refreshToken.browser.test.ts (1 test) 7ms
321
- ✓  node  test/sdk/localization/useBindingSelector.test.tsx (22 tests) 15ms
322
- ✓  node  test/pages/api/unlock.test.ts (15 tests) 201ms
323
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 9ms
319
+ ✓  node  test/sdk/localization/useBindingSelector.test.tsx (22 tests) 13ms
320
+ ✓  browser  test/sdk/account/refreshToken.browser.test.ts (1 test) 5ms
321
+ ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 10ms
322
+ ✓  node  test/pages/api/unlock.test.ts (15 tests) 147ms
324
323
  stderr | test/components/search/SearchInputComponent.test.tsx
325
324
  Warning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
326
325
 
@@ -385,22 +384,11 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
385
384
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
386
385
 
387
386
  ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 84ms
388
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 11ms
387
+ ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 9ms
389
388
  ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 54ms
390
- ✓  node  test/experimental/myAccountCmsServerSideProps.test.ts (5 tests) 9ms
391
- ✓  node  test/utils/clearCookies.test.ts (20 tests) 19ms
392
- stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
393
- Set password request failed: Bad Request
394
-
395
- ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 51ms
396
- ✓  node  test/components/quotes/MyAccountListQuotesTable.test.tsx (12 tests) 427ms
397
- ✓  node  test/components/quotes/quoteFilters.test.ts (23 tests) 33ms
398
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 5ms
399
- ✓  node  test/utils/localization/localizeRedirectDestination.test.ts (11 tests) 5ms
400
- ✓  node  test/components/quotes/MyAccountListQuotes.test.tsx (9 tests) 818ms
401
- ✓ navigates with the search term on blur  370ms
402
- ✓ navigates without a label param when the search is cleared  358ms
403
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 43ms
389
+ ✓  node  test/experimental/myAccountCmsServerSideProps.test.ts (5 tests) 10ms
390
+ ✓  node  test/utils/clearCookies.test.ts (20 tests) 29ms
391
+ ✓  node  test/components/quotes/MyAccountListQuotesTable.test.tsx (12 tests) 386ms
404
392
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
405
393
  Graphql execution returned with error: [
406
394
  {
@@ -447,47 +435,107 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
447
435
  { message: 'bad', status: 400, type: 'BadRequestError' }
448
436
  ]
449
437
 
450
- ✓  node  test/pages/api/graphql.test.ts (10 tests) 17ms
451
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 46ms
452
- ✓  node  test/sdk/analytics/useStartRecommendationSession.test.ts (6 tests) 58ms
453
- ✓  node  test/components/quotes/MyAccountQuotesFilterSlider.test.tsx (5 tests) 148ms
454
- ✓  node  test/proxy.localization.test.ts (5 tests) 40ms
455
- ✓  node  test/server/index.test.ts (7 tests) 708ms
456
- ✓  node  test/sdk/account/getMyAccountRoutes.test.ts (10 tests) 8ms
457
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 43ms
458
- ✓  node  test/proxy.test.ts (4 tests) 25ms
459
- ✓  node  test/server/webops-api.test.ts (9 tests) 28ms
460
- ✓  node  test/components/quotes/MyAccountQuotesSelectedTags.test.tsx (8 tests) 105ms
461
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 41ms
462
- ✓  node  test/sdk/account/refreshToken.test.ts (5 tests) 7ms
463
- ✓  node  test/server/cms/global.test.ts (3 tests) 4ms
464
- ✓  node  test/server/content/service.test.ts (5 tests) 10ms
438
+ stderr | test/pages/api/graphql.test.ts > /api/graphql request handling > maps BadRequestError thrown by execute to its status
439
+ Something unexpected occurred querying Graphql endpoint:
440
+ _ [FastStoreError]: malformed
441
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:190:31
442
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:196:39
443
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1024:60
444
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:145:11
445
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:915:26
446
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1243:20
447
+ at new Promise (<anonymous>)
448
+ at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1209:10)
449
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1653:37
450
+ at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/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/vitest/dist/chunks/traces.CCmnQaNT.js:142:27) {
451
+ extensions: { status: 400, type: 'BadRequestError' }
452
+ }
453
+
454
+ stderr | test/pages/api/graphql.test.ts > /api/graphql request handling > maps UnauthorizedError thrown by execute to its status
455
+ Something unexpected occurred querying Graphql endpoint:
456
+ te [FastStoreError]: expired
457
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:191:33
458
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:196:39
459
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1024:60
460
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:145:11
461
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:915:26
462
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1243:20
463
+ at new Promise (<anonymous>)
464
+ at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1209:10)
465
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1653:37
466
+ at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/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/vitest/dist/chunks/traces.CCmnQaNT.js:142:27) {
467
+ extensions: { status: 401, type: 'UnauthorizedError' }
468
+ }
469
+
470
+ stderr | test/pages/api/graphql.test.ts > /api/graphql request handling > maps an unexpected failure thrown by execute to its status
471
+ Something unexpected occurred querying Graphql endpoint:
472
+ Error: socket hang up
473
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:192:37
474
+ at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:196:39
475
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1024:60
476
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:145:11
477
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:915:26
478
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1243:20
479
+ at new Promise (<anonymous>)
480
+ at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1209:10)
481
+ at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1653:37
482
+ at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/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/vitest/dist/chunks/traces.CCmnQaNT.js:142:27)
483
+
484
+ ✓  node  test/pages/api/graphql.test.ts (17 tests) 20ms
485
+ stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
486
+ Set password request failed: Bad Request
487
+
488
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 29ms
489
+ ✓  node  test/components/quotes/MyAccountListQuotes.test.tsx (9 tests) 842ms
490
+ ✓ navigates with the search term on blur  362ms
491
+ ✓ navigates without a label param when the search is cleared  364ms
492
+ ✓  node  test/components/quotes/quoteFilters.test.ts (23 tests) 35ms
493
+ ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 6ms
494
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 30ms
495
+ ✓  node  test/utils/localization/localizeRedirectDestination.test.ts (11 tests) 5ms
496
+ ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 71ms
497
+ ✓  node  test/components/quotes/MyAccountQuotesFilterSlider.test.tsx (5 tests) 125ms
498
+ ✓  node  test/sdk/analytics/useStartRecommendationSession.test.ts (6 tests) 45ms
499
+ ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 40ms
500
+ ✓  node  test/proxy.localization.test.ts (5 tests) 45ms
501
+ ✓  node  test/server/index.test.ts (7 tests) 830ms
502
+ ✓ should handle options and execute  313ms
503
+ ✓  node  test/sdk/account/getMyAccountRoutes.test.ts (10 tests) 9ms
504
+ ✓  node  test/proxy.test.ts (4 tests) 14ms
505
+ ✓  node  test/server/webops-api.test.ts (9 tests) 15ms
506
+ ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 46ms
507
+ ✓  node  test/server/content/service.test.ts (5 tests) 5ms
508
+ ✓  node  test/components/quotes/MyAccountQuotesSelectedTags.test.tsx (8 tests) 103ms
509
+ ✓  node  test/sdk/account/refreshToken.test.ts (5 tests) 9ms
510
+ ✓  node  test/server/cms/global.test.ts (3 tests) 5ms
465
511
  ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
466
- ✓  node  test/sdk/analytics/hasEnabledRecommendationShelf.test.ts (6 tests) 5ms
467
512
  ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 27ms
468
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 5ms
469
- ✓  node  test/components/quotes/MyAccountQuotesStatusSelector.test.tsx (6 tests) 134ms
470
- ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 3ms
513
+ ✓  node  test/components/quotes/MyAccountQuotesStatusSelector.test.tsx (6 tests) 120ms
514
+ ✓  node  test/sdk/analytics/hasEnabledRecommendationShelf.test.ts (6 tests) 5ms
515
+ ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 7ms
516
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 9ms
517
+ ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 5ms
518
+ ✓  node  test/server/rootSpan.test.ts (4 tests) 31ms
471
519
  ✓  node  test/components/search/SearchInput.test.ts (6 tests) 8ms
472
- ✓  node  test/pages/api/preview.test.ts (2 tests) 8ms
473
520
  ✓  node  test/components/RecommendationShelf/vrn.test.ts (5 tests) 4ms
474
- ✓  node  test/server/cms/index.test.ts (2 tests) 5ms
475
- ✓  node  test/utils/retry.test.ts (5 tests) 14ms
476
- ✓  node  test/components/RecommendationShelf/useRecommendationUserId.test.ts (4 tests) 197ms
477
- ✓  node  test/components/account/Layout.test.tsx (4 tests) 52ms
478
- ✓  node  test/utils/unlockResponse.test.ts (11 tests) 6ms
521
+ ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
522
+ ✓  node  test/utils/retry.test.ts (5 tests) 13ms
523
+ ✓  node  test/components/account/Layout.test.tsx (4 tests) 39ms
524
+ ✓  node  test/components/RecommendationShelf/useRecommendationUserId.test.ts (4 tests) 193ms
525
+ ✓  node  test/utils/unlockResponse.test.ts (11 tests) 4ms
479
526
  ✓  node  test/server/cms/myAccountDefaultSections.test.ts (5 tests) 5ms
480
527
  ✓  node  test/components/RecommendationShelf/useRecommendations.test.ts (2 tests) 5ms
481
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 5ms
482
- ✓  node  test/components/account/OrganizationDrawerBody.test.tsx (3 tests) 47ms
528
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 6ms
529
+ ✓  node  test/components/account/OrganizationDrawerBody.test.tsx (3 tests) 39ms
483
530
  ✓  node  test/utils/userOrderStatus.test.ts (3 tests) 4ms
484
- ✓  node  test/sdk/analytics/utils.test.ts (2 tests) 4ms
485
- ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 42ms
486
- ✓  node  test/sdk/account/clearPersistedSessionState.test.ts (1 test) 9ms
487
- ✓  node  test/components/quotes/MyAccountQuoteStatusBadge.test.tsx (2 tests) 23ms
488
-
489
-  Test Files  73 passed (73)
490
-  Tests  570 passed (570)
491
-  Start at  23:06:30
492
-  Duration  36.09s (transform 8.20s, setup 0ms, collect 28.56s, tests 10.44s, environment 49.69s, prepare 1.25s)
531
+ ✓  node  test/sdk/analytics/utils.test.ts (2 tests) 3ms
532
+ ✓  node  test/instrumentation.test.ts (3 tests) 6ms
533
+ ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 27ms
534
+ ✓  node  test/sdk/account/clearPersistedSessionState.test.ts (1 test) 12ms
535
+ ✓  node  test/components/quotes/MyAccountQuoteStatusBadge.test.tsx (2 tests) 22ms
536
+
537
+  Test Files  75 passed (75)
538
+  Tests  584 passed (584)
539
+  Start at  22:51:57
540
+  Duration  33.94s (transform 8.01s, setup 0ms, import 27.87s, tests 10.10s, environment 44.06s)
493
541
 
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.6.0-dev.0](https://github.com/vtex/faststore/compare/v4.5.1-dev.4...v4.6.0-dev.0) (2026-08-11)
7
+
8
+ ### Features
9
+
10
+ - removing vtex/diagnostics-nodejs ([#3389](https://github.com/vtex/faststore/issues/3389)) ([74e2d50](https://github.com/vtex/faststore/commit/74e2d503a44903929b90af7701956536690d4e41))
11
+
6
12
  ## [4.5.1-dev.4](https://github.com/vtex/faststore/compare/v4.5.1-dev.3...v4.5.1-dev.4) (2026-08-10)
7
13
 
8
14
  **Note:** Version bump only for package @faststore/core
package/README.md CHANGED
@@ -31,7 +31,7 @@ packages/core/
31
31
  │ ├── server/ # Server-side utilities (CMS content fetching)
32
32
  │ ├── customizations/ # Store-level overrides: styles, fonts, components, fragments
33
33
  │ ├── styles/ # Global SCSS styles
34
- │ └── instrumentation.ts # Next.js instrumentation hook (boots @faststore/diagnostics when otelEnabled)
34
+ │ └── instrumentation.ts # Next.js instrumentation hook (boots @faststore/diagnostics — see docs/observability.md)
35
35
  ├── cms/faststore/ # CMS configuration: sections.json, content-types.json, schemas
36
36
  ├── @generated/ # Auto-generated GraphQL types — do not edit
37
37
  ├── discovery.config.default.js # Committed base store configuration (platform, sales channel, locale)
@@ -166,8 +166,7 @@ module.exports = {
166
166
  analytics: {
167
167
  // https://developers.google.com/tag-platform/tag-manager/web#standard_web_page_installation,
168
168
  gtmContainerId: 'GTM-PGHZ95N',
169
- serviceName: 'faststore-proxy',
170
- otelEnabled: true,
169
+ serviceName: 'faststore',
171
170
  },
172
171
 
173
172
  cms: {
package/next.config.js CHANGED
@@ -14,7 +14,6 @@ const getRootFolder = () => {
14
14
  console.log(`
15
15
  Root folder at: ${getRootFolder()}
16
16
  AccountID: ${storeConfig.api?.storeId ?? 'Unknown'}
17
- Analytics Enabled: ${storeConfig.analytics?.otelEnabled ?? false}
18
17
  `)
19
18
 
20
19
  /**
@@ -22,8 +21,6 @@ console.log(`
22
21
  * */
23
22
  const nextConfig = {
24
23
  /* config options here */
25
- /* Replaces terser by swc for minifying. It's the default in NextJS 13 */
26
- swcMinify: true,
27
24
  ...(Array.isArray(storeConfig.experimental?.transpilePackages) &&
28
25
  storeConfig.experimental.transpilePackages.length > 0 && {
29
26
  transpilePackages: storeConfig.experimental.transpilePackages,
@@ -55,9 +52,7 @@ const nextConfig = {
55
52
  sassOptions: {
56
53
  silenceDeprecations: ['if-function', 'legacy-js-api'],
57
54
  },
58
- // TODO: We won't need to enable this experimental feature when migrating to Next.js 13
59
55
  experimental: {
60
- instrumentationHook: true,
61
56
  scrollRestoration: !storeConfig.experimental.scrollRestoration,
62
57
  },
63
58
  /*
@@ -68,6 +63,27 @@ const nextConfig = {
68
63
  * */
69
64
  outputFileTracingRoot: getRootFolder(),
70
65
  webpack: (config, { isServer, dev }) => {
66
+ // `@opentelemetry/sdk-node` (pulled in by @faststore/diagnostics) does an
67
+ // optional `require('@opentelemetry/shim-opencensus')` guarded by a try/catch.
68
+ // The module is an optional peer that isn't installed, so webpack reports a
69
+ // "Module not found" error it can't see is intentional. Aliasing it to `false`
70
+ // resolves it to an empty module, matching the graceful degradation the SDK
71
+ // already expects at runtime (Turbopack handles this case on its own).
72
+ config.resolve.alias = {
73
+ ...config.resolve.alias,
74
+ '@opentelemetry/shim-opencensus': false,
75
+ }
76
+
77
+ // `require-in-the-middle` (used by OpenTelemetry instrumentation) patches
78
+ // modules through a dynamic `require` that webpack can't statically analyze,
79
+ // emitting a benign "Critical dependency" warning. `serverExternalPackages`
80
+ // handles this for Turbopack, but the webpack builder still traces into it,
81
+ // so we silence the warning for this module specifically.
82
+ config.ignoreWarnings = [
83
+ ...(config.ignoreWarnings ?? []),
84
+ { module: /require-in-the-middle/ },
85
+ ]
86
+
71
87
  // https://github.com/vercel/next.js/discussions/11267#discussioncomment-2479112
72
88
  // camel-case style names from css modules
73
89
  config.module.rules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.5.1-dev.4",
3
+ "version": "4.6.0-dev.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -71,11 +71,11 @@
71
71
  "style-loader": "^3.3.1",
72
72
  "swr": "^2.2.5",
73
73
  "use-sync-external-store": "^1.6.0",
74
- "@faststore/diagnostics": "4.5.1-dev.4",
75
- "@faststore/lighthouse": "4.5.1-dev.4",
76
- "@faststore/sdk": "4.5.1-dev.4",
77
- "@faststore/api": "4.5.1-dev.4",
78
- "@faststore/ui": "4.5.1-dev.4"
74
+ "@faststore/api": "4.6.0-dev.0",
75
+ "@faststore/diagnostics": "4.6.0-dev.0",
76
+ "@faststore/lighthouse": "4.6.0-dev.0",
77
+ "@faststore/sdk": "4.6.0-dev.0",
78
+ "@faststore/ui": "4.6.0-dev.0"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cypress/code-coverage": "^3.12.1",
@@ -88,7 +88,7 @@
88
88
  "@types/fs-extra": "^9.0.13",
89
89
  "@types/node": "20.19.13",
90
90
  "@vitejs/plugin-react": "^5.1.2",
91
- "@vitest/coverage-v8": "4.0.7",
91
+ "@vitest/coverage-v8": "4.0.18",
92
92
  "@vtex/prettier-config": "1.0.0",
93
93
  "axe-core": "^4.8.1",
94
94
  "cypress": "12.17.4",
@@ -99,7 +99,7 @@
99
99
  "is-ci": "^3.0.0",
100
100
  "jsdom": "^27.4.0",
101
101
  "typescript": "5.9.3",
102
- "vitest": "4.0.7"
102
+ "vitest": "4.0.18"
103
103
  },
104
104
  "peerDependencies": {
105
105
  "graphql": "16.11.0",
@@ -1,17 +1,25 @@
1
1
  import config from '../discovery.config'
2
2
  import pkgJSON from '../package.json'
3
3
 
4
+ /**
5
+ * Next.js instrumentation hook. This is the only place telemetry is booted, so
6
+ * the OTel SDK is registered before any request is served.
7
+ */
4
8
  export async function register() {
5
- if (
6
- process.env.NEXT_RUNTIME === 'nodejs' &&
7
- config.analytics.otelEnabled === true
8
- ) {
9
+ // Disabled feature until release date
10
+ const instrumentationEnabled = false
11
+
12
+ // The runtime check must wrap the import instead of guarding with an early
13
+ // return: bundlers replace `process.env.NEXT_RUNTIME` with a literal, so only
14
+ // a positive branch gets dropped from the edge bundle. Left reachable, the
15
+ // OTel SDK pulls in Node builtins (`fs`, `zlib`, `stream`) that fail to resolve.
16
+ if (process.env.NEXT_RUNTIME === 'nodejs' && instrumentationEnabled) {
9
17
  const { name, version } = pkgJSON
18
+
10
19
  try {
11
20
  const { getTelemetryClient } = await import('@faststore/diagnostics')
12
- console.log('Instrumemtation.ts: Getting telemetry client')
13
21
 
14
- return getTelemetryClient({
22
+ return await getTelemetryClient({
15
23
  serviceName: config.analytics?.serviceName ?? name,
16
24
  version,
17
25
  account: config.api.storeId,
@@ -19,7 +27,7 @@ export async function register() {
19
27
  packageName: name,
20
28
  })
21
29
  } catch (error) {
22
- console.error('Failed to initialize OTEL Instrumentation')
30
+ console.error('Failed to initialize OTEL Instrumentation', error)
23
31
  }
24
32
  }
25
33
  }
@@ -13,6 +13,9 @@ import { getRequestHostname } from 'src/utils/getRequestHostname'
13
13
  import { isLocalHost } from 'src/utils/isLocalHost'
14
14
  import { shouldForceRefreshTokenForValidateSession } from 'src/utils/validateSessionRefreshToken'
15
15
  import { execute } from '../../server'
16
+ import { logger } from '@faststore/diagnostics'
17
+
18
+ const OTELLogger = logger('@faststore/core')
16
19
 
17
20
  const DEFAULT_MAX_AGE = 5 * 60 // 5 minutes
18
21
  const DEFAULT_STALE_WHILE_REVALIDATE = 60 * 60 // 1 hour
@@ -150,6 +153,12 @@ const hasVtexIdclientAutCookie = (request: NextApiRequest): boolean => {
150
153
  const handler: NextApiHandler = async (request, response) => {
151
154
  if (request.method !== 'POST' && request.method !== 'GET') {
152
155
  response.status(405).end()
156
+ OTELLogger(
157
+ 'info',
158
+ 'Invalid request method: %s %s',
159
+ request.method,
160
+ request.url
161
+ )
153
162
 
154
163
  return
155
164
  }
@@ -158,6 +167,15 @@ const handler: NextApiHandler = async (request, response) => {
158
167
  // value is used to cache bust the request if there is a VtexIdclientAutCookie
159
168
  const { operation, variables, query, v: value } = parseRequest(request)
160
169
 
170
+ // Variables and the query body are deliberately not logged: they carry
171
+ // session and customer data.
172
+ OTELLogger(
173
+ 'debug',
174
+ 'operation: %s hash: %s',
175
+ operation?.__meta__?.operationName,
176
+ operation?.__meta__?.operationHash
177
+ )
178
+
161
179
  const isLocal = isLocalHost(getRequestHostname(request.headers.host))
162
180
 
163
181
  if (
@@ -209,18 +227,21 @@ const handler: NextApiHandler = async (request, response) => {
209
227
  // upstream status) is nested in `originalError`. Recover it so the BFF
210
228
  // propagates the real status instead of collapsing everything to 500.
211
229
  const fastStoreError = errors.map(recoverFastStoreError).find(Boolean)
230
+ const reportedErrors = errors.map((graphqlError) => {
231
+ const fsError = recoverFastStoreError(graphqlError)
232
+
233
+ return {
234
+ message: (graphqlError as { message?: string })?.message,
235
+ status: fsError?.extensions.status,
236
+ type: fsError?.extensions.type,
237
+ }
238
+ })
212
239
 
213
- console.error(
214
- 'Graphql execution returned with error: ',
215
- errors.map((graphqlError) => {
216
- const fsError = recoverFastStoreError(graphqlError)
217
-
218
- return {
219
- message: (graphqlError as { message?: string })?.message,
220
- status: fsError?.extensions.status,
221
- type: fsError?.extensions.type,
222
- }
223
- })
240
+ console.error('Graphql execution returned with error: ', reportedErrors)
241
+ OTELLogger(
242
+ 'error',
243
+ 'Graphql execution returned with error: %o',
244
+ reportedErrors
224
245
  )
225
246
 
226
247
  const status = fastStoreError?.extensions.status ?? 500
@@ -304,6 +325,11 @@ const handler: NextApiHandler = async (request, response) => {
304
325
  'Something unexpected occurred querying Graphql endpoint: \n',
305
326
  err
306
327
  )
328
+ OTELLogger(
329
+ 'error',
330
+ 'Something unexpected occurred querying Graphql endpoint: %o',
331
+ err
332
+ )
307
333
 
308
334
  if (err instanceof BadRequestError) {
309
335
  response.status(400).end()
@@ -16,6 +16,7 @@ import {
16
16
  GraphqlVtexSchema,
17
17
  isFastStoreError,
18
18
  } from '@faststore/api'
19
+ import { OTELAPI } from '@faststore/diagnostics'
19
20
  import { loadFilesSync } from '@graphql-tools/load-files'
20
21
  import { mergeTypeDefs } from '@graphql-tools/merge'
21
22
  import { makeExecutableSchema } from '@graphql-tools/schema'
@@ -28,7 +29,7 @@ import thirdPartyResolvers from '../customizations/src/graphql/thirdParty/resolv
28
29
  import vtexExtensionsResolvers from '../customizations/src/graphql/vtex/resolvers'
29
30
 
30
31
  import type { Operation } from '../sdk/graphql/request'
31
- import { apiOptions, withTraceClient } from './options'
32
+ import { apiOptions } from './options'
32
33
 
33
34
  interface ExecuteOptions<V = Record<string, unknown>> {
34
35
  operation: Operation
@@ -70,8 +71,7 @@ export function getFinalAPISchema() {
70
71
  }
71
72
 
72
73
  export const getEnvelop = async () => {
73
- const options = await withTraceClient(apiOptions)
74
- const apiContextFactory = await GraphqlVtexContextFactory(options)
74
+ const apiContextFactory = await GraphqlVtexContextFactory(apiOptions)
75
75
 
76
76
  return envelop({
77
77
  plugins: [
@@ -136,13 +136,17 @@ export const execute = async <V extends Maybe<{ [key: string]: unknown }>, D>(
136
136
  contextValue.storage.locale = locale
137
137
  }
138
138
 
139
- const { data, errors } = (await run({
140
- schema,
141
- document: parse(query),
142
- variableValues: variables,
143
- contextValue,
144
- operationName,
145
- })) as { data: D; errors: unknown[] }
139
+ const { data, errors } = await withRootSpan(
140
+ `graphql ${operationName ?? 'operation'}`,
141
+ () =>
142
+ run({
143
+ schema,
144
+ document: parse(query),
145
+ variableValues: variables,
146
+ contextValue,
147
+ operationName,
148
+ }) as Promise<{ data: D; errors: unknown[] }>
149
+ )
146
150
 
147
151
  return {
148
152
  data,
@@ -153,3 +157,27 @@ export const execute = async <V extends Maybe<{ [key: string]: unknown }>, D>(
153
157
  },
154
158
  }
155
159
  }
160
+
161
+ /**
162
+ * Runs an operation inside a per-request root span, made the active context so
163
+ * the resolver spans emitted by `@faststore/api` parent to it. Resolves to a
164
+ * plain call when telemetry is disabled.
165
+ */
166
+ async function withRootSpan<T>(name: string, run: () => Promise<T>) {
167
+ if (!apiOptions.OTEL_ENABLED) {
168
+ return run()
169
+ }
170
+
171
+ const span = OTELAPI.trace.getTracer('@faststore/core').startSpan(name)
172
+ const otelContext = OTELAPI.trace.setSpan(OTELAPI.context.active(), span)
173
+
174
+ try {
175
+ return await OTELAPI.context.with(otelContext, run)
176
+ } catch (error) {
177
+ span.setStatus({ code: OTELAPI.SpanStatusCode.ERROR })
178
+ span.recordException(error as Error)
179
+ throw error
180
+ } finally {
181
+ span.end()
182
+ }
183
+ }
@@ -1,9 +1,8 @@
1
1
  import type { APIOptions } from '@faststore/api'
2
- import { getTraceClient } from '@faststore/diagnostics'
3
2
  import storeConfig from '../../discovery.config'
4
3
  import pkgJSON from '../../package.json'
5
4
 
6
- const { name, version } = pkgJSON
5
+ const { version } = pkgJSON
7
6
 
8
7
  export const apiOptions: APIOptions = {
9
8
  platform: storeConfig.platform as APIOptions['platform'],
@@ -23,25 +22,7 @@ export const apiOptions: APIOptions = {
23
22
  storeConfig.api?.enableUnavailableItemsOnCart ?? false,
24
23
  },
25
24
  version,
26
- OTEL: {
27
- enabled: storeConfig.analytics.otelEnabled,
28
- },
25
+ // feature flag default to false as it should not emit traces/logs yet
26
+ OTEL_ENABLED: false,
29
27
  discoveryConfig: storeConfig,
30
28
  }
31
-
32
- export async function withTraceClient<T extends APIOptions = typeof apiOptions>(
33
- apiOptions: T
34
- ): Promise<T> {
35
- const OTEL = {}
36
- getTraceClient(
37
- apiOptions?.discoveryConfig?.analytics?.serviceName ?? name
38
- )?.inject(OTEL)
39
-
40
- return {
41
- ...apiOptions,
42
- OTEL: {
43
- ...OTEL,
44
- enabled: storeConfig.analytics?.otelEnabled?.toString() === 'true',
45
- },
46
- } as T
47
- }
@@ -0,0 +1,27 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ import { register } from '../src/instrumentation'
4
+
5
+ const getTelemetryClient = vi.hoisted(() => vi.fn())
6
+
7
+ vi.mock('@faststore/diagnostics', () => ({ getTelemetryClient }))
8
+
9
+ beforeEach(() => {
10
+ vi.clearAllMocks()
11
+ })
12
+
13
+ afterEach(() => {
14
+ vi.unstubAllEnvs()
15
+ })
16
+
17
+ describe('register', () => {
18
+ it.each(['nodejs', 'edge', undefined])(
19
+ 'does not boot telemetry on the %s runtime while the feature is off',
20
+ async (runtime) => {
21
+ vi.stubEnv('NEXT_RUNTIME', runtime)
22
+
23
+ await expect(register()).resolves.toBeUndefined()
24
+ expect(getTelemetryClient).not.toHaveBeenCalled()
25
+ }
26
+ )
27
+ })
@@ -29,9 +29,13 @@ const createResponse = () => {
29
29
  return res as unknown as NextApiResponse & typeof res
30
30
  }
31
31
 
32
- const createRequest = (operationName = 'ClientShippingSimulationQuery') =>
32
+ const createRequest = (
33
+ operationName = 'ClientShippingSimulationQuery',
34
+ method = 'GET'
35
+ ) =>
33
36
  ({
34
- method: 'GET',
37
+ method,
38
+ url: '/api/graphql',
35
39
  headers: { host: 'localhost:3000' },
36
40
  query: {
37
41
  operationName,
@@ -165,3 +169,37 @@ describe('/api/graphql error status propagation', () => {
165
169
  expect(res.status).toHaveBeenCalledWith(404)
166
170
  })
167
171
  })
172
+
173
+ describe('/api/graphql request handling', () => {
174
+ beforeEach(() => {
175
+ vi.clearAllMocks()
176
+ })
177
+
178
+ it.each(['PUT', 'DELETE', 'PATCH', 'OPTIONS'])(
179
+ 'rejects %s with 405 without reaching the GraphQL layer',
180
+ async (method) => {
181
+ const res = createResponse()
182
+ await handler(createRequest(undefined, method), res)
183
+
184
+ expect(res.status).toHaveBeenCalledWith(405)
185
+ expect(mockedExecute).not.toHaveBeenCalled()
186
+ }
187
+ )
188
+
189
+ it.each([
190
+ ['BadRequestError', () => new BadRequestError('malformed'), 400],
191
+ ['UnauthorizedError', () => new UnauthorizedError('expired'), 401],
192
+ ['an unexpected failure', () => new Error('socket hang up'), 500],
193
+ ])(
194
+ 'maps %s thrown by execute to its status',
195
+ async (_name, makeError, status) => {
196
+ mockedExecute.mockRejectedValue(makeError())
197
+
198
+ const res = createResponse()
199
+ await handler(createRequest(), res)
200
+
201
+ expect(res.status).toHaveBeenCalledWith(status)
202
+ expect(res.end).toHaveBeenCalled()
203
+ }
204
+ )
205
+ })
@@ -0,0 +1,90 @@
1
+ import { OTELAPI } from '@faststore/diagnostics'
2
+ import {
3
+ afterAll,
4
+ afterEach,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ it,
9
+ vi,
10
+ } from 'vitest'
11
+
12
+ import { execute } from '../../src/server'
13
+ import { apiOptions } from '../../src/server/options'
14
+
15
+ const span = {
16
+ end: vi.fn(),
17
+ setStatus: vi.fn(),
18
+ recordException: vi.fn(),
19
+ }
20
+
21
+ const startSpan = vi.fn(() => span)
22
+
23
+ const otelEnabledByDefault = apiOptions.OTEL_ENABLED
24
+
25
+ // `__typename` resolves inside GraphQL itself, so these run the whole envelop
26
+ // pipeline without reaching the VTEX platform.
27
+ const runOperation = (query: string, operationName?: string) =>
28
+ execute({
29
+ operation: { __meta__: { operationName, operationHash: 'not-persisted' } },
30
+ variables: {},
31
+ query,
32
+ })
33
+
34
+ beforeEach(() => {
35
+ vi.clearAllMocks()
36
+ vi.spyOn(OTELAPI.trace, 'getTracer').mockReturnValue({ startSpan } as never)
37
+ apiOptions.OTEL_ENABLED = true
38
+ })
39
+
40
+ afterEach(() => {
41
+ vi.restoreAllMocks()
42
+ })
43
+
44
+ afterAll(() => {
45
+ apiOptions.OTEL_ENABLED = otelEnabledByDefault
46
+ })
47
+
48
+ describe('execute root span', () => {
49
+ it('wraps the operation in a span named after it', async () => {
50
+ const { data } = await runOperation(
51
+ 'query RootSpanQuery { __typename }',
52
+ 'RootSpanQuery'
53
+ )
54
+
55
+ expect(data).toEqual({ __typename: 'Query' })
56
+ expect(startSpan).toHaveBeenCalledWith('graphql RootSpanQuery')
57
+ expect(span.end).toHaveBeenCalledTimes(1)
58
+ expect(span.setStatus).not.toHaveBeenCalled()
59
+ })
60
+
61
+ it('names the span generically when the operation is anonymous', async () => {
62
+ await runOperation('{ __typename }')
63
+
64
+ expect(startSpan).toHaveBeenCalledWith('graphql operation')
65
+ })
66
+
67
+ it('marks the span as failed and ends it when the operation throws', async () => {
68
+ await expect(
69
+ runOperation('this is not graphql', 'BrokenQuery')
70
+ ).rejects.toThrow(/Syntax Error/)
71
+
72
+ expect(span.setStatus).toHaveBeenCalledWith({
73
+ code: OTELAPI.SpanStatusCode.ERROR,
74
+ })
75
+ expect(span.recordException).toHaveBeenCalledWith(expect.any(Error))
76
+ expect(span.end).toHaveBeenCalledTimes(1)
77
+ })
78
+
79
+ it('skips instrumentation entirely when telemetry is disabled', async () => {
80
+ apiOptions.OTEL_ENABLED = false
81
+
82
+ const { data } = await runOperation(
83
+ 'query RootSpanQuery { __typename }',
84
+ 'RootSpanQuery'
85
+ )
86
+
87
+ expect(data).toEqual({ __typename: 'Query' })
88
+ expect(startSpan).not.toHaveBeenCalled()
89
+ })
90
+ })