E2E Test Optimizer
Quick Start
This skill helps fix three critical E2E test issues:
- •Anti-pattern removal: Replace arbitrary
waitForTimeoutwith smart waits - •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
typescript
// ❌ 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
typescript
// ❌ 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
typescript
// ❌ 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:
yaml
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
bash
# Find all waitForTimeout usage grep -r "waitForTimeout" tests/specs/*.spec.ts # Count per file grep -c "waitForTimeout" tests/specs/*.spec.ts
Standard Test Structure
typescript
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
typescript
// ✅ 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
waitForTimeoutwith smart wait - •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
--grepto manually distribute heavy tests across shards
Mock setup still slow
- •Implement global browser warm-up (see MOCK-OPTIMIZATION-GUIDE.md in tests/docs)
Success Criteria
- •Zero
waitForTimeoutcalls in active tests - •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