e2e-testing
tpavanipradeep/everything-claude-code/.agents/skills/e2e-testing/SKILL.md
Playwright E2E testing patterns, Page Object Model, configuration, CI/CD integration, artifact management, and flaky test strategies.
Skill104 starsChanged 7 months ago
- Reads credentials
What's in it
- E2E Testing Patterns
- Test File Organization
- Page Object Model (POM)
- Test Structure
- Playwright Configuration
- Flaky Test Patterns
- Quarantine
- Identify Flakiness
- Common Causes & Fixes
- Artifact Management
- Screenshots
- Traces
- Video
- CI/CD Integration
- Test Report Template
- Wallet / Web3 Testing
- Financial / Critical Flow Testing
---
name: e2e-testing
description: Playwright E2E testing patterns, Page Object Model, configuration, CI/CD integration, artifact management, and flaky test strategies.
origin: ECC
---
# E2E Testing Patterns
Comprehensive Playwright patterns for building stable, fast, and maintainable E2E test suites.
## Test File Organization
```
tests/
├── e2e/
│ ├── auth/
│ │ ├── login.spec.ts
│ │ ├── logout.spec.ts
│ │ └── register.spec.ts
│ ├── features/
│ │ ├── browse.spec.ts
│ │ ├── search.spec.ts
│ │ └── create.spec.ts
│ └── api/
│ └── endpoints.spec.ts
├── fixtures/
│ ├── auth.ts
│ └── data.ts
└── playwright.config.ts
```
## Page Object Model (POM)
```typescript
import { Page, Locator } from '@playwright/test'
export class ItemsPage {
readonly page: Page
readonly searchInput: Locator
readonly itemCards: Locator
readonly createButton: Locator
constructor(page: Page) {
this.page = page
this.searchInput = page.locator('[data-testid="search-input"]')
this.itemCards = page.locator('[data-testid="item-card"]')
this.createButton = page.locator('[data-testid="create-btn"]')
}
async goto() {
await this.page.goto('/items')
await this.page.waitForLoadState('networkidle')
}
async search(query: string) {
await this.searchInput.fill(query)
await this.page.waitForResponse(resp => resp.url().includes('/api/search'))
await this.page.waitForLoadState('networkidle')
}
async getItemCount() {
return await this.itemCards.count()
}
}
```
## Test Structure
```typescript
import { test, expect } from '@playwright/test'
import { ItemsPage } from '../../pages/ItemsPage'
test.describe('Item Search', () => {
let itemsPage: ItemsPage
test.beforeEach(async ({ page }) => {
itemsPage = new ItemsPage(page)
await itemsPage.goto()
})
test('should search by keyword', async ({ page }) => {
await itemsPage.search('test')
const count = await itemsPage.getItemCount()
expect(count).toBeGreaterThan(0)
await expect(itemsPage.itemCards.first()).toContainText(/test/i)
await page.screenshot({ path: 'artifacts/search-results.png' })
})
test('should handle no results', async ({ page }) => {
await itemsPage.search('xyznonexistent123')
await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
expect(await itemsPage.getItemCount()).toBe(0)
})
})
```
## Playwright Configuration
```typescript
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [
['html', { outputFolder: 'playwright-report' }],
['junit', { outputFile: 'playwright-results.xml' }],
['json', { outputFile: 'playwright-results.json' }]
],
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
actionTimeout: 10000,
navigationTimeout: 30000,
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},
})
```
## Flaky Test Patterns
### Quarantine
```typescript
test('flaky: complex search', async ({ page }) => {
test.fixme(true, 'Flaky - Issue #123')
// test code...
})
test('conditional skip', async ({ page }) => {
test.skip(process.env.CI, 'Flaky in CI - Issue #123')
// test code...
})
```
### Identify Flakiness
```bash
npx playwright test tests/search.spec.ts --repeat-each=10
npx playwright test tests/search.spec.ts --retries=3
```
### Common Causes & Fixes
**Race conditions:**
```typescript
// Bad: assumes element is ready
await page.click('[data-testid="button"]')
// Good: auto-wait locator
await page.locator('[data-testid="button"]').click()
```
**Network timing:**
```typescript
// Bad: arbitrary timeout
await page.waitForTimeout(5000)
// Good: wait for specific condition
await page.waitForResponse(resp => resp.url().includes('/api/data'))
```
**Animation timing:**
```typescript
// Bad: click during animation
await page.click('[data-testid="menu-item"]')
// Good: wait for stability
await page.locator('[data-testid="menu-item"]').waitFor({ state: 'visible' })
await page.waitForLoadState('networkidle')
await page.locator('[data-testid="menu-item"]').click()
```
## Artifact Management
### Screenshots
```typescript
await page.screenshot({ path: 'artifacts/after-login.png' })
await page.screenshot({ path: 'artifacts/full-page.png', fullPage: true })
await page.locator('[data-testid="chart"]').screenshot({ path: 'artifacts/chart.png' })
```
### Traces
```typescript
await browser.startTracing(page, {
path: 'artifacts/trace.json',
screenshots: true,
snapshots: true,
})
// ... test actions ...
await browser.stopTracing()
```
### Video
```typescript
// In playwright.config.ts
use: {
video: 'retain-on-failure',
videosPath: 'artifacts/videos/'
}
```
## CI/CD Integration
```yaml
# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
env:
BASE_URL: ${{ vars.STAGING_URL }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
```
## Test Report Template
```markdown
# E2E Test Report
**Date:** YYYY-MM-DD HH:MM
**Duration:** Xm Ys
**Status:** PASSING / FAILING
## Summary
- Total: X | Passed: Y (Z%) | Failed: A | Flaky: B | Skipped: C
## Failed Tests
### test-name
**File:** `tests/e2e/feature.spec.ts:45`
**Error:** Expected element to be visible
**Screenshot:** artifacts/failed.png
**Recommended Fix:** [description]
## Artifacts
- HTML Report: playwright-report/index.html
- Screenshots: artifacts/*.png
- Videos: artifacts/videos/*.webm
- Traces: artifacts/*.zip
```
## Wallet / Web3 Testing
```typescript
test('wallet connection', async ({ page, context }) => {
// Mock wallet provider
await context.addInitScript(() => {
window.ethereum = {
isMetaMask: true,
request: async ({ method }) => {
if (method === 'eth_requestAccounts')
return ['0x1234567890123456789012345678901234567890']
if (method === 'eth_chainId') return '0x1'
}
}
})
await page.goto('/')
await page.locator('[data-testid="connect-wallet"]').click()
await expect(page.locator('[data-testid="wallet-address"]')).toContainText('0x1234')
})
```
## Financial / Critical Flow Testing
```typescript
test('trade execution', async ({ page }) => {
// Skip on production — real money
test.skip(process.env.NODE_ENV === 'production', 'Skip on production')
await page.goto('/markets/test-market')
await page.locator('[data-testid="position-yes"]').click()
await page.locator('[data-testid="trade-amount"]').fill('1.0')
// Verify preview
const preview = page.locator('[data-testid="trade-preview"]')
await expect(preview).toContainText('1.0')
// Confirm and wait for blockchain
await page.locator('[data-testid="confirm-trade"]').click()
await page.waitForResponse(
resp => resp.url().includes('/api/trade') && resp.status() === 200,
{ timeout: 30000 }
)
await expect(page.locator('[data-testid="trade-success"]')).toBeVisible()
})
```
More agent context in tpavanipradeep/everything-claude-code
81 other files this repository gives its agents, the first 60 shown.
AGENTS.md
CLAUDE.md
Cursor rule
- .cursor/rules/common-agents.md
- .cursor/rules/common-coding-style.md
- .cursor/rules/common-development-workflow.md
- .cursor/rules/common-git-workflow.md
- .cursor/rules/common-hooks.md
- .cursor/rules/common-patterns.md
- .cursor/rules/common-performance.md
- .cursor/rules/common-security.md
- .cursor/rules/common-testing.md
- .cursor/rules/golang-coding-style.md
- .cursor/rules/golang-hooks.md
- .cursor/rules/golang-patterns.md
- .cursor/rules/golang-security.md
- .cursor/rules/golang-testing.md
- .cursor/rules/kotlin-coding-style.md
- .cursor/rules/kotlin-hooks.md
- .cursor/rules/kotlin-patterns.md
- .cursor/rules/kotlin-security.md
- .cursor/rules/kotlin-testing.md
- .cursor/rules/php-coding-style.md
- .cursor/rules/php-hooks.md
- .cursor/rules/php-patterns.md
- .cursor/rules/php-security.md
- .cursor/rules/php-testing.md
- .cursor/rules/python-coding-style.md
- .cursor/rules/python-hooks.md
- .cursor/rules/python-patterns.md
- .cursor/rules/python-security.md
- .cursor/rules/python-testing.md
- .cursor/rules/swift-coding-style.md
- .cursor/rules/swift-hooks.md
- .cursor/rules/swift-patterns.md
- .cursor/rules/swift-security.md
- .cursor/rules/swift-testing.md
- .cursor/rules/typescript-coding-style.md
- .cursor/rules/typescript-hooks.md
- .cursor/rules/typescript-patterns.md
- .cursor/rules/typescript-security.md
- .cursor/rules/typescript-testing.md
Skill
- api-design.agents/skills/api-design/SKILL.md
- article-writing.agents/skills/article-writing/SKILL.md
- backend-patterns.agents/skills/backend-patterns/SKILL.md
- bun-runtime.agents/skills/bun-runtime/SKILL.md
- claude-api.agents/skills/claude-api/SKILL.md
- coding-standards.agents/skills/coding-standards/SKILL.md
- content-engine.agents/skills/content-engine/SKILL.md
- crosspost.agents/skills/crosspost/SKILL.md
- deep-research.agents/skills/deep-research/SKILL.md
- dmux-workflows.agents/skills/dmux-workflows/SKILL.md
- documentation-lookup.agents/skills/documentation-lookup/SKILL.md
- eval-harness.agents/skills/eval-harness/SKILL.md
- exa-search.agents/skills/exa-search/SKILL.md
- fal-ai-media.agents/skills/fal-ai-media/SKILL.md
- frontend-patterns.agents/skills/frontend-patterns/SKILL.md
- frontend-slides.agents/skills/frontend-slides/SKILL.md
- investor-materials.agents/skills/investor-materials/SKILL.md
Also found in 21 other repositories
The same file, byte for byte, in the weekly crawl of public GitHub; the 10 with the most stars.
- loulanyue/awesome-claude-notes272
- mit-network/everything-claude-code76
- j7-dev/everything-github-copilot19
- Infopibe/everything-claude-code8
- zero-click/zero-ratchet8
- yapota2018/affaan-m-everything-claude-code4
- ArogyaReddy/https-github.com-affaan-m-everything-claude-code12
- ashutoshrathi0909-oss/everything-claude-code1
- divenhuang88/everything-claude-code1
- elainesmithburkel-code/everything-claude-code1
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

