Test stack#
- Vitest 4 runs the test suite.
- jsdom supplies the browser-like environment configured in
vite.config.ts. - Testing Library renders React components and queries their accessible output.
@testing-library/user-eventdrives user-style interactions.src/renderer/test/setup.tscleans up rendered React trees after every renderer test.
Tests are colocated with source files and use *.test.ts or *.test.tsx.
Commands#
npm test
npm run test:watch
npm run lint
npm run buildnpm run build is also the authoritative type and bundle check. It type-checks the renderer and Electron projects, then runs the integrated Vite build for renderer, main, preload, storage, and agent entries. TypeScript uses strict mode, rejects unused locals and parameters, and disallows fallthrough switch cases.
ESLint enforces a cyclomatic complexity ceiling of 15 per function. Orchestration that exceeds it should be split into named lifecycle or action handlers.
Current automated coverage#
The suite currently contains unit and component coverage across renderer, storage, autonomous-loop, activity, and Pi-session boundaries.
| File | What it protects |
|---|---|
suggestions/inbox.test.ts |
Presentation sorting and transient stale/withdrawn decoration. |
suggestions/useSuggestionController.test.ts |
Optimistic commands, serialization, event/RPC ordering, and preview update/retraction state. |
suggestions/state.test.ts |
Shared empty state, protected queue eviction, and canonical kind guards. |
workspace/useWorkspaceController.test.ts |
Hydration, serialized autosave, desktop events, control errors, and preview resolution. |
suggestions/dock/SuggestionDock.test.tsx |
Absence of legacy steering controls, unified stream, text preview action, pin presentation, and workspace placement callback. |
suggestions/workspace-pins/WorkspacePins.test.tsx |
Card content, return action, keyboard geometry, and pointer drag commit. |
workspace/DocumentHeader.test.tsx |
Desktop panel semantics, hidden-partner unread count, and independent mobile controls. |
ui/ResponsiveDrawer.test.tsx |
Escape/close behavior and focus restoration. |
src/utility/storage/service.test.ts |
Block/Markdown saves, mirror repair, stale suggestion rejection, and Markdown-only source import. |
src/utility/agent/domain/loop.test.ts |
Coalescing, yields, races, five-cycle cap, error sleep, wake, and restored loop state. |
src/main/diagnostics/activity.test.ts |
Aggregation, redaction, 50 KB cap, and 500-item eviction. |
src/utility/agent/pi/session.test.ts |
Project session continuation, extension entries, and the read-only tool contract. |
src/utility/agent/pi/activity.test.ts |
Lifecycle, message/reasoning/error, and tool activity conversion. |
src/utility/agent/extension.test.ts |
Active revisions, storage failures, wake behavior, and suggestion mutation results. |
Why transition and controller tests matter most#
transitions.ts contains durable lifecycle invariants shared by optimistic rendering and storage. useSuggestionController owns serialization and renderer-only selection/preview state. Changes to either boundary should begin with focused tests there; component tests should then verify the exposed user intent.
Geometry tests#
jsdom does not perform layout. Workspace tests mock clientWidth and clientHeight, and pointer-capture methods are stubbed where needed. A passing geometry unit test does not replace Electron renderer testing for actual scroll, resizing, and pointer behavior.
What is not covered automatically#
The current suite does not render the full App or BlockNote editor. It therefore does not directly verify:
- preview block insertion, editing, accepting, or cancellation;
- panel drag resizing and
localStoragerestoration; - breakpoint transitions and drawer/desktop handoff;
- initial workspace-card placement in the real scrolling canvas;
- canvas clamping through a real
ResizeObserver; - Mermaid SVG rendering and failure handling;
- production bundle execution, Electron readiness, and
file://asset resolution; - real-provider autonomous behaviour and provider-specific streaming;
- visual layout, overflow, font fallback, or contrast.
Changes in these areas require targeted tests where practical and the manual checks below.
Manual regression checklist#
Editor#
- The seeded document renders and remains editable.
- Editing document text does not create suggestions.
- Block formatting, selection, slash menu, and normal BlockNote editing still work.
Suggestion lifecycle#
- The inbox remains empty until the agent publishes a suggestion.
- Representative agent-produced kinds appear with their content and visual treatment.
- The workspace exposes no Generate Ideas, steering, or retry controls.
- Selecting marks an item read; Back returns to the correct queue.
- Pin and unpin preserve a frozen copy and correct ordering.
Preview lifecycle#
- Only text kinds offer Preview.
- The preview appears after the last active accepted block and receives focus.
- Only one preview can be active.
- The preview is editable; empty content disables Accept.
- Cancel removes the block and keeps a normal source suggestion.
- Accept converts it to a normal paragraph and removes the suggestion.
- Agent update/retraction does not overwrite an existing preview.
Desktop layout (>=80rem)#
- Both side columns can collapse independently.
- Pointer and keyboard resizing respect the editor's minimum space.
- Reload restores sizes; double-click resets them.
- A pinned detail can be placed on the workspace.
- Cards move, resize, stack, clamp, scroll internally, and return to Pins.
- Selecting suggestion detail does not make the center editor unusably narrow.
Below desktop (<80rem)#
- Navigation and writing partner open as the correct side drawers.
- Escape, backdrop, and close button dismiss a drawer.
- Focus enters the drawer, wraps, and returns to the trigger.
- Workspace placement is unavailable and no workspace card is shown.
- Header controls and status tabs remain reachable without horizontal page overflow.
Accessibility#
- Complete core flows with keyboard only.
- Inspect button/dialog/region names with browser accessibility tools.
- Confirm visible focus on all interactive elements.
- Confirm unread counts and errors are announced as text, not color alone.
- Force invalid Mermaid source and confirm the description remains available.
Electron runtime#
- Run
npm run devand confirm Electron launches without manually opening the Vite URL. - Change renderer code and confirm HMR; change main/storage/agent code and confirm Electron restarts; change preload and confirm the renderer reloads.
- Publish a suggestion through Pi, reload, and confirm it remains persisted.
- Launch the built application and confirm the renderer mounts without failed local script or stylesheet requests.
- Edit and restart to verify document hydration and the 650 ms autosave path.
- Import
.mdand.markdown, including duplicate names; reject invalid UTF-8 and other extensions. - Restart and confirm sources, suggestions, pins, and workspace geometry hydrate from SQLite.
- Confirm Pi
settings.json,auth.json, andmodels.jsonload; invalid configuration leaves the agent offline without exposing credentials. - Confirm every app launch begins stopped and editing or importing sources does not invoke the provider before Start Agent.
- Start after several stopped revisions and confirm only the latest revision is reviewed. Stop during streaming and confirm cancellation is immediate, no error is reported, and no new cycle begins.
- Start again after cancellation, error, or cap and confirm the latest revision is retried; stop/start after a successful yield must not repeat unchanged work.
- Observe multi-cycle work, a suggestion,
waiting, and immediate wake after a new durable revision. - Reload the renderer and retain current-launch Activity; restart the app and confirm Activity clears while the Pi session resumes.
- Force a storage or agent utility-process startup failure and confirm main reports the failure and exits instead of hanging without a window.
Adding tests#
Match the test boundary to the behavior:
- pure durable transition: add to
transitions.test.ts; - command/event reconciliation or transient preview state: add to
useSuggestionController.test.ts; - component semantics/callback: render the component with explicit props and query by accessible role/name;
- full editor integration: use a browser-level test rather than relying on jsdom layout and
contenteditableemulation.
Prefer public behavior over implementation details. Tests should query accessible names and roles, assert emitted events or callback arguments, and avoid snapshotting large Tailwind class strings.
Pre-handoff standard#
Before handing off a change:
- run lint;
- run all unit/component tests;
- run the production build;
- manually exercise each changed flow at the relevant breakpoints;
- update
/docsif a contract, invariant, command, breakpoint, persistence rule, or static/functional boundary changed.