write-playwright-e2e-code
Generates structured Playwright E2E tests using localized step definitions and minimal comments.
Install
mkdir -p .claude/skills/write-playwright-e2e-code && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/1899" && unzip -o skill.zip -d .claude/skills/write-playwright-e2e-code && rm skill.zipInstalls to .claude/skills/write-playwright-e2e-code
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Playwright E2E テストコードを生成。test.step で日本語ステップ名を使用し、コメント禁止。E2E テスト作成・Playwright コード生成時に使用。Key capabilities
- →Structure tests using test.step
- →Enforce comment-free code style
- →Manage locator scope for reusability
- →Handle value passing between steps
- →Standardize logical test flow
How it works
It generates Playwright code by wrapping actions in test.step blocks and enforcing strict naming conventions that describe intent without redundant comments.
Inputs & outputs
When to use write-playwright-e2e-code
- →Generate E2E test steps for a login flow
- →Convert manual test cases to Playwright code
- →Refactor existing tests to use test.step
About this skill
Playwright E2E テスト
test.step 区切り
- 論理的な区切りは
test.step("日本語", async () => { ... })で表現 - 適切な粒度: ユーザー操作単位・UI 状態確認単位で区切る。入れ子も可
- expect は step 内に含める
- 既に step に分かれている関数は step の外で呼び出す
Good:
await navigateToMain(page);
await test.step("ダウンロードモーダルを表示する", async () => {
await page.getByRole("button", { name: "ダウンロード" }).click();
await expect(page.getByRole("dialog")).toBeVisible();
});
await test.step("モーダルを閉じると消える", async () => {
await page.getByRole("button", { name: "閉じる" }).click();
await expect(page.getByRole("dialog")).toBeHidden();
});
step 名
- 「何をするか」「どうあるべきか」が分かる表現にする
- 詳細な説明文にはせず、フローの節目を表す短い動詞句にする
- 「~を確認する」など冗長な表現は避ける
- 体言止めは使わない
Good:
await test.step("ダウンロードモーダルを表示する", async () => {});
Bad 1 (step 名が体言止め):
await test.step("ダウンロードモーダルを表示", async () => {});
Bad 2 (step 名が冗長):
await test.step("ダウンロードボタンをクリックしてモーダルが表示されることを確認する", async () => {});
Bad 3 (step 名に「~を確認する」を含む):
await test.step("モーダルを閉じると消えることを確認する", async () => {});
コメント
- What を説明するコメントは削除: step 名で表現する
- Why(目的・意図・理由)を説明するコメントは残す: なぜその待機時間が必要か、なぜその順序で実行するか等
Good (意図を説明):
await page.waitForTimeout(5000); // エンジン読み込みを待機
locator の選択
locatorはユーザー向けの情報から取得できるものを優先する- 適切な
locatorが書けない場合は、WCAG の基準を満たしつつ WAI-ARIA の要件に合うようソースコードの変更を検討する - DOM 構造に依存するセレクターは原則使わず、他に取得方法がない場合だけ例外として使う
優先順位:
getByRole: 役割と名前で自然に取得できる場合に使う- 他の
getBy...:getByLabel・getByText・getByPlaceholder・getByAltText・getByTitleなどから対象を自然に表せるものを使う - コンポーネント名のクラス: コンポーネントの名前と同じ CSS クラス、あるいはコンポーネント名とパーツ名を組み合わせた CSS クラスは使ってよい
data-testid: ここまでの方法で自然に取得するのが難しい場合に使う
Good 1:
// コード
<button>ダウンロード</button>
// テスト
await page.getByRole("button", { name: "ダウンロード" }).click();
Bad 1 (不要なtestid):
// コード
<button data-testid="download-button">ダウンロード</button>
// テスト
await page.getByTestId("download-button").click();
Good 2:
// コード
<button aria-label="閉じる"><CloseIcon /></button>
// テスト
await page.getByRole("button", { name: "閉じる" }).click();
Bad 2 (不明な名前):
// コード
<button aria-label="close-icon"><CloseIcon /></button>
// テスト
await page.getByRole("button", { name: "close-icon" }).click();
locator・変数の共有
locator の宣言場所は使用範囲で決める:
- 複数 step で使う: test 関数直下で宣言
- 1 つの step でのみ使う: その step 内で宣言(外に出さない)
Good:
test("テスト名", async ({ page }) => {
const input = page.getByLabel("入力欄");
await test.step("入力する", async () => {
await input.fill("テスト");
});
await test.step("入力値が反映される", async () => {
await expect(input).toHaveValue("テスト");
});
});
Bad 1 (不要な外部宣言):
test("テスト名", async ({ page }) => {
const accentPhrase = page.locator(".accent-phrase");
await test.step("検証する", async () => {
await expect(accentPhrase).toBeVisible();
});
});
Bad 2 (重複宣言):
test("テスト名", async ({ page }) => {
await test.step("入力する", async () => {
const input = page.getByLabel("入力欄");
await input.fill("テスト");
});
await test.step("検証する", async () => {
const input = page.getByLabel("入力欄");
await expect(input).toHaveValue("テスト");
});
});
step 間の値の受け渡し
- 再代入しない: step から return して const で受け取る
- 再代入する: let で宣言して step 内で代入
Good 1:
const before = await test.step("初期値を取得する", async () => {
return await getValue(page);
});
await test.step("値が変化している", async () => {
expect(await getValue(page)).not.toEqual(before);
});
Bad 1 (再代入しないのに let で宣言):
let before: number;
await test.step("初期値を取得する", async () => {
before = await getValue(page);
});
await test.step("値が変化している", async () => {
expect(await getValue(page)).not.toEqual(before);
});
Good 2 (再代入する場合は let でも OK):
let count: number;
await test.step("1回目の操作をする", async () => {
await page.getByRole("button").click();
count = await getCount(page);
expect(count).toBe(1);
});
await test.step("2回目の操作をする", async () => {
await page.getByRole("button").click();
count = await getCount(page);
expect(count).toBe(2);
});
ロジックの共通化
| スコープ | 方法 |
|---|---|
| test 内のみ | test 関数内で変数やローカル関数を定義 |
| ファイル内の複数 test | ファイルスコープでローカル関数を定義 |
| 複数ファイル | 共通ファイルにエクスポート関数を追加 |
既存コードとの整合
既存ファイル・関数名の指定がある場合はそれを優先。ない場合は既存 E2E の命名・スタイルに合わせる。
When not to use it
- →Writing unit tests
- →Adding explanatory comments for code logic
Prerequisites
Limitations
- →Prohibits What-style comments
- →Requires specific naming conventions for steps
How it compares
Unlike manual coding, this enforces a specific architectural pattern that separates test steps and removes non-essential comments.
Compared to similar skills
write-playwright-e2e-code side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| write-playwright-e2e-code (this skill) | 3 | 6mo | No flags | Intermediate |
| vitest | 41 | 6mo | No flags | Intermediate |
| zod-4 | 12 | 7mo | No flags | Intermediate |
| write-unit-tests | 5 | 3mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
vitest
antfu
Vitest fast unit testing framework powered by Vite with Jest-compatible API. Use when writing tests, mocking, configuring coverage, or working with test filtering and fixtures.
zod-4
prowler-cloud
Zod 4 schema validation patterns. Trigger: When creating or updating Zod v4 schemas for validation/parsing (forms, request payloads, adapters), including v3 -> v4 migration patterns.
write-unit-tests
tldraw
Writing unit and integration tests for the tldraw SDK. Use when creating new tests, adding test coverage, or fixing failing tests in packages/editor or packages/tldraw. Covers Vitest patterns, TestEditor usage, and test file organization.
develop-ai-functions-example
vercel
Develop examples for AI SDK functions. Use when creating, running, or modifying examples under examples/ai-functions/src to validate provider support, demonstrate features, or create test fixtures.
javascript-testing-patterns
wshobson
Implement comprehensive testing strategies using Jest, Vitest, and Testing Library for unit tests, integration tests, and end-to-end testing with mocking, fixtures, and test-driven development. Use when writing JavaScript/TypeScript tests, setting up test infrastructure, or implementing TDD/BDD workflows.
ts-library
onmax
Use when authoring TypeScript libraries - covers project setup, package exports, build tooling (tsdown/unbuild), API design patterns, type inference tricks, testing, and release workflows. Patterns extracted from 20+ high-quality ecosystem libraries.