mcpField
P
playwright

playwright

github.com/gentleman-programmingテスト・品質661190 回インストール31 週間前に更新
リポジトリ

playwright について

playwrightは、Playwrightのエンドツーエンドテストを作成するためのスキルです。テスト作成前にページと実際の操作を確認し、ページオブジェクトの再利用、セレクター、テスト文書の規約を示します。

主な機能

  1. 01エンドツーエンドテストの作成
  2. 02テスト前のページ探索
  3. 03ロールとラベルのセレクターを優先
  4. 04ページオブジェクトと共通ヘルパーの再利用
  5. 05テストと文書の構成を統一

活用シーン

  1. 01ログインやサインアップのテスト作成
  2. 02フォーム操作とページ遷移の確認
  3. 03既存のページオブジェクトを使ったテスト追加
  4. 04テストヘルパーとケース文書の整理

MCP 対応

Playwright MCPツールが利用可能な場合、テスト作成前にナビゲーション、スナップショット確認、ページ操作、スクリーンショット撮影を行うよう定めています。利用できない場合は、文書とコードの分析に基づいてテストを作成します。

インストール

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

$npx skills add https://github.com/gentleman-programming/gentleman-skills --skill playwright

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

詳細

MCP ワークフロー(利用可能な場合は必須)

⚠️ Playwright MCP ツールがある場合は、テストを作成する前に必ず使用してください。

  1. 移動:対象ページに移動します
  2. スナップショットを取得:ページの構造と要素を確認します
  3. 操作:フォームや要素を操作して、ユーザーフローを正確に確認します
  4. スクリーンショットを撮影:想定される状態を記録します
  5. ページ遷移を確認:フロー全体(読み込み、成功、エラー)を検証します
  6. 実際のセレクターを記録:スナップショットから取得します(実際の ref とラベルを使用)
  7. 調査後にのみ、検証済みのセレクターを使ってテストコードを作成します

MCP を利用できない場合: ドキュメントとコードの分析に基づいてテストを作成してください。

これが重要な理由:

  • ✅ 正確なテスト — 必要な手順を正確に把握し、推測を避けます
  • ✅ 正確なセレクター — 想像上のものではなく、実際の DOM 構造を使用します
  • ✅ 実際のフローを検証 — ユーザーの操作経路が実際に機能することを確認します
  • ✅ 過剰な設計を回避 — 現状に必要な最小限のテストを作成します
  • ✅ 不安定なテストを防止 — 実際に調査することで、テストを安定させます
  • ❌ UI が「どうあるべきか」を決して想像しないでください

ファイル構成

tests/
├── base-page.ts              # Parent class for ALL pages
├── helpers.ts                # Shared utilities
└── {page-name}/
    ├── {page-name}-page.ts   # Page Object Model
    ├── {page-name}.spec.ts   # ALL tests here (NO separate files!)
    └── {page-name}.md        # Test documentation

ファイルの命名:

  • ✅ sign-up.spec.ts(サインアップ関連のすべてのテスト)
  • ✅ sign-up-page.ts(ページオブジェクト)
  • ✅ sign-up.md(ドキュメント)
  • ❌ sign-up-critical-path.spec.ts(誤り — ファイルを分割しないでください)
  • ❌ sign-up-validation.spec.ts(誤り)

セレクターの優先順位(必須)

// 1. BEST - getByRole for interactive elements
this.submitButton = page.getByRole("button", { name: "Submit" });
this.navLink = page.getByRole("link", { name: "Dashboard" });

// 2. BEST - getByLabel for form controls
this.emailInput = page.getByLabel("Email");
this.passwordInput = page.getByLabel("Password");

// 3. SPARINGLY - getByText for static content only
this.errorMessage = page.getByText("Invalid credentials");
this.pageTitle = page.getByText("Welcome");

// 4. LAST RESORT - getByTestId when above fail
this.customWidget = page.getByTestId("date-picker");

// ❌ AVOID fragile selectors
this.button = page.locator(".btn-primary");  // NO
this.input = page.locator("#email");         // NO

スコープの判定(曖昧な場合は確認)

ユーザーの依頼対応
「テストを1つ」「新しいテスト」「テストを追加」既存の spec に test() を1つ作成
「包括的なテスト」「すべてのテスト」「テストスイート」「テストを生成」テストスイート全体を作成

例:

  • 「ユーザーのサインアップのテストを作成」→ テストは1つのみ
  • 「ログインページの E2E テストを生成」→ テストスイート全体
  • 「フォームのバリデーションを確認するテストを追加」→ 既存の spec にテストを1つ追加

ページオブジェクトパターン

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

// BasePage - ALL pages extend this
export class BasePage {
  constructor(protected page: Page) {}

  async goto(path: string): Promise<void> {
    await this.page.goto(path);
    await this.page.waitForLoadState("networkidle");
  }

  // Common methods go here (see Refactoring Guidelines)
  async waitForNotification(): Promise<void> {
    await this.page.waitForSelector('[role="status"]');
  }

  async verifyNotificationMessage(message: string): Promise<void> {
    const notification = this.page.locator('[role="status"]');
    await expect(notification).toContainText(message);
  }
}

// Page-specific implementation
export interface LoginData {
  email: string;
  password: string;
}

export class LoginPage extends BasePage {
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;

  constructor(page: Page) {
    super(page);
    this.emailInput = page.getByLabel("Email");
    this.passwordInput = page.getByLabel("Password");
    this.submitButton = page.getByRole("button", { name: "Sign in" });
  }

  async goto(): Promise<void> {
    await super.goto("/login");
  }

  async login(data: LoginData): Promise<void> {
    await this.emailInput.fill(data.email);
    await this.passwordInput.fill(data.password);
    await this.submitButton.click();
  }

  async verifyCriticalOutcome(): Promise<void> {
    await expect(this.page).toHaveURL("/dashboard");
  }
}

ページオブジェクトの再利用(重要)

新しいページオブジェクトを作成する前に、必ず既存のページオブジェクトを確認してください。

// ✅ GOOD: Reuse existing page objects
import { SignInPage } from "../sign-in/sign-in-page";
import { HomePage } from "../home/home-page";

test("User can sign up and login", async ({ page }) => {
  const signUpPage = new SignUpPage(page);
  const signInPage = new SignInPage(page);  // REUSE
  const homePage = new HomePage(page);      // REUSE

  await signUpPage.signUp(userData);
  await homePage.verifyPageLoaded();  // REUSE method
  await homePage.signOut();           // REUSE method
  await signInPage.login(credentials); // REUSE method
});

// ❌ BAD: Recreating existing functionality
export class SignUpPage extends BasePage {
  async logout() { /* ... */ }  // ❌ HomePage already has this
  async login() { /* ... */ }   // ❌ SignInPage already has this
}

ガイドライン:

  • まず tests/ に既存のページオブジェクトがないか確認します
  • 既存のページをインポートして再利用します
  • ページが存在しない場合にのみ、ページオブジェクトを作成します
  • テストで複数のページが必要な場合は、すべてのページオブジェクトが存在することを確認します(必要に応じて作成します)

リファクタリングのガイドライン

次の場合は BasePage に移動します:
  • ✅ 複数のページで使用するナビゲーションヘルパー(waitForPageLoad()、getCurrentUrl())
  • ✅ 共通の UI 操作(通知、モーダル、テーマの切り替え)
  • ✅ 複数のページで繰り返される検証パターン(isVisible()、waitForVisible())
  • ✅ すべてのページに適用されるエラー処理
  • ✅ デバッグ用のスクリーンショットユーティリティ
次の場合は helpers.ts に移動します:
  • ✅ テストデータの生成(generateUniqueEmail()、generateTestUser())
  • ✅ セットアップ/クリーンアップ用ユーティリティ(createTestUser()、cleanupTestData())
  • ✅ カスタムアサーション(expectNotificationToContain())
  • ✅ テストセットアップ用の API ヘルパー(seedDatabase()、resetState())
  • ✅ 時間関連のユーティリティ(waitForCondition()、retryAction())

変更前(悪い例):

// Repeated in multiple page objects
export class SignUpPage extends BasePage {
  async waitForNotification(): Promise<void> {
    await this.page.waitForSelector('[role="status"]');
  }
}
export class SignInPage extends BasePage {
  async waitForNotification(): Promise<void> {
    await this.page.waitForSelector('[role="status"]');  // DUPLICATED!
  }
}

変更後(良い例):

// BasePage - shared across all pages
export class BasePage {
  async waitForNotification(): Promise<void> {
    await this.page.waitForSelector('[role="status"]');
  }
}

// helpers.ts - data generation
export function generateUniqueEmail(): string {
  return `test.${Date.now()}@example.com`;
}

export function generateTestUser() {
  return {
    name: "Test User",
    email: generateUniqueEmail(),
    password: "TestPassword123!",
  };
}

タグを使ったテストパターン

import { test, expect } from "@playwright/test";
import { LoginPage } from "./login-page";

test.describe("Login", () => {
  test("User can login successfully",
    { tag: ["@critical", "@e2e", "@login", "@LOGIN-E2E-001"] },
    async ({ page }) => {
      const loginPage = new LoginPage(page);

      await loginPage.goto();
      await loginPage.login({ email: "[email protected]", password: "pass123" });

      await expect(page).toHaveURL("/dashboard");
    }
  );
});

タグのカテゴリ:

  • 優先度:@critical、@high、@medium、@low
  • 種類:@e2e
  • 機能:@signup、@signin、@dashboard
  • テスト ID:@SIGNUP-E2E-001、@LOGIN-E2E-002

テストドキュメントの形式({page-name}.md)

### E2E Tests: {Feature Name}

**Suite ID:** `{SUITE-ID}`
**Feature:** {Feature description}

---

## Test Case: `{TEST-ID}` - {Test case title}

**Priority:** `{critical|high|medium|low}`

**Tags:**
- type → @e2e
- feature → @{feature-name}

**Description/Objective:** {Brief description}

**Preconditions:**
- {Prerequisites for test to run}
- {Required data or state}

### Flow Steps:
1. {Step 1}
2. {Step 2}
3. {Step 3}

### Expected Result:
- {Expected outcome 1}
- {Expected outcome 2}

### Key verification points:
- {Assertion 1}
- {Assertion 2}

### Notes:
- {Additional considerations}

ドキュメントのルール:

  • ❌ テストの実行に関する一般的な手順は含めない
  • ❌ ファイル構成の説明は含めない
  • ❌ コード例やチュートリアルは含めない
  • ❌ トラブルシューティングのセクションは含めない
  • ✅ 特定のテストケースのみに焦点を当てる
  • ✅ 可能な限り60行以内に収める

コマンド

npx playwright test                    # Run all
npx playwright test --grep "login"     # Filter by name
npx playwright test --ui               # Interactive UI
npx playwright test --debug            # Debug mode
npx playwright test tests/login/       # Run specific folder

キーワード

playwright, e2e, testing, page object model, selectors, end-to-end, mcp

コメント