create-pom について
Playwright の E2E テスト用に TypeScript の Page Object Model クラスを生成するスキルです。既存 POM の確認、ベースページの継承、生成結果の検証を支援します。
主な機能
- 01既存ページオブジェクトの確認
- 02共有ベースページの継承
- 03セレクター優先順位の適用
- 04JSDoc による公開メソッドの記述
- 05TypeScript コンパイルの確認
活用シーン
- 01新しいアプリページ用の POM 作成
- 02既存 POM への動作追加
- 03テスト規約に沿ったページオブジェクトの維持
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ agentmantis/ test-skills --skill create-pomインストール後、Claude Code で/create-pomを入力して読み込まれたか確認します。
同梱ファイルreferences/pom-template.md
詳細
ページオブジェクトモデルの作成
すべての E2E テストの規約に従って、指定されたページ用の POM クラスを生成します。
ワークフロー
- ユーザーのリクエストからページ名を判断します(例:「Settings」→
settings.page.ts) e2e/poms/にこのページの POM がすでにあるか確認します。ある場合は、既存の POM にメソッドを追加し、同じページ用の POM を新たに作成しないでくださいe2e/poms/base.page.tsにあるベースページクラスを特定し、それを継承します- アプリケーションで対象のページを読み込み、要素と操作を把握します
- 以下のテンプレートに従って POM ファイルを生成します
- ファイルを検証し、TypeScript エラーがないことを確認します
ルール
- 1 ページにつき POM は 1 つ — 個別のページ/ビューごとに、POM ファイルを必ず 1 つだけ作成します
- すべての POM はベースページクラスを継承します — 抽象クラスについては
e2e/poms/base.page.tsを確認してください setUp()とtearDown()を実装します — これらはベースクラスから継承します- 再利用可能なヘルパーは
BasePageに記述します — 複数の POM で役立つヘルパーメソッド(例:waitForToast、dismissModal)は、派生 POM ではなくBasePageに置く必要があります。派生 POM には、そのページ固有の動作だけを記述してください。同じヘルパーを 2 つ目の POM に書く必要が出てきた場合は、直ちにBasePageに移してください - POM 内から別の POM を絶対に参照しないでください — テストで複数のページが必要な場合は、spec ファイルで各 POM の処理を調整します
- すべてのパブリックメソッドに詳細な JSDoc を記述します — 実行手順を段階ごとに説明し、
@paramタグを付けてください - セレクターの優先順位を使用します:
getByRole()>getByLabel()>getByText()>getByPlaceholder()>locator()
POM の構成
コメントバナーを使用して、各 POM を以下の明確に分けられたセクションで構成します。
import { Page, Locator, expect } from '@playwright/test';
// TODO: Import your project's base page class
import { BasePage } from './base.page';
export class FeaturePage extends BasePage {
constructor(page: Page) {
super(page);
}
// ==========================================
// LIFECYCLE (from BasePage)
// ==========================================
/**
* Navigates to the feature page and cleans up any stale data
* left by previous failed test runs.
*
* Steps:
* 1. Navigates to /feature via direct URL.
* 2. Waits for the page heading to be visible.
* 3. Deletes any items matching the test data pattern.
*/
async setUp(): Promise<void> {
// TODO: Implement navigation and cleanup
}
/**
* Cleans up any data created during the test suite.
*
* Steps:
* 1. Navigates to /feature.
* 2. Deletes all items created by this test run.
*/
async tearDown(): Promise<void> {
// TODO: Implement cleanup
}
// ==========================================
// LOCATORS
// ==========================================
/** The main heading of the feature page. */
get heading(): Locator {
return this.page.getByRole('heading', { name: 'Feature Name' });
}
/** The "Create" button that opens the creation modal. */
get createButton(): Locator {
return this.page.getByRole('button', { name: /create/i });
}
// TODO: Add locators for all interactive elements on this page
// ==========================================
// NAVIGATION
// ==========================================
/**
* Navigates directly to the feature page via URL.
*
* Steps:
* 1. Calls page.goto('/feature').
* 2. Asserts the page heading is visible.
* 3. Asserts the URL contains '/feature'.
*/
async navigateToPage(): Promise<void> {
await this.page.goto('/feature');
await expect(this.heading).toBeVisible();
await expect(this.page).toHaveURL(/\/feature/);
}
// ==========================================
// VERIFICATION
// ==========================================
/**
* Verifies an item appears in the list with the expected name.
*
* Steps:
* 1. Locates the item row by name text.
* 2. Asserts the row is visible.
*
* @param name - The expected item name
*/
async verifyItemExists(name: string): Promise<void> {
await expect(
this.page.getByRole('row', { name: new RegExp(name, 'i') })
).toBeVisible();
}
// ==========================================
// CREATE
// ==========================================
/**
* Creates a new item via the creation modal.
*
* Steps:
* 1. Clicks the "Create" button to open the modal.
* 2. Fills in the name field.
* 3. Clicks "Submit" and waits for the modal to close.
*
* @param name - Display name for the new item
*/
async createItem(name: string): Promise<void> {
await this.createButton.click();
const modal = this.page.getByRole('dialog');
await modal.getByLabel('Name').fill(name);
await modal.getByRole('button', { name: 'Submit' }).click();
await expect(modal).toBeHidden();
}
// ==========================================
// EDIT
// ==========================================
// TODO: Add edit methods
// ==========================================
// DELETE
// ==========================================
// TODO: Add delete methods
}
JSDoc の要件
すべてのパブリックメソッドに、以下を含む JSDoc コメントを必ず付けてください。
- 概要行 — メソッドの動作
- 手順ブロック — 呼び出し時に実行される処理を番号付きリストで記載
@paramタグ — すべてのパラメーターに記載@returnsタグ — 値を返す場合に記載
LLM はこれらのコメントを読んで利用可能な操作を把握し、そこからテスト spec を生成するため、これは非常に重要です。
/**
* Updates an existing item's name and value.
*
* Steps:
* 1. Locates the item row by its current name.
* 2. Clicks the "Edit" button within that row.
* 3. Clears and fills the name field with the new name.
* 4. Clears and fills the value field with the new value.
* 5. Clicks "Save" and waits for the edit modal to close.
* 6. Waits for the success toast notification to appear.
*
* @param currentName - The item's current display name (used to locate the row)
* @param newName - The new display name
* @param newValue - The new value
*/
async editItem(currentName: string, newName: string, newValue: string): Promise<void> {
命名規則
- ファイル:
e2e/poms/{feature}.page.ts(小文字、ケバブケースの feature 名) - クラス:
{Feature}Page(パスカルケース) - feature 名は、対応する spec ファイルおよび test-data ファイルと一致させます
完全なボイラープレートについては、references/pom-template.md を参照してください。
コメント
Markdown 対応