Testing
The suites are large. Run the test file you changed, not a whole workspace. Let CI run the full suites.
Test categories
Section titled “Test categories”The filename suffix sets the category. Pick the suffix that matches what the test touches.
| Suffix | What it is | How to run the category |
|---|---|---|
*.test.ts(x) |
Unit test. No daemon, no network | npm run test:unit --workspace=@frogg/server |
*.posix.test.ts |
Unit test that needs POSIX behavior | With the unit tests |
*.browser.test.ts(x) |
UI test in a real headless Chromium (Vitest browser mode) | npm run test:browser --workspace=@frogg/app |
*.e2e.test.ts |
End-to-end against a real daemon | npm run test:e2e --workspace=@frogg/server |
*.real.e2e.test.ts |
End-to-end against a real provider | npm run test:e2e:real --workspace=@frogg/server |
*.local.e2e.test.ts |
End-to-end that needs a local-only resource | npm run test:e2e:local --workspace=@frogg/server |
- Server
test:unitexcludes every*.e2e.test.ts. Servertest:e2eruns e2e files with one worker and excludes therealandlocalvariants. - Real-provider tests read credentials from
packages/server/.env.test. The server Vitest setup (packages/server/src/test-utils/vitest-setup.ts) loads that file, setsFROGG_SUPERVISED=0and disables Git and SSH prompts..env.*files are gitignored;packages/server/.env.examplelists the variable names. - Live provider smoke tests belong in
*.real.e2e.test.ts, even when an environment variable guards them. Unit suites must stay deterministic.
Run one file
Section titled “Run one file”npx vitest run packages/server/src/server/agent/agent-manager.test.ts --bail=1For a broader sweep, write the output to a file and read it afterwards:
npx vitest run packages/server/src/server/session --bail=1 > /tmp/test-output.txt 2>&1UI unit and browser tests
Section titled “UI unit and browser tests”apps/ui/vitest.config.ts defines two Vitest projects:
- unit:
src/**/*.{test,spec}.{ts,tsx}andplugins/**, in Node, excluding*.browser.*files.apps/ui/vitest.setup.tsstubs a few native-only modules. - browser:
src/**/*.browser.{test,spec}.{ts,tsx}in headless Chromium through the Playwright provider, one file at a time.
npx vitest run --root apps/ui --project unitnpx vitest run --root apps/ui --project browser # needs: npx playwright install chromiumnpm run test --workspace=@frogg/app # both projectsBoth projects run tests in forked processes with at most two workers. Build build:server-deps
and @frogg/expo-two-way-audio first, as CI does.
Playwright e2e (apps/ui)
Section titled “Playwright e2e (apps/ui)”App end-to-end specs live in apps/ui/e2e/browser/. Shared harness code lives in
apps/ui/e2e/support/. apps/ui/playwright.config.ts defines three projects:
| Project | Matches | Script |
|---|---|---|
browser |
every spec except *.real.spec.ts |
npm run test:e2e --workspace=@frogg/app |
real-provider |
*.real.spec.ts except the relay deployment spec |
npm run test:e2e:real --workspace=@frogg/app |
relay-deployment |
relay-deployment-reconnect.real.spec.ts |
npm run test:e2e:relay-deployment --workspace=@frogg/app |
-
Global setup (
e2e/support/global-setup.ts) starts Metro on a free port. Workers default to 1 locally and 2 whenCIis set. CI gets one retry. -
test:e2e:realandtest:e2e:relay-deploymentfork provider state from.dev/frogg-home(E2E_FORK_FROGG_HOME_FROM).test:e2e:relay-deploymentalso builds the server and daemon web UI. -
test:e2e:uiopens the Playwright UI.E2E_RECORD_VIDEO=1records every test. -
Run a single spec when you need to prove one flow:
Terminal window cd apps/ui && npx playwright test --project=browser e2e/browser/<spec>.spec.ts
Mobile flows
Section titled “Mobile flows”apps/ui/maestro/ holds Maestro flows (flows/ has reusable steps such as launch.yaml) and
shell wrappers that combine Maestro with xcrun simctl or Android tooling, for example
bash apps/ui/maestro/test-sidebar-theme.sh 6 1. apps/ui/e2e/mobile/ holds agent-device
scripts and a composer keyboard check. These are manual reproduction tools. CI does not run
them, and some flows target specific past bugs.
Desktop tests
Section titled “Desktop tests”npm run test --workspace=@frogg/desktop-electron # vitest on src, then node --test test/*.test.mjsnpm run test:smoke --workspace=@frogg/desktop-electron # Playwright Electron smokeThe smoke test (apps/desktop-electron/e2e/smoke.mjs) launches the app twice with a temporary
profile. It checks sandbox and context isolation, settings persistence across launches, that
daemon commands are rejected, and that no daemon state is created. Without
FROGG_ELECTRON_SMOKE_EXECUTABLE it runs the unpacked app against apps/ui/dist, so run
npm run build:ui first. Set FROGG_ELECTRON_SMOKE_EXECUTABLE to test a packaged binary, and
FROGG_ELECTRON_SMOKE_NO_SANDBOX=1 where the Chromium sandbox is unavailable. The release workflow
runs it on the packaged Linux build under xvfb-run.
Script tests
Section titled “Script tests”npm run test:scriptsRuns node --test over scripts/ci/*.test.mjs, scripts/dev/*.test.mjs and
scripts/release/*.test.mjs. Run it when you change build, release or CI scripts.
Branding tests
Section titled “Branding tests”npm run brand:checkvalidates the selected brand.npm run test --workspace=@frogg/brandingruns the brand schema tests..github/workflows/branding.ymlruns on pull requests that touchbrands/,packages/branding/, branding scripts,scripts/release/,apps/desktop-electron/,deploy/or.github/. It buildsbrands/froggandbrands/exampleand runsbranding-acceptance.mjs,branding-contribution.mjs(see Coding standards),branding-browser.mjs, the install test, desktop packaging on Linux, Windows and macOS withbranding-package-inspect.mjs, an Android debug APK, an iOS simulator build, runtime isolation between the two brands, and a Nix build.
What CI runs
Section titled “What CI runs”.github/workflows/ci.yml runs on pull requests, pushes to main and manual dispatch.
| Job | Steps |
|---|---|
checks |
oxfmt --check ., oxlint ., npm run test:scripts, build:server, @frogg/expo-two-way-audio build, npm run typecheck |
tests |
build:server, then npm run test for protocol, client, highlight, relay and plugin, and test:unit for cli |
ui-tests (3 shards) |
UI unit project |
ui-browser-tests |
Installs Chromium, runs the UI browser project |
server-tests (5 shards) |
Server Vitest, excluding *.e2e.test.ts |
builds |
Not on pull requests. Calls build-selected.yml (Windows client, Linux daemon, Android APK) |
Other workflows:
electron-desktop.yml: on pull requests touching desktop, UI, packages or the lockfile. Builds the Windows x64 Electron app after its typecheck and tests.branding.yml: see Branding tests.release.yml: runs the Electron smoke test on Linux. See Release process.
No workflow builds or tests the Rust sources in apps/desktop/src-tauri or apps/daemon-rs.
The apps/desktop TypeScript is still typechecked by npm run typecheck.
.github/workflows/android-startup.yml is an Android startup diagnostic (manual dispatch, or
pushes to fix/android-launch-crash), not a gate.