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/ci-cd.md
1# CI/CD Integration23## Table of Contents451. [GitHub Actions](#github-actions)62. [Docker](#docker)73. [Reporting](#reporting)84. [Sharding](#sharding)95. [Environment Management](#environment-management)106. [Caching](#caching)1112## GitHub Actions1314### Basic Workflow1516```yaml17# .github/workflows/playwright.yml18name: Playwright Tests1920on:21push:22branches: [main]23pull_request:24branches: [main]2526jobs:27test:28timeout-minutes: 6029runs-on: ubuntu-latest30steps:31- uses: actions/checkout@v43233- uses: actions/setup-node@v434with:35node-version: 2236cache: "npm"3738- name: Install dependencies39run: npm ci4041- name: Install Playwright browsers42run: npx playwright install --with-deps4344- name: Run Playwright tests45run: npx playwright test4647- uses: actions/upload-artifact@v448if: ${{ !cancelled() }}49with:50name: playwright-report51path: playwright-report/52retention-days: 3053```5455### With Sharding5657```yaml58name: Playwright Tests5960on:61push:62branches: [main]6364jobs:65test:66timeout-minutes: 6067runs-on: ubuntu-latest68strategy:69fail-fast: false70matrix:71shardIndex: [1, 2, 3, 4]72shardTotal: [4]73steps:74- uses: actions/checkout@v47576- uses: actions/setup-node@v477with:78node-version: 2279cache: "npm"8081- name: Install dependencies82run: npm ci8384- name: Install Playwright browsers85run: npx playwright install --with-deps8687- name: Run Playwright tests88run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}8990- name: Upload blob report91if: ${{ !cancelled() }}92uses: actions/upload-artifact@v493with:94name: blob-report-${{ matrix.shardIndex }}95path: blob-report96retention-days: 19798merge-reports:99if: ${{ !cancelled() }}100needs: [test]101runs-on: ubuntu-latest102steps:103- uses: actions/checkout@v4104105- uses: actions/setup-node@v4106with:107node-version: 22108cache: "npm"109110- name: Install dependencies111run: npm ci112113- name: Download blob reports114uses: actions/download-artifact@v4115with:116path: all-blob-reports117pattern: blob-report-*118merge-multiple: true119120- name: Merge reports121run: npx playwright merge-reports --reporter html ./all-blob-reports122123- name: Upload HTML report124uses: actions/upload-artifact@v4125with:126name: html-report127path: playwright-report128retention-days: 14129```130131### With Container132133```yaml134jobs:135test:136timeout-minutes: 60137runs-on: ubuntu-latest138container:139# Use latest or more appropriate playwright version (match package.json)140image: mcr.microsoft.com/playwright:v1.40.0-jammy141steps:142- uses: actions/checkout@v4143144- uses: actions/setup-node@v4145with:146node-version: 22147cache: "npm"148149- name: Install dependencies150run: npm ci151152- name: Run tests153run: npx playwright test154env:155HOME: /root156```157158## Docker159160### Dockerfile161162```dockerfile163FROM mcr.microsoft.com/playwright:v1.40.0-jammy164165WORKDIR /app166167COPY package*.json ./168RUN npm ci169170COPY . .171172CMD ["npx", "playwright", "test"]173```174175### Docker Compose176177```yaml178# docker-compose.yml179version: "3.8"180181services:182playwright:183build: .184volumes:185- ./playwright-report:/app/playwright-report186- ./test-results:/app/test-results187environment:188- CI=true189- BASE_URL=http://app:3000190depends_on:191- app192193app:194build: ./app195ports:196- "3000:3000"197```198199### Run with Docker200201```bash202# Build and run203docker build -t playwright-tests .204docker run --rm -v $(pwd)/playwright-report:/app/playwright-report playwright-tests205206# With docker-compose207docker-compose run --rm playwright208```209210## Reporting211212### Configuration213214```typescript215// playwright.config.ts216export default defineConfig({217reporter: [218// Always generate219["html", { outputFolder: "playwright-report" }],220221// Console output222["list"],223224// CI-friendly225["github"], // GitHub Actions annotations226227// JUnit for CI integration228["junit", { outputFile: "results.xml" }],229230// JSON for custom processing231["json", { outputFile: "results.json" }],232233// Blob for merging shards234["blob", { outputDir: "blob-report" }],235],236});237```238239### CI-Specific Reporter240241```typescript242export default defineConfig({243reporter: process.env.CI244? [["github"], ["blob"], ["html"]]245: [["list"], ["html"]],246});247```248249## Sharding250251### Command Line252253```bash254# Split into 4 shards, run shard 1255npx playwright test --shard=1/4256257# Run shard 2258npx playwright test --shard=2/4259```260261### Configuration262263```typescript264// playwright.config.ts265export default defineConfig({266// Evenly distribute tests across shards267fullyParallel: true,268269// For blob reporter to merge later270reporter: process.env.CI ? [["blob"]] : [["html"]],271});272```273274### Merge Sharded Reports275276```bash277# After all shards complete, merge blob reports278npx playwright merge-reports --reporter html ./all-blob-reports279```280281## Environment Management282283### Environment Variables284285```typescript286// playwright.config.ts287import { defineConfig } from "@playwright/test";288import dotenv from "dotenv";289290// Load env file based on environment291dotenv.config({ path: `.env.${process.env.NODE_ENV || "development"}` });292293export default defineConfig({294use: {295baseURL: process.env.BASE_URL || "http://localhost:3000",296},297});298```299300### Multiple Environments301302```yaml303# .github/workflows/playwright.yml304jobs:305test:306strategy:307matrix:308environment: [staging, production]309steps:310- name: Run tests311run: npx playwright test312env:313BASE_URL: ${{ matrix.environment == 'staging' && 'https://staging.example.com' || 'https://example.com' }}314TEST_USER: ${{ secrets[format('TEST_USER_{0}', matrix.environment)] }}315```316317### Secrets Management318319```yaml320# GitHub Actions secrets321- name: Run tests322run: npx playwright test323env:324TEST_EMAIL: ${{ secrets.TEST_EMAIL }}325TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}326```327328```typescript329// tests use environment variables330test("login", async ({ page }) => {331await page.getByLabel("Email").fill(process.env.TEST_EMAIL!);332await page.getByLabel("Password").fill(process.env.TEST_PASSWORD!);333});334```335336## Caching337338### Cache Playwright Browsers339340```yaml341- name: Cache Playwright browsers342uses: actions/cache@v4343id: playwright-cache344with:345path: ~/.cache/ms-playwright346key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}347348- name: Install Playwright browsers349if: steps.playwright-cache.outputs.cache-hit != 'true'350run: npx playwright install --with-deps351352- name: Install system deps only353if: steps.playwright-cache.outputs.cache-hit == 'true'354run: npx playwright install-deps355```356357### Cache Node Modules358359```yaml360- uses: actions/setup-node@v4361with:362node-version: 22363cache: "npm"364365- name: Install dependencies366run: npm ci367```368369## Tag-Based Test Filtering370371### Run Specific Tags in CI372373```yaml374# Run smoke tests on PR375- name: Run smoke tests376run: npx playwright test --grep @smoke377378# Run full regression nightly379- name: Run regression380run: npx playwright test --grep @regression381382# Exclude flaky tests383- name: Run stable tests384run: npx playwright test --grep-invert @flaky385```386387### PR vs Nightly Strategy388389```yaml390# .github/workflows/pr.yml - Fast feedback391- name: Run critical tests392run: npx playwright test --grep "@smoke|@critical"393394# .github/workflows/nightly.yml - Full coverage395- name: Run all tests396run: npx playwright test --grep-invert @flaky397```398399### Tag Filtering in Config400401```typescript402// playwright.config.ts403export default defineConfig({404grep: process.env.CI ? /@smoke|@critical/ : undefined,405grepInvert: process.env.CI ? /@flaky/ : undefined,406});407```408409### Project-Based Tag Filtering410411```typescript412// playwright.config.ts413export default defineConfig({414projects: [415{416name: "smoke",417grep: /@smoke/,418},419{420name: "regression",421grepInvert: /@smoke/,422},423],424});425```426427## Best Practices428429| Practice | Benefit |430| ----------------------------- | ------------------------- |431| Use `npm ci` | Deterministic installs |432| Run headless in CI | Faster, no display needed |433| Set retries in CI only | Handle flakiness |434| Upload artifacts on failure | Debug failures |435| Use sharding for large suites | Faster execution |436| Cache browsers | Faster setup |437| Use blob reporter for shards | Merge reports correctly |438| Use tags for PR vs nightly | Fast feedback + coverage |439| Exclude @flaky in CI | Stable pipeline |440441## CI Configuration Reference442443```typescript444// playwright.config.ts - CI optimized445export default defineConfig({446testDir: "./tests",447fullyParallel: true,448forbidOnly: !!process.env.CI,449retries: process.env.CI ? 2 : 0,450workers: process.env.CI ? 1 : undefined,451reporter: process.env.CI452? [["github"], ["blob"], ["html"]]453: [["list"], ["html"]],454use: {455baseURL: process.env.BASE_URL || "http://localhost:3000",456trace: "on-first-retry",457screenshot: "only-on-failure",458video: "on-first-retry",459},460});461```462463## Related References464465- **Test tags**: See [test-tags.md](../core/test-tags.md) for tagging and filtering patterns466- **Performance optimization**: See [performance.md](performance.md) for sharding and parallelization467- **Debugging CI failures**: See [debugging.md](../debugging/debugging.md) for troubleshooting468- **Test reporting**: See [debugging.md](../debugging/debugging.md) for trace viewer usage469