install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/e2e-test-optimizer" ~/.claude/skills/majiayu000-claude-skill-registry-e2e-test-optimizer && rm -rf "$T"
manifest:
skills/data/e2e-test-optimizer/SKILL.mdsource content
E2E Test Optimizer
Quick Start
This skill helps fix three critical E2E test issues:
- Anti-pattern removal: Replace arbitrary
with smart waitswaitForTimeout - Test sharding: Enable parallel test execution in CI
- Mock optimization: Reduce mock setup overhead
When to Use
- E2E tests timing out or failing due to arbitrary waits
- CI execution time exceeds 10 minutes
- Need test parallelization for faster feedback
- Test flakiness from race conditions
Smart Wait Patterns
Navigation Waits
// ❌ Arbitrary wait await page.click('[data-testid="nav-dashboard"]'); await page.waitForTimeout(1000); // ✅ Wait for specific element await page.click('[data-testid="nav-dashboard"]'); await expect(page.getByTestId('dashboard-content')).toBeVisible({ timeout: 5000, });
State Transition Waits
// ❌ Arbitrary wait after action await page.getByRole('button', { name: 'Generate' }).click(); await page.waitForTimeout(2000); // ✅ Wait for loading state completion await page.getByRole('button', { name: 'Generate' }).click(); await expect(page.getByTestId('loading-spinner')).not.toBeVisible(); await expect(page.getByTestId('result')).toBeVisible();
Network Waits
// ❌ Arbitrary wait after submit await page.getByRole('button', { name: 'Save' }).click(); await page.waitForTimeout(1500); // ✅ Wait for network idle or success message await page.getByRole('button', { name: 'Save' }).click(); await page.waitForLoadState('networkidle'); // OR await expect(page.getByText('Saved successfully')).toBeVisible();
Test Sharding Setup
Add to
.github/workflows/ci.yml:
e2e-tests: name: 🧪 E2E Tests [Shard ${{ matrix.shard }}/3] runs-on: ubuntu-latest timeout-minutes: 30 needs: build-and-test strategy: fail-fast: false matrix: shard: [1, 2, 3] steps: - name: Run Playwright tests run: pnpm exec playwright test --shard=${{ matrix.shard }}/3 env: CI: true
Expected improvement: 60-65% faster (27 minutes → 9-10 minutes)
Detection Commands
# Find all waitForTimeout usage grep -r "waitForTimeout" tests/specs/*.spec.ts # Count per file grep -c "waitForTimeout" tests/specs/*.spec.ts
Standard Test Structure
import { test, expect } from '@playwright/test'; import { setupGeminiMock } from '../utils/mock-ai-gateway'; test.describe('Feature Name', () => { test.beforeEach(async ({ page }) => { await setupGeminiMock(page); await page.goto('/'); await page.waitForLoadState('networkidle'); }); test('should perform action', async ({ page }) => { // Navigate await page.getByTestId('nav-target').click(); await expect(page.getByTestId('target-page')).toBeVisible(); // Interact await page.getByRole('button', { name: 'Action' }).click(); await expect(page.getByTestId('loading')).not.toBeVisible(); // Assert await expect(page.getByTestId('result')).toBeVisible(); }); });
Element Selection Priority
// ✅ Best: data-testid (stable, explicit) await page.getByTestId('project-card'); // ✅ Good: role + name (semantic, accessible) await page.getByRole('button', { name: 'Create' }); // ⚠️ OK: text (can break with i18n) await page.getByText('Dashboard'); // ❌ Avoid: CSS selectors (brittle) await page.locator('.project-card > div.title');
Optimization Workflow
Phase 1: Analysis
- Scan test files for
waitForTimeout - Count occurrences per file
- Prioritize files by occurrence count
Phase 2: Fix Anti-Patterns
- Start with highest-priority file
- Replace each
with smart waitwaitForTimeout - Run tests after each file:
playwright test path/to/file.spec.ts - Commit per-file changes
Phase 3: Implement Sharding
- Update CI workflow with matrix strategy
- Test locally:
playwright test --shard=1/3 - Push and monitor all 3 shards in CI
Phase 4: Validation
- Verify all tests pass
- Confirm execution time < 10 minutes
- Check shard balance (±2 min variance acceptable)
Common Issues
Tests still timing out after fix
- Increase timeout on slow operations:
expect(...).toBeVisible({ timeout: 10000 })
Unbalanced shards (one takes much longer)
- Use
to manually distribute heavy tests across shards--grep
Mock setup still slow
- Implement global browser warm-up (see MOCK-OPTIMIZATION-GUIDE.md in tests/docs)
Success Criteria
- Zero
calls in active testswaitForTimeout - CI execution time < 10 minutes
- All shards complete within ±2 minutes of each other
- 100% test pass rate (no flaky tests)
References
See tests/docs/ for detailed guides:
- MOCK-OPTIMIZATION-GUIDE.md - Mock performance patterns
- MOCK-PERFORMANCE-ANALYSIS.md - Optimization results
External documentation:
- Playwright Best Practices: https://playwright.dev/docs/best-practices
- Test Sharding: https://playwright.dev/docs/test-sharding