playwright-skill について
playwright-skillは、Playwrightによるブラウザー自動化コードの作成と実行を支援するスキルです。Webテストや定型的なブラウザー操作を行うエージェント向けに、サーバー検出や一時スクリプトの利用手順を定めています。
主な機能
- 01ローカル開発サーバーの検出
- 02カスタムPlaywrightスクリプトの実行
- 03/tmpへのスクリプト保存
- 04URLとヘッダーの設定
- 05ブラウザー自動化ヘルパー
活用シーン
- 01ログインやフォームの確認
- 02レスポンシブレイアウトのテスト
- 03リンク切れの検出
- 04ページのスクリーンショット撮影
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ zenobi-us/ dotfiles --skill playwright-skillインストール後、Claude Code で/playwright-skillを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.temp-execution-1770342857274.jsAPI_REFERENCE.mdpackage.jsonrun.jslib/helpers.js詳細
重要 - パスの解決:
このスキルはさまざまな場所にインストールされる可能性があります(プラグインシステム、手動インストール、グローバル、またはプロジェクト固有)。コマンドを実行する前に、この SKILL.md ファイルをどこから読み込んだかに基づいてスキルディレクトリを特定し、以下のすべてのコマンドでそのパスを使用してください。$SKILL_DIR は、見つかった実際のパスに置き換えてください。
一般的なインストールパス:
- プラグインシステム:
~/.claude/plugins/marketplaces/playwright-skill/skills/playwright-skill - 手動インストール(グローバル):
~/.claude/skills/playwright-skill - プロジェクト固有:
<project>/.claude/skills/playwright-skill
Playwright ブラウザー自動化
汎用のブラウザー自動化スキルです。ご依頼のあらゆる自動化タスクに合わせてカスタムの 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 は常に環境変数、またはスクリプト冒頭の定数で設定可能にしてください
仕組み
- テストまたは自動化したい内容を説明してください
- 実行中の開発サーバーを自動検出します(外部サイトをテストする場合は URL を尋ねます)
/tmp/playwright-test-*.jsにカスタムの Playwright コードを書き出します(プロジェクトを散らかしません)- 次のコマンドで実行します:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js - 結果がリアルタイムに表示され、デバッグのためにブラウザーウィンドウが表示されます
- テストファイルは OS によって /tmp から自動的に削除されます
セットアップ(初回のみ)
cd $SKILL_DIR
npm run setup
これにより Playwright と Chromium ブラウザーがインストールされます。必要なのは一度だけです。
実行パターン
ステップ 1: 開発サーバーを検出する(localhost でのテスト用)
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
ステップ 2: URL パラメーター付きのテストスクリプトを /tmp に書き出す
// /tmp/playwright-test-page.js
const { chromium } = require('playwright');
// Parameterized URL (detected or user-provided)
const TARGET_URL = 'http://localhost:3001'; // <-- Auto-detected or from user
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(TARGET_URL);
console.log('Page loaded:', await page.title());
await page.screenshot({ path: '/tmp/screenshot.png', fullPage: true });
console.log('📸 Screenshot saved to /tmp/screenshot.png');
await browser.close();
})();
ステップ 3: スキルディレクトリから実行する
cd $SKILL_DIR && node run.js /tmp/playwright-test-page.js
よく使うパターン
ページのテスト(複数のビューポート)
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// Desktop test
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 });
// Mobile test
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();
ログインフローのテスト
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(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"]', '[email protected]');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
// Wait for redirect
await page.waitForURL('**/dashboard');
console.log('✅ Login successful, redirected to dashboard');
await browser.close();
})();
フォームの入力と送信
// /tmp/playwright-test-form.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 50 });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/contact`);
await page.fill('input[name="name"]', 'John Doe');
await page.fill('input[name="email"]', '[email protected]');
await page.fill('textarea[name="message"]', 'Test message');
await page.click('button[type="submit"]');
// Verify submission
await page.waitForSelector('.success-message');
console.log('✅ Form submitted successfully');
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(`✅ Working links: ${results.working}`);
console.log(`❌ Broken links:`, results.broken);
await browser.close();
})();
エラー処理付きのスクリーンショット撮影
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
try {
await page.goto('http://localhost:3000', {
waitUntil: 'networkidle',
timeout: 10000,
});
await page.screenshot({
path: '/tmp/screenshot.png',
fullPage: true,
});
console.log('📸 Screenshot saved to /tmp/screenshot.png');
} catch (error) {
console.error('❌ Error:', error.message);
} finally {
await browser.close();
}
})();
レスポンシブデザインのテスト
// /tmp/playwright-test-responsive-full.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
const viewports = [
{ name: 'Desktop', width: 1920, height: 1080 },
{ name: 'Tablet', width: 768, height: 1024 },
{ name: 'Mobile', width: 375, height: 667 },
];
for (const viewport of viewports) {
console.log(
`Testing ${viewport.name} (${viewport.width}x${viewport.height})`,
);
await page.setViewportSize({
width: viewport.width,
height: viewport.height,
});
await page.goto(TARGET_URL);
await page.waitForTimeout(1000);
await page.screenshot({
path: `/tmp/${viewport.name.toLowerCase()}.png`,
fullPage: true,
});
}
console.log('✅ All viewports tested');
await browser.close();
})();
インライン実行(簡単なタスク)
簡単な単発タスクでは、ファイルを作成せずにインラインでコードを実行できます:
# Take a quick screenshot
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('Screenshot saved');
await browser.close();
"
インラインとファイルの使い分け:
- インライン: 簡単な単発タスク(スクリーンショット、要素の存在確認、ページタイトルの取得など)
- ファイル: 複雑なテスト、レスポンシブデザインの確認、ユーザーが再実行したい可能性があるもの
利用可能なヘルパー
lib/helpers.js にあるオプションのユーティリティ関数:
const helpers = require('./lib/helpers');
// Detect running dev servers (CRITICAL - use this first!)
const servers = await helpers.detectDevServers();
console.log('Found servers:', servers);
// Safe click with retry
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// Safe type with clear
await helpers.safeType(page, '#username', 'testuser');
// Take timestamped screenshot
await helpers.takeScreenshot(page, 'test-result');
// Handle cookie banners
await helpers.handleCookieBanner(page);
// Extract table data
const data = await helpers.extractTableData(page, 'table.results');
全一覧は lib/helpers.js を参照してください。
カスタム HTTP ヘッダー
環境変数を通じて、すべての HTTP リクエストにカスタムヘッダーを設定できます。次のような場合に便利です:
- バックエンドへの自動化されたトラフィックを識別する
- LLM に適した応答を得る(例: スタイル付き HTML の代わりにプレーンテキストのエラーを返す)
- 認証トークンをグローバルに追加する
設定
単一のヘッダー(一般的なケース):
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() を使用すると、ヘッダーが自動的に適用されます:
const context = await helpers.createContext(browser);
const page = await context.newPage();
// All requests from this page include your custom headers
生の Playwright API を使用するスクリプトでは、注入された getContextOptionsWithHeaders() を使用してください:
const context = await browser.newContext(
getContextOptionsWithHeaders({ viewport: { width: 1920, height: 1080 } }),
);
高度な使い方
Playwright API の包括的なドキュメントについては、API_REFERENCE.md を参照してください:
- セレクターとロケーターのベストプラクティス
- ネットワークのインターセプトと API のモック
- 認証とセッション管理
- ビジュアルリグレッションテスト
- モバイルデバイスのエミュレーション
- パフォーマンステスト
- デバッグのテクニック
- CI/CD との統合
Tips
- CRITICAL: Detect servers FIRST - localhost でテストする前に、テストコードを書く際は必ず
detectDevServers()を実行してください - Custom headers -
PW_HEADER_NAME/PW_HEADER_VALUE環境変数を使用すると、バックエンドに届く自動化されたトラフィックを識別できます - Use /tmp for test files - テストファイルは
/tmp/playwright-test-*.jsに書き込み、スキルディレクトリやユーザーのプロジェクトには決して書き込まないでください - Parameterize URLs - 検出または指定された URL を、すべてのスクリプトの先頭にある
TARGET_URL定数に設定してください - DEFAULT: Visible browser - ユーザーがヘッドレスモードを明示的に求めない限り、常に
headless: falseを使用してください - Headless mode - ユーザーが「headless」または「background」での実行を特に要求した場合にのみ
headless: trueを使用してください - Slow down:
slowMo: 100を使用すると、操作が見えやすくなり、追跡しやすくなります - Wait strategies: 固定のタイムアウトではなく、
waitForURL、waitForSelector、waitForLoadStateを使用してください - Error handling: 堅牢な自動化のために、必ず try-catch を使用してください
- Console output:
console.log()を使用して進捗を追跡し、何が行われているかを表示してください
Troubleshooting
Playwright not installed:
cd $SKILL_DIR && npm run setup
Module not found:
run.js ラッパーを介して、必ずスキルディレクトリから実行してください
Browser doesn't open:
headless: false になっていることを確認し、ディスプレイが利用可能であることを確認してください
Element not found:
待機処理を追加してください: await page.waitForSelector('.element', { timeout: 10000 })
Example Usage
User: "Test if the marketing page looks good"
Claude: I'll test the marketing page across multiple viewports. Let me first detect running servers...
[Runs: detectDevServers()]
[Output: Found server on port 3001]
I found your dev server running on http://localhost:3001
[Writes custom automation script to /tmp/playwright-test-marketing.js with URL parameterized]
[Runs: cd $SKILL_DIR && node run.js /tmp/playwright-test-marketing.js]
[Shows results with screenshots from /tmp/]
User: "Check if login redirects correctly"
Claude: I'll test the login flow. First, let me check for running servers...
[Runs: detectDevServers()]
[Output: Found servers on ports 3000 and 3001]
I found 2 dev servers. Which one should I test?
- http://localhost:3000
- http://localhost:3001
User: "Use 3001"
[Writes login automation to /tmp/playwright-test-login.js]
[Runs: cd $SKILL_DIR && node run.js /tmp/playwright-test-login.js]
[Reports: ✅ Login successful, redirected to /dashboard]
Notes
- 各自動化は、ユーザーの特定のリクエストに合わせて個別に作成されます
- 事前に用意されたスクリプトに限定されず、あらゆるブラウザタスクに対応できます
- 実行中の開発サーバーを自動検出するため、URL をハードコーディングする必要がありません
- テストスクリプトは自動クリーンアップのために
/tmpに書き込まれます (ファイルが散らかりません) run.jsを介した適切なモジュール解決により、コードが確実に実行されます- 段階的開示: 高度な機能が必要な場合にのみ API_REFERENCE.md が読み込まれます