100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Playwright in CI/CD Pipelines

How to configure Playwright to run reliably on CI, including GitHub Actions setup, Docker images, and CI-aware config adjustments.

Scaling & CIIntermediate10 min readJul 10, 2026
Analogies

Why Playwright Needs CI-Specific Configuration

Continuous integration environments differ fundamentally from a developer's laptop: they're ephemeral, resource-constrained, and headless by default, so Playwright ships CI-aware defaults—retries default to 2 on CI versus 0 locally, and the reporter switches to a more CI-friendly format instead of the interactive 'list' reporter—triggered automatically when process.env.CI is set. Because CI runners are shared and often throttled, tests that pass reliably locally can fail intermittently on CI purely from timing pressure, which is why Playwright's auto-waiting and web-first assertions matter even more in this environment.

🏏

Cricket analogy: Playing a day-night Test under lights is different from a club match at your local ground — Playwright automatically switches to CI-tuned settings like more retries, just as a team adjusts its batting order for tricky floodlit conditions.

Setting Up GitHub Actions

A typical GitHub Actions workflow checks out the repo, installs Node dependencies, runs npx playwright install --with-deps to fetch browser binaries plus their OS-level dependencies (fonts, codecs, X11 libraries), and then executes npx playwright test, uploading the playwright-report directory as a build artifact so failures can be inspected after the job completes. The --with-deps flag is essential on fresh Ubuntu runners because the Chromium, Firefox, and WebKit builds Playwright downloads need system libraries that aren't present in a minimal CI image by default.

🏏

Cricket analogy: Setting up a GitHub Actions workflow is like arranging a full match-day schedule: toss, warm-up nets, then the innings — checkout code, install dependencies, install browsers, then run the actual Playwright test innings.

yaml
name: Playwright Tests
on:
  push:
    branches: [main]
  pull_request:
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 14

Docker Images and Browser Installation

For teams running Playwright inside Docker (e.g., Kubernetes-based CI or self-hosted runners), Microsoft publishes official mcr.microsoft.com/playwright images pinned to a specific Playwright version, pre-installed with all three browser engines and their OS dependencies, avoiding the need to run playwright install separately and guaranteeing the browser binary version always matches the npm package version. Version mismatches between the Playwright npm package and installed browsers are a common source of 'browser not found' errors, so pinning the Docker image tag to match package.json's playwright version is a standard CI hygiene practice.

🏏

Cricket analogy: Using Microsoft's pre-built Docker image with browsers baked in is like a touring team using pre-approved neutral-venue kit and stadium instead of shipping their own turf, guaranteeing everything matches without last-minute setup surprises.

dockerfile
FROM mcr.microsoft.com/playwright:v1.45.0-jammy

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

# Browsers and OS deps are already installed in the base image
CMD ["npx", "playwright", "test"]

Always pin the Docker image tag (e.g., v1.45.0-jammy) to match the playwright version in package.json exactly. A mismatched image and npm package version is the single most common cause of cryptic 'Executable doesn't exist' errors in containerized CI.

CI-Aware Config Adjustments

Beyond retries and reporters, playwright.config.ts commonly branches on process.env.CI to disable test.only enforcement (forbidOnly: !!process.env.CI, which fails the build if a developer accidentally left a .only in committed code), reduce workers to avoid oversubscribing shared runners, and enable trace: 'on-first-retry' so traces are only captured for failing tests, keeping artifact storage costs down while still giving full debugging context when something breaks in CI but not locally.

🏏

Cricket analogy: forbidOnly on CI is like an umpire enforcing a rule during a televised final that's relaxed during a friendly net session — a stricter standard applies only when the stakes and audience are higher.

Forgetting to set forbidOnly: !!process.env.CI means a developer's accidental test.only() left in a commit will silently make CI run (and appear to pass) only that one test, hiding the fact that the rest of the suite never executed.

  • Playwright auto-detects process.env.CI and adjusts defaults like retries and the reporter format.
  • A standard GitHub Actions workflow: checkout, install deps, playwright install --with-deps, run tests, upload the report artifact.
  • --with-deps installs OS-level libraries (fonts, codecs) that browser binaries need on minimal Linux runners.
  • Official mcr.microsoft.com/playwright Docker images bundle browsers pre-installed and version-matched.
  • Always pin the Docker image tag to match the playwright npm package version to avoid mismatch errors.
  • forbidOnly: !!process.env.CI fails the build if a stray test.only() was left in committed code.
  • trace: 'on-first-retry' balances debugging detail against artifact storage cost on CI.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#PlaywrightStudyNotes#TestingQA#PlaywrightInCICDPipelines#Playwright#Pipelines#Needs#Specific#DevOps#StudyNotes#SkillVeris