Merge fix/tracker-web-test-env: stable DOM env + Node-25 localStorage fix

This commit is contained in:
saravanakumardb1 2026-05-31 04:12:50 -07:00
commit f7740f13e9
6 changed files with 75 additions and 253 deletions

View File

@ -56,6 +56,7 @@
"bundlesize": "^0.18.1",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"happy-dom": "^20.9.0",
"husky": "^9.0.0",
"lint-staged": "^16.4.0",
"prettier": "^3.0.0",

View File

@ -1,4 +1,4 @@
// @vitest-environment jsdom
// @vitest-environment happy-dom
/**
* UX-5.3 command palette behaviour.
*

View File

@ -1,4 +1,4 @@
// @vitest-environment jsdom
// @vitest-environment happy-dom
import { describe, expect, it, beforeAll, beforeEach, vi } from 'vitest';
import { act, createElement } from 'react';

View File

@ -5,6 +5,7 @@ export default defineConfig({
test: {
environment: 'node',
globals: true,
setupFiles: ['./vitest.setup.ts'],
exclude: ['e2e/**', 'node_modules/**', '.next/**'],
coverage: {
provider: 'v8',

View File

@ -0,0 +1,47 @@
/**
* Test bootstrap for tracker-web.
*
* Node 25 ships a global `localStorage` (Web Storage) that is a non-functional
* stub unless started with `--localstorage-file=<path>` accessing it yields an
* object with no `getItem`/`setItem`/`clear`. That global shadows the DOM test
* environment's storage, so tests (and the code under test) that use
* `localStorage` break with "localStorage.clear is not a function".
*
* Install a real in-memory Web Storage over it when the active one is missing the
* Storage API. Tests that stub localStorage themselves (vi.stubGlobal) still work
* this only provides the baseline the rest of the suite assumes.
*/
function createMemoryStorage(): Storage {
let store: Record<string, string> = {};
return {
get length() {
return Object.keys(store).length;
},
clear() {
store = {};
},
getItem(key: string) {
return Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null;
},
setItem(key: string, value: string) {
store[String(key)] = String(value);
},
removeItem(key: string) {
delete store[key];
},
key(index: number) {
return Object.keys(store)[index] ?? null;
},
} as Storage;
}
for (const name of ['localStorage', 'sessionStorage'] as const) {
const current = (globalThis as Record<string, unknown>)[name] as Storage | undefined;
if (!current || typeof current.clear !== 'function') {
Object.defineProperty(globalThis, name, {
value: createMemoryStorage(),
configurable: true,
writable: true,
});
}
}

275
pnpm-lock.yaml generated
View File

@ -9,7 +9,7 @@ importers:
dependencies:
'@azure/cosmos':
specifier: '>=4.0.0'
version: 4.9.1(@azure/core-client@1.10.1)
version: 4.9.1
bcryptjs:
specifier: '>=2.4.0'
version: 3.0.3
@ -215,7 +215,7 @@ importers:
version: 9.39.2(jiti@2.6.1)
eslint-config-next:
specifier: 16.1.6
version: 16.1.6(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
version: 16.1.6(@typescript-eslint/parser@8.60.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
husky:
specifier: ^9.0.0
version: 9.1.7
@ -339,7 +339,10 @@ importers:
version: 9.39.2(jiti@2.6.1)
eslint-config-next:
specifier: 16.1.6
version: 16.1.6(@typescript-eslint/parser@8.60.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
version: 16.1.6(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
happy-dom:
specifier: ^20.9.0
version: 20.9.0
husky:
specifier: ^9.0.0
version: 9.1.7
@ -565,7 +568,7 @@ importers:
dependencies:
'@azure/cosmos':
specifier: '>=4.0.0'
version: 4.9.1(@azure/core-client@1.10.1)
version: 4.9.1
packages/create-app:
devDependencies:
@ -728,7 +731,7 @@ importers:
dependencies:
'@azure/cosmos':
specifier: '>=4.0.0'
version: 4.9.1(@azure/core-client@1.10.1)
version: 4.9.1
devDependencies:
vitest:
specifier: ^3.0.0
@ -1261,7 +1264,7 @@ importers:
dependencies:
vitest:
specifier: '>=3.0.0'
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.11)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@28.0.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
version: 3.2.4(@types/debug@4.1.12)(@types/node@25.9.1)(happy-dom@20.9.0)(jiti@2.6.1)(jsdom@28.0.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.9.0)
devDependencies:
'@bytelyst/fastify-core':
specifier: workspace:*
@ -7157,18 +7160,6 @@ packages:
integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==,
}
'@types/node@20.19.41':
resolution:
{
integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==,
}
'@types/node@22.19.11':
resolution:
{
integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==,
}
'@types/node@25.9.1':
resolution:
{
@ -10658,13 +10649,6 @@ packages:
}
engines: { node: '>=4' }
happy-dom@18.0.1:
resolution:
{
integrity: sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==,
}
engines: { node: '>=20.0.0' }
happy-dom@20.9.0:
resolution:
{
@ -15656,12 +15640,6 @@ packages:
}
engines: { node: '>= 0.4' }
undici-types@6.21.0:
resolution:
{
integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==,
}
undici-types@7.24.6:
resolution:
{
@ -16291,21 +16269,6 @@ packages:
utf-8-validate:
optional: true
ws@8.19.0:
resolution:
{
integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==,
}
engines: { node: '>=10.0.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
ws@8.21.0:
resolution:
{
@ -16614,7 +16577,7 @@ snapshots:
fast-xml-parser: 5.3.5
tslib: 2.8.1
'@azure/cosmos@4.9.1(@azure/core-client@1.10.1)':
'@azure/cosmos@4.9.1':
dependencies:
'@azure/abort-controller': 2.1.2
'@azure/core-auth': 1.10.1
@ -17932,7 +17895,7 @@ snapshots:
terminal-link: 2.1.1
toqr: 0.1.1
wrap-ansi: 7.0.0
ws: 8.19.0
ws: 8.21.0
zod: 3.25.76
optionalDependencies:
react-native: 0.84.1(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)
@ -18412,14 +18375,6 @@ snapshots:
'@inquirer/ansi@1.0.2': {}
'@inquirer/confirm@5.1.21(@types/node@22.19.11)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.11)
'@inquirer/type': 3.0.10(@types/node@22.19.11)
optionalDependencies:
'@types/node': 22.19.11
optional: true
'@inquirer/confirm@5.1.21(@types/node@25.9.1)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@25.9.1)
@ -18427,20 +18382,6 @@ snapshots:
optionalDependencies:
'@types/node': 25.9.1
'@inquirer/core@10.3.2(@types/node@22.19.11)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@22.19.11)
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.11
optional: true
'@inquirer/core@10.3.2(@types/node@25.9.1)':
dependencies:
'@inquirer/ansi': 1.0.2
@ -18463,11 +18404,6 @@ snapshots:
'@inquirer/figures@1.0.15': {}
'@inquirer/type@3.0.10(@types/node@22.19.11)':
optionalDependencies:
'@types/node': 22.19.11
optional: true
'@inquirer/type@3.0.10(@types/node@25.9.1)':
optionalDependencies:
'@types/node': 25.9.1
@ -18501,14 +18437,14 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.19.11
'@types/node': 25.9.1
jest-mock: 29.7.0
'@jest/fake-timers@29.7.0':
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
'@types/node': 22.19.11
'@types/node': 25.9.1
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@ -18542,7 +18478,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.19.11
'@types/node': 25.9.1
'@types/yargs': 17.0.35
chalk: 4.1.2
@ -20390,7 +20326,7 @@ snapshots:
recast: 0.23.11
semver: 7.7.4
util: 0.12.5
ws: 8.19.0
ws: 8.21.0
optionalDependencies:
prettier: 3.8.1
transitivePeerDependencies:
@ -20895,7 +20831,7 @@ snapshots:
'@types/graceful-fs@4.1.9':
dependencies:
'@types/node': 22.19.11
'@types/node': 25.9.1
'@types/hast@3.0.4':
dependencies:
@ -20925,15 +20861,6 @@ snapshots:
'@types/node@12.20.55': {}
'@types/node@20.19.41':
dependencies:
undici-types: 6.21.0
optional: true
'@types/node@22.19.11':
dependencies:
undici-types: 6.21.0
'@types/node@25.9.1':
dependencies:
undici-types: 7.24.6
@ -21325,24 +21252,6 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@22.19.11)(typescript@5.9.3)
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.10(@types/node@25.9.1)(typescript@5.9.3)
vite: 7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
'@vitest/mocker@3.2.4(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.9.0))':
dependencies:
'@vitest/spy': 3.2.4
@ -22018,7 +21927,7 @@ snapshots:
chrome-launcher@0.15.2:
dependencies:
'@types/node': 22.19.11
'@types/node': 25.9.1
escape-string-regexp: 4.0.0
is-wsl: 2.2.0
lighthouse-logger: 1.4.2
@ -22027,7 +21936,7 @@ snapshots:
chromium-edge-launcher@0.2.0:
dependencies:
'@types/node': 22.19.11
'@types/node': 25.9.1
escape-string-regexp: 4.0.0
is-wsl: 2.2.0
lighthouse-logger: 1.4.2
@ -23467,13 +23376,6 @@ snapshots:
duplexer: 0.1.2
pify: 3.0.0
happy-dom@18.0.1:
dependencies:
'@types/node': 20.19.41
'@types/whatwg-mimetype': 3.0.2
whatwg-mimetype: 3.0.0
optional: true
happy-dom@20.9.0:
dependencies:
'@types/node': 25.9.1
@ -23924,7 +23826,7 @@ snapshots:
'@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 22.19.11
'@types/node': 25.9.1
jest-mock: 29.7.0
jest-util: 29.7.0
@ -23934,7 +23836,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.9
'@types/node': 22.19.11
'@types/node': 25.9.1
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11
@ -23961,7 +23863,7 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.19.11
'@types/node': 25.9.1
jest-util: 29.7.0
jest-regex-util@29.6.3: {}
@ -23969,7 +23871,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.19.11
'@types/node': 25.9.1
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@ -23986,7 +23888,7 @@ snapshots:
jest-worker@29.7.0:
dependencies:
'@types/node': 22.19.11
'@types/node': 25.9.1
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
@ -25124,32 +25026,6 @@ snapshots:
ms@2.1.3: {}
msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3):
dependencies:
'@inquirer/confirm': 5.1.21(@types/node@22.19.11)
'@mswjs/interceptors': 0.41.3
'@open-draft/deferred-promise': 2.2.0
'@types/statuses': 2.0.6
cookie: 1.1.1
graphql: 16.13.0
headers-polyfill: 4.0.3
is-node-process: 1.2.0
outvariant: 1.4.3
path-to-regexp: 6.3.0
picocolors: 1.1.1
rettime: 0.10.1
statuses: 2.0.2
strict-event-emitter: 0.5.1
tough-cookie: 6.0.0
type-fest: 5.4.4
until-async: 3.0.2
yargs: 17.7.2
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
- '@types/node'
optional: true
msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3):
dependencies:
'@inquirer/confirm': 5.1.21(@types/node@25.9.1)
@ -27121,8 +26997,6 @@ snapshots:
has-symbols: 1.1.0
which-boxed-primitive: 1.1.1
undici-types@6.21.0: {}
undici-types@7.24.6: {}
undici@7.26.0:
@ -27293,27 +27167,6 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
vite-node@3.2.4(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vite-node@3.2.4(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
cac: 6.7.14
@ -27356,23 +27209,6 @@ snapshots:
- tsx
- yaml
vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.19.11
fsevents: 2.3.3
jiti: 2.6.1
lightningcss: 1.31.1
terser: 5.46.0
tsx: 4.21.0
yaml: 2.8.2
vite@6.4.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12
@ -27407,23 +27243,6 @@ snapshots:
tsx: 4.21.0
yaml: 2.9.0
vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.19.11
fsevents: 2.3.3
jiti: 2.6.1
lightningcss: 1.31.1
terser: 5.46.0
tsx: 4.21.0
yaml: 2.8.2
vite@7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
esbuild: 0.27.3
@ -27458,55 +27277,11 @@ snapshots:
tsx: 4.21.0
yaml: 2.9.0
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.11)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@28.0.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(vite@7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
debug: 4.4.3
expect-type: 1.3.0
magic-string: 0.30.21
pathe: 2.0.3
picomatch: 4.0.3
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 7.3.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
vite-node: 3.2.4(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 22.19.11
happy-dom: 18.0.1
jsdom: 28.0.0(@noble/hashes@1.8.0)
transitivePeerDependencies:
- jiti
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vitest@3.2.4(@types/debug@4.1.12)(@types/node@25.9.1)(happy-dom@20.9.0)(jiti@2.6.1)(jsdom@28.0.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
'@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@25.9.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.9.1)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.9.0))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@ -27769,8 +27544,6 @@ snapshots:
ws@7.5.10: {}
ws@8.19.0: {}
ws@8.21.0: {}
wsl-utils@0.1.0: