Files
SubMiner/docs/workflow/testing.md
T
sudacode f89f78b861 refactor(main): move plugins, session actions and subtitle generation into assemblies (#327)
* refactor(main): build overlay geometry and pointer interaction in the overlay assembly

Inject Electron's screen (and the stats-window promotion) into the overlay geometry and
visible-overlay interaction runtimes so they load under bun test, then construct both in
createOverlayAssembly together with the overlay visibility composer and the mpv subtitle
suppression handlers. Replace the three regex tests that pinned the moved Linux input and
shape code with behaviour tests on the runtimes.

* refactor(main): move the autoplay-ready gate into the playback assembly

The autoplay-ready gate, its post-warm subtitle prime, the current-media tokenization gate and
managed local subtitle selection all read playback state, and playback signals through the
gate, so createPlaybackAssembly now builds them. The overlay reaches the gate through a getter.

Replace the last four regex guards with behaviour tests: the gate holds the release until the
visible overlay has measured the line and ignores untokenized lines during warmup (playback),
cached autoplay priming never paints raw first and the sidebar media path is tagged only after
prefetch loads (priming runtime), and dashboard mining overrides the Hachidori Anki server only
when the proxy is on (stats server runtime). main-wiring.test.ts is now empty and removed.

* refactor(main): move the plugin host, panel and windows into a plugins assembly

* refactor(main): move session action dispatch and renderer mpv commands into an assembly

createSessionActionsAssembly owns the session action dispatcher, the secondary-subtitle mode cycle, queueing the clipboard's video, and the mpv commands the overlay renderer sends. The runtime option cycle both paths used is now one function.

* refactor(main): move Whisper subtitle generation into an assembly

* refactor(main): resolve subtitle annotation options in a runtime module

The runtime-option-over-config resolution that the texthooker page and the MeCab startup decision share moves out of main.ts into createAnnotationOptions.

* test(main): cover a non-boolean runtime annotation option value

* docs: describe the plugins, session actions and subtitle generation assemblies

Update ownership for overlay geometry and pointer interaction, the autoplay-ready gate, and annotation options; point the overlay priming entry points at their new modules; the main-wiring regex debt is gone.

* build: export MpvClientEvents so declaration emit can name the plugins assembly's return type
2026-11-04 21:54:49 -08:00

2.2 KiB

Testing Guidelines

Status: active
Last verified: 2026-10-04
Owner: Kyle Yasuda
Read when: adding or changing tests

Which lanes to run lives in Verification. This page covers what a good test looks like here.

Test Behavior, Not Wiring

  • Exercise a module through its public interface and assert outcomes: return values, resulting state, files written, rows in sqlite, messages sent to a fake process.
  • Prefer real collaborators that are cheap: tmp dirs, in-memory or tmp sqlite, fake executables, pure parsers. Fake only the edges (Electron, mpv socket, network).
  • Assert call order only when order is the behavior (startup sequencing, ABA races), and then assert relative order, not the whole call log.

Do Not Write

  • Pass-through tests: a handler or adapter that only forwards deps (*-runtime-handlers.ts) needs no test. TypeScript already checks the shape.
  • Source-text tests: reading .ts, .css, .html, .lua, .swift, or workflow YAML and asserting with regexes. If the invariant matters, extract the logic and run it (see src/preload-ipc-listeners.ts). Policy lints over workflow YAML are the exception and belong in one parsed-YAML check.
  • "Stays deleted" tests for removed modules, flags, or selectors. tsc and review catch reintroduction.
  • Tests that restate constants, defaults, labels, or window options.
  • The same rule at several layers. Test a rule once where it lives; keep one end-to-end case (for the tokenizer, the golden corpus) for integration.

Keep Tests Small

  • Shared setup goes in a makeDeps(overrides) helper or a *-test-harness.ts file, not pasted into every test.
  • Near-identical cases become a table: for (const c of cases) test(c.name, ...).
  • Inject timers, clocks, and loggers instead of patching globals or private members.
  • A bug fix gets a regression test for the behavior that broke, named after the behavior, not the ticket.

Known Debt

  • src/renderer/renderer-init-order.test.ts still regexes renderer.ts to guard startup ordering. Replace it with a behavioral test as that logic moves out of renderer.ts.