SoftwareTestPilot
Module 09 · Lesson 1intermediate 14 min read CI/CD

Playwright + GitHub Actions CI/CD

Ship the framework. Every push to a PR runs the full suite in parallel shards, posts annotations at the failing line, and uploads a browsable HTML report.

Quick answer

Add a workflow that installs Playwright, runs the suite in a shard matrix, uploads blob reports, then merges them into one HTML report in a final job. Add the github reporter for inline PR annotations.

1. The minimal workflow

.github/workflows/e2e.yml
yaml
name: E2E
on:
  pull_request:
  push:
    branches: [main]

jobs:
  e2e:
    timeout-minutes: 20
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test
        env:
          BASE_URL: ${{ secrets.STAGING_URL }}
          USER_EMAIL: ${{ secrets.USER_EMAIL }}
          USER_PWD: ${{ secrets.USER_PWD }}
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7

2. Sharding — cut runtime by N

jobs:
  e2e:
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test --shard=${{ matrix.shard }}/4 --reporter=blob
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: blob-report-${{ matrix.shard }}
          path: blob-report
          retention-days: 1

3. Merge the shards into one report

  merge-reports:
    if: ${{ !cancelled() }}
    needs: e2e
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - uses: actions/download-artifact@v4
        with: { path: all-blobs, pattern: blob-report-* }
      - run: npx playwright merge-reports --reporter=html ./all-blobs
      - uses: actions/upload-artifact@v4
        with:
          name: html-report
          path: playwright-report

4. Cache Playwright browsers

- name: Cache Playwright browsers
  uses: actions/cache@v4
  id: playwright-cache
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ hashFiles('package-lock.json') }}

- name: Install browsers
  if: steps.playwright-cache.outputs.cache-hit != 'true'
  run: npx playwright install --with-deps chromium

- name: Install OS deps only
  if: steps.playwright-cache.outputs.cache-hit == 'true'
  run: npx playwright install-deps chromium

5. Secrets & environment strategy

  • Store secrets in Repo → Settings → Secrets and variables → Actions. Reference with ${{ secrets.NAME }}.
  • Split per environment: STAGING_URL, PROD_URL, mapped to workflow inputs.
  • Never echo a secret — GitHub redacts but logs at other layers can leak.
  • Rotate tokens quarterly. Use a service account, not a real user.

6. PR annotations at failing lines

playwright.config.ts
ts
reporter: process.env.CI
  ? [['github'], ['html', { open: 'never' }], ['blob']]
  : [['list'], ['html', { open: 'on-failure' }]],
You now have production CI
Push a PR that breaks a test. You should see: (1) a red status check, (2) an inline annotation at the failing expect(...) line, (3) a downloadable HTML report artifact with trace, screenshot and video.

7. Hands-on task (35 minutes)

  1. 1

    Add the basic workflow

    Copy the minimal YAML into .github/workflows/e2e.yml. Push a PR — confirm the suite runs.

  2. 2

    Shard into 4 jobs

    Add the matrix + blob reporter + merge job. Watch runtime drop by ~4×.

  3. 3

    Wire secrets

    Move your staging URL and credentials into GitHub Secrets. Delete them from the config file.

Finally, sharpen your test-design instincts: Module 10 — Test Design Techniques.

Frequently asked questions

1.How do I run Playwright in GitHub Actions?
Use the official Playwright Docker image or `npx playwright install --with-deps` on ubuntu-latest. Run `npx playwright test` and upload the HTML report as an artifact on failure.
2.How do I shard a Playwright suite in CI?
Use a matrix strategy (`shard: [1/4, 2/4, 3/4, 4/4]`) and pass `--shard=${shard}` to Playwright. Use the `blob` reporter on each shard and merge with `npx playwright merge-reports` in a final job.
3.Should I cache node_modules and browsers?
Cache `~/.npm` and Playwright browsers at `~/.cache/ms-playwright`. Skip the install step when the cache hits. Trims 40–60 seconds per run.
4.How do I store secrets like API tokens?
GitHub → Repo Settings → Secrets and variables → Actions. Reference in a step as `env: { API_TOKEN: ${{ secrets.API_TOKEN }} }`. Never echo secrets to logs.
5.How do I comment test results on the PR?
Add the `github` reporter — Playwright will post annotations at failing line numbers. For a summary comment, upload the HTML report to GitHub Pages or use a marketplace action like `daun/playwright-report-summary`.
6.What about flaky test retries?
Set `retries: 2` only when `process.env.CI` is truthy. Never retry locally — that hides real bugs from developers.

Related lessons