AIにコードは書かせるのに、テストだけは自分で直していた
普段の開発では、Claude Codeにコードを書かせるのがもう当たり前になりました。実装もリファクタも、やりたいことを伝えるだけでAIがやってくれます。
ただ、Playwrightのテストコードだけは事情が違いました。画面のスクリーンショットをAIに渡して「クリックする部分を書いて」と頼んでも、AIは実際のページのDOM構造やクラス名を知りません。結局、自分でブラウザの開発者ツールを開いてロケータを確認し、書き直す作業を繰り返していました。
考えてみれば当たり前です。チャットに貼り付けた1枚の画像は、AIにとってはただの絵でしかありません。ボタンの見た目は分かっても、そのボタンが本当にクリックできる状態か、裏側でどんなHTMLになっているかまでは読み取れないからです。
テストコードのメンテナンスは、書くこと自体より地味に時間を食います。画面が少し変わるたびにロケータを直し、動かなくなった箇所を1つずつ探して直す。この繰り返しがしんどいと感じているPlaywrightユーザーは、私だけではないはずです。
そんな中で知ったのがPlaywright MCPです。AIに直接ブラウザを触らせて、実際のページを見ながらテストコードを書いてもらう仕組みです。チャットに画像を貼るのではなく、AI自身にブラウザを開かせて中身を確認させる、という発想の転換です。
今回は実際に手元で動かしてみて、何ができて何がまだ苦手なのかを正直に整理しておきます。普段Claude等のAIは使っているけれど、自分のテストにどう繋げればいいのか分からない、という方向けに書きました。
MCPって何よ、っていう話
いきなりMCPと言われてもピンとこない方も多いと思うので、噛み砕いておきます。MCP(Model Context Protocol)は、AI(LLM)が外部のツールやデータに接続するための共通の規格です。
Playwrightで言えば、AIとブラウザの間に立つ橋渡し役だと思ってください。AIは自分の目でブラウザの画面を見ているわけではないので、そのままではブラウザを操作できません。
そこにMCPサーバーを挟むことで、AIは「このURLを開いて」「このボタンをクリックして」と指示を出せるようになります。指示を受け取ったサーバーが、実際にブラウザを動かしてくれるわけです。
普段Claude Codeに「〜しておいて」とお願いする感覚のまま、ブラウザの操作までお願いできるようになる、というイメージを持ってもらえれば十分です。
MCP自体はPlaywright専用の仕組みではありません。SlackやGitHub、社内のデータベースなど、いろいろなツールをAIに繋ぐための共通規格として使われています。そのラインナップの1つに、ブラウザ操作を受け持つPlaywright公式のMCPサーバーがある、という位置づけです。
私の手元の環境にも、このPlaywright MCPのほかにChromeを操作するMCPが繋がっています。用途によって使い分けている、というくらいの感覚で捉えてもらえれば十分です。
もう少し登場人物を整理しておきます。「ホスト」と呼ばれるのがClaude CodeやClaude Desktopのような、普段AIとやり取りしているアプリ側です。「MCPサーバー」が今回のPlaywright MCPのように、実際の作業を引き受ける側です。ホストがサーバーに「繋げる」設定をすることで、AIがそのサーバーの持つ道具を使えるようになります。今回のケースでは、その道具の中身がブラウザ操作だった、というだけの話です。
なぜスクショじゃなくアクセシビリティツリーを見るのか
AIにブラウザを触らせると聞くと、画面のスクリーンショットを見せて「ここをクリックして」とお願いする仕組みを想像するかもしれません。実際、そういうやり方をするツールも存在します。
ですがPlaywright公式のMCPサーバーは違います。ページのスクリーンショットではなく、アクセシビリティツリーという、ページの構造をテキストで表した情報をAIに渡しています。これは以前Playwright + TypeScriptチュートリアルでも触れたgetByRoleと地続きの話です。要素の「役割(role)」と「名前(name)」をもとに、AIが要素を特定します。
たとえば、ボタンが1つあるだけの簡単なページなら、次のような情報がAIに渡されるイメージです(実際の書式は最新のバージョンで確認してください。あくまで雰囲気をつかむための例です)。
- heading "サンプルページ" [level=1]
- button "送信" [ref=e3]
見出しの下に「送信という名前のボタンがある」という情報が、テキストとしてそのまま渡っています。AIはこのref=e3を頼りに、迷わずそのボタンをクリックできるわけです。
これには理由があります。画像は文字に比べてデータ量が桁違いに大きく、AIが読み取るのにも余計な時間とコストがかかります。それに対してアクセシビリティツリーはただのテキストなので、軽くて速いです。
加えて、座標やピクセルで「ここをクリック」と指示する方式だと、レイアウトが少し変わっただけで違う場所を押してしまう事故が起きます。role名前ベースなら、見た目やクラス名が変わっても、AIは同じ要素を指し示し続けられます。
実際に手元でMCPサーバーのツール一覧を覗いてみました。browser_navigateはページを開くツール、browser_snapshotはアクセシビリティツリーを取得するツールです。browser_clickは要素をクリックするツールで、Playwrightの操作にほぼそのまま対応しています。
クリック用のツールには「スナップショットから得た要素の参照」を渡すようになっていました。加えて「今どの要素に対して何をしようとしているか」を、人間が読める言葉で添えるようにもなっています。これ、意外と使えます。途中でAIが暴走していないか、人間の目で追いやすくなるからです(ツール名や引数の細かい仕様は更新が速いので、正確なところは公式ドキュメントで確認してください)。
つまりAIは画面を「見て」いるのではなく、構造を「読んで」操作しているということです。この決定性の高さは、getByRoleが壊れにくいとexpectマッチャーのリファレンス記事で書いた話とそのままつながっています。
逆に言うと、画像を見せて操作させる従来型のやり方には、AIが微妙にずれた座標をクリックしてしまう、という弱点がありました。私も画像ベースの自動化ツールを試したとき、似たようなボタンが並んでいる画面で隣のボタンを押されてしまったことがあります。アクセシビリティツリーを見る方式は、この手の事故を根本から減らしてくれる考え方だと感じています。
余談ですが、AIの画像認識そのものも年々精度が上がっています。将来的にはスクリーンショットだけで十分、という日が来るのかもしれません。ただ、テキストの方が軽くて速いという性質は変わらないので、当面はアクセシビリティツリーが土台であり続けるだろうと私は見ています。
まず動かしてみましょう
説明はこのくらいにして、実際に手元で動かしてみましょう。前提として、Node.jsが入っている環境を使います。環境構築から知りたい方はPlaywright + TypeScriptチュートリアルを先に読んでおくと安心です。
MCPサーバーを立てる
Playwright公式のMCPサーバーは、npxコマンドで起動できます。
npx @playwright/mcp@latest
これだけで、Playwrightが操作専用のMCPサーバーとして立ち上がります。瞬殺ですね。ブラウザ本体がまだ入っていない場合は、初回にダウンロードが入ることがあるので少し待ちましょう。
AIと繋ぐ
繋ぎ先がClaude Codeなら、コマンド1本で登録できます。
claude mcp add playwright npx @playwright/mcp@latest
他のMCP対応クライアントの場合は、設定ファイルに次のようなJSONを追記する形が一般的です。
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
コマンド名やオプションはここ最近もちょくちょく変わっているので、うまく繋がらない場合は公式ドキュメントの最新の記載を確認してください。このあたりは本当に動きが速い分野です。
繋いだ直後は、AIがブラウザを勝手に操作していいものか少し不安になると思います。私が使っている環境では、AIがクリックや入力などの操作をするたびに、実行していいか確認が挟まるようになっていました。慣れないうちは、この確認を1つずつ見ながら進めると安心です。
ここでつまずいたら
- コマンドを打っても反応がない場合、Node.jsのバージョンが古いことがあります。
node -vで確認し、必要なら新しいLTS版に入れ替えてください - 「MCPサーバーが見つからない」といったエラーが出る場合、ホスト側の設定ファイルの書き方(キー名やインデント)を間違えていることが多いです。公式ドキュメントのサンプルと1文字ずつ見比べてみてください
- ブラウザは起動するのに操作が反映されない場合、別のウィンドウやプロファイルで開いてしまっていないか確認してみましょう
実際にブラウザを触らせてみる
繋がったら、あとは日本語で頼むだけです。私は最初、自分のブログのトップページを開かせて「ヘッダーのリンク一覧をアクセシビリティツリーで見せて」とお願いしてみました。役割と名前が並んだテキストがそのまま返ってきましたね。
続けて「『お問い合わせ』というリンクをクリックして、遷移先のURLを教えて」と頼むと、実際にクリックして結果を教えてくれました。
コードを1行も書かずにここまでできてしまうので、最初に動いたときは素直に驚きました。ここまで来たら、「今操作した内容をPlaywrightのテストコードにして」と続けて頼めます。実際に動かした手順をなぞって、次のようなコードに落としてくれました(生成される中身は毎回変わるので、あくまで一例です)。
import { test, expect } from "@playwright/test";
test("お問い合わせページへ遷移できる", async ({ page }) => {
await page.goto("https://www.katsulog.tech/");
await page.getByRole("link", { name: "お問い合わせ" }).click();
await expect(page).toHaveURL(/contact/);
});
真っ白な状態からロケータを1つずつ調べて書くより、だいぶ早く形になります。CSSセレクタではなくgetByRoleを自然に選んでくれたのも、地味にありがたいポイントでした。アクセシビリティツリーを見ながら書いているのだから、当然といえば当然です。それでも、初心者が同じ道具を使うだけで、放っておいても壊れにくいロケータの書き方に寄っていきます。これはうれしい副産物だと思います。
もちろん、この生成結果をそのまま使っていいかどうかは別の話です。それは次で正直に書きます。
できること、まだ苦手なこと
ここまで書くと万能に聞こえるかもしれませんが、正直に限界も書いておきます。
できることは次の4つです。
- 実際のページを見ながらロケータを決めてくれるので、存在しないクラス名やタグを想像で書かれることが減ります
- 一連の操作を試しながら、その場でPlaywrightのコードに落とし込んでくれます
- クリックのたびに何をしようとしているかを説明してくれるので、途中経過を人間が追いやすいです
- ログイン不要な簡単なページなら、頼んでから数分でひと通りの操作コードが手に入ります
まだ苦手なことも正直に書きます。
- 生成されたテストコードをそのままCIに入れるのは危険です。アサーションが甘かったり、たまたま動いた手順をそのままテストにしてしまったりすることがあります
- 対象のページが複雑だったり、ログインが必要だったりすると、途中で迷子になることがあります。認証周りは自分である程度状態を用意してから始めさせるほうが安定します
- 仕様の変化が速い分野なので、少し前に効いたコマンドやオプションが次のバージョンで変わっていることがあります
- 画面の見た目そのもの(アニメーションが動いているか、色が正しいかなど)は、アクセシビリティツリーだけでは判断できません。こういう検証はスクリーンショットに戻る必要があります
結局のところ、AIが書いたコードをそのまま信じない、というのがここでも大事な姿勢だと思います。生成されたコードは必ず自分の目で読んで、ロケータの選び方やアサーションの内容をレビューしてから使いましょう。
私が今のところ落ち着いている運用はこうです。まずAIにブラウザを触らせて操作の下書きを作ってもらいます。コードとして書き出させたあとは、いつも通り自分のリポジトリの中でレビューして手を入れます。MCPはあくまで「最初の1本を速く書く」ための道具です。テストを育てて壊れないようにしていく仕事は、これまでどおり人間の役目のままです。
まとめ:レビューする目は自分の中に残しておく
というわけで、Playwright MCPを一通り動かしてみました。AIとブラウザの間にアクセシビリティツリーという共通言語を渡すことで、画面を「見て」ではなく「読んで」操作できるようにする仕組みでした。スクショに頼らないぶん動きが安定していて、そのままPlaywrightのコードに落とし込みやすいのが強みです。
とはいえ、まだ発展途上の分野です。生成されたコードを鵜呑みにせず、レビューする目は自分の中に残しておきましょう。16年テストに関わってきた身としても、ここだけは譲れないところです。
普段Claude等のAIをコードで使っている方なら、今日設定したMCPサーバーはそのまま流用できます。特別な準備はいらないので、思っているより気軽に試せるはずです。
まずは自分がよく触っているページを開かせて、アクセシビリティツリーを覗かせてみるところから試してみてください。壊れたテストをAIに直させる話や、録画からロケータを書き換えさせる話も、また別の記事でまとめるつもりです。試してみて気づいたことがあれば、コメントで教えてもらえるとうれしいです。
関連記事も合わせてどうぞ。

コメント