e2e-testing

SKILL.md

E2E Testing Skill

E2Eテストの新規作成・設計・保守を支援する。

When to Use This Skill

  • 新規E2Eテストを作成する時
  • テスト設計方針を決める時(page object設計、fixture設計等)
  • 既存テストをメンテナンス・リファクタリングする時
  • flaky予防のための設計改善時

テスト失敗の修正: e2e-test-fixer エージェントを使うこと(タイムアウト、セレクタエラー、flake等)


ワークフロー: 新規テスト作成 (MANDATORY)

"Build evaluations FIRST before writing extensive documentation. This ensures your Skill solves real problems rather than documenting imagined ones." — Anthropic Skill Best Practices

新規テスト作成時は、以下の検証フローを必ず実行してください。

Step 1: 機能の実装状況を確認

テスト対象の機能が実際に実装されているか確認します。

# Server Actionsの確認
ls src/app/actions/
grep -r "対象関数名" src/app/actions/

# API Routesの確認(必要な場合)
ls src/app/api/

# コンポーネントの確認
grep -r "data-testid" src/components/ | grep "対象要素"

確認項目:

  • Server Action/API Routeが存在する
  • UIコンポーネントが実装されている
  • data-testid属性が定義されている

Step 2: 実装コードを読む

テスト対象の実装を理解してからテストを書く:

# 例: 翻訳機能のテスト
Read src/app/actions/translate.ts
Read src/app/[locale]/preview/[id]/hooks/use-translation.ts

# 例: アップロード機能のテスト
Read src/app/actions/upload/index.ts
Read src/components/upload/upload-dropzone.tsx

確認項目:

  • 実装の動作を理解した
  • エラーハンドリングを確認した
  • 期待する戻り値/状態遷移を把握した

Step 3: MVP範囲の確認

テスト対象がMVP機能に含まれるか確認します。

MVP機能一覧(テスト対象):

機能 実装場所 テスト優先度
認証 src/app/actions/auth/
アップロード src/app/actions/upload/
プレビュー src/app/[locale]/preview/
翻訳 src/app/actions/translate.ts
ダウンロード src/app/api/files/[id]/download/
決済 src/app/actions/payment.ts

上記以外の機能は、明確な要件がない限りテストしないでください。

Step 4: 既存テストとの重複確認

同じ機能をテストする既存テストがないか確認します。

grep -r "テスト対象機能" e2e/
grep -r "該当data-testid" e2e/

Step 5: テスト設計の妥当性確認

テストを書く前の最終チェック:

妥当性チェックリスト:
- [ ] 実装コードを読んで動作を理解した
- [ ] テストするセレクタ(data-testid等)が実装に存在する
- [ ] 期待する動作が実装されている
- [ ] 推測や仮定に基づいていない
- [ ] MVP範囲内の機能である

禁止事項

パターン 説明 回避策
推測テスト 「こうあるべき」という仮定 実装を確認してから書く
未実装機能テスト 存在しない機能のテスト 実装完了後に書く
過剰テスト MVP範囲外の機能 MVP範囲に限定

必須ルール

ハードコード禁止

// ❌ WRONG
await page.fill("input[name='email']", "test@example.com");

// ✅ CORRECT
import { UNIFIED_TEST_CONFIG } from "../config/unified-test-config";
await page.fill("input[name='email']", UNIFIED_TEST_CONFIG.users.standard.email);

認証状態ファイル

// ❌ WRONG
storageState: "playwright-auth.json"

// ✅ CORRECT
storageState: UNIFIED_TEST_CONFIG.paths.authState  // .auth/user.json

ログイン待機

// ❌ WRONG - /api/auth/login は存在しない
await page.waitForResponse(r => r.url().includes("/api/auth/login"));

// ✅ CORRECT - ナビゲーション待機
await page.click('button[type="submit"]');
await page.waitForURL("**/dashboard", { timeout: 15000 });

テストコマンド

コマンド 用途
npm run e2e 全E2Eテスト(標準。run.ts envelope)
npm run e2e:smoke スモークテスト
npm run e2e:flows setup + flows + cleanup
npm run e2e:ui UIモード (デバッグ)
npm run e2e:debug DevTools付きデバッグ

環境変数

CSRF_RELAXED_IN_E2E=true              # CSRF緩和
DISABLE_RATE_LIMIT_IN_E2E=true        # Rate limit無効
NEXT_PUBLIC_TEST_MODE=true            # テストモード
ENABLE_TRANSLATION_TEST_FAST_PATH=true # ダミー翻訳(100倍高速)

参照ドキュメント

ディレクトリ構造

e2e/
├── config/                        # テスト設定
│   ├── e2e-constants.ts          # SSOT定数
│   └── unified-test-config.ts    # 統一設定(CRITICAL)
├── smoke/                         # スモークテスト
├── flows/                         # フローテスト(認証→アップロード→翻訳等)
├── infrastructure/                # インフラテスト
├── server-actions/                # Server Actionsテスト
├── visual/                        # ビジュアルテスト
├── fixtures/                      # テストフィクスチャ
├── helpers/                       # ヘルパー関数
├── page-objects/                  # ページオブジェクト
├── utils/                         # ユーティリティ
└── test-files/                    # テスト用ファイル

セキュリティE2Eテンプレート (3本)

セキュリティ関連のE2Eテストを書く場合、以下の3テンプレートを使う。 増やしすぎない。まずこの3パターンで十分。

Template 1: IDOR (他ユーザーリソースアクセス → 403/404)

import { test, expect } from "@playwright/test";
import { UNIFIED_TEST_CONFIG } from "../config/unified-test-config";

test.describe("IDOR Protection: [対象機能]", () => {
  // 認証済みユーザーAでセットアップ
  test.use({ storageState: UNIFIED_TEST_CONFIG.paths.authState });

  test("他ユーザーのリソースにアクセスできない", async ({ page }) => {
    // 他ユーザーが所有するリソースIDでアクセス
    const otherUserResourceId = "known-other-user-resource-id";
    const response = await page.goto(`/preview/${otherUserResourceId}`);

    // 403 or 404 を期待(実装による)
    // ページレベル: エラーページが表示される
    await expect(page.locator("[data-testid='error-message']")).toBeVisible();
    // または: リダイレクトされる
    await expect(page).toHaveURL(/\/(dashboard|404)/);
  });
});

使い方: [対象機能]otherUserResourceId を実際の値に差し替える。

Template 2: Rate Limit (N回超過 → 429)

import { test, expect } from "@playwright/test";
import { UNIFIED_TEST_CONFIG } from "../config/unified-test-config";

test.describe("Rate Limit: [対象エンドポイント]", () => {
  // NOTE: E2E環境では DISABLE_RATE_LIMIT_IN_E2E=true でスキップされるため、
  // このテストは明示的に X-Bypass-Rate-Limit ヘッダーを送らない

  test.skip(
    process.env.DISABLE_RATE_LIMIT_IN_E2E === "true",
    "Rate limit disabled in E2E environment"
  );

  test("制限回数を超えると429が返る", async ({ request }) => {
    const endpoint = "/api/translate/single";
    const limit = 50; // エンドポイントの制限値

    // 制限値+1回リクエストを送信
    let lastStatus = 200;
    for (let i = 0; i <= limit; i++) {
      const response = await request.post(endpoint, {
        data: { text: "test", targetLang: "en" },
      });
      lastStatus = response.status();
      if (lastStatus === 429) break;
    }

    expect(lastStatus).toBe(429);
  });
});

使い方: endpointlimit を対象に合わせる。E2E環境ではskipされることに注意。

Template 3: Auth (無効/期限切れトークン → 401)

import { test, expect } from "@playwright/test";

test.describe("Auth Protection: [対象エンドポイント]", () => {
  // storageState を使わない = 未認証状態
  test.use({ storageState: { cookies: [], origins: [] } });

  test("未認証リクエストは401/リダイレクトされる", async ({ page }) => {
    // 認証必須ページにアクセス
    await page.goto("/dashboard");

    // ログインページにリダイレクトされることを確認
    await expect(page).toHaveURL(/\/login/);
  });

  test("未認証APIリクエストは401が返る", async ({ request }) => {
    const response = await request.get("/api/files");
    expect(response.status()).toBe(401);
  });
});

使い方: 対象のページ/APIに差し替える。ページはリダイレクト、APIは401を期待。


AI Assistant Instructions

このスキルが有効化された時:

新規テスト作成時 (CRITICAL)

  1. 実装を確認する: テスト対象の機能が実装されているか確認
  2. コードを読む: 実装の動作を理解してからテストを書く
  3. MVP範囲を確認: テスト対象がMVP機能に含まれるか確認
  4. セレクタを確認: data-testid属性が実装に存在するか確認

Always

  • UNIFIED_TEST_CONFIG から設定値を取得する
  • ハードコードされた値を使用しない
  • 修正後は必ず単一テストで検証する
  • 新規テスト作成前に実装コードを読む

Never

  • /api/auth/login を待機しない(存在しない)
  • playwright-auth.json をハードコードしない
  • タイムアウトを過度に長くしない(最大30秒)
  • 実装を確認せずにテストを書かない
  • 「こうあるべき」という推測でテストを書かない
  • MVP範囲外の機能をテストしない
Weekly Installs
30
First Seen
Jan 25, 2026
Installed on
opencode30
gemini-cli30
codex30
antigravity29
codebuddy29
windsurf29