mcpField
E
e2e-testing

e2e-testing

github.com/hieutrtrテスト・品質81.6k 回インストール38 週間前に更新
リポジトリ

e2e-testing について

e2e-testingは、ユーザーワークフロー全体や重要経路を対象とするPlaywrightのエンドツーエンドテスト設計スキルです。ページオブジェクト、セレクター、テストデータ、認証の再利用、デバッグ、CIの指針を示します。

主な機能

  1. 01Playwright E2Eテスト構成
  2. 02ページオブジェクトモデルの指針
  3. 03堅牢なセレクター戦略
  4. 04明示的な待機と認証の再利用
  5. 05テストデータの作成と削除
  6. 06不安定なテストのデバッグとCI

活用シーン

  1. 01ログインとCRUDワークフローのテスト
  2. 02クロスブラウザー動作の確認
  3. 03ファイルのアップロードとダウンロードの検証
  4. 04デプロイ時のスモークテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/hieutrtr/ai1-skills --skill e2e-testing

インストール後、Claude Code で/e2e-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
e2e-test-template.ts
page-object-template.ts
playwright-config-example.ts
scripts/
run-e2e-with-report.sh

詳細

E2E テスト

使用する場面

以下の場合にこのスキルを有効にします。

  • ユーザーの一連のワークフロー(ログイン、CRUD 操作、複数ページにわたるフロー)の E2E テストを作成するとき
  • スタック全体を検証する、重要な経路の回帰テストを作成するとき
  • クロスブラウザー互換性(Chromium、Firefox、WebKit)をテストするとき
  • 認証フローをエンドツーエンドで検証するとき
  • ファイルのアップロード/ダウンロードのワークフローをテストするとき
  • デプロイを検証するスモークテストを作成するとき

以下の場合はこのスキルを使用しないでください。

  • React コンポーネントのユニットテスト(react-testing-patterns を使用)
  • Python バックエンドのユニットテスト/統合テスト(pytest-patterns を使用)
  • TDD ワークフローの適用(tdd-workflow を使用)
  • ブラウザーを使用しない API コントラクトテスト(httpx を使用する pytest-patterns を使用)

手順

テストの構成
e2e/
├── playwright.config.ts         # Global Playwright configuration
├── fixtures/
│   ├── auth.fixture.ts          # Authentication state setup
│   └── test-data.fixture.ts     # Test data creation/cleanup
├── pages/
│   ├── base.page.ts             # Base page object with shared methods
│   ├── login.page.ts            # Login page object
│   ├── users.page.ts            # Users list page object
│   └── user-detail.page.ts     # User detail page object
├── tests/
│   ├── auth/
│   │   ├── login.spec.ts
│   │   └── logout.spec.ts
│   ├── users/
│   │   ├── create-user.spec.ts
│   │   ├── edit-user.spec.ts
│   │   └── list-users.spec.ts
│   └── smoke/
│       └── critical-paths.spec.ts
└── utils/
    ├── api-helpers.ts           # Direct API calls for test setup
    └── test-constants.ts        # Shared constants

命名規則:

  • テストファイル:<feature>.spec.ts
  • ページオブジェクト:<page-name>.page.ts
  • フィクスチャ:<concern>.fixture.ts
  • テスト名:ユーザーの操作と期待される結果を説明する、人が読んで理解しやすい文
ページオブジェクトモデル

各ページには、セレクターとアクションをカプセル化するページオブジェクトクラスを用意します。テストからセレクターを直接操作してはいけません。

基本ページオブジェクト:

// e2e/pages/base.page.ts
import { type Page, type Locator } from "@playwright/test";

export abstract class BasePage {
  constructor(protected readonly page: Page) {}

  /** Navigate to the page's URL. */
  abstract goto(): Promise<void>;

  /** Wait for the page to be fully loaded. */
  async waitForLoad(): Promise<void> {
    await this.page.waitForLoadState("networkidle");
  }

  /** Get a toast/notification message. */
  get toast(): Locator {
    return this.page.getByRole("alert");
  }

  /** Get the page heading. */
  get heading(): Locator {
    return this.page.getByRole("heading", { level: 1 });
  }
}

具体的なページオブジェクト:

// e2e/pages/users.page.ts
import { type Page, type Locator } from "@playwright/test";
import { BasePage } from "./base.page";

export class UsersPage extends BasePage {
  // ─── Locators ─────────────────────────────────────────
  readonly createButton: Locator;
  readonly searchInput: Locator;
  readonly userTable: Locator;

  constructor(page: Page) {
    super(page);
    this.createButton = page.getByTestId("create-user-btn");
    this.searchInput = page.getByRole("searchbox", { name: /search users/i });
    this.userTable = page.getByRole("table");
  }

  // ─── Actions ──────────────────────────────────────────
  async goto(): Promise<void> {
    await this.page.goto("/users");
    await this.waitForLoad();
  }

  async searchFor(query: string): Promise<void> {
    await this.searchInput.fill(query);
    // Wait for search results to update (debounced)
    await this.page.waitForResponse("**/api/v1/users?*");
  }

  async clickCreateUser(): Promise<void> {
    await this.createButton.click();
  }

  async getUserRow(email: string): Promise<Locator> {
    return this.userTable.getByRole("row").filter({ hasText: email });
  }

  async getUserCount(): Promise<number> {
    // Subtract 1 for header row
    return (await this.userTable.getByRole("row").count()) - 1;
  }
}

ページオブジェクトのルール:

  • ページまたは主要な UI セクションごとにページオブジェクトを 1 つ作成します
  • ロケーターは public readonly プロパティにします
  • アクションは async メソッドにします
  • ページオブジェクトにアサーションを含めてはいけません。アサーションはテストで行います
  • ページオブジェクトは、アクション後の待機を内部で処理します
セレクター戦略

優先順位(高い順):

優先度セレクター例使用場面
1data-testidgetByTestId("submit-btn")インタラクティブ要素、動的コンテンツ
2ロールgetByRole("button", { name: /save/i })ボタン、リンク、見出し、入力欄
3ラベルgetByLabel("Email")ラベルのあるフォーム入力欄
4プレースホルダーgetByPlaceholder("Search...")検索入力欄
5テキストgetByText("Welcome back")静的なテキストコンテンツ

次は絶対に使用しないでください。

  • CSS セレクター(.class-name、#id)-- 壊れやすく、スタイルの変更で動作しなくなります
  • XPath(//div[@class="foo"])-- 読みにくく、非常に壊れやすいです
  • DOM 構造セレクター(div > span:nth-child(2))-- レイアウトの変更で動作しなくなります

data-testid 属性の追加:

// In React components -- add data-testid to interactive elements
<button data-testid="create-user-btn" onClick={handleCreate}>
  Create User
</button>

// Convention: kebab-case, descriptive
// Pattern: <action>-<entity>-<element-type>
// Examples: create-user-btn, user-email-input, delete-confirm-dialog
待機戦略

ハードコードした待機は絶対に使用しないでください。

// BAD: Hardcoded wait -- flaky, slow
await page.waitForTimeout(3000);

// BAD: Sleep
await new Promise((resolve) => setTimeout(resolve, 2000));

明示的な待機条件を使用してください。

// GOOD: Wait for a specific element to appear
await page.getByRole("heading", { name: "Dashboard" }).waitFor();

// GOOD: Wait for navigation
await page.waitForURL("/dashboard");

// GOOD: Wait for API response
await page.waitForResponse(
  (response) =>
    response.url().includes("/api/v1/users") && response.status() === 200,
);

// GOOD: Wait for network to settle
await page.waitForLoadState("networkidle");

// GOOD: Wait for element state
await page.getByTestId("submit-btn").waitFor({ state: "visible" });
await page.getByTestId("loading-spinner").waitFor({ state: "hidden" });

自動待機: Playwright は、クリックや入力などの前に、要素が操作可能になるまで自動で待機します。明示的な待機が必要なのは、アサーションや複雑な状態遷移の場合のみです。

認証状態の再利用

すべてのテストの前にログインするのは避けてください。認証状態を保存して再利用します。

認証状態を一度だけセットアップする:

// e2e/fixtures/auth.fixture.ts
import { test as base } from "@playwright/test";
import path from "path";

const AUTH_STATE_PATH = path.resolve("e2e/.auth/user.json");

export const setup = base.extend({});

setup("authenticate", async ({ page }) => {
  // Perform real login
  await page.goto("/login");
  await page.getByLabel("Email").fill("[email protected]");
  await page.getByLabel("Password").fill("TestPassword123!");
  await page.getByRole("button", { name: /sign in/i }).click();

  // Wait for auth to complete
  await page.waitForURL("/dashboard");

  // Save signed-in state
  await page.context().storageState({ path: AUTH_STATE_PATH });
});

テストで再利用する:

// playwright.config.ts
export default defineConfig({
  projects: [
    // Setup project runs first and saves auth state
    { name: "setup", testDir: "./e2e/fixtures", testMatch: "auth.fixture.ts" },
    {
      name: "chromium",
      use: {
        storageState: "e2e/.auth/user.json",  // Reuse auth state
      },
      dependencies: ["setup"],
    },
  ],
});
テストデータ管理

原則:

  • テストでは独自のデータを作成します(既存のデータに依存しないでください)
  • テストでは実行後にデータをクリーンアップします(または API を使ってリセットします)
  • セットアップには UI 操作ではなく API 呼び出しを使用します(より高速で信頼性が高いため)

テストデータ用 API ヘルパー:

// e2e/utils/api-helpers.ts
import { type APIRequestContext } from "@playwright/test";

export class TestDataAPI {
  constructor(private request: APIRequestContext) {}

  async createUser(data: { email: string; displayName: string }) {
    const response = await this.request.post("/api/v1/users", { data });
    return response.json();
  }

  async deleteUser(userId: number) {
    await this.request.delete(`/api/v1/users/${userId}`);
  }

  async createOrder(userId: number, items: Array<Record<string, unknown>>) {
    const response = await this.request.post("/api/v1/orders", {
      data: { user_id: userId, items },
    });
    return response.json();
  }
}

テストでの使用:

test("edit user name", async ({ page, request }) => {
  const api = new TestDataAPI(request);

  // Setup: create user via API (fast)
  const user = await api.createUser({
    email: "[email protected]",
    displayName: "Before Edit",
  });

  try {
    // Test: edit via UI
    const usersPage = new UsersPage(page);
    await usersPage.goto();
    // ... perform edit via UI ...
  } finally {
    // Cleanup: remove test data
    await api.deleteUser(user.id);
  }
});
不安定なテストのデバッグ

1. 失敗の調査にはトレースビューアーを使用します。

// playwright.config.ts
use: {
  trace: "on-first-retry",  // Capture trace only on retry
}

トレースを表示:npx playwright show-trace trace.zip

2. デバッグでは headed モードで実行します。

npx playwright test --headed --debug tests/users/create-user.spec.ts

3. 不安定なテストの一般的な原因:

原因対処方法
ハードコードした待機明示的な待機条件を使用する
テストデータの共有各テストで独自のデータを作成する
アニメーションの干渉設定で animations: "disabled" を指定する
競合状態アサーションの前に API レスポンスを待つ
ビューポートに依存する動作設定でビューポートを明示的に指定する
テスト間のセッション漏れstorageState を正しく使用し、Cookie をクリアする

4. 再試行戦略:

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,  // Retry in CI only
});
CI の設定
# .github/workflows/e2e.yml
name: E2E Tests
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps chromium

      - name: Start application
        run: |
          docker compose up -d
          npx wait-on http://localhost:3000 --timeout 60000

      - name: Run E2E tests
        run: npx playwright test

      - name: Upload test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 14

      - name: Upload traces on failure
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: test-traces
          path: test-results/

npx playwright を HTML レポート出力付きでローカル実行するには、scripts/run-e2e-with-report.sh を使用します。

例

注釈付きのページオブジェクトクラスについては、references/page-object-template.ts をご覧ください。 注釈付きの E2E テストについては、references/e2e-test-template.ts をご覧ください。 本番環境向けの Playwright 設定については、references/playwright-config-example.ts をご覧ください。

コメント