はじめに
技術本部Quality Assurance Engineering Unitの杉本です。
QAでPlaywrightを使ったE2Eテストを推進している者です。以前、SETチーム始動 Playwrightで実現した最初の成果 - Sansan Tech Blogという記事で、立ち上げと導入について書きました。この記事を公開してから約1年、私たちのチームであるSET(Software Engineer in Test)は、社内でのE2Eテスト自動化の取り組みをさらに加速させてきました。
現在では、Bill Oneから始まり、Sansan、Contract Oneに導入し、これからEightへ導入しようとしているところです。これで、Sansanが展開する主要プロダクトすべてにE2Eテスト自動化の基盤を整えることができました。
Playwright Agentsの紹介
今回ご紹介するのは、2025年10月6日にリリースされたPlaywright バージョン1.56の新機能、Playwright Agentsとそれを利用した取り組みです。この機能は3つのエージェントで構成されています。
🎭 Planner(プランナー)
アプリケーションを探索し、テスト計画をMarkdown形式で生成します。ページ構成、ユーザーフロー、主要なアクションを分析し、体系的なテスト計画を作成します。
🎭 Generator(ジェネレーター)
Plannerが作成したMarkdownのテスト計画を、実行可能なPlaywrightのテストファイルに変換します。計画と自動化の間のギャップを埋める役割を担います。
🎭 Healer(ヒーラー)
テストを実行し、失敗したテストケースを検出して自動的に修正します。不安定なテストへの対処やデバッグ時間の削減に貢献します。
Playwright Agentsの導入は驚くほど簡単で、以下のコマンドを実行するだけです。
npx playwright init-agents --loop={利用したいツール}このコマンドを実行すると、3つのエージェント(Planner、Generator、Healer)の定義ファイルと、テンプレートとなるseed.spec.tsファイルが自動生成され、あとは、エージェントとチャットするだけです。
「商品検索のテスト計画を作って」「商品検索のテストを生成して」
こんな風に会話するだけで、次々とテストが実装されていきます。
実際のところ
既存のAI技術とPlaywrightの機能を組み合わせた構成のため、技術的に目新しいものではありませんが、精度は高いという所感を持ちました。
この様子を見ていると、つい思ってしまいます。
「もうテスターはいらないんじゃないか?」
確かに、エージェントは驚くほど高速にテストを生成します。しかも、ちゃんと動くものを作ってきます。でも、これは典型的な「AIあるあるの落とし穴」で、自身ではAIの「70点の壁」と勝手に呼んでいます。AIツールを触ったことがある人なら、こんな経験があるはずです。
パッと見ていい感じ! → 導入を決定
実際に使ってみると... → 細かいところで期待と違う
完璧を求めると... → 結局、人の手で大幅な修正が必要
これが、今のAIの現実です。70点までは簡単に持っていけます。でも、70点から90点、100点に引き上げるには、経験と技術がまだまだ必要だと思っています。Playwright Agentsも例外ではありません。
✅ それなりに良いテストを作ってくる
✅ ちゃんと動くコードを生成する
❌ でも、足りない部分は必ずある
この問題を解決するために、プロンプトの調整やチャットでの指示について、あれこれ思考を巡らせます。でも、毎回同じことを指示するのは非効率です。しかも、プロンプトだけでは伝えきれないニュアンスやベストプラクティスがあります。
プロンプトではなく、コードで示す
私たちのアプローチは、プロンプトで毎回指示するのではなく、プロジェクト構成で示します。
- 生成されるseed.spec.tsファイルにはfixtureやbefore/afterだけを記述
- Page Objectやユーティリティメソッドを別ファイルとして用意
- それらを活用したサンプルコードを別ファイルとして用意
エージェントに「こう書いてね」と毎回お願いするのではなく、「こういうコードを書くんだよ」という見本を最初から用意しておくのです。種をコーティングする、と言えばいいでしょうか。あるいは、種の周辺環境を整える、より良くさせる、というイメージです。これを試してみよう、と思いました。
私たちは、この考え方に基づいてSEED(Seed for E2E Engineering Development)構想を考えました。このSEED構想は、単なるseed.spec.tsファイルだけではなく、テスト生成に必要な全ての要素を含むプロジェクトテンプレートです。
プロジェクト構成
seed-project/ ├── tests/ │ ├── sample.spec.ts # サンプルコード │ └── seed.spec.ts # fixtureインポートのみ ├── fixtures/ │ └── index.ts # カスタムfixture定義 ├── page-objects/ │ ├── home-page.ts # Page Object1 │ └── login-page.ts # Page Object2 ├── utils/ │ ├── reload-until-success.ts # ユーティリティ1 │ └── ensure-continued-success.ts # ユーティリティ2 └── playwright.config.ts
seed.spec.tsの役割
seedファイル自体はシンプルに保ちます。私たちの場合はfixtureのみの利用ですが、beforeやafterの処理やdescribeを利用したい場合もここに追記します。
import { test, expect } from '../fixtures'; test('seed', async ({ page }) => { // ここには基本的な初期化処理のみを記述する });
カスタムユーティリティの導入
生成されるテストの質を上げるため、2つのユーティリティメソッドを追加します。この2つのメソッドは、 どのプロダクトでも汎用的に利用することができ、E2Eテストの安定稼働に大きく貢献するものです。今回のSEED構想に関わらず、どのE2Eテストでも有用であるため、ぜひ参考にしていただければと思います。
1. reloadUntilSuccess - リトライ機能付きリロード
exponential-backoffを利用して、該当のデータが表示されるまでリロードを繰り返します。データの読み込みに時間がかかる場合や、非同期処理が不安定な場合に有効です。
import { backOff } from 'exponential-backoff'; import { Page } from 'playwright'; export const reloadUntilSuccess = async <T>( page: Page, func: () => Promise<T>, option?: { numOfAttempts?: number; }, ) => { return await backOff( async () => { return await func(); }, { maxDelay: 5_000, numOfAttempts: option?.numOfAttempts, retry: async () => { await page.reload(); return true; }, }, ); };
活用例:
- データベースからの情報取得が完了するまで待機
- 外部APIの応答待機
- キャッシュのクリアや再読み込みが必要な場面
使用例:
await reloadUntilSuccess(page, async () => { await expect(page.locator('#user-name')).toContainText('杉本'); // ここに複数書いてもOK });
2. ensureContinuedSuccess - 処理の完全完了を保証
PlaywrightのtoPass()を拡張したようなメソッドで、処理が成功した状態が一定期間継続することを確認します。
ローディングアイコンなど、表示されて消えたと思ったら別の処理でローディングアイコンが表示されるような場合を考慮した作りになっています。
import { expect } from '@playwright/test'; import { differenceInMilliseconds } from 'date-fns'; import settings from 'settings'; export const ensureContinuedSuccess = async ( func: () => Promise<void>, { interval = 100, duration, timeout = settings.expectTimeout, }: { interval?: number; duration: number; timeout?: number }, ) => { let start = new Date(); return await expect .poll( async () => { try { await func(); } catch { start = new Date(); } return differenceInMilliseconds(new Date(), start); }, { intervals: [interval], timeout: timeout }, ) .toBeGreaterThanOrEqual(duration); };
活用例:
- アニメーションの完了確認
- 状態遷移の安定待機
- 非同期処理の完了確認
使用例:
// ローディングが消えて、1秒間その状態が継続することを確認 await ensureContinuedSuccess( async () => { expect(await loadingIcon.count()).toBe(0); }, { duration: 1_000 } );
Page Objectの活用
前回の記事でも紹介したPage Object Modelを活用するため、最初のログインページなどをPage Objectとして用意しておきます。そうすることで、Page Object Modelを利用するということを理解してくれるようになります。
これらのPage Objectやユーティリティを用意しておくことで、エージェントは生成時にこれらのパターンを学習し、最初から保守性の高いテストコードを自動生成することが可能になります。
SEEDによるE2Eテストの増殖
SEEDプロジェクトの真価は、各開発チームへの展開で発揮されます。
以下のようなフローを想像しています。
- SEEDプロジェクトを開発チームに配布
- 各チームが自分たちのドメイン知識を追加
- Playwright Agentsでテストを生成
- そのチーム専用の、より洗練されたSEED環境が生成(次のテスト生成の基盤にもなり得る)
このサイクルを回すことで、組織全体で精度の高いE2Eテストが増殖していきます。
E2Eテストの民主化へ
Playwright Agentsによって、E2Eテスト作成の敷居は大きく下がりました。
しかし、本当に価値あるテストを作るには、
ドメイン知識が必要。
保守性の高い設計が必要。
チームに合わせたカスタマイズが必要。
SEEDプロジェクトは、これらを全て満たしながら、AIの力を最大限に活用するアプローチです。
私たちが目指す未来
開発者全員が気軽にE2Eテストを書ける環境。
AIが実行を担当し、人間は設計に集中できる体制。
チームごとにカスタマイズされた、生きたSEED環境が存在する組織。
E2Eテストは特別なスキルを持つ人だけのものではなくなります。Playwright AgentsとSEEDプロジェクトは、その未来への第一歩です。
まとめ
Playwright 1.56で登場したPlaywright Agentsは、技術的には革新的ではないかもしれません。しかし、公式サポートされた標準的なアプローチとして提供されることで、E2Eテスト自動化はより多くの人にとって身近なものになります。ただし、AIには「70点の壁」があります。本当に価値のあるテストを作るには、人の経験と技術がまだまだ必要です。
私たちのSEEDプロジェクトは、その「足りない30点」を補うために、seedファイルの周辺環境を充実させるアプローチを取りました。プロンプトで指示するのではなく、Page Objectやサンプルコード、ユーティリティといった具体的なコードで見本を示すことで、生成されるテストの質を底上げします。
Playwright Agentsは、E2Eテストの未来を変える可能性を秘めています。私たちのSEED構想が、その可能性をさらに広げる一助となれば幸いです。