Skip to content
Rymflux Documentation
Esc
navigateopen⌘Jpreview
On this page

Testing strategy — Rymflux v2

Testing strategy — Rymflux v2

Status

Draft v1 — 2026-07-31

Purpose

This document is the authoritative testing strategy for Rymflux v2. It extends frontend-architecture.md §13: it details the test layers, the tooling (including the Browser Mode component-testing choice formalized in ADR-017), the traceability rule that ties every Must-have FR to a test case, and the evidence artifacts the coverage-reports/, performance-benchmarks/, and security-scan-results/ folders are meant to receive.

Audience: QA, developers, security reviewers.

Test layers

Layer Tooling What is tested
Rust unit cargo test (per crate) Service logic: plugin manifest parsing + discovery (FR-PLUGIN-1/2), search dispatch/merge/timeout (FR-CORE-4), playback state transitions, library CRUD + dedup (FR-CORE-3), content resolution, dominant-color extraction (ADR-016), UUID content ids (FR-ID-1). Audio fixtures rendered via phonic’s wav-output dev feature.
Rust integration cargo test in src-tauri Command handlers invoke the documented command names with documented payloads (ADR-014 seam); SQL migrations apply cleanly against a tempfile temp database (ADR-002); Tauri events are emitted with the documented shapes (tauri-events.md).
Frontend state (unit) Vitest node project, *.svelte.ts runes (ADR-013) Queue mutations (ADR-010), search state machine (progressive results, per-plugin error), player state transitions, room state hoisting (ADR-012). The ipc/ bridge is mocked (vi.mock('@rymflux/ipc/...')).
Frontend component + integration Vitest browser projectvitest-browser-svelte (chromium) UI primitives (ADR-015 tokens), EmptyState/Loading/Error fallbacks, MiniPlayer, RoomRenderer lifecycle, event → state → component flow (e.g. queue_updated re-renders QueueView). @tauri-apps/api mocked at module level. See Browser Mode notes below.
E2E (deferred) WebdriverIO + @wdio/tauri-service over tauri-driver; Playwright against the dev server Full user journeys (journey-listener-music.md); deferred until the app is feature-complete enough for smoke tests (frontend-architecture.md §13 / §16.5). See E2E below.

Browser Mode (component + integration tests)

Component and integration tests run in Vitest Browser Mode with vitest-browser-svelte (ADR-017). Conventions:

  • Test files are named .svelte.test.ts next to the code they cover, per the traceability rule — Svelte’s rune transform is enabled for test files by that extension.
  • Locators use the real DOM: page.getByRole, page.getByTestId, expect.element(...). Assertions auto-retry until the UI settles.
  • flushSync() after state mutation: universal state lives in *.svelte.ts modules (ADR-013); mutating it does not by itself flush a DOM update in browser tests. Wrap the mutating call in flushSync(() => ...) (from svelte) before asserting on the DOM.
  • @tauri-apps/api is mocked at the module boundary; nothing in a component test should touch real IPC.
  • Runs headless chromium in CI; pnpm vitest --browser opens the headed browser for local debugging.

vitest.config.ts (starting shape)

import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { svelteTesting } from '@testing-library/svelte/vite';

export default defineConfig({
  plugins: [svelte(), svelteTesting()],
  test: {
    projects: [
      { test: { name: 'state', environment: 'node' } },          // *.svelte.ts unit tests
      { test: { name: 'browser', browser: { enabled: true, name: 'chromium', headless: true } } },
    ],
    coverage: { provider: 'v8', reportsDirectory: 'coverage-reports' },
  },
});

The exact plugin wiring is pinned when vitest.config.ts is first scaffolded; this is the intended shape, not a guarantee of a specific Vitest minor’s API.

E2E (deferred — plan)

  • Official backend-driven path: WebdriverIO + @wdio/tauri-service over tauri-driver (W3C WebDriver). browserName: "wry" targets the real webview; IPC is driven and mocked with browser.tauri.execute(). On macOS the tauri-wd automation server is required (there is no native WKWebView WebDriver client).
  • Frontend-only path: Playwright against the Vite dev server, intercepting invoke() to drive journeys without a backend. Good for shell/navigation smoke tests before the Rust app is wired.
  • Future/community: tauri-plugin-playwright (embeds a control server, drives the real native webview) is promising but unstable — not part of the v1 baseline.
  • Stand-up gate: when the app is feature-complete enough for smoke tests (frontend-architecture.md §16.5). Until then, add per-feature test cases to test-cases/ as features land.

Traceability

Every Must-have FR with a Gherkin scenario in functional.md gets at least one test case filed under test-cases/<fr-slug>.md (using the test-case.md template; the upstream template is referenced via KIT.md, and test-cases/example-test-case.md is the in-repo starter stub) plus the beside-code spec it documents. The IPC bridge is a seam: tests assert the wrappers invoke the documented command names with the documented payloads, not the Rust internals.

FR Title Primary layers Test case target
FR-PLUGIN-1 Plugin discovery and registration RU test-cases/fr-plugin-1.md
FR-PLUGIN-2 Plugin manifest format RU test-cases/fr-plugin-2.md
FR-PLUGIN-3 Plugin lifecycle RU, RI test-cases/fr-plugin-3.md
FR-PLUGIN-4 Plugin search capability RU, FS test-cases/fr-plugin-4.md
FR-PLUGIN-5 Plugin streaming capability RU, RI test-cases/fr-plugin-5.md
FR-PLUGIN-6 Plugin metadata capability RU, FS test-cases/fr-plugin-6.md
FR-ROOM-1 Room registration and lifecycle FS, FC test-cases/fr-room-1.md
FR-ROOM-2 Room search integration FI test-cases/fr-room-2.md
FR-ROOM-3 Room player expansion FC, FI test-cases/fr-room-3.md
FR-CORE-1 Source-agnostic playback engine RU, RI test-cases/fr-core-1.md
FR-CORE-2 Queue management FS, RU test-cases/fr-core-2.md
FR-CORE-3 Unified library RU, FS test-cases/fr-core-3.md
FR-CORE-4 Parallel search manager RU, FS test-cases/fr-core-4.md
FR-ID-1 Stable content UUIDs RU test-cases/fr-id-1.md
FR-MUSIC-1 Music Room browsing FC, FI, E2E† test-cases/fr-music-1.md
FR-MUSIC-2 Music Room player expansion FC, FI, E2E† test-cases/fr-music-2.md
FR-HOME-1 Home (Lobby) FC, FI, E2E† test-cases/fr-home-1.md
FR-REF-1 Local-files reference plugin RU, RI, E2E† test-cases/fr-ref-1.md

† E2E columns are deferred per the E2E section; add the cases when E2E stands up.

Evidence artifacts

Folder Contents
coverage-reports/ v8 coverage output (HTML + cobertura) from pnpm test and cargo llvm-cov for the workspace. Thresholds set in CI (frontend state ≥ 80%, components ≥ 80%, Rust core ≥ 85% — adjust once a baseline exists).
performance-benchmarks/ Measurements against frontend-architecture.md §12 targets: room switch ≤ 300ms p95 (NFR-PERF-6), startup ≤ 3s cold (NFR-MAINT-3), search results ≤ 2s p95 (NFR-PERF-4). Timed in browser mode / release builds; logged as dated runs.
security-scan-results/ cargo audit and pnpm audit output per run, plus RLS/supply-chain notes.

CI gates (pre-merge order)

  1. cargo fmt --check and cargo clippy --workspace --all-targets (deny warnings).
  2. cargo test --workspace.
  3. pnpm check (svelte-check), pnpm lint.
  4. pnpm test (node + browser projects) with coverage thresholds.
  5. Build smoke: pnpm build.

A change that touches user-visible behavior lands with its test case and spec (traceability rule) or explicitly flags the missing case in the PR.

References

Was this page helpful?