Run the front-end unit tests from the repo root, with one storage for every Node - #596
Conversation
This comment has been minimized.
This comment has been minimized.
Ten test files carried their own matchMedia stub, each a near copy of the last: five identical, two keeping listeners so a test could flip the OS preference, three inline in a render helper, and two in LiveAircraftMap installed through vi.stubGlobal. A fix to one (a listener that is never removed, a missing media field) reached none of the others. dashboard/src/test/matchMedia.ts now holds the one stub, with the listener-keeping behaviour the theme tests need, and every file imports it. It installs through vi.stubGlobal so LiveAircraftMap's unstubAllGlobals teardown still removes it, and its implementation is given to vi.fn directly so a vi.resetAllMocks cannot empty it. It stays a helper the tests call rather than a default in the shared setup file. ThemeContext treats a missing matchMedia as a real case (jsdom, any non-browser render), and a test that does not stub one exercises that path; a setup-file default would take it away from every test at once. Raised by the review on #596. ClickUp 2.4 (123zgec4mxr). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1c672f2 to
2251bb2
Compare
|
Both review findings are addressed in 2251bb2.
|
Ten test files carried their own matchMedia stub, each a near copy of the last: five identical, two keeping listeners so a test could flip the OS preference, three inline in a render helper, and two in LiveAircraftMap installed through vi.stubGlobal. A fix to one (a listener that is never removed, a missing media field) reached none of the others. dashboard/src/test/matchMedia.ts now holds the one stub, with the listener-keeping behaviour the theme tests need, and every file imports it. It installs through vi.stubGlobal so LiveAircraftMap's unstubAllGlobals teardown still removes it, and its implementation is given to vi.fn directly so a vi.resetAllMocks cannot empty it. It stays a helper the tests call rather than a default in the shared setup file. ThemeContext treats a missing matchMedia as a real case (jsdom, any non-browser render), and a test that does not stub one exercises that path; a setup-file default would take it away from every test at once. Raised by the review on #596. ClickUp 2.4 (123zgec4mxr). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2251bb2 to
57963be
Compare
This comment has been minimized.
This comment has been minimized.
Node 25 and later define localStorage and sessionStorage globals of their own (localStorage is undefined without --localstorage-file), and in vitest's jsdom environment they hide jsdom's. Eight test files worked around it with their own in-memory Storage, each a copy of the last, and LiveAircraftMap.test.tsx used the ambient one and failed its beforeEach on any local Node 25+ while CI's Node 20 passed. One setup file now installs jsdom's own storage on window before collection and again before every test, emptying it each time, so every test sees the same implementation on every Node, and a test that swaps in a throwing storage cannot leak it into the next. The per-file copies go, and the tests seed and read window.localStorage directly. jsdom's storage rather than a hand-written Map keeps the Storage semantics real. Closes the Node 25+ half of ClickUp 123zgec36re; part of 2.4 (123zgec4mxr). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he repo root There was no root Vitest config and no root test script. A bare vitest from the root collected e2e's Playwright specs and ran the dashboard tests without dashboard/vite.config.js (no jsdom, no globals, no jest-dom, no @edsc/timeline alias), which reads as about eleven failing files. The only documented way to run everything was a chained one-liner in ONBOARDING. A root vitest.config.js now runs every workspace with a test script as a project under its own config, derived from package.json so a new workspace joins without an edit here. The root package.json gains test, typecheck, lint, build and check; check runs the four in CI's order, so a local pass covers what web-build runs. It is the npm half of the just check recipe 2.2 adds. CI keeps running each workspace's scripts from its matrix, so nothing there changes. ClickUp 2.4 (123zgec4mxr). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ten test files carried their own matchMedia stub, each a near copy of the last: five identical, two keeping listeners so a test could flip the OS preference, three inline in a render helper, and two in LiveAircraftMap installed through vi.stubGlobal. A fix to one (a listener that is never removed, a missing media field) reached none of the others. dashboard/src/test/matchMedia.ts now holds the one stub, with the listener-keeping behaviour the theme tests need, and every file imports it. It installs through vi.stubGlobal so LiveAircraftMap's unstubAllGlobals teardown still removes it, and its implementation is given to vi.fn directly so a vi.resetAllMocks cannot empty it. It stays a helper the tests call rather than a default in the shared setup file. ThemeContext treats a missing matchMedia as a real case (jsdom, any non-browser render), and a test that does not stub one exercises that path; a setup-file default would take it away from every test at once. Raised by the review on #596. ClickUp 2.4 (123zgec4mxr). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
57963be to
128adab
Compare
This comment has been minimized.
This comment has been minimized.
|
Claude finished @jehanazad's task in 2m 10s —— View job Tasks
ReviewIsolated this PR's own diff (
This matches the outcome of the two earlier review passes already in this thread (the No issues found. |
ClickUp: 2.4 Run the front-end unit tests from the repo root, with one localStorage stub. Also closes the Node 25+ half of 123zgec36re.
Stacked on #613, at the top of the stack main ← #595 ← #602 ← #620 ← #607 ← #617 ← #613 ← #596, which lands in one deploy.
Why
testscript. A barevitestfrom the root collected e2e's Playwright specs and ran the dashboard tests withoutdashboard/vite.config.js(no jsdom, globals, jest-dom or@edsc/timelinealias): about eleven false failures. The only documented way to run everything was a chained one-liner in ONBOARDING.localStorageandsessionStorageglobals that hide jsdom's (localStorage isundefinedwithout--localstorage-file). Eight test files carried their own copy of an in-memory Storage to get round it, andLiveAircraftMap.test.tsx, which used the ambient one, failed on any local Node 25+ while CI's Node 20 passed.What
Two commits:
dashboard/src/test/setupStorage.ts, a secondsetupFilesentry, installs jsdom's ownlocalStorageandsessionStorageonwindowbefore collection and again before every test, emptied each time. So every Node sees the same implementation, and a test that swaps in a throwing storage cannot leak it into the next. The eight copies go; tests seed and readwindow.localStoragedirectly. The throwing-storage stubs stay, as they test a different thing.vitest.config.jsruns every workspace whosetestscript runs Vitest (dashboard, packages/shared) as a project under its own config. The rootpackage.jsongainstest,typecheck,lint,buildandcheck, the last running the four inweb-build's order. This is what 2.2'sjust checkis to call. ONBOARDING's one-liner is replaced.CI is unchanged:
web-buildstill runs each workspace's own scripts from its matrix.Verification
npm teston Node 26.9 (the laptop), with noNODE_OPTIONS: 119 files, 1388 tests, all passed.web-buildruns these same suites on it, so this PR's run is the Node 20 result. A local run innode:20-alpineat a load average above 250 failed only on timeouts (13 at the 5 s limit, onefindByRole), all in tests that pass on Node 26 and none touching storage, plusscalarTheme.test.ts, which readsbackend/and so could not import from the copy that run used.LiveAircraftMap.test.tsxandusePersistedState.test.tsxfail 11 tests on Node 26 withCannot read properties of undefined (reading 'setItem').--pool=vmThreads.vitest listfrom the root collects 116 dashboard and 3 shared files, and no e2e specs.npm run typecheckandnpm run lintpass (one pre-existingset-state-in-effectwarning).🤖 Generated with Claude Code