playwright
PlaywrightによるブラウザI自動化とE2Eテストを実行します。開発サーバーを自動検出し、クリーンなテストスクリプトを生成。ページのテスト、フォーム入力、スクリーンショット撮影、レスポンシブデザインの確認、UX検証、ログインフローのテスト、リンクチェック、あらゆるブラウザ操作の自動化に対応します。TypeScript/JavaScriptおよびPythonプロジェクトでのクロスブラウザテスト、ビジュアルリグレッション、APIテスト、コンポーネントテストに活用できます。
description の原文を見る
Browser automation and E2E testing with Playwright. Auto-detects dev servers, writes clean test scripts. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use for cross-browser testing, visual regression, API testing, component testing in TypeScript/JavaScript and Python projects.
SKILL.md 本文
Playwright - ブラウザオートメーション & E2E テスト
Playwright による最新のクロスブラウザテストフレームワークを活用したブラウザオートメーションとエンドツーエンドテストの専門知識。
重要 - パス解決:
このスキルは異なる場所にインストールできます。コマンドを実行する前に、このSKILL.mdファイルをロードした場所に基づいてスキルディレクトリを特定し、すべてのコマンドでそのパスを使用してください。$SKILL_DIR を実際に検出されたパスに置き換えてください。
一般的なインストールパス:
- プラグインシステム:
~/.claude/plugins/*/playwright/skills/playwright - 手動グローバル:
~/.claude/skills/playwright - プロジェクト固有:
<project>/.claude/skills/playwright
重要なワークフロー - これらのステップに従ってください
ブラウザタスクを自動化する場合:
-
デバサーバーの自動検出 - localhost テスト用には、常にサーバー検出を最初に実行してください:
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"- 1 つのサーバーが見つかった場合: 自動的に使用して、ユーザーに通知
- 複数のサーバーが見つかった場合: テストするサーバーをユーザーに選択させる
- サーバーが見つからない場合: URL を求めるか、デバサーバー起動の支援を提供
-
スクリプトを /tmp に書き込む - テストファイルをスキルディレクトリに書き込まないでください。常に
/tmp/playwright-test-*.jsを使用してください -
デフォルトで表示ブラウザを使用 - ユーザーが明示的にヘッドレスモードをリクエストしない限り、常に
headless: falseを使用してください -
URL をパラメータ化 - スクリプトの上部の定数で、常に URL を構成可能にしてください
-
run.js 経由で実行 - 常に実行してください:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
クイックスタート
初回セットアップ
# スキルディレクトリに移動
cd $SKILL_DIR
# bun を使用してインストール (推奨)
bun run setup
# または npm を使用
npm run setup:npm
これにより Playwright と Chromium ブラウザがインストールされます。1 回のみ必要です。
インストール (E2E テストプロジェクト用)
# Bun を使用 (推奨)
bun add -d @playwright/test
bunx playwright install
# npm を使用
npm init playwright@latest
設定
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests',
fullyParallel: true,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
webServer: {
command: 'bun run dev',
url: 'http://localhost:3000',
},
})
ブラウザオートメーションパターン
仕組み
- テスト/自動化したい内容を説明します
- 実行中のデバサーバーを自動検出します (または URL を求めます)
/tmp/playwright-test-*.jsにカスタム Playwright コードを書き込みますcd $SKILL_DIR && node run.js /tmp/playwright-test-*.js経由で実行します- 結果はリアルタイムで表示され、ブラウザウィンドウが表示されます
ページをテスト (複数のビューポート)
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動検出
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// デスクトップテスト
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto(TARGET_URL);
console.log('Desktop - Title:', await page.title());
await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });
// モバイルテスト
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();
実行: cd $SKILL_DIR && node run.js /tmp/playwright-test-responsive.js
ログインフローをテスト
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自動検出
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/login`);
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard');
console.log('✅ ログイン成功、ダッシュボードにリダイレクト');
await browser.close();
})();
リンク切れをチェック
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const links = await page.locator('a[href^="http"]').all();
const results = { working: 0, broken: [] };
for (const link of links) {
const href = await link.getAttribute('href');
try {
const response = await page.request.head(href);
if (response.ok()) {
results.working++;
} else {
results.broken.push({ url: href, status: response.status() });
}
} catch (e) {
results.broken.push({ url: href, error: e.message });
}
}
console.log(`✅ 正常なリンク: ${results.working}`);
console.log(`❌ リンク切れ:`, results.broken);
await browser.close();
})();
E2E テストパターン
テストを実行
# すべてのテストを実行
bunx playwright test
# ヘッドモード (ブラウザを表示)
bunx playwright test --headed
# 特定のファイル
bunx playwright test tests/login.spec.ts
# デバッグモード
bunx playwright test --debug
# UI モード (インタラクティブ)
bunx playwright test --ui
# 特定のブラウザ
bunx playwright test --project=chromium
# レポートを生成
bunx playwright show-report
テストを書く
import { test, expect } from '@playwright/test'
test.describe('ログインフロー', () => {
test('ログインに成功', async ({ page }) => {
await page.goto('/')
await page.getByRole('link', { name: 'ログイン' }).click()
await page.getByLabel('メール').fill('user@example.com')
await page.getByLabel('パスワード').fill('password123')
await page.getByRole('button', { name: 'サインイン' }).click()
await expect(page.getByRole('heading', { name: 'ダッシュボード' })).toBeVisible()
})
test('無効な認証情報でエラーを表示', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('メール').fill('wrong@example.com')
await page.getByLabel('パスワード').fill('wrongpassword')
await page.getByRole('button', { name: 'サインイン' }).click()
await expect(page.getByText('無効な認証情報')).toBeVisible()
})
})
セレクタ (ベストプラクティス)
// ✅ ロールベース (推奨)
await page.getByRole('button', { name: '送信' })
await page.getByRole('link', { name: 'ホーム' })
// ✅ テキスト/ラベル
await page.getByText('Hello World')
await page.getByLabel('メール')
// ✅ テスト ID (フォールバック)
await page.getByTestId('submit-button')
// ❌ CSS セレクタは避ける (脆い)
await page.locator('.btn-primary')
アサーション
// 可視性
await expect(page.getByText('成功')).toBeVisible()
await expect(page.getByRole('button')).toBeEnabled()
// テキスト
await expect(page.getByRole('heading')).toHaveText('ようこそ')
await expect(page.getByRole('alert')).toContainText('エラー')
// 属性
await expect(page.getByRole('link')).toHaveAttribute('href', '/home')
// URL/タイトル
await expect(page).toHaveURL('/dashboard')
await expect(page).toHaveTitle('ダッシュボード')
// カウント
await expect(page.getByRole('listitem')).toHaveCount(5)
アクション
// クリック
await page.getByRole('button').click()
await page.getByText('ファイル').dblclick()
// タイピング
await page.getByLabel('メール').fill('user@example.com')
await page.getByLabel('検索').press('Enter')
// 選択
await page.getByLabel('国').selectOption('jp')
// ファイルアップロード
await page.getByLabel('アップロード').setInputFiles('path/to/file.pdf')
ネットワークモッキング
test('API レスポンスをモック', async ({ page }) => {
await page.route('**/api/users', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'テストユーザー' }]),
})
})
await page.goto('/users')
await expect(page.getByText('テストユーザー')).toBeVisible()
})
ビジュアルテスト
test('スクリーンショットをキャプチャ', async ({ page }) => {
await page.goto('/')
await page.screenshot({ path: 'screenshot.png', fullPage: true })
await expect(page).toHaveScreenshot('homepage.png')
})
認証状態
// ログイン後に状態を保存
setup('認証', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('メール').fill('user@example.com')
await page.getByLabel('パスワード').fill('password123')
await page.getByRole('button', { name: 'サインイン' }).click()
await page.context().storageState({ path: 'auth.json' })
})
// 設定で再利用
use: { storageState: 'auth.json' }
ページオブジェクトモデル
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test'
export class LoginPage {
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(page: Page) {
this.emailInput = page.getByLabel('メール')
this.passwordInput = page.getByLabel('パスワード')
this.submitButton = page.getByRole('button', { name: 'サインイン' })
}
async login(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
await this.submitButton.click()
}
}
// 使用方法
const loginPage = new LoginPage(page)
await loginPage.login('user@example.com', 'password123')
利用可能なヘルパー
lib/helpers.js のオプションのユーティリティ関数:
const helpers = require('./lib/helpers');
// 実行中のデバサーバーを検出 (重要 - これを最初に使用してください!)
const servers = await helpers.detectDevServers();
console.log('見つかったサーバー:', servers);
// 再試行して安全なクリック
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// クリアして安全なタイピング
await helpers.safeType(page, '#username', 'testuser');
// タイムスタンプ付きスクリーンショットを撮影
await helpers.takeScreenshot(page, 'test-result');
// Cookie バナーを処理
await helpers.handleCookieBanner(page);
// テーブルデータを抽出
const data = await helpers.extractTableData(page, 'table.results');
// カスタムヘッダー付きコンテキストを作成
const context = await helpers.createContext(browser);
カスタム HTTP ヘッダー
環境変数経由ですべての HTTP リクエストにカスタムヘッダーを設定:
# 単一ヘッダー (一般的なケース)
PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill \
cd $SKILL_DIR && node run.js /tmp/my-script.js
# 複数のヘッダー (JSON 形式)
PW_EXTRA_HEADERS='{"X-Automated-By":"playwright-skill","X-Debug":"true"}' \
cd $SKILL_DIR && node run.js /tmp/my-script.js
ヘッダーは helpers.createContext() を使用する場合、自動的に適用されます。
インライン実行 (シンプルなタスク)
簡単な一度きりのタスク用:
cd $SKILL_DIR && node run.js "
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/quick-screenshot.png', fullPage: true });
console.log('スクリーンショット保存');
await browser.close();
"
使用時期:
- インライン: クイックな一度きりのタスク (スクリーンショット、要素チェック)
- ファイル: 複雑なテスト、再利用可能な自動化
ベストプラクティス
- 重要: サーバーを最初に検出 - テストコードを書く前に、常に
detectDevServers()を実行してください - テストファイルは /tmp に -
/tmp/playwright-test-*.jsに書き込み、スキルディレクトリには書き込まないでください - URL をパラメータ化 - 検出/提供された URL を
TARGET_URL定数に入れてください - デフォルト: 表示ブラウザ - 明示的にリクエストされない限り、常に
headless: falseを使用してください - ロールベースセレクタを推奨 - CSS セレクタより安定しています
- 自動待機を信頼 - 手動スリープは不要です
- 各テストは新規コンテキスト - 自動的に隔離されます
- テストは並列実行 - デフォルト動作です
- 外部依存をモック -
page.route()を使用してください - トレースビューアを使用 - タイムトラベルデバッグ
ヒント
- 速度低下:
slowMo: 100を使用してアクションを可視化 - 待機戦略: 固定タイムアウトの代わりに
waitForURL、waitForSelector、waitForLoadStateを使用 - エラーハンドリング: 堅牢な自動化のため、常に try-catch を使用
- コンソール出力:
console.log()を使用して進行状況を追跡
トラブルシューティング
Playwright がインストールされていない:
cd $SKILL_DIR && bun run setup
モジュルが見つからない:
run.js ラッパー経由でスキルディレクトリから実行していることを確認
ブラウザが開かない:
headless: false を確認し、ディスプレイが利用可能であることを確認
要素が見つからない:
待機を追加: await page.waitForSelector('.element', { timeout: 10000 })
セキュアなインストール
Playwright とブラウザバイナリをインストールする場合、サプライチェーンセキュリティのベストプラクティスに従ってください:
- ポストインストールスクリプトをブロック —
npm config set ignore-scripts true(その後、手動でnpx playwright installを実行してブラウザをダウンロード) - クールダウン期間 — 新しいパッケージバージョンがコミュニティで検証されるまで 7 日間待機
- インストール前に監査 —
socket package score npm <pkg>を実行するか、socket npm install <pkg>を使用してパッケージをチェック
完全なセキュリティ設定の場合は dependency-upgrade スキルをロードしてください。Socket CLI 統合、クールダウン設定、ロックファイル検証、CI 強制を含みます。
参照
vitest-testing- ユニットテストと統合テストapi-testing- HTTP API テストtest-quality-analysis- テスト品質パターン
参考文献をロードする時期
以下の場合は references/API_REFERENCE.md をロード:
- 高度なセレクタパターンとロケータ戦略
- ネットワークインターセプションとリクエスト/レスポンスモッキング
- 認証パターンとセッション管理
- ビジュアルリグレッションテスト設定
- モバイルデバイスエミュレーション設定
- パフォーマンステストとメトリクス
- デバッグ技法 (トレースビューア、インスペクタ)
- CI/CD パイプライン統合
- axe-core によるアクセシビリティテスト
- データ駆動およびパラメータ化テスト
- ページオブジェクトモデルの高度なパターン
- 並列実行戦略
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- secondsky
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/secondsky/claude-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。