Skip to content

Test setup loads the editor stack for every test file #133

Description

@Azganoth

Summary

Every frontend test file loads the entire Milkdown and Shiki stack before its first assertion, whatever it covers, and the cost surfaces as intermittent beforeEach timeouts rather than as slow tests.

The chain, verified link by link:

  1. The global beforeEach in src/test/setup/common.ts:28 does await import("../utils/appStores").
  2. src/test/utils/appStores.ts:17 imports useSessionStore from the @/features/session public API.
  3. src/features/session/index.ts:3 re-exports documentEditorBridge.
  4. src/features/session/services/documentEditorBridge.ts:1-7 imports @/features/editor, whose index exports MilkdownEditor, pulling @milkdown/kit/* and Shiki.

The same edge affects production, not only tests. Nine modules import @/features/session, and seven of them never touch the editor otherwise: App.tsx, commands/actions/edit.ts, commands/actions/file.ts, commands/actions/view.ts, commands/hooks/useAppCommands.ts, components/layout/Shell.tsx, and components/screens/WelcomeScreen.tsx. Only commands/dispatch.ts and components/screens/DocumentScreen.tsx import the editor directly. WelcomeScreen.tsx is the clearest case: the screen shown before any document is open transitively pulls the whole editor stack.

Affected areas

  • src/test/setup/common.ts and src/test/utils/appStores.ts.
  • src/features/session/index.ts and src/features/session/services/documentEditorBridge.ts.
  • The nine production modules importing @/features/session listed above.
  • vite.config.ts, if a hookTimeout override is added.

Intended outcome

A test file that does not exercise the editor does not load Milkdown or Shiki, and @/features/session stops being an entry point into the editor module graph for consumers that only need session state. Test count and assertions stay unchanged.

Related context

  • Related issues or pull requests: Test setup is re-inlined instead of reused from src/test/ #128 and its pull requests touched the same test setup but did not change the import graph.
  • Prior investigation: the measurements below were taken in an earlier session on a 12-core, 34 GB Windows machine and are recorded as reported, not re-measured here.
    • formatFileSize.test.ts, 16 trivial assertions with 14ms of own imports, spends 4.30s in the tests phase.
    • The same file drops to 1.57s when useSessionStore is deep-imported from src/features/session/stores/session, a 2.7x improvement.
    • Full-suite flake on one commit across three runs: 1 file failed at 12 workers, 4 files failed at 4 workers, 0 failed on the third run. The failure is always the beforeEach hook exceeding the 10s Vitest default, never an assertion.

Done when

  • A test file that does not exercise the editor no longer loads Milkdown or Shiki.
  • @/features/session no longer pulls the editor module graph into consumers that do not import the editor themselves.
  • Any deliberate deep import in src/test/ states why, as src/AGENTS.md requires for exceptions to the feature-root import rule.
  • pnpm check:frontend passes with the test count unchanged.

Notes

CI history is established rather than assumed: 100 runs since 2026-07-07 show 99 successes and one failure, and that failure was an assertion in Dialog.test.tsx > keeps dialogs open when dragging starts from the titlebar drag region, not a hook timeout. CI has never produced this failure mode.

That evidence complicates the explanation rather than confirming it. The failing CI run took 209s for 79 files and 545 tests, far slower in wall clock than local runs of about 78s for 90 files and 882 tests, and GitHub runners have fewer cores than the machine where the flake reproduces. Fewer workers made the flake worse locally, so the configuration that should be most vulnerable is the one that never fails. The trigger is therefore not simply a slow machine, and this is unexplained.

Implementation direction

Deep-importing useSessionStore from src/features/session/stores/session in appStores.ts is the cheap mitigation, and src/test/utils/tauriApi.ts already deep-imports feature internals, so the precedent exists. It fixes the test symptom while leaving the production edge in place.

Removing documentEditorBridge from the session public API addresses the cause and is the change with production value, but it moves a real API boundary and deserves its own review.

Out of scope

  • Raising Vitest's hookTimeout. It hides the symptom, and because the trigger is not understood, there is no basis for choosing a value that would reliably help.
  • Bundle-size claims. The module graph edge is confirmed, but no bundle measurement has been taken, so no claim is made about what survives tree shaking.

Metadata

Metadata

Assignees

Labels

MaintenanceChore, refactor, dependency, or test work without user-facing change

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions