Tests in CI
There are two lanes. The managed lane is the one to set up for a team: your repo keeps zero secrets, and results land everywhere your team looks. The manual lane is plain exit codes for any CI system.
The managed lane: tests on every pull request
If your repo uses the GitHub App for PR previews, tests are one input away. The workflow step that runs the preview also runs your Maestro flows:
maestro: auto uses peach’s Maestro workspace discovery for .maestro/ or
maestro/. The default selects only root YAML flows. To select nested tests,
add .maestro/config.yaml with flows: ["flows/**"], keeping reusable
runFlow helpers outside those globs.
You can also pass explicit paths, comma-separated, and control which events
run tests with maestro-on (default pull_request; add push:main style
entries for branch builds):
Each flow runs against the same app the preview booted, records itself, and uploads its own recording. On every PR you get:
- +A comment with a Tests table: each flow, its result, and a recording link.
- +A “Contrast Tests” check on the commit whose conclusion is the real aggregate, so a failing flow blocks merges under branch protection.
- +Dashboard rows: every flow indexed in your dashboard with branch, commit, PR, and a per-step trace.
The repo adds no API keys and no secrets; the workflow authenticates with its own GitHub token. A failing flow marks the check red and the run failed without aborting the preview itself. This lane requires cloud access and available usage funds; see Plans.
Setup from zero: install the GitHub App and accept the bootstrap PR, per GitHub PR Previews.
The manual lane: any CI, exit codes
Test runs are free and account-less: the runner exits nonzero when any flow or spec fails, so any CI gates on the exit code.
The same shape works on any CI system: your app toolchain, your dev server, and
the standalone peach executable are the whole dependency list. On first use
peach open installs a pinned playwright-core (or uses the app’s own
playwright) and the Chromium build it expects. The installer verifies the executable and does not register
the background daemon. peach open installs the runtime when needed, starts the
lightweight bridge for the job, and the operating system removes it with the
rest of the job environment.
To ALSO get recordings and dashboard rows from the manual lane, add a
PEACH_API_KEY secret (created in the Peach account UI, on the account
that should own the runs) and pass --preview:
Runs registered from CI carry their git provenance automatically (branch, commit, PR number, workflow run) so the dashboard can group and link them.
Faster runs on Linux runners
On a Linux x64 runner, add one step before peach open to install the headless
desktop host:
Every headless peach open after that draws the sim with the host’s own
software GPU, so Chromium only composites the page. In a three-run benchmark
on a clean four-vCPU Linux VM, a test-drive journey took about a fifth less
wall time and a third less CPU than headless Chromium alone. The host download
is about 90 MB and includes Node, Mesa and the libraries its software GPU
needs. It supports glibc 2.34 or newer, including Debian 12 and Ubuntu 22.04.
The CLI installs missing Chromium libraries under ~/.peach, so a non-root
container with curl and CA certificates needs no sudo or system graphics
packages. Start your app’s Expo or React Native dev server before peach open.
Without that step, peach open --headless renders in Chromium as before.
When a run fails
A failing flow marks the check red without aborting the preview itself, so a red check next to a working preview means the app booted and a flow failed. Open the recording link in the PR comment’s Tests table, or the per-step trace in the dashboard, fix the flow, and push again. The common failures and their fastest fixes:
| symptom | fix |
|---|---|
| red check, working preview | a flow failed; the recording and the per-step trace show which step |
| no flows ran in the managed lane | maestro: auto selects root flows or configured globs; check the selected folder and maestro-on event |
| the preview never boots | flows run against the app the preview booted, so check the step’s start and port inputs match the dev server |
manual lane: peach open cannot connect | the dev server must listen before open runs; keep the wait loop ahead of it |
| manual lane: no recordings or dashboard rows | recordings need PEACH_API_KEY plus --preview; without them the run still gates on its exit code |