learning_ai_common_plat/dashboards/tracker-web/vitest.setup.ts
saravanakumardb1 06d7d881a0 fix(tracker-web): stable test DOM env + working localStorage (Node 25)
product-context.test.tsx failed with "localStorage.clear is not a function".
Root cause: Node 25 ships a global `localStorage` Web Storage stub that is
non-functional without --localstorage-file, and it shadows the test DOM
environment's storage. The two DOM tests also relied on `jsdom`, which was only
present transitively (not a tracker-web dependency) while the rest of the
monorepo standardizes on happy-dom.

- Add happy-dom as a tracker-web devDependency; switch the two `@vitest-environment
  jsdom` tests (product-context, command-menu) to happy-dom.
- Add vitest.setup.ts that installs a real in-memory Web Storage over Node 25's
  non-functional stub when the active localStorage/sessionStorage lacks the
  Storage API; wire it via test.setupFiles.

Verified: full tracker-web suite 230/230 (was 228/2).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-31 04:12:34 -07:00

48 lines
1.6 KiB
TypeScript

/**
* 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,
});
}
}