e2e-test-optimizer

📁 d-oit/do-novelist-ai 📅 13 days ago
1
总安装量
1
周安装量
#43646
全站排名
安装命令
npx skills add https://github.com/d-oit/do-novelist-ai --skill e2e-test-optimizer

Agent 安装分布

opencode 1
cursor 1

Skill 文档

E2E Test Optimizer

Quick Start

This skill helps fix three critical E2E test issues:

  1. Anti-pattern removal: Replace arbitrary waitForTimeout with smart waits
  2. Test sharding: Enable parallel test execution in CI
  3. 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

  1. Scan test files for waitForTimeout
  2. Count occurrences per file
  3. Prioritize files by occurrence count

Phase 2: Fix Anti-Patterns

  1. Start with highest-priority file
  2. Replace each waitForTimeout with smart wait
  3. Run tests after each file: playwright test path/to/file.spec.ts
  4. Commit per-file changes

Phase 3: Implement Sharding

  1. Update CI workflow with matrix strategy
  2. Test locally: playwright test --shard=1/3
  3. Push and monitor all 3 shards in CI

Phase 4: Validation

  1. Verify all tests pass
  2. Confirm execution time < 10 minutes
  3. 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 --grep to 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 waitForTimeout calls 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: