</>

Technology

Playwright

Difficulty

Advanced

Interview Question

How do you integrate Playwright with GitHub Actions CI/CD?

Answer

Playwright + GitHub Actions

Basic Workflow

YAML
# .github/workflows/playwright.yml
name: Playwright Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  playwright:
    timeout-minutes: 60
    runs-on: ubuntu-latest

    steps:
      # 1. Checkout code
      - uses: actions/checkout@v4

      # 2. Set up Node.js
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      # 3. Install npm dependencies
      - name: Install dependencies
        run: npm ci

      # 4. Install Playwright browsers + OS dependencies
      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      # 5. Run tests
      - name: Run Playwright tests
        run: npx playwright test
        env:
          BASE_URL: ${{ secrets.STAGING_URL }}
          TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

      # 6. Upload HTML report (always, even on failure)
      - name: Upload Playwright report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Sharded Matrix Workflow (4 Parallel Machines)

YAML
name: Playwright Tests (Sharded)

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4]
        shardTotal: [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

      - name: Run shard
        run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
        env:
          BASE_URL: ${{ secrets.BASE_URL }}

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: blob-report-${{ matrix.shardIndex }}
          path: blob-report/

  merge-reports:
    needs: test
    if: always()
    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-reports, pattern: blob-report-* }
      - run: npx playwright merge-reports --reporter html ./all-reports
      - uses: actions/upload-artifact@v4
        with: { name: playwright-report, path: playwright-report/ }

playwright.config.ts for CI

TypeScript
export default defineConfig({
  workers:    process.env.CI ? 2 : undefined,
  retries:    process.env.CI ? 2 : 0,
  reporter:   process.env.CI ? [['github'], ['html']] : [['html']],
  use: {
    baseURL:    process.env.BASE_URL || 'http://localhost:3000',
    trace:      'retain-on-failure',
    screenshot: 'only-on-failure',
    video:      'retain-on-failure',
  },
});

Caching Browser Binaries

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

- name: Install browsers (only if not cached)
  if: steps.playwright-cache.outputs.cache-hit != 'true'
  run: npx playwright install --with-deps

Follow AutomateQA

Related Topics