スキル一覧に戻る
wodsmith

e2e-test

by wodsmith

0🍴 1📅 2026年1月25日
GitHubで見るManusで実行

SKILL.md


name: e2e-test description: End-to-end testing with Playwright. Use when writing E2E tests, implementing page objects, setting up test fixtures, handling authentication in tests, adding visual regression testing, or configuring E2E tests for CI. Covers when to use E2E vs integration tests, critical path identification, page object pattern, test isolation, and CI considerations.

E2E Testing with Playwright

E2E tests verify critical user journeys through the entire stack. Highest confidence, slowest to run, most expensive to maintain.

When to Use E2E

Use for: Critical revenue flows, auth flows, multi-step journeys, paths that cannot break in production.

Don't use for: Business logic (unit), API validation (integration), edge cases (unit/integration), component behavior (component tests).

Rule: If integration tests catch it, don't write E2E. E2E is for happy paths and critical flows only.

Critical Path Identification

Tier 1 (Must): Signup/signin, core product actions, revenue flows Tier 2 (Should): Team features, secondary features, admin ops Tier 3 (Nice): Settings, edge workflows, power user features

Start with Tier 1. One signup test > 20 preference tests.

Page Object Pattern

Encapsulate page selectors and interactions for maintainability.

export class LoginPage {
  constructor(private readonly page: Page) {}

  readonly emailInput = () => this.page.locator('input[type="email"]');
  readonly submitButton = () => this.page.locator('button[type="submit"]');

  async goto() { await this.page.goto('/sign-in'); }
  async login(email: string) {
    await this.emailInput().fill(email);
    await this.submitButton().click();
  }
  async assertLoggedIn() { await this.page.waitForURL('/workouts'); }
}

Principles:

  • Selectors as methods (lazy, prevents stale elements)
  • Actions return void
  • Assertions in page objects only if reused
  • One page object per logical page, not per route

Test Fixtures & Setup

// fixtures/auth.ts
export const TEST_USER = { email: 'e2e@test.com', password: 'Test123!' };

export async function loginAsTestUser(page: Page) {
  await page.goto('/sign-in');
  await page.getByLabel(/email/i).fill(TEST_USER.email);
  await page.getByRole('button', { name: /sign in/i }).click();
  await page.waitForURL(/\/(workouts|dashboard)/);
}
// global-setup.ts - runs once before all tests
async function globalSetup() { await seedTestUsers(); }

Key: Pre-seed test users in global setup. Faster and more reliable than creating per-test.

Test Isolation

Strategy 1: Reset per test (slowest) - beforeEach(() => resetDB()) Strategy 2: Unique data (recommended) - const name = \Test-${Date.now()}`` Strategy 3: Read-only (fastest) - global seed, no mutations

Use Strategy 2. Move to 1 only if tests interfere.

Authentication

Strategy 1: Login each test - Simple, slow (2-3s/test) Strategy 2: Session storage - Save once, reuse. Caveat: expires mid-run Strategy 3: API auth - Fastest, bypass UI

// Strategy 2: global-setup.ts
await page.context().storageState({ path: '.auth/user.json' });

// Strategy 3: beforeEach
const session = await createSessionViaAPI(TEST_USER);
await page.context().addCookies([{ name: 'session', value: session.token }]);

Use Strategy 3 for most tests. Use Strategy 1 only to test login flow itself.

Visual Regression

test('page looks correct', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('baseline.png');
});

Best practices:

  • Disable animations: page.emulateMedia({ reducedMotion: 'reduce' })
  • Stabilize dynamic content (mock timestamps/randomness)
  • Use sparingly (brittle, slow)
  • Focus on critical UI only (login, checkout)

Don't screenshot every page. Do screenshot where design regressions are risky.

CI Configuration

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? '50%' : undefined,
  reporter: process.env.CI ? [['blob'], ['github']] : [['html']],
});

Flakiness mitigation:

  • Explicit waits: await page.waitForSelector('.result') before asserting
  • Semantic selectors: getByRole('button', { name: /submit/i })
  • Retry in CI: 2 retries catches transient issues

Speed:

  • Parallelize (4+ workers in CI)
  • API for setup (bypass UI)
  • Shard across machines
  • Run on critical branches only (main, release)

Decision Tree

Single function → Unit | API endpoint → Integration | Multi-page flow → E2E | Business logic → Integration

WODsmith Structure

e2e/
├── fixtures/auth.ts      # Login helpers
├── pages/login.ts        # Page objects
├── auth.spec.ts          # Test specs
├── global-setup.ts       # DB seeding
└── playwright.config.ts

Global setup seeds DB. Fixtures provide auth. Page objects encapsulate UI. Specs test journeys.

Common Pitfalls

Testing too much: 10-step test fails at step 7 → unclear what broke. Split into focused tests.

No cleanup: Use unique data (Test-${Date.now()}) instead of cleanup. No conflicts, faster.

Implicit waits: Always waitForSelector() before assertions. Prevents race conditions.

References

See WODsmith e2e/ directory for real patterns: fixtures, page objects, global setup.

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です