Testing
Trove leans on a small number of high-signal test layers: unit tests with a hard coverage gate on the typed contract, Rust tests for the core, an end-to-end browser suite for the UI, and a hand-driven harness × platform matrix that gates releases.
Running the tests
Section titled “Running the tests”The whole TypeScript suite runs from the workspace root with coverage:
pnpm test # vitest run --coverage --reporter=verbosepnpm test:watch # vitest in watch mode (no coverage gate)For the Rust core:
cargo test --manifest-path packages/app/src-tauri/Cargo.tomlThe coverage gate
Section titled “The coverage gate”Vitest collects coverage with the v8 provider. The thresholds are deliberately strict, matching the gate Trove inherited from claude-sentinel:
| Metric | Threshold |
|---|---|
| Lines | ≥ 95% |
| Statements | ≥ 95% |
| Functions | ≥ 95% |
| Branches | ≥ 93% |
The gate is enforced where the logic lives — the @trove/shared package
(schemas, constants, IPC messages). Two deliberate exclusions keep the
number honest:
- The app frontend (
packages/app/src/) is excluded from unit coverage. It’s exercised end-to-end with Playwright instead, so unit- coverage gating sits on the shared package rather than on React components. - Pure re-export barrels (like
packages/shared/src/index.ts) are excluded. v8 reports them as 0% covered, which would sink the aggregate even when the real schema and IPC files are at 100%.
Rust coverage
Section titled “Rust coverage”Rust coverage is gated separately in CI, not by Vitest:
cargo llvm-cov --fail-under-lines 95 --fail-under-functions 95The bulk of the Rust surface — detection, the safety contract, adapters, and
the supervisor — is covered by unit and integration tests, including a
collector integration test
(packages/app/src-tauri/tests/collector_integration.rs) that runs against
a freshly built sidecar.
UI end-to-end tests
Section titled “UI end-to-end tests”The React UI is validated with Playwright, which runs against the built front end:
pnpm --filter @trove/app e2epnpm --filter @trove/app e2e:install # one-time: install the Chromium runnerThe harness × platform matrix
Section titled “The harness × platform matrix”Trove’s hardest correctness question can’t be answered by unit tests alone: does every harness actually land real telemetry in every backend? The automated testing plan codifies a per-pairing protocol that produces a release-gating results matrix.
The topology under test is the real pipeline:
Harness (claude, agy, …) │ OTLP HTTP/protobuf ▼Trove's bundled collector (127.0.0.1:4318) ← driven by the active preset │ per-preset exporter ▼Platform OTLP intake (local Docker, or a cloud OTLP endpoint)Each cell is verified two ways — collector receipt (the signal reached the sidecar) and a read-side query (it’s queryable in the destination backend). Because Trove is a desktop GUI with no headless IPC to toggle adapters, an operator drives the harness enable/disable in the UI while the rest of the verification is scripted.
Local checks before a PR
Section titled “Local checks before a PR”These mirror CI exactly:
pnpm lintpnpm format:checkpnpm typecheckpnpm testcargo clippy --manifest-path packages/app/src-tauri/Cargo.toml --all-targets -- -D warningscargo test --manifest-path packages/app/src-tauri/Cargo.tomlRun pnpm lint:fix and pnpm format to auto-fix where possible. Every PR
must keep CI green and update tests in the same change as the code they
cover.