Skip to content

Cover the app entry with tests - #8

Merged
BJMCox merged 1 commit into
mainfrom
main-tests
Jul 28, 2026
Merged

Cover the app entry with tests#8
BJMCox merged 1 commit into
mainfrom
main-tests

Conversation

@BJMCox

@BJMCox BJMCox commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

src/main.ts had no tests. It is where every bug found by hand-driving the built app actually lived — the failed load that stripped ?sample=&node= from a model still on screen, the onerror handler that Chrome never fires, the search stepping that hung off change — and none of those were visible to the suite. CI now runs on every push, so it was worth giving it something to protect.

The harness

Importing main.ts wires the whole UI to the current document, so it cannot be called into. test/app-harness.ts rebuilds the DOM and re-imports the module for each case (vi.resetModules() + dynamic import). The DOM is read from the real index.html, not restated, so a control main.ts looks up by id but the markup has lost fails loudly instead of silently disabling a feature.

Fakes for what jsdom lacks, each documented in the harness:

Fake Why
Worker jsdom has none. Records what main.ts posts and answers on demand — answer() runs the real detectAndParse, i.e. the worker's own body — so the ready handshake, load tokens, superseded replies and the startup watchdog are all drivable.
fetch Bundled samples read off disk from public/.
localStorage Undefined under this runner; main.ts optional-chains it, so the persistence paths would otherwise just be skipped.
<dialog> jsdom implements only open — no showModal, close, returnValue. submitDialog() stands in for the browser's form[method=dialog] step, so these cases cover our handlers, not the browser semantics under them.
Element.scrollIntoView No layout in jsdom, and the tree scrolls the selected row into view on every selection.

Coverage

67 cases, 180 → 247 in the suite.

Loading (main-load.test.ts): startup empty state and the one-click sample CTA; the registry-derived dropdown; sample fetch, parse and reporting; fetch failure; the file picker; drag-and-drop including the overlay's enter/leave/child-crossing behaviour; paste, cancel and empty paste; the large-file warning both ways; parse failure keeping the previous model; superseded replies ignored; the watchdog firing for a worker that never starts and not firing for a slow parse once ready; onerror and onmessageerror; the deep-linkable URL, including an unknown sample and an unknown node.

Interaction (main-ui.test.ts): search by id, by type, no-match, empty; Enter stepping and wrapping; change staying idempotent; debounced suggestions; / and Escape, including that typing is never hijacked; pane resizing by keyboard and by pointer, clamping, Home, and persistence; pane tabs; the model dialog's summary, metadata, worst-first diagnostics, node xref, and the diagnostic count button.

Verification

The suite passes 247/247, three consecutive runs, plus tsc --noEmit and the build.

The two cases carrying regression notes were mutation-checked: reverting each fix in main.ts makes exactly that case fail (and reverting the search fix fails 7 search cases). The watchdog case was checked the same way. So these aren't tests that merely pass.

src/main.ts had no tests at all. It is where every bug found by hand-driving
the built app actually lived, and three of those were invisible to the suite.

Importing main.ts wires the entire UI, so test/app-harness.ts rebuilds the DOM
from the real index.html and re-imports the module for each case. Reading the
markup from disk means a control main.ts looks up by id but index.html has lost
fails loudly instead of silently disabling a feature. Fakes stand in for what
jsdom lacks: Worker (there is none), fetch (samples are read off disk),
localStorage, <dialog> (only `open` is implemented), and Element.scrollIntoView.
The worker fake replays the real parser, so the ready handshake, load tokens,
superseded replies and the startup watchdog can be driven exactly.

67 cases: the loading paths (samples, picker, drag-and-drop, paste, the
large-file warning, fetch and parse failures, the deep-linkable URL) and the
interaction paths (search stepping and suggestions, / and Escape, pane resizing
and persistence, pane tabs, the model and diagnostics dialog).

Two cases carry a regression note, and both were checked by reverting the fix
and confirming only that case fails: the failed load that used to strip
?sample=&node= from a model still on screen, and search stepping that hung off
`change`, which a browser does not fire when the value has not been edited.
@BJMCox
BJMCox merged commit 847d8e4 into main Jul 28, 2026
2 checks passed
@BJMCox
BJMCox deleted the main-tests branch July 28, 2026 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant