---
name: Tests
type: architecture-map-page
slice: 02-tauri-runtime
last_verified: 2026/05/09
---

# Tests

> **Where you are:** [Architecture map](../README.md) → [Tauri runtime](README.md) → Tests

**Plain English summary.** A single integration test file that protects three security-relevant config invariants: the loopback LLM CSP must stay narrow, any updater config that ships must carry a non-empty pubkey, and the secondary windows must never get high-risk plugin permissions. Unit tests live alongside the code they test (each command file has its own `#[cfg(test)]` module).

## At a glance

- Path: `src-tauri/tests/config_hardening.rs` (93 LOC).
- Tauri commands exposed: none.
- Events emitted: none.
- Depends on: `serde_json` (for parsing the JSON configs), `std::fs` and `std::path::Path` (for walking the capabilities directory).

## What's in here

### `csp_keeps_loopback_narrow` (`src-tauri/tests/config_hardening.rs:15`)

Reads `src-tauri/tauri.conf.json`, finds the `connect-src` directive of `app.security.csp`, asserts:

- `http://127.0.0.1:*` is present.
- `ws://127.0.0.1:*` is present.
- `http://localhost:*` is absent.
- `ws://localhost:*` is absent.

This is the runtime sibling of the build-time guard in `src-tauri/build.rs:30`. Both must agree. The build guard is the harder check (it stops compilation) and the integration test is the safety net for someone running `cargo test` without `cargo build` between edits.

### `updater_is_signed_or_absent` (`src-tauri/tests/config_hardening.rs:35`)

If `plugins.updater` exists in `tauri.conf.json`, asserts the `pubkey` field is a non-empty string. If `plugins.updater` is absent (which it currently is), the test is a no-op. The intent is that you cannot accidentally ship an updater config with a placeholder / empty key.

### `secondary_windows_do_not_get_high_risk_plugin_permissions` (`src-tauri/tests/config_hardening.rs:50`)

Scans `src-tauri/capabilities/*.json`. For each capability whose `windows` array references any of `tasks-float`, `transcript-viewer`, or `transcription-preview`, asserts no permission starts with the prefixes `dialog:`, `autostart:`, `global-shortcut:`, `opener:`, or `updater:`. Catches drift the moment someone adds, say, `dialog:default` to a secondary capability. See [Capabilities and ACL](capabilities-and-acl.md).

### Unit tests (other locations)

Each command module has its own `#[cfg(test)] mod tests` block. Notable ones:

- `commands/audio.rs` — `recording_filenames_are_unique_across_rapid_calls` (RB-06 regression for filename collisions), `stop_worker_awaits_full_termination_no_writes_after_join`, `stop_worker_is_idempotent`.
- `commands/models.rs` — `compose_accelerators` matrix (RB-07 regression for the hard-coded `["cpu", "vulkan"]` bug).
- `commands/llm.rs` — `classify_llm_load_error` covers VRAM / corrupt-file / permission / unknown classifications.
- `commands/paste.rs` — terminal classifier and PowerShell escape-sequence tests.
- `commands/intentions.rs` — `validate_hhmm` accepts/rejects.
- `commands/power.rs` — `power_assertion_is_a_no_op_drop` (registry hygiene), `multiple_assertions_get_unique_ids`.
- `commands/security.rs` — `accepts_main_window` / `rejects_secondary_windows` for `ensure_main_window_label`.
- `commands/tts.rs` — rate-clamp, platform-specific rate-mapping, macOS voice parser, Windows here-string escape.
- `commands/fs.rs` — `write_text_file_roundtrips_utf8`, `write_text_file_errors_on_bad_parent`.
- `commands/mod.rs` — `build_initial_prompt` shape across all combinations of caller/profile/term inputs.

## Data flow

- The integration test file loads `tauri.conf.json` and the `capabilities/*.json` files at runtime via `env!("CARGO_MANIFEST_DIR")`. No Tauri runtime is started.
- Unit tests stay in the same compilation units as their target code, so they have direct access to private functions.

## Watch-outs

- The integration test crate does not build with the full Tauri runtime. If you ever need a test that exercises `tauri::Builder` end-to-end, you will need to add a `#[tokio::test]` with a `tauri::test::mock_app()` helper, which is not currently used anywhere.
- `csp_keeps_loopback_narrow` uses `directive.starts_with("connect-src ")` (with trailing space) which would match `connect-src-elem` — BUT the build-time guard in `build.rs` does the stricter full-name match. If the CSP ever gains a `connect-src-elem` directive that shouldn't include the loopback entries, this integration test would still pass while the build guard correctly checks the actual `connect-src`. Worth tightening for parity.
- The `updater_is_signed_or_absent` test is currently a no-op because no `plugins.updater` block ships. The first time a real updater config lands, the test will run. Document that fact in the PR that adds the updater so reviewers know the previously-passing test now checks something.

## See also

- [Tauri config](tauri-config.md) — the file the CSP test reads.
- [Capabilities and ACL](capabilities-and-acl.md) — the files the secondary-windows test walks.
- [Cargo and features](cargo-and-features.md) — the build-time CSP guard pair.
- [Commands README](commands/README.md) — index of the command-level unit tests.
