Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Playwright testing guide covering E2E, component, API, visual, accessibility, and security tests.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
infrastructure-ci-cd/github-actions.md
1# GitHub Actions for Playwright23## Table of Contents451. [CLI Commands](#cli-commands)62. [Workflow Patterns](#workflow-patterns)73. [Scenario Guide](#scenario-guide)84. [Common Mistakes](#common-mistakes)95. [Troubleshooting](#troubleshooting)106. [Related](#related)1112> **When to use**: Automating Playwright tests on pull requests, main branch merges, or scheduled runs.1314## CLI Commands1516```bash17npx playwright install --with-deps # browsers + OS dependencies18npx playwright test --shard=1/4 # run shard 1 of 419npx playwright test --reporter=github # PR annotations20npx playwright merge-reports ./blob-report # combine shard reports21```2223## Workflow Patterns2425### Basic Workflow2627**Use when**: Starting a new project or running a small test suite.2829```yaml30# .github/workflows/e2e.yml31name: E2E Tests3233on:34push:35branches: [main]36pull_request:37branches: [main]3839concurrency:40group: e2e-${{ github.ref }}41cancel-in-progress: true4243env:44CI: true4546jobs:47test:48timeout-minutes: 3049runs-on: ubuntu-latest5051steps:52- uses: actions/checkout@v45354- run: npm ci5556- name: Cache browsers57id: browser-cache58uses: actions/cache@v459with:60path: ~/.cache/ms-playwright61key: pw-${{ runner.os }}-${{ hashFiles('package-lock.json') }}6263- name: Install browsers64if: steps.browser-cache.outputs.cache-hit != 'true'65run: npx playwright install --with-deps6667- name: Install OS dependencies68if: steps.browser-cache.outputs.cache-hit == 'true'69run: npx playwright install-deps7071- run: npx playwright test7273- name: Upload report74uses: actions/upload-artifact@v475if: ${{ !cancelled() }}76with:77name: test-report78path: playwright-report/79retention-days: 148081- name: Upload traces82uses: actions/upload-artifact@v483if: failure()84with:85name: traces86path: test-results/87retention-days: 788```8990### Sharded Execution9192**Use when**: Test suite exceeds 10 minutes. Sharding cuts wall-clock time significantly.93**Avoid when**: Suite runs under 5 minutes—sharding overhead negates benefits.9495```yaml96# .github/workflows/e2e-sharded.yml97name: E2E Tests (Sharded)9899on:100push:101branches: [main]102pull_request:103branches: [main]104105concurrency:106group: e2e-${{ github.ref }}107cancel-in-progress: true108109env:110CI: true111112jobs:113test:114timeout-minutes: 20115runs-on: ubuntu-latest116strategy:117fail-fast: false118matrix:119shard: [1/4, 2/4, 3/4, 4/4]120121steps:122- uses: actions/checkout@v4123124- run: npm ci125126- name: Cache browsers127id: browser-cache128uses: actions/cache@v4129with:130path: ~/.cache/ms-playwright131key: pw-${{ runner.os }}-${{ hashFiles('package-lock.json') }}132133- name: Install browsers134if: steps.browser-cache.outputs.cache-hit != 'true'135run: npx playwright install --with-deps136137- name: Install OS dependencies138if: steps.browser-cache.outputs.cache-hit == 'true'139run: npx playwright install-deps140141- name: Run tests (shard ${{ matrix.shard }})142run: npx playwright test --shard=${{ matrix.shard }}143144- name: Upload blob report145uses: actions/upload-artifact@v4146if: ${{ !cancelled() }}147with:148name: blob-${{ strategy.job-index }}149path: blob-report/150retention-days: 1151152merge:153if: ${{ !cancelled() }}154needs: test155runs-on: ubuntu-latest156157steps:158- uses: actions/checkout@v4159160- run: npm ci161162- name: Download blob reports163uses: actions/download-artifact@v4164with:165path: all-blobs166pattern: blob-*167merge-multiple: true168169- name: Merge reports170run: npx playwright merge-reports --reporter=html ./all-blobs171172- name: Upload merged report173uses: actions/upload-artifact@v4174with:175name: test-report176path: playwright-report/177retention-days: 14178```179180**Config for sharding**—enable blob reporter:181182```typescript183// playwright.config.ts184import { defineConfig } from '@playwright/test';185186export default defineConfig({187reporter: process.env.CI188? [['blob'], ['github']]189: [['html', { open: 'on-failure' }]],190});191```192193### Container-Based Execution194195**Use when**: Reproducible environment matching local Docker setup, or runner OS dependencies cause issues.196**Avoid when**: Standard `ubuntu-latest` with `--with-deps` works fine.197198```yaml199# .github/workflows/e2e-container.yml200name: E2E Tests (Container)201202on:203pull_request:204branches: [main]205206jobs:207test:208timeout-minutes: 30209runs-on: ubuntu-latest210container:211image: mcr.microsoft.com/playwright:v1.48.0-noble212213steps:214- uses: actions/checkout@v4215216- run: npm ci217218- name: Run tests219run: npx playwright test220env:221HOME: /root222223- uses: actions/upload-artifact@v4224if: ${{ !cancelled() }}225with:226name: test-report227path: playwright-report/228retention-days: 14229```230231### Environment Secrets232233**Use when**: Tests target staging/production with credentials.234**Avoid when**: Tests only run against local dev server.235236```yaml237# .github/workflows/e2e-staging.yml238name: Staging Tests239240on:241push:242branches: [main]243workflow_dispatch:244245jobs:246test:247timeout-minutes: 30248runs-on: ubuntu-latest249environment: staging250251env:252CI: true253BASE_URL: ${{ vars.STAGING_URL }}254TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}255API_TOKEN: ${{ secrets.API_TOKEN }}256257steps:258- uses: actions/checkout@v4259260- run: npm ci261262- name: Cache browsers263id: browser-cache264uses: actions/cache@v4265with:266path: ~/.cache/ms-playwright267key: pw-${{ runner.os }}-${{ hashFiles('package-lock.json') }}268269- name: Install browsers270if: steps.browser-cache.outputs.cache-hit != 'true'271run: npx playwright install --with-deps272273- name: Install OS dependencies274if: steps.browser-cache.outputs.cache-hit == 'true'275run: npx playwright install-deps276277- name: Run smoke tests278run: npx playwright test --grep @smoke279280- uses: actions/upload-artifact@v4281if: ${{ !cancelled() }}282with:283name: staging-report284path: playwright-report/285retention-days: 14286```287288### Scheduled Runs289290**Use when**: Full regression suite is too slow for every PR—run nightly instead.291**Avoid when**: Suite runs under 15 minutes and can run on every PR.292293```yaml294# .github/workflows/nightly.yml295name: Nightly Regression296297on:298schedule:299- cron: '0 3 * * 1-5'300workflow_dispatch:301302jobs:303test:304timeout-minutes: 60305runs-on: ubuntu-latest306307env:308CI: true309BASE_URL: ${{ vars.STAGING_URL }}310311steps:312- uses: actions/checkout@v4313314- run: npm ci315316- name: Install browsers317run: npx playwright install --with-deps318319- name: Run full regression320run: npx playwright test --grep @regression321322- uses: actions/upload-artifact@v4323if: ${{ !cancelled() }}324with:325name: nightly-${{ github.run_number }}326path: playwright-report/327retention-days: 30328329- name: Notify on failure330if: failure()331uses: slackapi/slack-github-action@latest332with:333payload: |334{335"text": "Nightly regression failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"336}337env:338SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}339```340341### Reusable Workflow342343**Use when**: Multiple repositories share the same Playwright setup.344**Avoid when**: Single repo with one workflow.345346```yaml347# .github/workflows/pw-reusable.yml348name: Playwright Reusable349350on:351workflow_call:352inputs:353node-version:354type: string355default: 'lts/*'356test-command:357type: string358default: 'npx playwright test'359secrets:360BASE_URL:361required: false362TEST_PASSWORD:363required: false364365jobs:366test:367timeout-minutes: 30368runs-on: ubuntu-latest369370env:371CI: true372BASE_URL: ${{ secrets.BASE_URL }}373TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}374375steps:376- uses: actions/checkout@v4377378- uses: actions/setup-node@v4379with:380node-version: ${{ inputs.node-version }}381cache: npm382383- run: npm ci384385- name: Cache browsers386id: browser-cache387uses: actions/cache@v4388with:389path: ~/.cache/ms-playwright390key: pw-${{ runner.os }}-${{ hashFiles('package-lock.json') }}391392- name: Install browsers393if: steps.browser-cache.outputs.cache-hit != 'true'394run: npx playwright install --with-deps395396- name: Install OS dependencies397if: steps.browser-cache.outputs.cache-hit == 'true'398run: npx playwright install-deps399400- name: Run tests401run: ${{ inputs.test-command }}402403- uses: actions/upload-artifact@v4404if: ${{ !cancelled() }}405with:406name: test-report407path: playwright-report/408retention-days: 14409```410411**Calling the reusable workflow:**412413```yaml414# .github/workflows/ci.yml415name: CI416on:417pull_request:418branches: [main]419420jobs:421e2e:422uses: ./.github/workflows/pw-reusable.yml423with:424node-version: 'lts/*'425secrets:426BASE_URL: ${{ secrets.STAGING_URL }}427TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}428```429430## Scenario Guide431432| Scenario | Approach |433|---|---|434| Small suite (< 5 min) | Single job, no sharding |435| Medium suite (5-20 min) | 2-4 shards with matrix |436| Large suite (20+ min) | 4-8 shards + blob merge |437| Cross-browser on PRs | Chromium only on PRs; all browsers on main |438| Staging/prod smoke tests | Separate workflow with `environment:` |439| Nightly full regression | `schedule` trigger + `workflow_dispatch` |440| Multiple repos, same setup | Reusable workflow with `workflow_call` |441| Reproducible env needed | Container job with Playwright image |442443## Common Mistakes444445| Mistake | Problem | Fix |446|---|---|---|447| No `concurrency` group | Duplicate runs waste minutes | Add `concurrency: { group: ..., cancel-in-progress: true }` |448| `fail-fast: true` with sharding | One failure cancels others | Set `fail-fast: false` |449| No browser caching | 60-90 seconds wasted per run | Cache `~/.cache/ms-playwright` |450| No `timeout-minutes` | Stuck jobs run for 6 hours | Set explicit timeout: 20-30 minutes |451| Artifacts only on failure | No report when tests pass | Use `if: ${{ !cancelled() }}` |452| Hardcoded secrets | Security risk | Use GitHub Secrets and Environments |453| All browsers on every PR | 3x CI cost | Chromium on PR; cross-browser on main |454| No artifact retention | Default 90-day fills storage | Set `retention-days: 7-14` |455| Missing `--with-deps` | Browser launch failures | Always use `npx playwright install --with-deps` |456457## Troubleshooting458459### Browser launch fails: "Missing dependencies"460461**Cause**: Browsers restored from cache but OS dependencies weren't cached.462463**Fix**: Run `npx playwright install-deps` on cache hit:464465```yaml466- name: Install OS dependencies467if: steps.browser-cache.outputs.cache-hit == 'true'468run: npx playwright install-deps469```470471### Tests pass locally but timeout in CI472473**Cause**: CI runners have fewer resources than dev machines.474475**Fix**: Reduce workers and increase timeouts:476477```typescript478// playwright.config.ts479import { defineConfig } from '@playwright/test';480481export default defineConfig({482workers: process.env.CI ? '50%' : undefined,483use: {484actionTimeout: process.env.CI ? 15_000 : 10_000,485navigationTimeout: process.env.CI ? 30_000 : 15_000,486},487});488```489490### Sharded reports incomplete491492**Cause**: Artifact names collide or `merge-multiple` not set.493494**Fix**: Unique names per shard and enable merge:495496```yaml497# Upload in each shard498- uses: actions/upload-artifact@v4499with:500name: blob-${{ strategy.job-index }}501path: blob-report/502503# Download in merge job504- uses: actions/download-artifact@v4505with:506path: all-blobs507pattern: blob-*508merge-multiple: true509```510511### `webServer` fails: "port already in use"512513**Cause**: Zombie process from previous run.514515**Fix**: Kill stale processes before starting:516517```yaml518- name: Kill stale processes519run: lsof -ti:3000 | xargs kill -9 2>/dev/null || true520```521522### No PR annotations523524**Cause**: `github` reporter not configured.525526**Fix**: Add `github` reporter for CI:527528```typescript529// playwright.config.ts530import { defineConfig } from '@playwright/test';531532export default defineConfig({533reporter: process.env.CI534? [['html', { open: 'never' }], ['github']]535: [['html', { open: 'on-failure' }]],536});537```538539## Related540541- [test-tags.md](../core/test-tags.md) — tagging and filtering tests542- [parallel-sharding.md](parallel-sharding.md) — sharding strategies543- [reporting.md](reporting.md) — reporter configuration544- [docker.md](docker.md) — container images545- [gitlab.md](gitlab.md) — GitLab CI equivalent546- [other-providers.md](other-providers.md) — CircleCI, Azure DevOps, Jenkins547