fix(test): pin loopover-ui + ui-kit jsdom localStorage over Node 26's broken global#7616
Conversation
… broken global (#7612) Node 26 predefines an experimental globalThis.localStorage accessor (nodejs/node#60303) that returns undefined without --localstorage-file. It exists on globalThis before jsdom's environment is installed, so Vitest's populateGlobal skips copying jsdom's working Storage over it, and every bare localStorage call throws under Node 26 while passing on Node 22/24 -- the identical gap #7597 fixed in apps/loopover-miner-ui, which never got mirrored into apps/loopover-ui or packages/loopover-ui-kit. Confirmed via a full npm run test:ci on Node 26: 5 files / 26 tests failed in apps/loopover-ui with "Cannot read properties of undefined (reading 'clear')" on window.localStorage.clear() -- routes/index, api/try-it, app-panels/onboarding-preview-card, lib/analytics-window, lib/use-local-storage. packages/loopover-ui-kit has no test that currently touches localStorage, so this guard is preventive there. Point globalThis.localStorage at jsdom's real Storage from the raw JSDOM window unconditionally: a no-op where the global already is that object, the fix on Node 26+. All 5 previously-failing files now pass on Node 26 (426/426 in apps/loopover-ui, 19/19 in ui-kit), with no change on Node 22/24. Closes #7612
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
loopover-ui | d57a509 | Commit Preview URL Branch Preview URL |
Jul 21 2026, 02:14 AM |
…ge guard npm run ui:lint flagged the previous wrap of the jsdom.window?.localStorage chain; break before ?.window instead of before ?.localStorage to match apps/loopover-ui's printWidth-100 prettier config. No behavior change.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Bundle ReportChanges will increase total bundle size by 1 bytes (0.0%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: loopover-uiAssets Changed:
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-21 03:07:51 UTC
Review summary Nits — 6 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|


Closes #7612
Summary
apps/loopover-ui/vitest.setup.tsandpackages/loopover-ui-kit/vitest.setup.tsnever receivedfix(test): pin miner-ui jsdom localStorage over Node 26's broken global #7597's guard against Node 26's broken
globalThis.localStorageglobal, so any barelocalStorage.*call throws under Node 26 (while passing on Node 22/24, what CI actually runs). Mirrors the exact fix
already accepted for
apps/loopover-miner-ui.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateIf any required check was skipped, explain why:
vitest.setup.ts(outside Codecov'ssrc/**-only includeglob, so no patch-coverage obligation either way). The regression proof is the 5 previously-Node-26-red
apps/loopover-uitest files (routes/index,api/try-it,app-panels/onboarding-preview-card,lib/analytics-window,lib/use-local-storage) turning green — verified directly on Node 26: 426/426in
apps/loopover-ui, 19/19 inpackages/loopover-ui-kit.packages/loopover-ui-kithas no test thatcurrently touches
localStorage, so its guard is preventive rather than fixing a currently-red test.Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.UI Evidence
Not applicable — test-infrastructure-only change, no visible UI/frontend difference.
Notes
narrow — that one also closes the loop so this exact class of gap can't silently recur.