e2e-test-conventions
PlaywrightとTypeScriptを使ったE2Eテストにおける、プロジェクト構成、命名規則、セレクタ戦略、認証、環境設定など、テスト作成・レビュー・設定に必要なルールを適用し、効率的で保守性の高いテストを支援するSkill。
📜 元の英語説明(参考)
Core conventions and rules for Playwright E2E testing with TypeScript. Covers project structure, naming conventions, selector strategy, authentication, navigation, environment configuration, test independence, and parallelism. Automatically loaded when writing or modifying E2E tests. Use when: generating E2E tests, creating POMs, reviewing test code, or setting up a Playwright test suite.
🇯🇵 日本人クリエイター向け解説
PlaywrightとTypeScriptを使ったE2Eテストにおける、プロジェクト構成、命名規則、セレクタ戦略、認証、環境設定など、テスト作成・レビュー・設定に必要なルールを適用し、効率的で保守性の高いテストを支援するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o e2e-test-conventions.zip https://jpskill.com/download/10198.zip && unzip -o e2e-test-conventions.zip && rm e2e-test-conventions.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10198.zip -OutFile "$d\e2e-test-conventions.zip"; Expand-Archive "$d\e2e-test-conventions.zip" -DestinationPath $d -Force; ri "$d\e2e-test-conventions.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
e2e-test-conventions.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
e2e-test-conventionsフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
E2Eテストの規約
これらの規約は、すべての Playwright E2E テストコードに適用されます。テストの生成、変更、またはレビューを行う際は、必ずこれらを読み、従ってください。
技術スタック
- ブラウザ自動化とテスト実行のための Playwright
- すべてのテストコードのための TypeScript (プレーンな JavaScript は使用しない)
- フレームワークに依存しない - プロジェクトで使用する UI フレームワークに合わせてセレクタとヘルパーを調整する
プロジェクト構成
e2e/ ディレクトリは、次のレイアウトに従います。
e2e/
├── auth/ # 認証設定 (すべてのテストの前に実行)
│ └── auth.setup.ts # ログインしてセッション状態を保存
├── fixtures/ # カスタム Playwright フィクスチャ
│ └── base.ts # Playwright のテストをカスタムフィクスチャで拡張
├── helpers/ # 共有ユーティリティ関数 (ページオブジェクトではない)
│ └── env-config.ts # 環境解決
├── poms/ # ページオブジェクトモデル (ページごとに1つのファイル)
│ └── base.page.ts # 抽象基底クラス - すべての POM はこれを拡張
├── test-data/ # 外部テストデータ (JSON ファイル)
├── tests/ # スイートごとに整理されたテストスペック
│ ├── handover/ # チケット駆動の引き継ぎテスト (一時的)
│ ├── regression/ # 完全なリグレッションテスト (永続的)
│ └── smoke/ # クイックなクリティカルパスチェック
├── playwright.config.ts
├── tsconfig.json
└── .env.example # 環境変数のテンプレート
ルール:
- この構造の外にファイルを作成しないでください
- 明示的な許可なしに既存のファイルを移動しないでください
各ディレクトリの詳細については、references/folder-structure.md を参照してください。
ブラウザ × スイート構成
Playwright の設定では、{browser}:{suite} という名前を使用してプロジェクトを定義します。
ブラウザ: chromium, firefox, webkit, mobile-chrome, mobile-safari
スイート:
| スイート | ディレクトリ | 目的 | ライフサイクル |
|---|---|---|---|
regression |
tests/regression/ |
完全なリグレッション | 永続的 |
handover |
tests/handover/ |
チケット駆動の引き継ぎ | 一時的 - 昇格または削除 |
smoke |
tests/smoke/ |
クリティカルパスの健全性確認 | 永続的 |
すべてのプロジェクトは、認証を処理する setup プロジェクトに依存します。
テストの実行
# e2e/ ディレクトリから
npx playwright test # すべてのブラウザ × すべてのスイート
npx playwright test --project="chromium:regression" # 単一のプロジェクト
npx playwright test --project="*:smoke" # 1つのスイート、すべてのブラウザ
npx playwright test --project="firefox:*" # 1つのブラウザ、すべてのスイート
命名規則
| タイプ | パターン | 例 |
|---|---|---|
| ページオブジェクトモデル | poms/ 内の {feature}.page.ts |
dashboard.page.ts |
| リグレッションスペック | tests/regression/ 内の {feature}.spec.ts |
dashboard.spec.ts |
| スモークスペック | tests/smoke/ 内の {feature}.spec.ts |
dashboard.spec.ts |
| 引き継ぎスペック | tests/handover/ 内の {TICKET}-{description}.spec.ts |
PROJ-123-bulk-delete.spec.ts |
| テストデータ | test-data/ 内の {feature}.json |
dashboard.json |
{feature} 名は、POM、スペック、およびテストデータファイル全体で 一致させる 必要があります。
テストの独立性と並列性
すべてのテストは完全に独立している必要があります
- 各テストは 隔離された状態 で、任意の順序 で実行されます
- テストは、前のテストで作成された状態に 決して 依存してはなりません
- 各テストは、POM のナビゲーションメソッドを介してそのページに移動します
並列安全性
すべてのテストは、複数のワーカー間で並行して実行されます。衝突を避けるために:
- すべてのテストデータ値に一意のサフィックス (タイムスタンプ + ランダム ID) を付加します
- テスト間で可変状態を共有しないでください
- 各テストは独自のデータを作成し、それを検証してクリーンアップします
認証
認証は、すべてのテストプロジェクトの前に実行されるセットアッププロジェクト (auth/auth.setup.ts) で 一度 実行されます。セッション状態はファイルに保存され、Playwright の storageState 設定を介して再利用されます。
スペック、POM、beforeEach、または beforeAll にログインロジックを 決して 記述しないでください。認証はすでに処理されています。
アプリケーションが認証トークンを IndexedDB (Firebase Auth, Supabase, AWS Amplify など) に保存する場合は、indexedDB オプションを使用します。
await page.context().storageState({ path: authFile, indexedDB: true });
完全なパターンについては、references/auth-setup.md を参照してください。
ナビゲーション
- 常に直接 URL ナビゲーションを使用してください (
page.goto('/dashboard')) - メニューやサイドバーをクリックしないでください - メニューの状態とアニメーションにより、テストが不安定になる可能性があります
- ナビゲーション後、URL とキーとなる見出し/要素が表示されることをアサートします
BasePage と派生 POM メソッド
BasePage は、複数のページで役立つ 再利用可能なヘルパーメソッド の単一のホームです。派生 POM は、ページ固有の動作のみに焦点を当てる必要があります。
メソッドが BasePage に属する場合
ヘルパーが次の場合は、BasePage に移動します。
- 複数の POM で再利用可能 - たとえば、モーダルの解除、トースト通知の待機、またはローディングスピナーのチェック
- 単一のページに密接に結合されていない - どのページがアクティブであるかに関係なく、同じように動作します
- 十分に汎用的で、きれいに継承できる - ページ固有のセレクタや仮定はありません
- 機能固有の POM に残されている場合、重複する可能性が高い
BasePage ヘルパーの例:
waitForToast(message)- トースト通知を待機して検証しますdismissModal()- 開いているモーダルダイアログを閉じますwaitForLoadingComplete()- ローディングスピナーが消えるのを待ちますgetTableRowCount()- 多くのページに存在するデータテーブルの行数をカウントします
メソッドが派生 POM に属する場合
ヘルパーが次の場合は、特定の POM に保持します。
- 1つのページに固有 - たとえば、ページ固有のフォームへの入力
- ページ固有の構造に依存する - そのページにのみ存在するセレクタを使用します
- 他の場所で再利用されることが予想されない
これが重要な理由
- 重複を減らす - 共有ロジックは1つの場所に存在します
(原文はここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
E2E Test Conventions
These conventions apply to all Playwright E2E test code. Read and follow them whenever generating, modifying, or reviewing tests.
Technology Stack
- Playwright for browser automation and test running
- TypeScript for all test code (no plain JavaScript)
- Framework-agnostic — adapt selectors and helpers to whatever UI framework the project uses
Project Structure
The e2e/ directory follows this layout:
e2e/
├── auth/ # Authentication setup (runs before all tests)
│ └── auth.setup.ts # Logs in and saves session state
├── fixtures/ # Custom Playwright fixtures
│ └── base.ts # Extends Playwright's test with custom fixtures
├── helpers/ # Shared utility functions (NOT page objects)
│ └── env-config.ts # Environment resolution
├── poms/ # Page Object Models (one file per page)
│ └── base.page.ts # Abstract base class — all POMs extend this
├── test-data/ # External test data (JSON files)
├── tests/ # Test specs organised by suite
│ ├── handover/ # Ticket-driven handover tests (temporary)
│ ├── regression/ # Full regression tests (permanent)
│ └── smoke/ # Quick critical-path checks
├── playwright.config.ts
├── tsconfig.json
└── .env.example # Template for environment variables
Rules:
- Do NOT create files outside this structure
- Do NOT move existing files without explicit permission
See references/folder-structure.md for details on each directory.
Browser × Suite Configuration
The Playwright config defines projects using {browser}:{suite} naming:
Browsers: chromium, firefox, webkit, mobile-chrome, mobile-safari
Suites:
| Suite | Directory | Purpose | Lifecycle |
|---|---|---|---|
regression |
tests/regression/ |
Full regression | Permanent |
handover |
tests/handover/ |
Ticket-driven handover | Temporary — promote or delete |
smoke |
tests/smoke/ |
Critical-path sanity | Permanent |
Every project depends on the setup project which handles authentication.
Running Tests
# From e2e/ directory
npx playwright test # All browsers × all suites
npx playwright test --project="chromium:regression" # Single project
npx playwright test --project="*:smoke" # One suite, all browsers
npx playwright test --project="firefox:*" # One browser, all suites
Naming Conventions
| Type | Pattern | Example |
|---|---|---|
| Page Object Model | {feature}.page.ts in poms/ |
dashboard.page.ts |
| Regression spec | {feature}.spec.ts in tests/regression/ |
dashboard.spec.ts |
| Smoke spec | {feature}.spec.ts in tests/smoke/ |
dashboard.spec.ts |
| Handover spec | {TICKET}-{description}.spec.ts in tests/handover/ |
PROJ-123-bulk-delete.spec.ts |
| Test data | {feature}.json in test-data/ |
dashboard.json |
The {feature} name must match across POM, spec, and test-data files.
Test Independence and Parallelism
Every Test Must Be Fully Independent
- Each test runs in isolation and in any order
- A test must never depend on state created by a previous test
- Each test navigates to its page via the POM's navigation method
Parallel Safety
All tests run in parallel across multiple workers. To avoid collisions:
- Append unique suffixes (timestamp + random ID) to all test data values
- Never share mutable state between tests
- Each test creates its own data, verifies it, and cleans it up
Authentication
Authentication is performed once in a setup project (auth/auth.setup.ts) that runs before all test projects. The session state is saved to a file and reused via Playwright's storageState configuration.
NEVER write login logic in specs, POMs, beforeEach, or beforeAll. Authentication is already handled.
If the application stores auth tokens in IndexedDB (Firebase Auth, Supabase, AWS Amplify, etc.), use the indexedDB option:
await page.context().storageState({ path: authFile, indexedDB: true });
See references/auth-setup.md for the full pattern.
Navigation
- Always use direct URL navigation (
page.goto('/dashboard')) - Do NOT click through menus or sidebars — menu state and animations cause flaky tests
- After navigating, assert the URL and a key heading/element are visible
BasePage vs Derived POM Methods
BasePage is the single home for reusable helper methods that are useful across multiple pages. Derived POMs should stay focused on page-specific behavior only.
When a method belongs in BasePage
Move a helper to BasePage when it is:
- Reusable across multiple POMs — e.g., dismissing a modal, waiting for a toast notification, or checking a loading spinner
- Not tightly coupled to a single page — it works the same regardless of which page is active
- Generic enough to be inherited cleanly — no page-specific selectors or assumptions
- Likely to be duplicated if left in a feature-specific POM
Examples of BasePage helpers:
waitForToast(message)— waits for and verifies a toast notificationdismissModal()— closes any open modal dialogwaitForLoadingComplete()— waits for a loading spinner to disappeargetTableRowCount()— counts rows in a data table present on many pages
When a method belongs in a derived POM
Keep a helper in the specific POM when it is:
- Unique to one page — e.g., filling a page-specific form
- Dependent on page-specific structure — uses selectors that only exist on that page
- Not expected to be reused elsewhere
Why this matters
- Reduces duplication — shared logic lives in one place instead of being copied across POMs
- Centralises shared behavior — updates to a common helper propagate to all POMs automatically
- Keeps derived POMs small and focused — each POM only contains what is specific to its page
- Improves discoverability — developers know to look at
BasePagefor shared utilities
Rule
If you find yourself writing the same helper in a second POM, promote it to BasePage immediately. Do not leave duplicate helpers scattered across feature POMs.
Selectors and Locator Strategy
Use this priority order:
getByRole()— buttons, headings, dialogs (most resilient)getByLabel()— form fieldsgetByText()— visible text contentgetByPlaceholder()— input placeholderslocator()with CSS /filter()— last resort
Tips:
- Dynamically rendered attributes (tooltips, popovers) may not be in the DOM at query time — use
filter()to match child content - Icon buttons often lack visible text — match by
aria-labelor child icon content - Prefer role-based and label-based selectors over CSS classes (brittle and framework-specific)
See references/selector-priority.md for examples.
Environment Configuration
Each environment has its own .env.{env} file in the e2e/ directory:
| File | Environment |
|---|---|
.env.local |
Local development |
.env.dev |
Development server |
.env.test |
Test server |
.env.uat |
UAT server |
.env.production |
Production |
Every file uses the same variable names — only the values differ:
BASE_URL="https://your-app.example.com"
LOGIN_EMAIL="test-user@example.com"
LOGIN_PASSWORD="your-password"
AUTH_FILE="e2e/.auth/user.json"
Selecting the Active Environment
TEST_ENV is required. If it is not set, env-config.ts throws immediately — the test run will not start. This prevents accidental E2E runs against production when someone forgets to set the variable.
TEST_ENV=dev npx playwright test # loads .env then .env.dev
TEST_ENV=production npx playwright test # loads .env then .env.production
npx playwright test # ❌ ERROR — TEST_ENV is not set
Two-Layer Loading
helpers/env-config.ts reads TEST_ENV and loads environment variables in two layers via dotenv:
e2e/.env— base file (can holdTEST_ENVand all variables)e2e/.env.{env}— optional environment-specific override
Both files are optional. If neither exists the process relies on variables already present in the environment (e.g. injected by CI or a container). dotenv never overwrites a variable that is already set, so CLI exports and CI-injected values always win.
The module exports helper functions — getEnvConfig(), getBaseUrl(), getCredentials(), and getAuthFilePath() — instead of a static constant. Loading runs once per process; subsequent calls are no-ops.
Rules
TEST_ENVis required — missing it throws an error so E2E runs never silently target production- All variables (
BASE_URL,LOGIN_EMAIL,LOGIN_PASSWORD,AUTH_FILE) are required — missing ones throw an error - Never fall back to hardcoded defaults for required environment values; throw an error if they are missing
.env.*files contain secrets and are git-ignored.env.exampleis the only env file committed — it serves as the template
Test Data
- All test data lives in
e2e/test-data/{feature}.json - Never hardcode data in spec or POM files
- Use a custom fixture to load and stamp test data with unique suffixes
- Always import
testfrom your custom fixtures, not from@playwright/test
Spec File Rules
- All page interaction goes through POMs — never call
page.getByRole(),page.locator(), etc. directly in specs - The only acceptable uses of
pagein a spec: passing to POM constructor, or creating contexts inbeforeAll - Use
test.beforeAllwith a manually created browser context to call POMsetUp()for cleanup - Each test navigates independently via POM navigation methods