Skip to content

Add end-to-end tests that boot the real desktop app #188

Description

@utof

Problem

Four runtime-only defects reached a working build in a single session, none of which any existing gate could catch:

Defect Symptom
set_provider_key sent api_key instead of apiKey Saving an API key in Settings always failed
cancel_transcription sent request_uuid instead of requestUuid Cancel silently non-functional
transcribe sent file_uuid / file_name / language_hint Transcribe button always failed
Provider registry is built once in build_container Saving a key in Settings has no effect until the app is relaunched

The first three are one bug class (Tauri exposes snake_case Rust params to JS as camelCase unless rename_all opts out) and are now closed by a static cross-check — see apps/desktop/src/__tests__/ipc-contract.test.ts, which derives the command list from lib.rs's invoke_handler and fails on its own parser blind spots.

The fourth is not catchable that way, and neither is anything else that depends on a booted app.

Why the existing gates can't cover this

  • tsc -b — invoke args are typed Record<string, unknown>; anything type-checks.
  • just bindingsbindings.ts is tauri-specta's type output only. It emits no command wrappers, so argument names are never inspected.
  • Component tests — mock ../api wholesale, so no payload is ever observed.
  • ipc-contract.test.ts — static source cross-check. Catches name mismatches; cannot catch runtime wiring.

Uncovered surface

Everything requiring a real process:

  • Keyring round-trip: save in Settings, relaunch, key still resolves.
  • build_container startup wiring: config + keyring produce a registered, active backend.
  • Config directory resolution — desktop reads <app_data_dir>/config.toml while the CLI reads <XDG_CONFIG>/perima/config.toml. GH CLI and desktop write to different SQLite databases on the same machine #154 unified the database path for both shells; config was not included, so the two can silently diverge.
  • Cancel semantics against a real in-flight job.
  • ffmpeg sidecar resolution (desktop uses the Tauri sidecar; the CLI uses which::which) — these are different code paths and only one is exercised today.

Proposal

Stand up tauri-driver + WebdriverIO against a debug build, covering at minimum:

  1. Settings → enter key → save → relaunch → key persists and the provider is active.
  2. Select a file → transcribe → terminal event observed (stubbed provider endpoint, no live API calls in CI).
  3. Cancel an in-flight job → app returns to idle.

Needs research before committing to an approach. Open questions: tauri-driver maturity on Linux (WebKitWebDriver), whether it runs headless on GitHub runners, how to point the app at a stub transcription endpoint without shipping a test-only code path, and whether the cost is justified on the Linux runner only vs the full matrix.

Acceptance criteria

  • A documented local command that boots the app and drives one scenario end to end.
  • At least the Settings key-persistence scenario running in CI.
  • Reintroducing any of the four defects above turns the suite red.
  • If tauri-driver proves unworkable, the research outcome is recorded here and a narrower alternative is proposed rather than the issue being closed silently.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/ciCI pipeline, GitHub Actions, workflowsarea/frontendTouches apps/desktop frontend (React/Vite/Tailwind/ESLint)priority/highHigh-priority work — block other features until this landsstatus/needs-researchDeep multi-source research required before committing to an approachtype/choreRoutine maintenance / repo hygiene

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions