0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Playwright Test Agents(Planner / Generator / Healer)を実際に触ってみた ―― つまずいたポイントと解決メモ

0
Posted at

はじめに

Playwright v1.56 から導入された Playwright Test Agents を、実際に手を動かして試してみました。

AI エージェントがブラウザを操作しながらテスト計画を立て、テストコードを生成し、壊れたテストを自動修復してくれる、という機能です。触ってみると「なるほど、そう動くのか」という発見と、「あれ、なんでこうなる?」というつまずきがいくつもあったので、体験ベースで整理しておきます。

同じように「記事を読んで真似したけど、記事に書いてない前提でハマった」という人の助けになれば幸いです。

注:エージェント呼び出しの記法やツール構成は、Playwright / Claude Code のバージョンによって変わる部分があります。この記事は執筆時点(2026年7月)の体験メモとして読んでください。


Playwright Test Agents とは

3 つのエージェントが役割分担して、E2E テストの「作る・書く・保守する」を分担してくれる仕組みです。

  • 🎭 Planner … アプリを実際に探索して、Markdown のテスト計画を作る
  • 🎭 Generator … テスト計画を読んで、実行可能な Playwright テストコードを生成する
  • 🎭 Healer … テストを実行し、失敗したテストを自動で修復する

それぞれ単独でも、順番につなげても使えます。今回は Planner → Generator の流れを中心に触りました。


セットアップ

前提

  • Playwright v1.56 以降
  • 今回は Claude Code を AI ツールとして使う構成(--loop=claude

初期化

npm install -D @playwright/test@latest
npx playwright install chromium
npx playwright init-agents --loop=claude

--loop は使う AI ツールに応じて変えます(vscode / codex / opencode など)。

初期化後のフォルダ構成

--loop=claude で初期化すると、こんな構成になりました。

repo/
  .claude/          # planner / generator / healer のエージェント定義
  node_modules/
  specs/            # 空。テスト計画がここに出力される想定
  .mcp.json         # Playwright MCP の設定(ブラウザアクセスの経路)
  package.json
  package-lock.json
  seed.spec.ts      # ★ 最重要ファイル(後述)

各ファイルの役割をざっくり整理すると:

ファイル / フォルダ 役割
.claude/ 3 エージェントの定義(指示文+使えるツールの集合)
.mcp.json Playwright MCP サーバーの設定。エージェントがブラウザにアクセスする経路
seed.spec.ts テストの「起点」を作る準備テスト。Planner / Generator のお手本にもなる
specs/ Planner が出力するテスト計画(Markdown)の置き場

つまずき①:Planner に「サイト情報も認証情報も渡してないのに、なぜ動くの?」

多くの記事では「Planner に指示を出すと、勝手にサイトを探索して計画を作ってくれる」と書かれています。でも冷静に考えると、サイトの URL も認証情報も渡していないのに、どうやってアプリを見に行くのか? が謎でした。

答えは、記事が省略している 2 つの前提にありました。

1. seed.spec.ts がすべての起点

Planner は生のプロンプトだけで動いているわけではありません。seed.spec.ts がコンテキストに渡されていて、Planner はこれを実際に実行してからアプリの探索を始めます。

  • どのサイトを見るか → seed 内の page.goto(...) や config の baseURL で決まる
  • 認証情報 → seed(と fixture)がログイン処理や storageState の読み込みを担当する

つまり「情報が無い」のではなく、「seed に書いてある」のです。記事はこの seed の準備ステップを飛ばしていたので、混乱しました。

2. Planner はライブのアプリをブラウザで見に行く

Planner は .mcp.json の Playwright MCP 経由で実際にブラウザを開き、DOM を見ながら探索します。だから「サイト構造を事前に教える」必要がなく、その場で観察する。逆に言うと、起動中のアプリが無いと Planner は動けません。

seed.spec.ts のサンプル

初期状態の seed は中身が空の雛形でした。

import { test, expect } from '@playwright/test';

test.describe('Test group', () => {
  test('seed', async ({ page }) => {
    // generate code here.
  });
});

まずは公開サイト(TodoMVC)で動かすなら、最低限これだけで OK。

import { test, expect } from '@playwright/test';

test.describe('Test group', () => {
  test('seed', async ({ page }) => {
    await page.goto('https://demo.playwright.dev/todomvc');
    await expect(page).toHaveTitle(/TodoMVC/);
  });
});

seed の役割は「Planner がアプリと対話できる状態まで持っていく」こと。最低限「開始 URL を開く」だけで機能します。認証が必要なフローの場合は、Planner を回す前にセッションを確立しておく(seed で storageState を読み込む等)必要があります。


Planner の使い方

Claude Code をプロジェクトのルートで起動し、planner エージェントを呼び出して指示します。

use the planner agent

seed test: seed.spec.ts

todoの追加と完了のテスト計画を作成して

ポイントは 3 つ。

  • planner エージェントを明示的に指定する
  • seed test をコンテキストに含める(これが起点になる)
  • お題を渡す(最初は狭いお題にすると結果が読みやすい)

実行すると Planner がブラウザを開いてアプリを操作しながら探索し、少し待つと Markdown のテスト計画が出力されます。


つまずき②:バックグラウンド実行の状態が分からない

指示を出したら「エージェントがバックグラウンドで動いています。完了次第通知されます」と出たものの、今どうなっているのか分からない。

これは Claude Code 側の機能で確認できました。

  • /tasks を実行すると、動作中のバックグラウンドプロセスが ID と状態付きで一覧表示される
  • 新しめのバージョンなら Agent View(\ キーで開く)で、各エージェントが今どのツールを使っているかまで見られる

Planner の探索はブラウザでサイトを一通り操作するので、それなりに時間がかかります。まずは /tasks で状態を見るのがシンプルです。


つまずき③:「Write ツールが無くて保存できなかった」と言われた

計画は作れたのに「Write ツールがなくファイル保存ができなかったため、代わりに保存します」というメッセージが出ました。外部エージェントには書き込み権限がないのか? と気になって、planner の定義ファイルを覗いてみました。

.claude/agents/ の planner 定義の tools: を見ると、確かに汎用の Write はありません。でも、リストの中にこれがありました。

mcp__playwright-test__planner_save_plan

つまり Planner は「汎用 Write は持たず、計画保存専用の planner_save_plan を使う設計」でした。余計な書き込み権限を与えず、用途を絞ったツールセットになっているわけです。

今回はこの専用ツールがうまく使われず、メインの Claude Code がフォールバックで保存したため、本来 specs/ に入るはずの計画が tests/todo-add-complete.plan.md という別の場所・名前で保存されていました。動作自体は問題ないですが、「専用ツール経由なら置き場所が変わっていたはず」という学びでした。

教訓:「エージェントに書き込み権限が無い」という一般ルールがあるわけではなく、そのエージェント定義に何のツールが割り当てられているか次第。 挙動が気になったら定義ファイルを読むのが早いです。


Generator の使い方

計画ができたら Generator にコード生成させます。

use the generator agent

@tests/todo-add-complete.plan.md

この計画からPlaywrightのテストコードを生成して

記法の話:@ は何?

呼び出しの各行はこういう意味です。

  • use the generator agent … サブエージェントの指定(自然言語なので厳密なルールは無い)
  • ファイルパスの指定 … 「どのファイルを使うか」を伝えているだけ

@ファイルパスClaude Code のファイル参照ショートカットで、ファイルの中身を確実にコンテキストへ取り込めます。補完も効くので、確実に読ませたいときはこちらが堅いです。パスを文字列で伝えるだけでもエージェントが自分で開いてくれますが、迷ったら @ を使うのが安全でした。

Generator は計画を読み、実際にブラウザで各シナリオを操作しながらセレクタやアサーションをライブ検証しつつ、.spec.ts を生成します。


Healer と「非決定的な UI 仕様」について(考察)

Healer は「失敗したテストをリプレイし、UI を見て同等の要素を探し、パッチを当てて通るまで再実行」してくれます。

ここで気になったのが、アプリ側の仕様が非決定的な場合はどうなるか です。たとえば「成功メッセージが、機能によってスナックバーだったりダイアログだったりネイティブダイアログだったりして統一されていない」ようなケース。

結論としては、Healer はこの手の非決定的な仕様を賢く吸収してはくれないと考えたほうが安全です。

  • Healer が得意なのは「UI は変わったが正解は 1 つに定まる」ケース(セレクタのズレ、待機不足など)
  • 「同じ機能なのに実行ごとに正解が変わる」ケースは守備範囲外
  • むしろ、たまたま観測できた 1 パターンにテストを固定してしまい、次の実行で別パターンが出て落ちる → また修復…という「いたちごっこ」になりうる

対処の方向性

1. テスト側で OR を許容する

const snackbar = page.getByRole('status').filter({ hasText: '保存しました' });
const dialog   = page.getByRole('dialog').filter({ hasText: '保存しました' });
await expect(snackbar.or(dialog)).toBeVisible();

ただしネイティブダイアログ(alert / confirm 等)は DOM 要素ではないので、ロケータでは拾えず page.on('dialog', ...) で別途ハンドリングが必要。検知の仕組みが別物なので、単純な OR では統合できない点に注意。

2. 意味ベースの検証に逃がす

表示方法で検証せず、「保存後にレコードが増えている」「一覧に反映される」「API が 200」など、表示手段に依存しない結果で検証する。表示のブレに引きずられず、より頑健。

3. 計画段階で明示しておく

Planner の計画 Markdown に「成功メッセージは複数の表示方法がありうる。いずれでも成功と判定する」と書いておくと、Generator がそれを汲みやすい。計画は手で編集できるので、こういう作り込みが効く。

そもそも「表示方法が統一されていない」のはアプリ側の設計の乱れであって、テストで吸収すればするほどテストは複雑・脆弱になります。テストの複雑さは、しばしばプロダクト設計の乱れを映す鏡。可能ならアプリ側に統一を働きかけるのが本筋です。


つまずき④:VSCode の Test ビューにテストが出てこない

spec.ts はあってエラーも無いのに、VSCode のサイドバーの Test をクリックしても「このワークスペースでまだテストが見つかりません」と表示される。Playwright Test for VSCode 拡張はインストール済み。

原因

Playwright 拡張は spec.ts を直接探すのではなく、まず playwright.config.ts を見つけて、その testDir を基準にテストを探します。

自分のケースでは config がサブフォルダにありました。

e2e/playwright.config.ts   ← config はここ
export default defineConfig({
  testDir: './tests',   // ← config の場所からの相対 = e2e/tests/
  // ...
});

testDir: './tests'config 自身の場所からの相対パスなので、実際に見に行くのは e2e/tests/。config がサブフォルダに隠れていると、VSCode で開いているルートと食い違って拡張がうまく拾えないことがあります(Test ビューに Python 用のボタンが出ていたのがサインでした)。

解決

コマンドパレット(Ctrl+Shift+P)から:

Test: Refresh Tests

これを実行したら、無事テストが認識されました 🎉

他にも効きうる対処:

  • Developer: Reload Window でウィンドウ再読み込み
  • config が入れ子になっているなら、そのフォルダ自体を VSCode のルートとして開き直す
  • 拡張のコマンドで config を明示選択する

教訓:spec.ts 単体が正しくても、拡張は config を起点に探すので、config の場所と testDir と VSCode で開いているルートの三者の位置関係が合っていないと検知されない。


まとめ

Playwright Test Agents を実際に触って得た学びを整理します。

  • seed.spec.ts がすべての起点。 サイト URL も認証もここ(と config の baseURL)で決まる。記事はこの準備を省略しがちなので要注意
  • Planner はライブのアプリをブラウザで見に行くので、起動中のアプリが必要
  • バックグラウンド実行の状態は /tasks や Agent View で確認できる
  • エージェントのツール権限は定義ファイル次第。気になったら .claude/agents/ の定義を読む
  • @ファイルパス は Claude Code のファイル参照ショートカット。確実に読ませたいとき便利
  • Healer は非決定的な UI 仕様は吸収してくれない。テスト側で OR や意味ベース検証を作り込むか、アプリ側の統一を検討する
  • VSCode でテストが出ないときは config の場所・testDir・開いているルートの三者を疑い、まず Test: Refresh Tests

AI に丸投げ、ではなく「AI がグランドワークをやり、人間が要所をレビュー・作り込みする」のがちょうどいい距離感だと感じました。特に非決定的な仕様やビジネスクリティカルなパスは、人間が明示的に書く前提で使うのがよさそうです。

少しずつ触りながら、また続きを書いていきます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?