Skip to main content

CI

This page covers how the Playwright suite runs in CI: the shared runner script, the official Playwright Docker image, browser selection, and the validator pipeline.


The shared runner script

All CI pipelines (local Jenkins, DevOps/main Jenkins) call the same script:

ci/run-e2e.sh

The script is driven entirely by environment variables — no pipeline-specific logic lives in the pipelines themselves.

Environment variables

VariableDefaultPurpose
TEST_ENVdev2Target environment (dev2, dev3, qa2, demo5, local)
WORKERS4Playwright --workers parallelism
TESTS(blank = full suite)Space-separated spec paths/dirs under tests/e2e/
GREP(blank = no filter)Title regex passed to Playwright -g
WAIT_URL(blank = skip)URL to poll until reachable before testing (for async deploys)
PW_CHANNELchromiumBrowser channel — see Browser selection
INSTALL_DEPStrueRun pnpm install --frozen-lockfile before testing

What the script does

  1. Optionally runs pnpm install --frozen-lockfile (idempotent in CI images that cache node_modules).
  2. If WAIT_URL is set, polls it with curl up to 5 minutes, treating any non-5xx response as "up" — a redirect to login (302/401) is acceptable.
  3. Builds the Playwright argv array and calls pnpm exec playwright test — no eval, so TESTS and GREP cannot be shell-interpreted.

The script sets CI=true unconditionally so playwright.config.ts activates CI-mode settings (see below).


CI-mode settings in playwright.config.ts

When process.env.CI is set, the config applies three changes:

SettingValue in CIValue locally
retries20
workers1Playwright default (CPU-based)
forbidOnlytruefalse

forbidOnly: true causes the run to fail immediately if a test.only was accidentally committed to the spec files.

Note: ci/run-e2e.sh passes --workers=${WORKERS} on the command line (default 4), which overrides the workers: 1 from the config. The script's intent is to allow parallelism control at the pipeline level while retaining the safety net (forbidOnly, retries) that CI=1 provides.


Browser selection

playwright.config.ts reads PW_CHANNEL to select the browser:

  • PW_CHANNEL=chrome (or omitted locally) — uses the branded Google Chrome channel. Available on macOS and Windows; not available in Linux containers.
  • PW_CHANNEL=chromium — uses Playwright's bundled Chromium build. This is the default inside ci/run-e2e.sh and the correct value for any Linux/arm64 environment, including the official Playwright Docker image.

When PW_CHANNEL=chromium, the config omits the channel field from the project definition, which tells Playwright to use the bundled build rather than a system browser.


Official Playwright Docker image

The recommended CI runner image is:

mcr.microsoft.com/playwright:v<version>-noble

where <version> matches the @playwright/test version pinned in package.json. This image ships with:

  • Bundled Chromium (and other browsers) plus all OS-level dependencies.
  • Node and corepack, so pnpm is activated automatically from the packageManager field in package.json.

Because browsers are baked into the image, no separate playwright install step is needed in CI. On a bare host (without the Docker image), install once with:

pnpm exec playwright install --with-deps chromium

Validator pipeline

In addition to the Playwright test run, CI runs the full validator suite:

pnpm run validate

This is a shorthand that expands to:

pnpm run checkTs # tsc --noEmit (infra code only; specs are smoke-run)
pnpm run lint # eslint
pnpm run format:check # prettier --check
pnpm run test:validate-data # Zod-validates tests/data/*.jsonc
pnpm run test:validate-spec # validates tests/specs/**/*.md frontmatter + structure

All five must pass before a build is considered green. checkTs is scoped to the framework infra; Playwright spec files are transpiled on-the-fly by the runner and are not type-gated by this check.


Credentials in CI

The runner script expects a .env file at the repo root containing TEST_USERNAME and TEST_PASSWORD. In CI, inject these as pipeline secrets and write the file before invoking the script — for example:

echo "TEST_USERNAME=$SECRET_USER" > .env
echo "TEST_PASSWORD=$SECRET_PASS" >> .env
bash ci/run-e2e.sh

No other environment-specific values need to be in .env: project IDs, estimate names, and similar data live in tests/data/*.jsonc and are version- controlled.