Datler is a Tauri app, which rules out one thing only: launching the real window from Node. Everything behind the Repository Seam is plain TypeScript with no Tauri runtime, so the domain, the database layer and the components are tested cheaply and fast, and the real window is checked by attaching to it. The seam is what makes the app testable.
Layers
| Layer | Tool | Covers |
|---|---|---|
| Domain and database | Vitest, node | @datler/core: the repositories, the migration runner, sync, the seeds, over real SQLite |
| Components | Vitest, jsdom, with Testing Library | the renderer’s components and hooks |
| Rust | cargo test | that the shell builds, and the unit tests of its file operations |
| The real window | the CDP probe (playwright-core) | the running app: console, routes, flows, timings, layout (Driving the App (CDP)) |
The database is real. Core’s tests run the same SQL the app runs, against an in-memory node:sqlite database (packages/core/test/memory-driver.ts) injected through the SqlDriver the app’s plugin connection also satisfies, so a query, a migration or a merge is exercised for real without Tauri.
Tauri is mocked at the module. The few renderer files that call the shell directly are tested with vi.mock("@tauri-apps/api/core") or vi.mock("@tauri-apps/plugin-sql").
jsdom lays nothing out, so it cannot test what needs layout: a drag or an arrow key moves nothing there, and a Base UI combobox does not mount. Those are checked in the real app or the browser build with the probe, and a test never passes by rendering nothing.
The Rust layer is thin on purpose. The shell runs no migrations, so it holds no schema tests: the migration runner is tested where it runs, over real SQLite, in packages/core/src/migrator.test.ts. What the shell does own, it tests: the one-time copy of the former identifier’s profiles, the profile state file, which files may be deleted, and the export folder’s names. cargo test also builds the crate, which is where a broken Tauri configuration or dependency shows.
No scripted end-to-end suite. A maintained suite over a UI that is still changing would be rewritten faster than it paid for itself. The probe gives the same real-window coverage per change at a fraction of the upkeep, at the cost of running only by hand against a live app, not in CI.
Running them
The root vitest.config.ts defines two projects: node for **/*.test.ts and dom (jsdom) for **/*.test.tsx, with @ resolving to apps/renderer/src and src-tauri/, apps/docs/ (Quartz’s own tests) and .claude/ left out. The dom project loads vitest.setup.ts (Testing Library’s matchers and cleanup, 24-hour clock text) and keeps Vitest’s 5-second limit. It needs jsdom 27 or later, whose selector engine is @asamuzakjp/dom-selector: jsdom 26’s nwsapi (2.2.27) recurses on :modal and :popover-open, which floating-ui checks on every positioning pass, so a test that opens a popover or dialog takes seconds there.
pnpm test # every Vitest test
pnpm run test:watch
pnpm exec vitest run <path> # a subset, from the root
pnpm run test:rust # cargo test for the shell
A subset is run from the root: filtering into the renderer’s package skips the root config that puts .test.tsx under jsdom.
CI (.github/workflows/ci.yml) runs on every push to develop and every pull request: biome ci ., pnpm run typecheck (the workspaces and scripts/, see DB Dev Commands), pnpm test and vault-kit validate; and, in a job of its own with the Rust toolchain and webkit2gtk on the runner, cargo test for the desktop shell. It does not run the probe, which needs a running app. Biome lints scripts/ as well as the apps, so a dev-script change is checked by both lint and types.
Every change ships its tests
Domain logic is tested against the in-memory database, components in jsdom, and a claim about the real app with a pnpm run drive run whose ACTIONS block shows the flow actually ran. Some rules of the writing are tests too: apps/renderer/src/ui-copy.test.ts fails on a label written as an “Its …” phrase.
Related
Driving the App (CDP) · Repository Seam · Migration Runner · DB Dev Commands · Architecture Overview