jpskill.com
🛠️ 開発・MCP コミュニティ

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本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
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
🪟 Windows (PowerShell)
$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. 1. 下の青いボタンを押して e2e-test-conventions.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → e2e-test-conventions フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

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 notification
  • dismissModal() — closes any open modal dialog
  • waitForLoadingComplete() — waits for a loading spinner to disappear
  • getTableRowCount() — 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 BasePage for 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:

  1. getByRole() — buttons, headings, dialogs (most resilient)
  2. getByLabel() — form fields
  3. getByText() — visible text content
  4. getByPlaceholder() — input placeholders
  5. locator() 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-label or 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:

  1. e2e/.env — base file (can hold TEST_ENV and all variables)
  2. 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_ENV is 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.example is 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 test from 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 page in a spec: passing to POM constructor, or creating contexts in beforeAll
  • Use test.beforeAll with a manually created browser context to call POM setUp() for cleanup
  • Each test navigates independently via POM navigation methods