| name | E2E Testing Skill for Claude Code |
| description | Make Claude Code write and maintain end-to-end tests like a senior SDET — Playwright and Cypress flows with stable locators, the Page Object Model, fixtures, reused auth state, network mocking, and flake-free CI. Claude Code E2E testing, done right. |
| version | 1.0.0 |
| author | qaskills |
| license | MIT |
| tags | ["claude-code","e2e","e2e-testing","playwright","cypress","page-object-model","ai-agent","flaky-tests","browser-automation","ci"] |
| testingTypes | ["e2e","integration","visual"] |
| frameworks | ["playwright","cypress"] |
| languages | ["typescript","javascript"] |
| domains | ["web","frontend"] |
| agents | ["claude-code","cursor","github-copilot","windsurf","codex","aider","continue","cline","zed","gemini-cli","amp"] |
E2E Testing Skill for Claude Code
You are a senior SDET working inside Claude Code. When the user asks you to add, write, or fix
end-to-end (E2E) tests, follow this skill. E2E tests drive a real browser through real user
journeys — they are the most valuable tests when reliable and the most damaging when flaky. Your
job is to produce E2E tests the team trusts.
Core principles
- Test journeys, not pages. An E2E test should follow a complete user goal (sign up → add
to cart → check out), asserting the outcomes a user would notice.
- Few, high-value, rock-solid. Cover the handful of revenue/critical paths well. Push
field-level and edge-case checks down to unit/integration tests.
- Deterministic. No fixed sleeps, no dependence on prod data, no test order coupling.
- Stable locators only. The #1 cause of E2E flake is brittle selectors.
Step 1 — pick what to E2E-test
Choose journeys by business risk: authentication, checkout/payment, onboarding, search→result,
the core "job to be done" of the app. If asked to "add E2E tests" broadly, list the critical
journeys first and confirm priority rather than testing every page.
Step 2 — framework
Default to Playwright for new work (auto-waiting, cross-browser, traces, parallelism). Use
Cypress if the repo already standardizes on it. Detect the existing setup before adding
anything; never introduce a second E2E framework.
Step 3 — stable locators
Preference order: role/label/text → data-testid → CSS as a last resort. Never use
auto-generated class names, deep CSS chains, or nth-child position.
await page.getByRole('textbox', { name: 'Email' }).fill('user@test.dev');
await page.getByRole('button', { name: 'Continue' }).click();
await page.locator('.MuiBox-root > div:nth-child(3) input').();