Playwright in CI/CD
Run Playwright in GitHub Actions, Docker, and sharded parallel pipelines.
CI Setup
GitHub Actions workflow installs Node, npm ci, npx playwright install --with-deps for OS libraries, runs playwright test. Upload html report and trace artifacts on failure.
Set CI=true for Playwright to adjust retries and forbid test.only.
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- name: Run tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/webServer Config
playwright.config webServer starts dev server before tests and shuts down after—eliminates separate CI step coordination.
ReuseExistingServer: !process.env.CI skips start if dev already running locally.
webServer: {
command: "npm run dev",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
timeout: 120000,
}Sharding and Merge Reports
Split suite: playwright test --shard=1/4 across four jobs with same CI_BUILD_ID. Merge blob reports: playwright merge-reports for unified html.
Balance shards by historical timing from report JSON.
- Each shard needs own workers count tuned to runner CPU
- Install browsers once per job cached layer
- Fail pipeline if test.only detected via grep in CI script
npx playwright test --shard=${{ matrix.shard }}/4Docker
Official mcr.microsoft.com/playwright Docker image includes browsers and deps. Mount repo, run tests inside container matching CI environment.
Align image version with @playwright/test package version exactly.
docker run --rm -v $(pwd):/work -w /work mcr.microsoft.com/playwright:v1.44.0-jammy npx playwright test
Protected Branch Gates
Require Playwright check before merge per team AGENTS.md policy. Stable tests must pass—fix app regressions before weakening tests.
Store test credentials in CI secrets; inject via environment in config.
- Separate smoke job under 5 minutes for fast PR feedback
- Nightly full browser matrix catches Safari-only bugs
- Track test duration trend—slow suite gets skipped locally