🎯 What You Will Learn
Run browser tests on pushes and pull requests, install system dependencies, upload reports, and keep CI stable.
- Create a complete GitHub Actions workflow
- Install matching Playwright browsers and system dependencies
- Upload HTML reports even when tests fail
- Balance retries, workers, artifacts, and execution time
Make the Local Test Deterministic First
CI amplifies existing flakiness. Before adding a workflow, run the complete suite from a clean install and confirm it does not depend on local browser state.
npm ci
npx playwright install --with-deps
npx playwright testChoose Workflow Triggers
Run on pull requests to protect reviews and on pushes to the default branch to catch integration failures.
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
branches: [main]Create the Test Job
Use a Linux runner, add a timeout, check out the commit, and install the Node.js LTS release.
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
cache: npmInstall Packages and Browsers
Use the lockfile-backed install, then install browser binaries with their Linux system dependencies.
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-depsRun the Test Suite
The test step should fail the job when a test fails. Keep credentials in GitHub secrets and expose only the variables the suite needs.
- name: Run Playwright tests
run: npx playwright test
env:
E2E_BASE_URL: ${{ vars.E2E_BASE_URL }}
E2E_EMAIL: ${{ secrets.E2E_EMAIL }}
E2E_PASSWORD: ${{ secrets.E2E_PASSWORD }}Upload the HTML Report
Upload artifacts even after a test failure, but skip the upload when the workflow was cancelled.
- uses: actions/upload-artifact@v5
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30Tune Retries and Workers for CI
Retries can collect a trace for intermittent failures. A single worker prioritizes stability on shared hosted runners; increase concurrency only after measuring.
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [['html', { open: 'never' }]],
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
});Debug CI-only Failures
Download the report, open its trace, compare environment variables and base URLs, and reproduce with the same browser project locally.
- Open the failed job and download playwright-report.
- Inspect the trace and failing assertion.
- Check whether the application server was ready.
- Reproduce with the same project and clean state.
- Fix the race or environment difference before increasing retries.
Retries are evidence, not a cure: A test that passes only on retry is still flaky. Use the retry trace to remove the underlying race.
Recap
- Run a clean local install before moving the suite to CI.
- Install browsers with Linux dependencies on the runner.
- Upload reports and traces when failures occur.
- Use retries to collect evidence and workers to balance stability with speed.
Checkpoint: You have completed the workflow and have a repeatable reference for your next Playwright project.