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倍高速)
参照ドキュメント
- failure-patterns.md - 失敗パターンと解決策
- page-objects.md - ページオブジェクトの使い方
- e2e/config/unified-test-config.ts - 設定値
ディレクトリ構造
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);
});
});
使い方: endpoint と limit を対象に合わせる。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)
- 実装を確認する: テスト対象の機能が実装されているか確認
- コードを読む: 実装の動作を理解してからテストを書く
- MVP範囲を確認: テスト対象がMVP機能に含まれるか確認
- セレクタを確認: data-testid属性が実装に存在するか確認
Always
UNIFIED_TEST_CONFIGから設定値を取得する- ハードコードされた値を使用しない
- 修正後は必ず単一テストで検証する
- 新規テスト作成前に実装コードを読む
Never
/api/auth/loginを待機しない(存在しない)playwright-auth.jsonをハードコードしない- タイムアウトを過度に長くしない(最大30秒)
- 実装を確認せずにテストを書かない
- 「こうあるべき」という推測でテストを書かない
- MVP範囲外の機能をテストしない
Weekly Installs
30
Repository
yusuketsunoda/ppt-transFirst Seen
Jan 25, 2026
Security Audits
Installed on
opencode30
gemini-cli30
codex30
antigravity29
codebuddy29
windsurf29