mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-12 17:22:38 +02:00
9.8 KiB
9.8 KiB
CI/CD Integration
Table of Contents
GitHub Actions
Basic Workflow
# .github/workflows/playwright.yml
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
With Sharding
name: Playwright Tests
on:
push:
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
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: 22
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1
merge-reports:
if: ${{ !cancelled() }}
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge reports
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report
path: playwright-report
retention-days: 14
With Container
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
container:
# Use latest or more appropriate playwright version (match package.json)
image: mcr.microsoft.com/playwright:v1.40.0-jammy
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run tests
run: npx playwright test
env:
HOME: /root
Docker
Dockerfile
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npx", "playwright", "test"]
Docker Compose
# docker-compose.yml
version: "3.8"
services:
playwright:
build: .
volumes:
- ./playwright-report:/app/playwright-report
- ./test-results:/app/test-results
environment:
- CI=true
- BASE_URL=http://app:3000
depends_on:
- app
app:
build: ./app
ports:
- "3000:3000"
Run with Docker
# Build and run
docker build -t playwright-tests .
docker run --rm -v $(pwd)/playwright-report:/app/playwright-report playwright-tests
# With docker-compose
docker-compose run --rm playwright
Reporting
Configuration
// playwright.config.ts
export default defineConfig({
reporter: [
// Always generate
["html", { outputFolder: "playwright-report" }],
// Console output
["list"],
// CI-friendly
["github"], // GitHub Actions annotations
// JUnit for CI integration
["junit", { outputFile: "results.xml" }],
// JSON for custom processing
["json", { outputFile: "results.json" }],
// Blob for merging shards
["blob", { outputDir: "blob-report" }],
],
});
CI-Specific Reporter
export default defineConfig({
reporter: process.env.CI
? [["github"], ["blob"], ["html"]]
: [["list"], ["html"]],
});
Sharding
Command Line
# Split into 4 shards, run shard 1
npx playwright test --shard=1/4
# Run shard 2
npx playwright test --shard=2/4
Configuration
// playwright.config.ts
export default defineConfig({
// Evenly distribute tests across shards
fullyParallel: true,
// For blob reporter to merge later
reporter: process.env.CI ? [["blob"]] : [["html"]],
});
Merge Sharded Reports
# After all shards complete, merge blob reports
npx playwright merge-reports --reporter html ./all-blob-reports
Environment Management
Environment Variables
// playwright.config.ts
import { defineConfig } from "@playwright/test";
import dotenv from "dotenv";
// Load env file based on environment
dotenv.config({ path: `.env.${process.env.NODE_ENV || "development"}` });
export default defineConfig({
use: {
baseURL: process.env.BASE_URL || "http://localhost:3000",
},
});
Multiple Environments
# .github/workflows/playwright.yml
jobs:
test:
strategy:
matrix:
environment: [staging, production]
steps:
- name: Run tests
run: npx playwright test
env:
BASE_URL: ${{ matrix.environment == 'staging' && 'https://staging.example.com' || 'https://example.com' }}
TEST_USER: ${{ secrets[format('TEST_USER_{0}', matrix.environment)] }}
Secrets Management
# GitHub Actions secrets
- name: Run tests
run: npx playwright test
env:
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
// tests use environment variables
test("login", async ({ page }) => {
await page.getByLabel("Email").fill(process.env.TEST_EMAIL!);
await page.getByLabel("Password").fill(process.env.TEST_PASSWORD!);
});
Caching
Cache Playwright Browsers
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install --with-deps
- name: Install system deps only
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps
Cache Node Modules
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
- name: Install dependencies
run: npm ci
Tag-Based Test Filtering
Run Specific Tags in CI
# Run smoke tests on PR
- name: Run smoke tests
run: npx playwright test --grep @smoke
# Run full regression nightly
- name: Run regression
run: npx playwright test --grep @regression
# Exclude flaky tests
- name: Run stable tests
run: npx playwright test --grep-invert @flaky
PR vs Nightly Strategy
# .github/workflows/pr.yml - Fast feedback
- name: Run critical tests
run: npx playwright test --grep "@smoke|@critical"
# .github/workflows/nightly.yml - Full coverage
- name: Run all tests
run: npx playwright test --grep-invert @flaky
Tag Filtering in Config
// playwright.config.ts
export default defineConfig({
grep: process.env.CI ? /@smoke|@critical/ : undefined,
grepInvert: process.env.CI ? /@flaky/ : undefined,
});
Project-Based Tag Filtering
// playwright.config.ts
export default defineConfig({
projects: [
{
name: "smoke",
grep: /@smoke/,
},
{
name: "regression",
grepInvert: /@smoke/,
},
],
});
Best Practices
| Practice | Benefit |
|---|---|
Use npm ci |
Deterministic installs |
| Run headless in CI | Faster, no display needed |
| Set retries in CI only | Handle flakiness |
| Upload artifacts on failure | Debug failures |
| Use sharding for large suites | Faster execution |
| Cache browsers | Faster setup |
| Use blob reporter for shards | Merge reports correctly |
| Use tags for PR vs nightly | Fast feedback + coverage |
| Exclude @flaky in CI | Stable pipeline |
CI Configuration Reference
// playwright.config.ts - CI optimized
export default defineConfig({
testDir: "./tests",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: process.env.CI
? [["github"], ["blob"], ["html"]]
: [["list"], ["html"]],
use: {
baseURL: process.env.BASE_URL || "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "on-first-retry",
},
});
Related References
- Test tags: See test-tags.md for tagging and filtering patterns
- Performance optimization: See performance.md for sharding and parallelization
- Debugging CI failures: See debugging.md for troubleshooting
- Test reporting: See debugging.md for trace viewer usage