fix: repair broken test infra masking Real-time Balance Sync and Dark Mode Theme Engine bugs - #1406
Merged
emdevelopa merged 1 commit intoAug 28, 2026
Conversation
… Dark Mode Theme Engine bugs - Fix Node 22+/24+ native localStorage stub shadowing jsdom's real implementation in Vitest (src/test/setup.ts), which silently broke every test relying on localStorage across the repo. - Fix RealTimeBalanceSync.test.tsx's framer-motion mock missing motion.div and motion.svg, which crashed every test in the file with 'Element type is invalid'. - Add axe-core accessibility scans across all RealTimeBalanceSync states (loaded, empty, error, loading) — zero violations found once the test could actually render. - Fix RealTimeBalanceSync balance-row layout: long balance values (up to 7 decimal places) were silently clipped by the list's overflow-hidden with no wrap/truncate handling; now wraps instead of hiding digits. - Rewrite theme-context.test.tsx's Dark Mode Theme Engine suite: it replaced globalThis.document/window wholesale, which broke @testing-library/react's render() (no real document.body). Now spies on the real document/window so render() keeps working, adds the legacy addListener/removeListener MediaQueryList API next-themes needs internally, and fixes three incorrect test assumptions (an unobservable pre-effect timing check, a mocked matchMedia() that never reflected the simulated system-preference change, and a setItem call-count assumption that didn't match actual single-call behavior). Closes emdevelopa#1363 Closes emdevelopa#1362 Closes emdevelopa#1361 Closes emdevelopa#1360
|
@davedumto is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@davedumto Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both
RealTimeBalanceSyncand the Dark Mode Theme Engine (theme-context.tsx, wired viaThemeProvider/CommandPalette) already had solid implementations. The problem in both cases was that their test coverage was broken, which is worse than no coverage — it gave false confidence and masked real, smaller bugs underneath.#1363 — Real-time Balance Sync accessibility violation
RealTimeBalanceSync.test.tsx'sframer-motionmock only stubbedmotion.section/button/p/ul/li/span, but the component also usesmotion.divandmotion.svg— every test in the file crashed withElement type is invalid: expected a string ... but got: undefinedbefore ever rendering. Fixed the mock, then addedaxe-corescans (already a transitive dependency via@axe-core/cli) across all four component states (loaded, empty, error, loading). Result: zero accessibility violations — the component'saria-liveregions, roles, and reduced-motion handling were already correct.#1362 — Real-time Balance Sync responsive layout issue
A real one: the balance row (
flex items-center justify-between gap-4) had no wrap/truncate handling, and its parent<ul>hasoverflow-hidden. A balance formatted to the component's own max of 7 decimal places (e.g.1,234,567.1234567) would be silently clipped on narrow viewports instead of visibly reflowing — for a financial app, silently hidden digits are worse than an ugly wrap. Fixed: the row now wraps (flex-wrap) instead of clipping, the balance value breaks onto a new line if needed (break-all) instead of being cut off, and the asset code truncates gracefully if unusually long.#1361 / #1360 — Dark Mode Theme Engine UI revamp / incorrect state rendering
The actual live dark-mode engine is
src/lib/theme-context.tsx(wired into the app viaThemeProvider→layout.tsx, toggled throughCommandPalette) — the varioustheme-engine*.tsx/ThemeToggle*.tsxfiles elsewhere insrc/lib/src/componentsare unused/orphaned experiments, not wired into any route.theme-context.test.tsx's "Dark Mode Theme Engine" suite (added for #651) was 26/27 failing, plus 25 more failures across the file's other suites — 0/27 passing overall before this PR. Two compounding causes, both fixed:Environment bug (root cause, fixed in
src/test/setup.ts, affects the whole repo): Node 22.4+/24+ ships a nativeglobalThis.localStorage, but without a--localstorage-fileit's a non-functional stub (getItem/setItem/clearallundefined) — only a runtime warning marks it. Vitest's jsdom environment only copies jsdom's real Storage implementation onto a global key when that key isn't already present onglobal; since the broken native stub already occupies it, jsdom's working implementation is silently never installed. Fixed by re-pointingglobalThis.localStorage/sessionStorageat jsdom's real implementation (exposed by Vitest asglobalThis.jsdom.window) in test setup. This alone fixed dozens of unrelated failing tests repo-wide (full suite: 242→180 failing tests, 18→13 failing files).Test-design bug (fixed in
theme-context.test.tsx): the suite replacedglobalThis.document/globalThis.windowwholesale with bare mock objects, but@testing-library/react'srender()needs a realdocument.bodyto mount into — every test callingrender()crashed withCannot read properties of undefined (reading 'appendChild'). Rewrote to spy on the realdocument/windowinstead of replacing them (vi.spyOnonclassList.add/remove,document.querySelector,window.matchMedia), which preserves every existing assertion while keepingrender()functional. Also added the legacyaddListener/removeListenerMediaQueryList methods to thematchMediamock, sincenext-themes(wrapped internally byThemeProvider) still calls those directly and none of the mocks provided them. Fixed three more incorrect test assumptions along the way: a synchronous pre-mount-state assertion that isn't observable given React 18 + RTL'sact()effect-flushing timing; amatchMediamock whosematchesvalue never actually changed when simulating a system-preference-change event; and asetItem-call-count assumption (throw only on the 2nd call) that didn't match the component's real single-call-per-setThemebehavior.Net result: 0/27 → 27/27 in this file, and the underlying theme engine logic (persistence, system-preference resolution, error rollback,
forcedThemeoverride) is now genuinely verified rather than just assumed passing/failing arbitrarily.Disclosure: the full frontend suite still has 13 failing test files unrelated to this PR (confirmed identical on a clean
maincheckout) — e.g.SettingsWidget.tsx'shexToRgbthrowing on certain inputs. Out of scope here; flagging for visibility.Closes #1363
Closes #1362
Closes #1361
Closes #1360