Skip to content

Address correctness-review findings; migrate component tests to render() - #71

Merged
trevormunoz merged 3 commits into
mainfrom
test/render-migration-and-correctness-fixes
Sep 10, 2026
Merged

trevormunoz merged 3 commits into
mainfrom
test/render-migration-and-correctness-fixes

Conversation

@trevormunoz

Copy link
Copy Markdown
Member

Addresses three findings from a correctness review (verified against source before accepting), plus a reviewer-supplied end-to-end regression test.

Changes

fix(sync) (60d50d9) — production bug. videoController ran the near-end backoff (duration - 1) after the lower clamp, so any duration shorter than the 1s backoff produced a negative seek (duration 0.5 → -0.5; duration 0 → -1). Now re-clamps the lower bound afterward. New tests cover short/zero durations and a [0, duration] invariant sweep; the prior tests only used 60s durations.

test(sync) (b1bc631) — guard tests. Three syncMachine guard tests named behavior they never exercised (one asserted state topology instead of sending a scroll; one had no assertion; the annotation-unchanged case never sent a second update). Rewritten to await the mediaDriven → ready return and then send the competing event. Calibrated: breaking either guard now fails the matching test.

test (699c249) — unmount-leak fix, done idiomatically. The suite mounted components with raw svelte.mount() (260 calls, 1 unmount), so Svelte destruction never ran between tests — effects, listeners, and transcript polling leaked across the suite. Switched to render() from the already-installed vitest-browser-svelte, whose beforeEach(cleanup) auto-unmounts (the idiomatic Svelte 5 browser-mode tool, not a hand-rolled registry). Net −744 lines as mount/target/teardown boilerplate and the createChildSnippet/createContextCapture helpers go away.

  • Adds TestContextHarness / TestRootContextCapture / TestTranscriptContextHarness and a small TestTwoTranscripts wrapper (context goes through a wrapper because Svelte's createContext key can't be injected via render()'s context map).
  • Adds Root.unmount-lifecycle test: a VTT resolution completing after unmount must not write transcript state. Calibrated by awaiting the exact loadVTTTranscript promise, after an earlier microtask-drain version produced a false green.
  • Integrates element-scroll-seek test: scrolling the real custom element's transcript to the bottom seeks the audio to the last cue end (29s), not media duration (40s). Closes a gap where disabling the scroll listener passed every prior test.
  • Root.transcript-generation: replaces a 100ms wall-clock wait with vi.waitFor (flaky under full-suite load; behavior unchanged).
  • Two Root tests with a genuine render()-vs-mount() async-fetch race are left on mount() + explicit unmount() (documented; no leak).

Verification

  • pnpm test: 745 passed across 70 files
  • pnpm typecheck: 0 errors
  • pnpm lint: eslint + prettier clean
  • Each finding fixed test-first and calibrated (breaking the guarded code fails the test)

No public API or demo changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_015KfYGrLi7iJoevyVQsn5ur

trevormunoz and others added 3 commits September 10, 2026 08:02
The near-end backoff (seek to duration-1) ran after the lower clamp, so a
duration shorter than the 1s backoff produced a negative seek (e.g. duration
0.5 -> -0.5; duration 0 -> -1). Re-enforce the lower bound after the
adjustment. Add tests for short/zero durations and a [0, duration] invariant
sweep; existing tests only used 60s durations and never reached this.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KfYGrLi7iJoevyVQsn5ur
The guard tests named behavior they never drove: one asserted machine state
topology instead of sending a scroll, one had no assertion, and the
annotation-unchanged test never sent a second update. Rewrite them to await
the mediaDriven->ready return (xstate waitFor), then send the competing event
and assert the guarded transition. Calibrated: breaking either guard now
fails the matching test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KfYGrLi7iJoevyVQsn5ur
The suite mounted components with raw svelte.mount() (260 calls, 1 unmount),
so Svelte destruction never ran between tests — effects, listeners, and
transcript polling outlived each test. Switch to render() from the
already-installed vitest-browser-svelte, whose beforeEach(cleanup) auto-
unmounts; this is the idiomatic Svelte 5 browser-mode tool, not a hand-rolled
registry. Net -744 lines as the mount/target/teardown boilerplate and the
createChildSnippet/createContextCapture helpers go away.

- Add TestContextHarness / TestRootContextCapture / TestTranscriptContextHarness
  and a small TestTwoTranscripts wrapper; context is supplied through a wrapper
  because Svelte's createContext key can't be injected via render()'s context map.
- Add Root.unmount-lifecycle test: a VTT resolution completing after unmount
  must not write transcript state. Calibrated by awaiting the exact
  loadVTTTranscript promise (vttRegistry), after an earlier microtask-drain
  version produced a false green.
- Add element-scroll-seek test: scrolling the real custom element's transcript
  to the bottom seeks the audio to the last cue end (29s), not media duration.
  Closes a gap where disabling the scroll listener passed every prior test.
- Root.transcript-generation: replace a 100ms wall-clock wait with vi.waitFor
  (flaky under full-suite load; behavior unchanged).
- Two Root tests with a genuine render()-vs-mount() async-fetch race are left on
  mount() + explicit unmount() (documented; no leak).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KfYGrLi7iJoevyVQsn5ur
@trevormunoz
trevormunoz merged commit e92c0fb into main Sep 10, 2026
1 check passed
@trevormunoz
trevormunoz deleted the test/render-migration-and-correctness-fixes branch September 10, 2026 12:04
trevormunoz added a commit that referenced this pull request Sep 10, 2026
…ased

The [0, duration] seek fix merged in #71 landed without a changelog entry;
record it so the next release promotes it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KfYGrLi7iJoevyVQsn5ur
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