Skip to main content
With command in your config, the job is install, browser, run.
.github/workflows/e2e.yml
Actions are pinned to commit SHAs. A tag is mutable, and a workflow with repository secrets is the wrong place to run code that can change under you. --no-install makes npx fail rather than fetch a mutable version from the registry; with --frozen-lockfile, the runner, the engine, and the browser all come from your lockfile. Point your CI’s test summary at .e2e/junit.xml and failures show up as test results instead of a red step. A startup failure such as APP_UNREACHABLE appears there too, as a run suite. For the failure itself on the pull request, add the GitHub reporter.

What CI changes

CI mode is on when the CI variable is set and is not empty, 0, or false. That is the only signal, so CI=1 npx --no-install e2e run reproduces CI behavior locally. Override any of them when you mean it:
Telemetry attributes CI runs to the vendor rather than to a machine and prints no notice. Add E2E_TELEMETRY_DISABLED: '1' to the job’s env to send nothing from CI.

Model credentials

Deterministic tests need no model. For a suite that uses agent, the job passes the key the provider package reads:
The runner reads none of these variables, so the value never enters logs, reports, or the app process. Which variable each provider reads is on Choosing a model.

Keep model-backed tests opt-in

Deterministic tests are reproducible. Agentic tests can take a different, equally valid path on each run. Gating merges on them makes the model a shared dependency of every pull request.
1

Split the config

A separate e2e.agent.config.ts with its own tests glob and a larger timeout, since every planned step includes model round trips.
2

Split the workflow

Run it on workflow_dispatch or schedule, never on pull_request.
3

Keep it out of required checks

Branch protection requires the deterministic job only.
Nightly agentic run

Exit codes

A non-zero exit fails the step, which is usually all you want. When you react to the class of failure: 1 is a test failure, 2 is configuration or policy, 3 is infrastructure, 130 is a cancellation.
Do not retry the whole job on exit code 2. Configuration and collection errors are deterministic, so a re-run burns minutes and produces the same red. Exit 3 is the only code where a job-level retry is a reasonable reflex.

Pull request comments

One comment per run, edited in place on a rerun.

CLI reference

Flags, reporters, and every exit code.