はじめに
Webアプリケーションのリリース前には、主要機能が壊れていないことを確認するために回帰テストを行います。
今回対象となったWebアプリでは、決済までの導線が複数存在しており、リリースのたびにそれぞれのパターンを手動で確認していました。
決済処理という性質上、確認自体を省略することは難しい一方で、
- 毎回似た操作を繰り返す
- ユーザー種別によって操作が異なる
- 承認処理を挟むケースがある
- 外部決済画面への遷移確認が必要なケースもある
と、地味に時間のかかる作業になっていました。
そこで今回は、Playwrightを使って決済導線のE2E回帰テストを整備し、その作成過程をPlaywright MCPに支援してもらうことにしました。
最終的には、操作特性の異なる5つのケースを自動化し、1コマンドでまとめて実行できるところまで構築しています。
今回やりたかったこと
今回の目的は、複数存在する決済導線について、毎回手動で行っていた動作確認をE2Eテストとして自動化することです。
対象には、
- 即時に決済まで進むケース
- 承認処理を挟んでから決済するケース
- 外部決済画面への遷移を確認するケース
- ユーザー種別によって操作が異なるケース
などがありました。
個々の業務フローそのものをテスト記事として紹介したいわけではないため、本記事では詳細な製品仕様には触れません。
重要なのは、単純な1画面のテストではなく、画面遷移やユーザー切り替えを含む複数のシナリオを自動化したという点です。
最終的には合計5ケースの回帰テストを作成しました。
Playwright MCPを使った理由
Playwright MCPとは
Playwright MCPを利用すると、Claude CodeなどのAIエージェントからMCP経由でブラウザを操作できます。
今回の構成はシンプルです。
Claude Code
↓
Playwright MCP
↓
Browser
↓
ステージング環境
今回期待していたのは、単純なテストコード生成ではありません。
例えばAIに、
この画面のE2Eテストを書いて
と依頼する場合、人間側で画面構造やセレクタ、操作方法をある程度説明する必要があります。
Playwright MCPを利用すれば、
実際の画面を確認
↓
操作方法を調査
↓
ブラウザで操作
↓
挙動を確認
↓
Playwrightテストとして実装
という進め方ができます。
実際の画面をAI自身に確認させながらテストを作れる
という点が、今回Playwright MCPを使った一番の理由です。
Claude CodeにPlaywright MCPを登録する
まず、Claude CodeからPlaywright MCPを利用できるようにします。
今回はuserスコープで登録しました。
claude mcp add --scope user playwright -- npx -y @playwright/mcp@latest
登録後、以下のコマンドで接続状態を確認します。
claude mcp list
Playwright MCPについて、
✓ Connected
と表示されれば接続自体は完了です。
登録直後のセッションでは使えなかった
ここで1点注意があります。
MCPサーバーを登録して✓ Connectedになっていても、その時点ですでに起動していたClaude CodeのセッションにはPlaywright MCPのツール一覧が反映されませんでした。
そのため、一度現在のセッションを終了し、新しいClaude Codeセッションを開始します。
新しいセッションではPlaywright MCPのツールを利用できるようになりました。
接続できているはずなのにPlaywright MCPが使えない場合は、セッションを再起動してみるとよさそうです。
実際の画面を操作しながらテストを作る
MCPの接続が完了したら、いきなりテストコードを書かせるのではなく、まず対象のステージング環境を実際に操作してもらいました。
ステージング環境へアクセス
↓
画面構造を確認
↓
フォームを操作
↓
画面遷移を確認
↓
一連の操作を完了
↓
テストコードへ落とし込む
この進め方にすると、人間側で、
- ボタンのセレクタ
- フォームの構造
- 画面遷移後の状態
- 操作によって発生するイベント
などを細かく説明する必要がありません。
Claude Code自身がPlaywright MCPを使って確認できます。
実際にテストを作っていく中では、単純にclick()やfill()を並べるだけでは解決しない問題もいくつか出てきました。
実装でハマったポイント
Basic認証とTurboの組み合わせ
今回テスト対象としていたステージング環境にはBasic認証が設定されていました。
Basic認証を突破するだけであれば、認証情報をURLに含めてアクセスできます。
https://user:password@example.com
当初はこの方法でそのまま画面遷移していました。
しかし今回のWebアプリではTurboを利用しており、認証情報を含んだURLのまま遷移すると、historyStateの書き換えと干渉してページのJavaScript初期化が正常に行われないケースがありました。
そこで、
- 初回アクセスだけBasic認証情報を含んだURLを利用
- 認証通過後は通常のURLへ遷移
という方式に変更しました。
初回アクセス
https://user:password@example.com
↓
Basic認証通過
↓
以降は通常URL
https://example.com/...
単純に「認証を通過できれば終わり」ではなく、その後のフロントエンドの挙動まで含めて確認する必要がありました。
Google Places Autocompleteはfillだけでは動かなかった
フォームの一部ではGoogle Places Autocompleteを利用していました。
最初は通常の入力欄と同じように、
await page.locator('input').fill('...');
とすれば動作すると考えていました。
しかし、文字列を入力しただけではGoogle Places側の内部イベントが発火せず、必要な位置情報がhidden fieldへ反映されませんでした。
画面上では値が入っているように見えるため、少し分かりづらい問題です。
最終的には、実際のユーザー操作に近い、
文字列入力
↓
候補表示
↓
ArrowDown
↓
Enter
というキーボード操作を再現することで解決しました。
Playwright MCPで実際の画面を確認しながら操作を試せたことが、特に役立った部分です。
Turbo Streamによる再描画で入力値が消える
フォームの一部はTurbo Streamによって動的に再描画されます。
その影響で、フォーム入力直後に別の処理が走ると、入力済みの値が失われるケースがありました。
値を入力
↓
別項目を変更
↓
Turbo Streamで部分再描画
↓
入力値が消える
一度テストが成功しても、実行タイミングによって失敗するため、E2Eテストとしては不安定になります。
そこで、
入力
↓
入力値を検証
↓
消えていた場合は再入力
という検証・リトライ処理を追加しました。
AIが一度操作できたことと、繰り返し安定して実行できるテストになることは別だと感じたポイントでもあります。
固定データでは繰り返し実行できなかった
もう1つ問題になったのが、テストデータです。
今回対象としたシステムでは、予約可能数に上限があるため、毎回同じ条件でテストを実行すると、テスト自身によって利用可能なデータを消費してしまいます。
固定値でテストを繰り返していると、最終的にはテストコードに問題がなくても失敗する状態になります。
そこで、テスト実行ごとに利用する条件を変えるようにしました。
テスト開始
↓
利用可能な未来条件を生成
↓
その条件でテスト実行
実システムのE2Eテストでは、画面操作だけではなく、テストデータを継続的に利用できる状態にすることも重要だと感じました。
テストコードを共通化する
複数のテストケースを作成すると、
- ログイン
- フォーム入力
- 画面遷移
- 承認処理
- 決済処理
など、共通する操作が増えてきます。
そのまま各テストファイルへ書くと重複が多くなるため、共通処理をsupport配下へ切り出しました。
tests/payment/
├── support/
│ ├── frontAuth.ts
│ ├── bizAuth.ts
│ ├── adminAuth.ts
│ ├── placeAutocomplete.ts
│ ├── reservationForm.ts
│ ├── bizReservationForm.ts
│ └── gmoPayment.ts
├── front/
│ ├── immediate-payment.spec.ts
│ └── pending-approval.spec.ts
└── biz/
├── immediate-payment.spec.ts
└── pending-approval.spec.ts
テストファイル本体にはシナリオの流れを残し、細かな画面操作は共通処理側へ寄せています。
個々のファイルの業務上の意味については、本記事では詳しく触れません。
重要なのは、Playwright MCPで操作を確認して終わりではなく、最終的には継続してメンテナンスできるPlaywrightのテストコードとして整理したという点です。
5つの回帰テストをまとめて実行する
最終的には、今回作成した決済系テストを以下のコマンドだけでまとめて実行できるようにしました。
npm run test:payment
対象は合計5ケースです。
それぞれを並列実行し、約50秒ですべてPASSすることを確認しました。
5 passed
これまでは複数の画面を人間が順番に操作して確認していました。
それが、
npm run test:payment
の1コマンドで確認できるようになったのは、大きな変化です。
Playwright MCPを使って感じたこと
コード生成より「実際に確認できる」ことが強い
今回一番便利だったのは、Playwrightのコードを書いてもらえること自体ではありませんでした。
むしろ、
画面を確認
↓
操作を試す
↓
失敗
↓
原因を調査
↓
別の操作を試す
↓
テストコードへ反映
という試行錯誤をClaude Code側で進められることです。
特に今回の、
- Basic認証
- Turbo
- Google Places
- 動的なフォーム再描画
といった、実際にブラウザを動かさないと分かりづらい問題とは相性が良いと感じました。
MCPに任せれば安定したテストが完成するわけではない
一方で、Playwright MCPで一度正常に操作できたからといって、それがそのまま安定したE2Eテストになるわけではありません。
今回も、
- リトライ処理
- テストデータ
- 認証後の画面遷移
- 共通処理の整理
などを考える必要がありました。
Playwright MCPは、
「E2Eテストを自動的に完成させてくれるもの」
というより、
「実際のブラウザを操作しながらE2Eテストを一緒に作っていけるもの」
という捉え方が近いと感じています。
今後やりたいこと
今回は、
E2Eテストを作成し、1コマンドでまとめて実行する
ところまで整備しました。
今後は、
- CIでの自動実行
- Pull Request時の回帰テスト
- ステージング環境へのデプロイ後に自動実行
- TraceやScreenshotの保存
- テスト失敗時の通知
などにも広げていきたいと考えています。
最終的には、
コード変更
↓
デプロイ
↓
E2E回帰テスト
↓
結果通知
まで自動化できると理想です。
まとめ
今回、Playwright MCPを利用して、複数存在する決済導線のE2E回帰テストを作成しました。
Playwright MCPの導入自体は数コマンドで完了しましたが、実際のWebアプリを操作してみると、
- Basic認証とTurbo
- Google Places Autocomplete
- Turbo Streamによる再描画
- テストデータの継続利用
など、サンプルコードだけでは見えない問題がいくつも出てきました。
逆に、こうした実際にブラウザを操作して初めて分かる問題を、AI自身に確認させながら解決できることがPlaywright MCPの面白いところだと思います。
最終的には、5つの回帰テストを1コマンドで並列実行し、約50秒ですべて確認できる状態になりました。
毎回手作業で行っているWebアプリの回帰テストを自動化したい場合、PlaywrightとAIエージェントの組み合わせはかなり実用的だと感じています。


