## 概要
[[Playwright]] v1.56でリリースされた[[Playwright Test Agents]]をいじってみる。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://playwright.dev/img/playwright-logo.ico" />
<span class="link-card-v2-site-name">playwright.dev</span>
</div>
<div class="link-card-v2-title">
Agents | Playwright
</div>
<div class="link-card-v2-content">
Introduction
</div>
<img class="link-card-v2-image" src="https://repository-images.githubusercontent.com/221981891/8c5c6942-c91f-4df1-825f-4cf474056bd7" />
<a href="https://playwright.dev/docs/test-agents"></a>
</div>
### 環境
| 対象 | バージョン |
| -------------- | ------- |
| [[macOS]] | 15.7.2 |
| [[Playwright]] | 1.56.1 |
| [[VSCode]] | 1.106.0 |
## プロジェクトのセットアップ
```console
toki playwright playwright-sandbox
cd playwright-sandbox
```
エージェントファイル一式作成。
```console
$ pnpm playwright init-agents --loop=vscode
Writing file: .github/chatmodes/🎭 generator.chatmode.md
Writing file: .github/chatmodes/🎭 healer.chatmode.md
Writing file: .github/chatmodes/ 🎭 planner.chatmode.md
Writing file: .vscode/mcp.json
Writing file: tests/seed.spec.ts
```
動作確認。
```console
pnpm exec playwright test
```
通常のテストファイルは削除する。
```console
rm -rf tests/example.spec.ts
```
## プランをつくる
[[VSCode]]を起動してプランをつくる。
![[2025-11-20-05-42-56.avif]]
日本語でOK。
![[2025-11-20-05-40-30.avif]]
`navitime-transit-test-plan.md` が作成される。なんか凄い。
> [!code]- `navitime-transit-test-plan.md`
> ```markdown
> # NAVITIME 乗換検索機能 - テストプラン
>
> ## アプリケーション概要
>
> NAVITIMEは日本の総合ナビゲーションサービスで、電車・バス・自動車など様々な交通手段のルート検索機能を提供しています。本テストプランでは、主に電車の乗換検索機能を対象としています。
>
> ### 主な機能
> - **ルート検索**: 出発地と到着地を指定した経路検索
> - **検索モード**: トータルナビ、乗換、自動車、バス、徒歩、自転車、飛行機、トラック
> - **オートコンプリート**: 地名入力時の候補表示機能
> - **詳細条件設定**: 時刻指定、経由地追加、詳細な検索条件の指定
> - **履歴機能**: 過去の検索履歴の管理(ログイン時)
> - **時刻表表示**: 検索結果の時刻表表示
> - **運行情報**: リアルタイムの運行情報の確認
>
> ## テストシナリオ
>
> ### Seed: `tests/seed.spec.ts`
>
> ---
>
> ### 1. 基本的な乗換検索
>
> #### 1.1 正常系 - 駅名指定での乗換検索
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「乗換」タブが選択されていることを確認
> 3. 「出発」入力欄に「東京」と入力
> 4. オートコンプリートから「東京 (東京都千代田区丸の内)」を選択
> 5. 「到着」入力欄に「新宿」と入力
> 6. オートコンプリートから「新宿 (東京都新宿区西新宿)」を選択
> 7. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 検索結果ページに遷移する
> - 東京駅から新宿駅までの複数の経路が表示される
> - 各経路に所要時間、料金、乗り換え回数が表示される
> - 推奨順、料金順、乗換回数順などのソート機能が利用可能
> - 各経路の詳細が確認できる
>
> #### 1.2 正常系 - 住所指定での乗換検索
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄に「東京都千代田区丸の内」と入力
> 3. オートコンプリートから住所を選択
> 4. 「到着」入力欄に「東京都渋谷区道玄坂」と入力
> 5. オートコンプリートから住所を選択
> 6. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 検索結果ページに遷移する
> - 指定した住所間の乗換経路が表示される
> - 徒歩移動も含めた総合的なルートが提示される
>
> #### 1.3 正常系 - ランドマーク指定での乗換検索
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄に「東京スカイツリー」と入力
> 3. オートコンプリートから「東京スカイツリー(R) (東京都墨田区押上1-1-2)」を選択
> 4. 「到着」入力欄に「東京タワー」と入力
> 5. オートコンプリートから該当施設を選択
> 6. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 検索結果ページに遷移する
> - 観光スポット間の乗換経路が表示される
> - 最寄り駅からの徒歩ルートも含めて表示される
>
> ---
>
> ### 2. 時刻指定での乗換検索
>
> #### 2.1 出発時刻指定
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」、「到着」に「大阪」と入力して選択
> 3. 「時刻の基準」が「出発時刻」であることを確認
> 4. 日付を翌日に設定
> 5. 時刻を「09時00分」に設定
> 6. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 指定した出発時刻以降の経路が表示される
> - 新幹線を含む最適なルートが表示される
> - 各経路の出発時刻、到着時刻が明確に表示される
>
> #### 2.2 到着時刻指定
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「横浜」、「到着」に「品川」と入力して選択
> 3. 「時刻の基準」をクリックして「到着時刻」に変更
> 4. 時刻を「18時00分」に設定
> 5. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 指定した到着時刻までに到着できる経路が表示される
> - 最も遅い出発時刻の経路も含めて表示される
> - 時刻に間に合わない場合は適切なメッセージが表示される
>
> #### 2.3 現在時刻セット機能
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「池袋」、「到着」に「新宿」と入力
> 3. 時刻設定エリアで「現在時刻をセット」ボタンをクリック
> 4. 現在の日時が設定されたことを確認
> 5. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 日付と時刻が現在時刻に更新される
> - 現在時刻からすぐに利用可能な経路が検索される
>
> ---
>
> ### 3. 検索条件の詳細設定
>
> #### 3.1 経由地の追加
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」、「到着」に「横浜」と入力
> 3. 「経由地の追加・詳細条件の設定」ボタンをクリック
> 4. 経由地入力欄に「品川」と入力して選択
> 5. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 東京→品川→横浜の経路が検索される
> - 経由地を通るルートのみが表示される
> - 所要時間や料金が正しく計算されている
>
> #### 3.2 複数経由地の設定
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」、「到着」に「横浜」と入力
> 3. 「経由地の追加・詳細条件の設定」ボタンをクリック
> 4. 経由地1に「品川」、経由地2に「川崎」と入力
> 5. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 東京→品川→川崎→横浜の経路が検索される
> - 複数の経由地を順番通りに通過する
> - 最適な接続が提案される
>
> ---
>
> ### 4. 出発地・到着地の入れ替え
>
> #### 4.1 出発地と到着地の入れ替え
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」と入力して選択
> 3. 「到着」に「大阪」と入力して選択
> 4. 出発地と到着地の間にある「入れ替えアイコン」(↕)をクリック
> 5. 入れ替わったことを確認
>
> **期待される結果:**
> - 出発地が「大阪」、到着地が「東京」に入れ替わる
> - 時刻設定などその他の設定は保持される
> - 即座に検索は実行されない(検索ボタンをクリックする必要がある)
>
> ---
>
> ### 5. 交通手段の切り替え
>
> #### 5.1 自動車ルート検索への切り替え
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「自動車」タブをクリック
> 3. 「出発」に「東京駅」、「到着」に「横浜駅」と入力
> 4. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 自動車専用のルート検索結果が表示される
> - 高速道路利用・一般道優先などのオプションが表示される
> - 所要時間、距離、高速料金が表示される
> - カーナビ風のルート案内が確認できる
>
> #### 5.2 バス乗換検索への切り替え
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「バス」タブをクリック
> 3. 「出発」に「東京駅」、「到着」に「お台場」と入力
> 4. 「検索」ボタンをクリック
>
> **期待される結果:**
> - バス路線を含む経路が優先的に表示される
> - バス停名、系統番号が明記される
> - 電車との組み合わせルートも提示される
>
> #### 5.3 徒歩ルート検索への切り替え
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「徒歩」タブをクリック
> 3. 「出発」に「東京駅」、「到着」に「有楽町駅」と入力
> 4. 「検索」ボタンをクリック
>
> **期待される結果:**
> - 徒歩専用のルートが表示される
> - 所要時間と距離が表示される
> - 地図上で徒歩ルートが確認できる
> - 消費カロリーなどの情報が表示される場合がある
>
> ---
>
> ### 6. オートコンプリート機能
>
> #### 6.1 駅名のオートコンプリート
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄をクリック
> 3. 「しん」と入力
>
> **期待される結果:**
> - 「しん」から始まる駅名のリストが表示される
> - 「新宿」「新橋」「新大阪」などの候補が表示される
> - リストから選択すると入力欄に反映される
> - 矢印キーで候補を選択できる
>
> #### 6.2 施設名のオートコンプリート
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「到着」入力欄をクリック
> 3. 「東京ディズニー」と入力
>
> **期待される結果:**
> - 「東京ディズニーランド」「東京ディズニーシー」などの候補が表示される
> - 各施設の住所も併記される
> - 正確な場所が特定できる情報が提供される
>
> #### 6.3 空港のオートコンプリート
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄に「羽田」と入力
>
> **期待される結果:**
> - 羽田空港の各ターミナルが候補として表示される
> - 「羽田空港(東京国際空港) 第1旅客ターミナルビル」などが表示される
> - 各ターミナルが個別に選択できる
>
> ---
>
> ### 7. 入力値のクリア
>
> #### 7.1 出発地のクリア
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」と入力して選択
> 3. 出発地入力欄の右側にある「×」アイコンをクリック
>
> **期待される結果:**
> - 出発地の入力内容がクリアされる
> - プレースホルダー「出発地を入力」が再表示される
> - 到着地やその他の設定には影響しない
>
> ---
>
> ### 8. エラーハンドリング
>
> #### 8.1 出発地未入力での検索
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「到着」のみに「新宿」と入力
> 3. 「検索」ボタンをクリック
>
> **期待される結果:**
> - エラーメッセージが表示される
> - 「出発地を入力してください」などの適切なメッセージが表示される
> - 検索は実行されない
>
> #### 8.2 到着地未入力での検索
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」のみに「東京」と入力
> 3. 「検索」ボタンをクリック
>
> **期待される結果:**
> - エラーメッセージが表示される
> - 「目的地を入力してください」などの適切なメッセージが表示される
> - 検索は実行されない
>
> #### 8.3 存在しない地名の入力
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「あいうえおかきくけこ」と入力
> 3. オートコンプリートの挙動を確認
>
> **期待される結果:**
> - 「該当する地点が見つかりません」などのメッセージが表示される
> - または候補が表示されない
> - 検索ボタンをクリックしてもエラーとなる
>
> #### 8.4 同一地点の指定
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」と入力して選択
> 3. 「到着」にも「東京」と入力して選択
> 4. 「検索」ボタンをクリック
>
> **期待される結果:**
> - エラーメッセージが表示される、または
> - 「出発地と目的地が同じです」などの警告が表示される
> - 検索結果は表示されないか、徒歩0分などの結果が表示される
>
> ---
>
> ### 9. UI/UX検証
>
> #### 9.1 レスポンシブ表示の確認
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. ブラウザのウィンドウサイズを変更
> 3. モバイルサイズ(375px幅)まで縮小
>
> **期待される結果:**
> - レイアウトが崩れない
> - すべての機能が利用可能
> - スマートフォン向けのレイアウトに切り替わる
> - タッチ操作に適したUI要素のサイズになる
>
> #### 9.2 タブの切り替え動作
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」「到着」に値を入力
> 3. 「自動車」タブをクリック
> 4. 再度「乗換」タブをクリック
>
> **期待される結果:**
> - タブ切り替え時も入力内容が保持される
> - 各タブに応じた検索オプションが表示される
> - スムーズにタブが切り替わる
>
> ---
>
> ### 10. 履歴・My地点機能(ログイン必要)
>
> #### 10.1 履歴表示の確認
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄をクリック
> 3. 表示される履歴/My地点エリアを確認
>
> **期待される結果:**
> - 未ログイン時は「有料会員登録をして履歴/My地点を利用する」リンクが表示される
> - ログイン時は過去の検索履歴が表示される
> - よく使う地点が素早く選択できる
>
> #### 10.2 ルート履歴リンク
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「ルート履歴」リンクをクリック
>
> **期待される結果:**
> - ログインページまたはルート履歴ページに遷移
> - 過去の検索履歴が一覧表示される(ログイン時)
>
> ---
>
> ### 11. 地図連携機能
>
> #### 11.1 地図で探すリンク
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 検索フォーム下の「地図で探す」リンクをクリック
>
> **期待される結果:**
> - 地図ページに遷移する
> - 地図上で出発地・目的地を視覚的に選択できる
> - 地図からの地点選択が可能
>
> ---
>
> ### 12. パフォーマンス検証
>
> #### 12.1 検索レスポンス時間
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」に「東京」、「到着」に「大阪」と入力
> 3. 「検索」ボタンをクリック
> 4. レスポンス時間を計測
>
> **期待される結果:**
> - 検索結果が3秒以内に表示される
> - ローディングインジケーターが表示される
> - ユーザーに待ち時間が長いと感じさせない
>
> #### 12.2 オートコンプリートの応答速度
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. 「出発」入力欄に「と」と入力
> 3. 候補リストが表示されるまでの時間を確認
>
> **期待される結果:**
> - 1秒以内に候補リストが表示される
> - タイピング速度に追従できる
> - スムーズな入力体験が提供される
>
> ---
>
> ### 13. アクセシビリティ
>
> #### 13.1 キーボード操作
> **手順:**
> 1. https://www.navitime.co.jp/ にアクセス
> 2. Tabキーで「出発」入力欄にフォーカス
> 3. 駅名を入力
> 4. 矢印キーで候補を選択
> 5. Enterキーで確定
> 6. Tabキーで次の入力欄に移動
> 7. 同様に入力後、Tabキーで「検索」ボタンまで移動
> 8. Enterキーで検索を実行
>
> **期待される結果:**
> - すべての操作がキーボードのみで完結できる
> - フォーカス位置が視覚的に明確
> - タブオーダーが論理的
> - オートコンプリートがキーボードで操作可能
>
> ---
>
> ## テスト実行時の前提条件
>
> - ブラウザ: Chromium (Playwright のデフォルト)
> - ネットワーク: インターネット接続が必要
> - 実行環境: 日本のタイムゾーン(JST)を想定
> - Cookie: 初回訪問時の状態(クッキーなし)を想定
> - 画面解像度: 1280x720 以上を推奨
>
> ## 注意事項
>
> - 運行情報は日々変動するため、検索結果の詳細内容は日時により異なる
> - テスト実行時の時刻によって検索結果が変わる可能性がある
> - ログイン機能を使用するテストは、テスト用アカウントが必要
> - リアルタイムデータを使用しているため、運行遅延等の影響を受ける可能性がある
>
> ```
## テストコードをつくる
generatorエージェントを使う。
![[2025-11-20-05-43-27.avif]]
`tests/basic-transit-search.spec.ts` が作成される。5分以上かかった。
> [!code]- `tests/basic-transit-search.spec.ts`
> ```ts
> // spec: navitime-transit-test-plan.md
> // seed: tests/seed.spec.ts
>
> import { test, expect } from '@playwright/test';
>
> test.describe('基本的な乗換検索', () => {
> test('正常系 - 駅名指定での乗換検索', async ({ page }) => {
> // 1. https://www.navitime.co.jp/ にアクセス
> await page.goto('https://www.navitime.co.jp/');
>
> // 3. 「出発」入力欄に「東京」と入力
> await page.getByRole('textbox', { name: '出発' }).click();
> await page.getByRole('textbox', { name: '出発' }).fill('東京');
>
> // 4. オートコンプリートから「東京 (東京都千代田区丸の内)」を選択
> await page.getByText('東京 (東京都千代田区丸の内)').click();
>
> // 5. 「到着」入力欄に「新宿」と入力
> await page.getByRole('textbox', { name: '到着' }).click();
> await page.getByRole('textbox', { name: '到着' }).fill('新宿');
>
> // 6. オートコンプリートから「新宿 (東京都新宿区新宿)」を選択
> await page.getByText('新宿 (東京都新宿区新宿)', { exact: true }).click();
>
> // 7. 「検索」ボタンをクリック
> await page.locator('#body-top').getByRole('button', { name: '検索' }).click();
>
> // 期待される結果: 検索結果ページに遷移する
> // 期待される結果: 東京駅から新宿駅までの複数の経路が表示される
> await expect(page.getByText('東京')).toBeVisible();
> await expect(page.getByText('新宿')).toBeVisible();
>
> // 期待される結果: 各経路に所要時間、料金、乗り換え回数が表示される
> await expect(page.getByText('13分')).toBeVisible();
> await expect(page.getByText('¥210')).toBeVisible();
> await expect(page.getByText('乗換0回')).toBeVisible();
> });
> });
>
> ```
## テストを実行する
```console
pnpm exec playwright test --headed --trace on
```
![[2025-11-20-05-55-44.avif]]
ここが表示されなくて失敗してそう。
```ts
// 期待される結果: 検索結果ページに遷移する
// 期待される結果: 東京駅から新宿駅までの複数の経路が表示される
await expect(page.getByText('東京')).toBeVisible();
await expect(page.getByText('新宿')).toBeVisible();
```
## 修復する
healerエージェントを使う。
![[2025-11-20-05-57-35.avif]]
出だし良さそうだったけど、途中で動かなくなった。。
![[2025-11-20-06-03-33.avif]]
再起動したら動いた。
![[2025-11-20-06-06-02.avif]]
一応最後までいってる。
![[2025-11-20-06-07-38.avif]]
ただ、このテストコードでいいのかというのはある。
```ts
// spec: navitime-transit-test-plan.md
// seed: tests/seed.spec.ts
import { test, expect } from "@playwright/test";
test.describe("基本的な乗換検索", () => {
test("正常系 - 駅名指定での乗換検索", async ({ page }) => {
// 1. https://www.navitime.co.jp/ にアクセス
await page.goto("https://www.navitime.co.jp/");
// 3. 「出発」入力欄に「東京」と入力
await page.getByRole("textbox", { name: "出発" }).click();
await page.getByRole("textbox", { name: "出発" }).fill("東京");
// 4. オートコンプリートから「東京 (東京都千代田区丸の内)」を選択
await page.getByText("東京 (東京都千代田区丸の内)").click();
// 5. 「到着」入力欄に「新宿」と入力
await page.getByRole("textbox", { name: "到着" }).click();
await page.getByRole("textbox", { name: "到着" }).fill("新宿");
// 6. オートコンプリートから「新宿 (東京都新宿区新宿)」を選択
await page.getByText("新宿 (東京都新宿区新宿)", { exact: true }).click();
// 7. 「検索」ボタンをクリック
await page
.locator("#body-top")
.getByRole("button", { name: "検索" })
.click();
// 期待される結果: 検索結果ページに遷移する
await expect(page).toHaveURL(/routeResult/);
// 期待される結果: 東京駅から新宿駅までの複数の経路が表示される
await expect(
page.getByText("出発:").locator("..").getByText("東京")
).toBeVisible();
await expect(
page.getByText("目的:").locator("..").getByText("新宿")
).toBeVisible();
// 期待される結果: 各経路に所要時間、料金、乗り換え回数が表示される
await expect(page.getByText(/\(\d+分\)/).first()).toBeVisible();
await expect(page.getByText(/¥\d+/).first()).toBeVisible();
await expect(page.getByText(/乗換\d+回/).first()).toBeVisible();
});
});
```
`navitime-transit-test-plan.md` には沿っていそう。
```markdown
### 1. 基本的な乗換検索
#### 1.1 正常系 - 駅名指定での乗換検索
**手順:**
1. https://www.navitime.co.jp/ にアクセス
2. 「乗換」タブが選択されていることを確認
3. 「出発」入力欄に「東京」と入力
4. オートコンプリートから「東京 (東京都千代田区丸の内)」を選択
5. 「到着」入力欄に「新宿」と入力
6. オートコンプリートから「新宿 (東京都新宿区西新宿)」を選択
7. 「検索」ボタンをクリック
**期待される結果:**
- 検索結果ページに遷移する
- 東京駅から新宿駅までの複数の経路が表示される
- 各経路に所要時間、料金、乗り換え回数が表示される
- 推奨順、料金順、乗換回数順などのソート機能が利用可能
- 各経路の詳細が確認できる
```
この期待結果がどうかはなんとも言えない。
> - 各経路の詳細が確認できる
## 感想
以下の条件を満たす場合はアリ。
- 既存のテストが存在しない
- 何かの片手間で作業をする必要がある
- [[TypeScript]]やWeb、[[Playwright]]が得意なエンジニアではない
時間があって、自分で実装できる場合は自分で設計して実装したほうが現時点だと速いし安定すると思う。