| name | tsh-e2e-testing |
| description | E2E testing patterns, verification procedures, and CI readiness checklists using Playwright. Use for writing, debugging, or reviewing end-to-end tests, fixing flaky tests, creating Page Objects, mocking external APIs. |
| user-invocable | false |
E2E Testing Patterns & Practices
Page Object Pattern
export class FeaturePage {
constructor(readonly page: Page) {}
get submitBtn() {
return this.page.getByRole('button', { name: 'Submit' });
}
async navigate() { await this.page.goto('/feature'); }
}
Test Structure
test('should [behavior] when [condition]', async ({ page }) => {
const id = `test-${Date.now()}-${test.info().parallelIndex}`;
});
Mocking (external APIs only)
await page.route('**/api/external/**', route => route.fulfill({ status: 200, body: '{}' }));
Verification Loop
RUN → FAIL? → DEBUG (browser_snapshot) → FIX → REPEAT
| Rule | Limit |
|---|
| Max per test | 5 iterations → test.fixme() |
| Max per suite | 15 iterations → stop |
| Flaky detection | 3 pass/fail mix → investigate |
| Stability | 3+ consecutive passes required |
| App bug | Mark test.fixme('BUG: desc') |
Error Recovery
| Error | Action |
|---|
| Timeout | Increase once → check selector → check if element renders |
| Element not found | Alternative locator → check DOM → verify page loaded |
| Network | Retry → consider mock → verify backend |
| Flaky | Explicit waits → check race conditions → run 5x |
| App bug | Mark test.fixme('BUG: desc') - test is skipped; CI usually still passes unless skipped tests fail the build |
CI Readiness Checklist
Quick Reference
Always: accessible locators, unique test data, 3+ passes, mock external APIs
Never: waitForTimeout(), CSS selectors, test interdependencies, hardcoded creds