Claude Code × Playwright MCPで対話型UI自動テストを構築する
Claude CodeとPlaywright MCPを組み合わせて、ブラウザ操作を確認しながらUIテストを自動構築する方法をハンズオン形式で解説します。セットアップから実践的なテスト生成まで網羅。

はじめに
「テストを書く時間がない」——これは多くのフロントエンド開発者が抱える悩みです。
UIテストは重要だと分かっていても、セレクタの指定やテストシナリオの作成に時間がかかり、後回しにされがちです。さらに、UIの変更でテストが壊れるメンテナンスコストも無視できません。
もし、ブラウザを操作しながらAIに「今の操作をテストにして」と伝えるだけで、テストコードが自動生成されるとしたらどうでしょうか?
Claude CodeとPlaywright MCPを組み合わせれば、それが実現できます。本記事では、セットアップから実践的なテスト生成まで、ハンズオン形式で解説します。
Playwright MCPとは
Playwright MCPは、Microsoftが公式に提供するModel Context Protocol(MCP)サーバーです。Claude Codeなどの AI エージェントに、ブラウザ操作の能力を与えます。
従来のスクリーンショット方式との違い
Playwright MCPの最大の特徴は、アクセシビリティツリーを活用する点です。
| 項目 | スクリーンショット方式 | Playwright MCP |
|---|---|---|
| データサイズ | 数百KB〜数MB | 2〜5KB |
| 解析速度 | Vision モデルが必要で低速 | 構造化データで高速 |
| 精度 | ピクセル座標ベースで不安定 | アクセシビリティツリーで高精度 |
| コスト | 画像トークンが高い | テキストトークンのみ |
| セレクタ生成 | 推測ベース | ロール・ラベルベースで堅牢 |
アクセシビリティツリーを使うことで、getByRole('button', { name: '送信' }) のような壊れにくいセレクタを自動生成できます。
セットアップ
前提条件
- Node.js 18以上
- Claude Code がインストール済み
Step 1: Playwright MCPをClaude Codeに登録
ターミナルで以下のコマンドを実行します。
claude mcp add playwright npx @playwright/mcp@latest
これだけで設定完了です。プロジェクトディレクトリごとに設定が保存されるため、他のプロジェクトには影響しません。
Step 2: 設定の確認
登録した設定は .mcp.json で確認できます。
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
オプション設定
用途に応じてオプションを追加できます。
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser", "chrome",
"--viewport-size", "1280x720"
]
}
}
}
主要なオプション一覧です。
| オプション | 説明 | 例 |
|---|---|---|
--browser | ブラウザ種類 | chrome, firefox, webkit |
--headless | ヘッドレスモード | CI環境向け |
--viewport-size | 画面サイズ | 1280x720 |
--caps | 追加機能 | vision,pdf,devtools |
--storage-state | 認証情報の読み込み | auth.json |
実践:対話型UIテストの構築
基本的な使い方
Claude Codeを起動し、Playwright MCPを使うよう指示します。
> Playwright MCPでhttp://localhost:3000を開いて、トップページの表示を確認して
ポイントは、最初のリクエストで**「Playwright MCP」**と明示的に伝えることです。これにより、Claude CodeがBashでの代替手段を試みることなく、MCP経由でブラウザを制御します。
実行すると、実際のChromeブラウザが起動し、Claude Codeがページの構造を解析します。
ユースケース1:フォームバリデーションのテスト生成
実際のプロジェクトで、お問い合わせフォームのテストを生成してみましょう。
> Playwright MCPで/contactページを開いて、
> フォームに何も入力せず送信ボタンを押して、
> バリデーションエラーが表示されることを確認して。
> その操作をPlaywrightのテストコードとして出力して。
Claude Codeは以下のような流れで動作します。
生成されるテストコードの例です。
import { test, expect } from '@playwright/test';
test('お問い合わせフォーム - 未入力で送信するとバリデーションエラーが表示される', async ({ page }) => {
await page.goto('/contact');
// 送信ボタンをクリック
await page.getByRole('button', { name: '送信' }).click();
// バリデーションエラーの確認
await expect(page.getByText('お名前は必須です')).toBeVisible();
await expect(page.getByText('メールアドレスは必須です')).toBeVisible();
await expect(page.getByText('お問い合わせ内容は必須です')).toBeVisible();
});
注目すべきは、getByRole や getByText といったアクセシビリティベースのセレクタが使われている点です。CSSクラス名やdata属性に依存しないため、UIリファクタリングでもテストが壊れにくくなります。
ユースケース2:ナビゲーションフローのテスト
ページ遷移を伴うテストも対話的に構築できます。
> トップページからブログ一覧に遷移して、
> 最初の記事をクリックして、記事タイトルが表示されることを確認して。
> 一連の操作をテストコードにして。
import { test, expect } from '@playwright/test';
test('トップページ → ブログ一覧 → 記事詳細の遷移', async ({ page }) => {
await page.goto('/');
// ブログ一覧へ遷移
await page.getByRole('link', { name: 'ブログ' }).click();
await expect(page).toHaveURL('/blog');
// 最初の記事をクリック
const firstArticle = page.getByRole('article').first();
const articleTitle = await firstArticle.getByRole('heading').textContent();
await firstArticle.getByRole('link').click();
// 記事タイトルが表示されていることを確認
await expect(page.getByRole('heading', { level: 1 })).toHaveText(articleTitle!);
});
ユースケース3:認証が必要なページのテスト
Playwright MCPの優れた点として、認証が簡単なことが挙げられます。ブラウザが可視化された状態で操作できるため、ログイン画面で自分の認証情報を手動入力できます。
> Playwright MCPでログインページを開いて
ブラウザが開いたら、手動でログインします。セッションCookieはセッション中ずっと保持されるため、その後は認証済みの状態でテストを進められます。
> ログインしたので、ダッシュボードのテストを作成して。
> ユーザー名が表示されていること、
> サイドバーのメニューが正しく動作することを確認して。
認証状態を保存して再利用することも可能です。
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--storage-state", "tests/auth.json"
]
}
}
}
CI/CDへの統合
対話的に作成したテストは、そのままCI/CDパイプラインで実行できます。
Playwrightのプロジェクト設定
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
use: {
baseURL: 'http://localhost:3000',
},
webServer: {
command: 'npm run dev',
port: 3000,
reuseExistingServer: !process.env.CI,
},
});
GitHub Actionsでの実行
# .github/workflows/e2e-test.yml
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
テスト生成のワークフロー
実際の開発フローに組み込む場合の全体像を整理します。
効率的なテスト生成のコツ
| コツ | 説明 |
|---|---|
| ハッピーパスから始める | まず正常系を作成し、その後エラーケースを追加 |
| ページオブジェクトを活用 | 「このページのPage Objectも作って」と伝える |
| 既存テストを参考にさせる | 「tests/e2eの既存テストに合わせて」と指示 |
| 認証状態は保存する | --storage-state で認証済み状態を再利用 |
| ヘッドレスで高速化 | CI環境では --headless を有効に |
まとめ
Claude Code × Playwright MCPの組み合わせは、UIテスト構築の体験を大きく変えます。
- アクセシビリティツリー活用により、スクリーンショット方式より高速・低コスト・高精度
- 対話的なテスト生成で、ブラウザを操作しながら自然言語でテストを記述
- 壊れにくいセレクタ(
getByRole,getByText)を自動生成 - 認証も簡単——可視化ブラウザで手動ログイン後、そのままテスト作成
- CI/CDにそのまま統合できる本番品質のテストコード
セットアップはコマンド1つ。まずは claude mcp add playwright npx @playwright/mcp@latest を実行して、自分のプロジェクトで試してみてください。「テストを書く時間がない」という悩みが、「テストは会話するだけ」に変わるはずです。
参考リンク: