E2E Test Framework
Current State
!cat package.json 2>/dev/null | grep -oE 'playwright|cypress|selenium' || echo 'No E2E framework detected'
Overview
Execute end-to-end tests that simulate real user workflows across the full application stack -- browser interactions, API calls, database operations, and third-party integrations. Supports Playwright (recommended), Cypress, Selenium, and Puppeteer.
Prerequisites
- E2E testing framework installed (Playwright, Cypress, or Selenium WebDriver)
- Application running in a test environment with seeded test data
- Browser binaries installed (
npx playwright install or Cypress binary)
- Test user accounts created with known credentials
- Environment variables configured for base URL, API keys, and test credentials
Instructions
- Identify critical user journeys to cover:
- User registration and login flow.
- Primary feature workflow (e.g., create item, edit, delete).
- Search and filtering functionality.
- Checkout or payment flow (if applicable).
- Error handling (404 pages, form validation, session expiry).
- Create page object models (POM) for reusable page interactions:
- One class per page or major component.
- Encapsulate locators, actions (click, fill, select), and assertions.
- Use
data-testid attributes as primary selectors for stability.
- Write E2E test files organized by user journey:
- Each test file covers one complete workflow.
- Use
beforeEach to navigate to the starting page and reset state.
- Use
afterEach to capture screenshots on failure.
- Keep tests independent -- no test should depend on another test's output.
- Handle authentication efficiently:
- Store authenticated session state to a file (
storageState in Playwright).
- Reuse session across tests that require login.
- Create a separate auth setup fixture that runs once per worker.
- Configure multi-browser and responsive testing:
- Run tests on Chromium, Firefox, and WebKit.
- Test at mobile (375px), tablet (768px), and desktop (1280px) viewports.
- Use Playwright projects to define browser/viewport combinations.
- Add retry and stability mechanisms:
- Use
expect with auto-waiting locators (Playwright) instead of explicit waits.
- Configure test retries (max 2) for CI environments.
- Add
networkidle or domcontentloaded wait conditions for page transitions.
- Generate test reports with screenshots, traces, and video on failure.
Output
- E2E test files organized by user journey in
tests/e2e/ or e2e/
- Page object model classes in
tests/e2e/pages/
- Playwright/Cypress configuration file with browser and viewport matrix
- Authentication state file for session reuse
- HTML test report with screenshots, traces, and failure details
Error Handling
| Error |
Cause |
Solution |
| Element not found / timeout |
Selector changed or element lazy-loaded after timeout |
Use data-testid attributes; increase timeout; use waitFor with proper state checks |
| Test passes locally but fails in CI |
Headless browser behavior differs or CI is slower |
Run CI in headless mode locally to reproduce; increase timeouts; check viewport size |
| Authentication state expired |
Stored session tokens have short TTL |
Regenerate auth state before each test run; use long-lived test account tokens |
| Flaky test due to animation |
Click registered before animation completes |
Disable CSS animations in test config; use force: true on click; add waitForLoadState |
| Database state pollution |
Previous test left data that affects current test |
Seed database in beforeEach; use transactional rollback; reset via API endpoint |
Examples
Playwright test for user registration flow:
import { test, expect } from '@playwright/test';
test('new user can register and see dashboard', async ({ page }) => {
await page.goto('/register');
await page.getByTestId('name-input').fill('Test User');
await page.getByTestId('email-input').fill('test@example.com');
await page.getByTestId('password-input').fill('SecurePass123!');
await page.getByTestId('register-button').click();
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByTestId('welcome-message')).toContainText('Test User');
});
Page object model:
export class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string) {
await this.page.goto('/login');
await this.page.getByTestId('email').fill(email);
await this.page.getByTestId('password').fill(password);
await this.page.getByTestId('submit').click();
await this.page.waitForURL(/\/dashboard/);
}
}
Playwright config with multi-browser projects:
export default defineConfig({
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'mobile', use: { ...devices['iPhone 14'] } },
],
use: { screenshot: 'only-on-failure', trace: 'on-first-retry' },
});
Resources
Source: jeremylongshore/claude-code-plugins-plus-skills → skills/.curated/running-e2e-tests/SKILL.md
Also appears in: jeremylongshore/claude-code-plugins-plus-skills/plugins/testing/e2e-test-framework/skills/running-e2e-tests/SKILL.md
1---
2name: running-e2e-tests
3description: "'Execute end-to-end tests covering full user workflows across frontend and backend. Use when performing specialized testing. Trigger with phrases like \"run end-to-end tests\", \"test user flows\", or \"execute E2E suite\". '"
4allowed-tools: "Read, Write, Edit, Grep, Glob, Bash(test:e2e-*)"
5category: testing-and-qa
6source_repo: jeremylongshore/claude-code-plugins-plus-skills
7source_path: "skills/.curated/running-e2e-tests/SKILL.md"
8source_url: https://github.com/jeremylongshore/claude-code-plugins-plus-skills/blob/HEAD/skills/.curated/running-e2e-tests/SKILL.md
9---
10
11# E2E Test Framework
12
13## Current State
14
15!`cat package.json 2>/dev/null | grep -oE 'playwright|cypress|selenium' || echo 'No E2E framework detected'`
16
17## Overview
18
19Execute end-to-end tests that simulate real user workflows across the full application stack -- browser interactions, API calls, database operations, and third-party integrations. Supports Playwright (recommended), Cypress, Selenium, and Puppeteer.
20
21## Prerequisites
22
23- E2E testing framework installed (Playwright, Cypress, or Selenium WebDriver)
24- Application running in a test environment with seeded test data
25- Browser binaries installed (`npx playwright install` or Cypress binary)
26- Test user accounts created with known credentials
27- Environment variables configured for base URL, API keys, and test credentials
28
29## Instructions
30
311. Identify critical user journeys to cover:
32 - User registration and login flow.
33 - Primary feature workflow (e.g., create item, edit, delete).
34 - Search and filtering functionality.
35 - Checkout or payment flow (if applicable).
36 - Error handling (404 pages, form validation, session expiry).
372. Create page object models (POM) for reusable page interactions:
38 - One class per page or major component.
39 - Encapsulate locators, actions (click, fill, select), and assertions.
40 - Use `data-testid` attributes as primary selectors for stability.
413. Write E2E test files organized by user journey:
42 - Each test file covers one complete workflow.
43 - Use `beforeEach` to navigate to the starting page and reset state.
44 - Use `afterEach` to capture screenshots on failure.
45 - Keep tests independent -- no test should depend on another test's output.
464. Handle authentication efficiently:
47 - Store authenticated session state to a file (`storageState` in Playwright).
48 - Reuse session across tests that require login.
49 - Create a separate auth setup fixture that runs once per worker.
505. Configure multi-browser and responsive testing:
51 - Run tests on Chromium, Firefox, and WebKit.
52 - Test at mobile (375px), tablet (768px), and desktop (1280px) viewports.
53 - Use Playwright projects to define browser/viewport combinations.
546. Add retry and stability mechanisms:
55 - Use `expect` with auto-waiting locators (Playwright) instead of explicit waits.
56 - Configure test retries (max 2) for CI environments.
57 - Add `networkidle` or `domcontentloaded` wait conditions for page transitions.
587. Generate test reports with screenshots, traces, and video on failure.
59
60## Output
61
62- E2E test files organized by user journey in `tests/e2e/` or `e2e/`
63- Page object model classes in `tests/e2e/pages/`
64- Playwright/Cypress configuration file with browser and viewport matrix
65- Authentication state file for session reuse
66- HTML test report with screenshots, traces, and failure details
67
68## Error Handling
69
70| Error | Cause | Solution |
71|-------|-------|---------|
72| Element not found / timeout | Selector changed or element lazy-loaded after timeout | Use `data-testid` attributes; increase timeout; use `waitFor` with proper state checks |
73| Test passes locally but fails in CI | Headless browser behavior differs or CI is slower | Run CI in headless mode locally to reproduce; increase timeouts; check viewport size |
74| Authentication state expired | Stored session tokens have short TTL | Regenerate auth state before each test run; use long-lived test account tokens |
75| Flaky test due to animation | Click registered before animation completes | Disable CSS animations in test config; use `force: true` on click; add `waitForLoadState` |
76| Database state pollution | Previous test left data that affects current test | Seed database in `beforeEach`; use transactional rollback; reset via API endpoint |
77
78## Examples
79
80**Playwright test for user registration flow:**
81
82```typescript
83import { test, expect } from '@playwright/test';
84
85test('new user can register and see dashboard', async ({ page }) => {
86 await page.goto('/register');
87 await page.getByTestId('name-input').fill('Test User');
88 await page.getByTestId('email-input').fill('test@example.com');
89 await page.getByTestId('password-input').fill('SecurePass123!');
90 await page.getByTestId('register-button').click();
91
92 await expect(page).toHaveURL(/\/dashboard/);
93 await expect(page.getByTestId('welcome-message')).toContainText('Test User');
94});
95```
96
97**Page object model:**
98
99```typescript
100export class LoginPage {
101 constructor(private page: Page) {}
102 async login(email: string, password: string) {
103 await this.page.goto('/login');
104 await this.page.getByTestId('email').fill(email);
105 await this.page.getByTestId('password').fill(password);
106 await this.page.getByTestId('submit').click();
107 await this.page.waitForURL(/\/dashboard/);
108 }
109}
110```
111
112**Playwright config with multi-browser projects:**
113
114```typescript
115export default defineConfig({
116 projects: [
117 { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
118 { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
119 { name: 'mobile', use: { ...devices['iPhone 14'] } },
120 ],
121 use: { screenshot: 'only-on-failure', trace: 'on-first-retry' },
122});
123```
124
125## Resources
126
127- Playwright documentation: https://playwright.dev/docs/intro
128- Cypress documentation: https://docs.cypress.io/
129- Page Object Model pattern: https://playwright.dev/docs/pom
130- Playwright best practices: https://playwright.dev/docs/best-practices
131- E2E testing strategies: https://martinfowler.com/bliki/TestPyramid.html
132
133---
134
135**Source:** [`jeremylongshore/claude-code-plugins-plus-skills`](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) → `skills/.curated/running-e2e-tests/SKILL.md`
136
137**Also appears in:** `jeremylongshore/claude-code-plugins-plus-skills/plugins/testing/e2e-test-framework/skills/running-e2e-tests/SKILL.md`