mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-13 17:52:38 +02:00
chore: add playwright cursor skill
This commit is contained in:
parent
25aad38ca4
commit
d52225c18d
57 changed files with 25244 additions and 0 deletions
468
.cursor/skills/playwright-testing/infrastructure-ci-cd/ci-cd.md
Normal file
468
.cursor/skills/playwright-testing/infrastructure-ci-cd/ci-cd.md
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
# CI/CD Integration
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [GitHub Actions](#github-actions)
|
||||
2. [Docker](#docker)
|
||||
3. [Reporting](#reporting)
|
||||
4. [Sharding](#sharding)
|
||||
5. [Environment Management](#environment-management)
|
||||
6. [Caching](#caching)
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
```yaml
|
||||
# .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
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```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
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
reporter: process.env.CI
|
||||
? [["github"], ["blob"], ["html"]]
|
||||
: [["list"], ["html"]],
|
||||
});
|
||||
```
|
||||
|
||||
## Sharding
|
||||
|
||||
### Command Line
|
||||
|
||||
```bash
|
||||
# Split into 4 shards, run shard 1
|
||||
npx playwright test --shard=1/4
|
||||
|
||||
# Run shard 2
|
||||
npx playwright test --shard=2/4
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```bash
|
||||
# After all shards complete, merge blob reports
|
||||
npx playwright merge-reports --reporter html ./all-blob-reports
|
||||
```
|
||||
|
||||
## Environment Management
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```yaml
|
||||
# .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
|
||||
|
||||
```yaml
|
||||
# GitHub Actions secrets
|
||||
- name: Run tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
||||
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```yaml
|
||||
- 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
|
||||
|
||||
```yaml
|
||||
- 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
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# .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
|
||||
|
||||
```typescript
|
||||
// playwright.config.ts
|
||||
export default defineConfig({
|
||||
grep: process.env.CI ? /@smoke|@critical/ : undefined,
|
||||
grepInvert: process.env.CI ? /@flaky/ : undefined,
|
||||
});
|
||||
```
|
||||
|
||||
### Project-Based Tag Filtering
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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](../core/test-tags.md) for tagging and filtering patterns
|
||||
- **Performance optimization**: See [performance.md](performance.md) for sharding and parallelization
|
||||
- **Debugging CI failures**: See [debugging.md](../debugging/debugging.md) for troubleshooting
|
||||
- **Test reporting**: See [debugging.md](../debugging/debugging.md) for trace viewer usage
|
||||
Loading…
Add table
Add a link
Reference in a new issue