[ Documentation ]
Tests in CI

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:

- uses: sootbean/soot-preview-action@v1
with:
start: npm run dev
port: 8081
maestro: auto

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):

maestro: .maestro/login.yaml,.maestro/checkout.yaml
maestro-on: pull_request,push:main

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.

name: peach tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: curl -fsSL https://peachsim.com/install.sh | PEACH_NO_MODIFY_PATH=1 sh
- run: bun dev &
- run: |
for i in $(seq 1 60); do
curl -sf http://localhost:8081 > /dev/null && break
sleep 2
done
- run: peach open 8081 --driver playwright --headless --no-describe
- run: peach maestro test .maestro/

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:

- run: peach maestro test .maestro/ --preview
env:
PEACH_API_KEY: ${{ secrets.PEACH_API_KEY }}

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:

- run: peach desktop install --native --yes
- run: peach open 8081 --driver playwright --headless --no-describe

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:

symptomfix
red check, working previewa flow failed; the recording and the per-step trace show which step
no flows ran in the managed lanemaestro: auto selects root flows or configured globs; check the selected folder and maestro-on event
the preview never bootsflows 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 connectthe dev server must listen before open runs; keep the wait loop ahead of it
manual lane: no recordings or dashboard rowsrecordings need PEACH_API_KEY plus --preview; without them the run still gates on its exit code

Next