---
name: manual-test
description: "testing.md や spec/manual-tests/ のテスト手順書を agent-browser で自動実行し、実装の動作をブラウザ上で検証するスキル。失敗時は原因分析して GitHub Issue を起票する。起動条件: `/manual-test` の実行、スキル名の明示的な指定、他スキル（issue-implement / spec-implement など）からの委譲のみ。「動作確認して」程度の依頼や、testing.md が存在するという状況だけでは自動起動しない。手順書のない探索的テストは manual-test-dashboard を使う。"
user-invokable: true
---

# Browser Verify — agent-browser によるテスト手順の自動実行＋修正ループ

testing.md や spec/manual-tests/ に書かれたテスト手順を、agent-browser で実際のブラウザ上で自動実行する。テスト結果はレポートとして記録し、失敗したテストは原因分析→修正→再テストのループで解消する。

## 前提条件

`agent-browser` CLI が必要。セットアップ・頻出コマンド・ターン数を抑える書き方は `../_shared/references/agent-browser.md` に集約してある。ブラウザ操作の前に読む。

## アーキテクチャ

```
メインエージェント（オーケストレーション）
  ├── サブエージェント: seed-data（シードデータ整備）
  └── サブエージェント: verify-{TC番号}（テスト実行）× N
```

メインエージェントはオーケストレーションに集中する。ブラウザ操作・コード修正はサブエージェントに委譲する。委譲方式は `../_shared/references/subagent-policy.md` に従う。

手順と期待結果はテストソースで確定しているので、サブエージェントはブラウザを操作して観測した事実を返すだけにし、**PASS/FAIL の確定と原因分析はメインが行う**。

## Workflow Overview

```
Phase 1: 準備
  テストソース特定 → サーバー起動コマンド検出 → agent-browser 確認

Phase 2: シードデータ整備
  テストに必要なデータの準備（DB投入・ファイル配置・環境変数設定等）

Phase 3: サーバー起動
  空きポート検出 → サーバーをバックグラウンド起動 → ヘルスチェック

Phase 4: テスト実行
  テストケースを agent-browser で順番に実行 → 結果記録 → FAIL は録画付きで再実行

Phase 5: 失敗分析＆Issue起票
  失敗テストの原因分析 → 分類 → GitHub Issue を起票

Phase 6: レポート＆クリーンアップ
  最終レポート生成 → サーバー停止 → セッションクリーンアップ
```

---

## Phase 1: 準備

### テストソースの特定

以下の優先順で検索し、テストケースのソースを決定する:

1. ユーザーが明示的に指定したファイル
2. `.thread/{Issue番号}/testing.md` — issue-implement から呼ばれた場合
3. `spec/manual-tests/` — 単体実行の場合
4. プロジェクトルート直下や docs/ の testing 関連ファイル

テストソースが見つからない場合はユーザーに確認する。

### サーバー起動コマンドの検出

`references/server-detection.md` を読み、その手順に従ってサーバー起動コマンドとポートを検出する。

### agent-browser の確認

```bash
agent-browser --version
```

利用できない場合はユーザーにインストールを案内して中断する。

### gh の添付対応確認

証跡（スクリーンショット・録画）を Issue・PR に埋め込むには `gh` 2.99.0 以上の `--attach` が要る。有無を控え、Phase 5 の起票と呼び出し元の PR 更新で使う:

```bash
gh pr edit --help 2>/dev/null | grep -q -- '--attach' && echo "attach: yes" || echo "attach: no（gh 2.99.0 以上で対応）"
```

無くてもテストは続行する。証跡メディアはローカルに残さないので、添付できなければ証跡は残らない。レポートの証跡欄に「gh が `--attach` 非対応のため証跡なし」と記録し、完了報告で gh の更新を案内する。

コマンドの正は `../_shared/references/agent-browser.md`。**メインもサブエージェントも `agent-browser --help` / `skills get` を実行しない。** サブエージェントに渡すプロンプトには、このファイルの**絶対パス**を埋めて「これを読む」と指示する（本文は転記しない）。

### agent-browser プロセスのクリーンアップ

この実行の namespace `{ns}` を決め、前回の取り残しを閉じてからテストを開始する（`../_shared/references/agent-browser.md` の「実行ごとに namespace を分ける」）。以降の agent-browser コマンドとサブエージェントへの指示には、この `{ns}` を使う:

```bash
agent-browser session id --scope worktree --prefix manual-test
agent-browser --namespace {ns} close --all 2>/dev/null || true
```

クリーンアップが完了したら、そのまま次のステップ（タイムアウト設定）に進むこと。ここで中断しない。

### タイムアウト設定

agent-browser のデフォルトタイムアウトを設定する。25秒では不足するケース（SPA の初回描画等）があるため、テスト実行前に環境変数を設定する:

```bash
export AGENT_BROWSER_DEFAULT_TIMEOUT=20000   # コマンド単位: 20秒
export AGENT_BROWSER_IDLE_TIMEOUT_MS=120000  # daemon無操作: 2分で自動終了
```

### 成果物ディレクトリの決定

**呼び出し元が成果物ディレクトリを指定していればそれをそのまま使う。** 指定がない単体実行のときだけ既定値を使い、実行日を `YYYY-MM-DD` 形式のサブディレクトリにして複数回の実行結果を混在させない:

```bash
TEST_DATE=$(date +%Y-%m-%d)
```

| 呼び出し元 | 成果物ディレクトリ |
| --- | --- |
| issue-implement | `.thread/{Issue番号}/manual-test/`（Issue 単位で1回なので日付サブディレクトリなし） |
| 単体実行 | `.manual-test/{YYYY-MM-DD}/` |

以降、この保存先を `{output_dir}` と表記する。

証跡メディア（テストケースごとのスクリーンショットと、FAIL のテストケースの録画）は**リポジトリにも成果物ディレクトリにも残さない**。`{scratchpad}/media/`（`{scratchpad}` の定義は `../_shared/references/scratchpad.md`）に置き、Issue・PR に添付したら破棄する。呼び出し元が証跡ディレクトリを指定していればそれを使う。以降この保存先を `{media_dir}` と表記する。添付側がファイルを拾えるよう、ファイル名は次に固定する:

| ファイル | 内容 |
| --- | --- |
| `TC-{番号}.png` | テストケース終了時の画面 |
| `TC-{番号}-step{N}.png` | 期待結果と食い違ったステップの画面 |
| `TC-{番号}.webm` | FAIL の録画付き再実行の、セッション開始から終了までの録画 |

添付先と後始末は呼び出し元で分かれる:

| 呼び出し元 | 添付先 | `{media_dir}` の後始末 |
| --- | --- | --- |
| issue-implement | FAIL 分は Phase 5 で Issue に、全 TC 分は呼び出し元が PR に | 呼び出し元が PR 添付後に削除する（manual-test は消さない） |
| 単体実行 | FAIL 分の Issue のみ | Phase 6 で削除する |

使い捨てのファイル（サーバーログ・pid・確認用スクリーンショット）は `{output_dir}` ではなく `{scratchpad}` に置く（定義は `../_shared/references/scratchpad.md`）。

---

## Phase 2: シードデータ整備

ブラウザテストの前に、テストに必要なデータ・環境を整備する。テストケースの前提条件セクションと、プロジェクトのセットアップ手順から必要な準備を特定する。

サブエージェントを起動してシードデータを整備する:

```
あなたはテスト環境のセットアップを行うエンジニアです。

## 前提
- まずプロジェクトルートの CLAUDE.md を読み、プロジェクトの構成を把握する
- README.md のセットアップ手順も確認する

## テストソース
{テストソースのファイルパス}

## やること
1. テストソースを読み、テストケースの前提条件・テストデータを洗い出す
2. 以下の観点でデータ整備が必要か判断する:
   - DB のマイグレーション実行が必要か
   - シードデータ（初期データ）の投入が必要か
   - テスト用のユーザーアカウントや設定が必要か
   - 環境変数やコンフィグファイルの設定が必要か
   - テスト用のファイル（画像、CSV等）の配置が必要か
3. 必要な準備を実行する
   - プロジェクトに seed スクリプトがあればそれを使う
   - なければ手動で投入する（SQL実行、API呼び出し等）
   - .env.example → .env のコピーや環境変数設定
4. 整備後、テストに使うデータの一覧をまとめる

## 重要な原則
- 既存の本番データを上書き・削除しない
- プロジェクトの既存のシード仕組み（seed スクリプト、fixtures 等）を優先的に使う
- テスト用データは明確にテスト用とわかる値にする（test-user@example.com 等）
- 環境変数でテスト環境と判別できる場合は、テスト環境向けの設定を使う

## 出力
- 実行した準備作業の一覧
- 投入したシードデータの概要（テーブル名・レコード数等）
- テストで使用するアカウント情報（ユーザー名・パスワード等）
- 設定した環境変数（値はマスクしてキー名のみ）
- 問題があった場合はその内容と対処
```

シードデータ整備の結果は `{output_dir}/seed-data.md` に記録する。テスト実行時に参照する。

シードデータ整備が不要な場合（静的サイトのテスト等）はスキップする。

テスト実行中に追加のデータ投入・復元が必要になった場合も、同じ形でサブエージェントに委譲する。メインが API やブラウザで直接データを触らない。

---

## Phase 3: サーバー起動

### 空きポート検出

Phase 1 で検出したポートが使用中の場合、空いているポートを探す:

```bash
# ポートが使用中か確認
lsof -i :{port} 2>/dev/null

# 空きポートを探す（検出ポートから順に試す）
for port in {detected_port} {detected_port+1} {detected_port+2} ...; do
  lsof -i :$port 2>/dev/null || echo "Port $port is available"
done
```

### サーバーのバックグラウンド起動

検出したコマンドでサーバーをバックグラウンド起動する。ポートが変わった場合は環境変数やコマンドラインオプションで指定する:

```bash
# 例: Next.js
PORT={port} nohup pnpm dev > {scratchpad}/server.log 2>&1 &
SERVER_PID=$!
echo $SERVER_PID > {scratchpad}/server.pid
```

### ヘルスチェック

サーバーが応答可能になるまで待つ:

```bash
for i in $(seq 1 30); do
  curl -s -o /dev/null -w "%{http_code}" http://localhost:{port}/ && break
  sleep 2
done
```

30回（60秒）以内に応答がなければ、サーバーログを確認してエラーを報告する。

起動結果（PID、ポート、URL）を `{scratchpad}/server-info.md` に記録する。実行中の受け渡しにしか使わないので成果物には残さない。

---

## Phase 4: テスト実行

`references/test-execution.md` を読み、その手順に従ってテストを実行する。

テストケースごとにセッションを分離し、サブエージェントで実行する。**1体に載せるのは1テストケース。** 前提操作を共有するケースも1体にまとめず、共有する前提操作は Phase 2 のシードデータ整備で済ませる。サブエージェントが返すのは観測ログまでで、合否はメインが付ける。

メインは起動前に `mkdir -p {media_dir}` で証跡ディレクトリを作る。サブエージェントはテストケースごとに終了時のスクリーンショット1枚（食い違いがあればその時点でもう1枚）をそこに保存する。録画は FAIL の再実行でだけ撮る（下の「FAIL の録画付き再実行」）。撮影の手順は `references/test-execution.md` の指示テンプレートにある。**メインもサブエージェントも撮ったファイルを画像として読まない。** 判断は snapshot のテキストで行い、メディアは人が後から見る証跡として PR・Issue に添付し、添付が済んだら破棄する。

### 実行戦略: 原則として順次実行

テストケースは **1つずつ順番に実行する（順次実行）** のがデフォルト。並列実行はリソース消費・セッション衝突・デバッグ困難の原因になるため、原則として行わない。

並列実行を許容するのは以下の条件を **すべて** 満たす場合のみ:
- テストケースが完全に独立している（前後関係なし、共有リソースなし）
- テストケース数が6つ以上ある
- ユーザーが明示的に「並列でやって」と指示した

並列実行する場合でも **同時実行数は最大2つ** とする。

サブエージェントから観測ログが返ったら、メインが各ステップの期待結果と実際の結果を突き合わせて判定を付ける。**「だいたい合ってる」は FAIL。** 判定を付けた結果を `{output_dir}/results/TC-{番号}.md` に以下の形式で保存する:

```markdown
# TC-{番号}: {テスト名}

**結果**: PASS / FAIL
**実行時間**: {秒}
**セッション**: verify-tc-{番号}
**証跡**: TC-{番号}.png（食い違い時: TC-{番号}-step{N}.png、FAIL 時: TC-{番号}.webm）— 添付先の URL は report.md の証跡表

## 実行ログ

| # | 操作 | 期待結果 | 実際の結果 | 判定 |
|---|------|---------|-----------|------|
| 1 | {操作内容} | {期待結果} | {実際に確認できた内容} | PASS/FAIL |
| 2 | ... | ... | ... | ... |

## 失敗詳細（FAILの場合）

- **失敗ステップ**: Step {N}
- **期待**: {期待結果}
- **実際**: {実際の結果}
- **画面状態**: {失敗時点の snapshot から読み取れる画面の要点（表示されていた要素・エラーメッセージ等）}
- **録画付き再実行**: 再現 / 再現せず（{再実行で観測した内容}）
```

### FAIL の録画付き再実行

FAIL を付けたら、次のテストケースに進む前にそのテストケースを録画付きで1回だけ再実行する。新しいサブエージェントに同じ指示テンプレートを「録画: あり」で渡す。PASS のテストケースは録画しない。

- 初回の実行でデータが変わってテストの前提が崩れるなら、再実行の前に Phase 2 と同じ形でサブエージェントにデータを戻させる
- 合否は初回の判定のまま変えない。再実行の観測は `results/TC-{番号}.md` の「録画付き再実行」に書く
- 再実行で食い違いが再現しなくても録画は添付し、Issue 本文に「録画付き再実行では再現せず」と書く
- 録画の保存に失敗したら再試行せず、`results/TC-{番号}.md` に「録画なし（保存失敗）」と書いて次へ進む

全テストケースの実行が完了したら、サマリーを `{output_dir}/results/summary.md` に生成する:

```markdown
# テスト実行サマリー

**実行日時**: {日時}
**テストソース**: {ファイルパス}
**サーバー**: http://localhost:{port}

| TC | テスト名 | 種別 | 結果 | 失敗ステップ |
|----|---------|------|------|-------------|
| TC-001 | {名前} | 正常系 | PASS | - |
| TC-002 | {名前} | 異常系 | FAIL | Step 3 |

**合計**: {数} 件（PASS: {数} / FAIL: {数}）
**証跡**: TC ごとに終了時スクリーンショット、FAIL の TC は録画付き再実行の録画（PR・Issue に添付）
```

---

## Phase 5: 失敗分析＆Issue起票

FAIL のテストケースがない場合はこの Phase をスキップして Phase 6 へ進む。

### 原因分析

失敗した各テストケースについて:
1. 失敗ステップの snapshot 記録（テスト結果ファイルの「画面状態」）とサーバーログを確認する
2. 期待結果と実際の結果の差分を分析する
3. 以下のいずれかに分類する:
   - **実装バグ**: コードが仕様通りに動いていない
   - **テスト手順の問題**: テスト手順や期待結果が現実と合っていない
   - **環境問題**: データ不足・サーバー状態等
   - **デザイン差異**: 機能は動くがUI配置やテキストが異なる
   - **agent-browser 偽陽性**: 実ブラウザでは動くが agent-browser でのみ FAIL（下記 Known Issue 参照）

分析結果は `{output_dir}/results/analysis.md` に記録する。

#### Known Issue: agent-browser の `click @ref` が React の合成 onClick まで届かないことがある

**症状**: `agent-browser --namespace {ns} --session ... click @eN` でボタンをクリックしても、React の `onClick` ハンドラが発火せず、サーバーに POST も飛ばない。Console エラーも出ず、サイレントに失敗する。同セッションでナビゲーションリンク等の他のクリックは正常動作する。

**観察された例**: `/billing/closing` の「請求書を作成」ボタン（Issue #601、PR #605）。React Router v7 + React 19 + `useFetcher` の programmatic `fetcher.submit(formData, { method: "post" })` パターン。

**切り分け**: 実ブラウザ（Chrome / Safari 等）で同じ手順を踏み、PASS するなら agent-browser 起因の偽陽性。FAIL するなら実装バグ。**「実装バグ」と即断する前に、必ず実ブラウザでの再現確認を行う**。

**ワークアラウンド**: agent-browser 上で再現したい場合、`button.click()` を `eval` 経由で直接呼ぶと発火することがある。ただし synthetic event と trusted event の差があるため、それで通っても実装の動作保証にはならない。**切り分けには実ブラウザを使う**。

**Issue 起票の判断**: 偽陽性と確定したらコード側の Issue は起票しない（または既存 Issue を close）。テスト手順書側（testing.md）に「実ブラウザでの確認を必須」と注記しておくと再発防止に効く。

### Issue起票

失敗を次の打ち手につなぐのが狙い。Issueの量産・細分化ではない。

- **簡単なものは起票しない。** 即座に直せる軽微なもの（小さなデザイン差異、テスト手順の誤り、シードデータ不足のような環境問題）は、その場で直すかレポートに一行記録。起票はまとまった調査・修正が要るバグに絞る。
- **割らずにまとめる。** 同じ原因・テーマの失敗は1本に束ねる。
- **既存へのマージを優先。** `gh issue list --search "{キーワード}"` で関連を探し、近ければ既存にコメント追記。独立した新規だけ起票する。

```bash
gh issue create --title "{タイトル}" --body "$(cat <<'EOF'
## 概要

ブラウザ検証（manual-test）で以下のテストケースが失敗しました。

## 失敗したテストケース

| TC | テスト名 | 失敗ステップ | 分類 |
|----|---------|-------------|------|
| TC-{番号} | {テスト名} | Step {N} | {分類} |

## 再現手順

1. {サーバー起動コマンド}
2. {失敗ステップの操作手順}

## 期待される動作

{期待結果}

## 実際の動作

{実際の結果}

## 失敗時の画面状態

{失敗時点の snapshot から読み取れた画面の要点}

![TC-{番号} Step {N}]({media_dir}/TC-{番号}-step{N}.png)

## 原因分析

{原因分析の結果}

## 関連ファイル

- テストソース: {testing.md or manual-tests のパス}
- テスト結果: {output_dir}/results/TC-{番号}.md
- 検証レポート: {output_dir}/report.md

---
🤖 Generated by manual-test skill
EOF
)" --label "bug" --attach "{media_dir}/TC-{番号}-step{N}.png" --attach "{media_dir}/TC-{番号}.webm"
```

`--attach` は Phase 1 で確認した gh の対応があるときだけ付ける。本文中の `![...]({media_dir}/...)` と同じパス文字列を渡すと、gh がアップロード先の URL に書き換える。録画は本文で参照せず末尾に添付する。

起票したら `gh issue view {Issue番号} --json body -q .body` で書き換わった URL を控え、`{output_dir}/report.md` の証跡表に書く。

対応が無ければ `--attach` を外し、画像行と証跡表に「gh が `--attach` 非対応のため証跡なし」と書く。

ラベルについて:
- **実装バグ**: `bug` ラベル
- **テスト手順の問題**: `documentation` ラベル
- **デザイン差異**: `design` ラベル（なければ `bug`）
- **環境問題**: `infrastructure` ラベル（なければ `bug`）

ラベルがリポジトリに存在しない場合は `bug` にフォールバックする。

起票した Issue 一覧は `{output_dir}/issues.md` に記録する。

---

## Phase 6: レポート＆クリーンアップ

### 最終レポート生成

`references/report-format.md` を読み、最終レポートを `{output_dir}/report.md` に生成する。

### クリーンアップ

「タイムアウト＆スタック対策」セクションの Phase 6 クリーンアップ手順に従う。

証跡メディアは添付が済んだら破棄する。呼び出し元が証跡ディレクトリを指定していた場合は、PR に添付する呼び出し元が消すので削除しない:

```bash
rm -rf {media_dir}
```

### 完了報告

```
ブラウザ検証が完了しました！

## テスト結果
- テストソース: {ファイルパス}
- サーバー: http://localhost:{port}
- テストケース: {数}件（PASS: {数} / FAIL: {数}）

## 起票したIssue
- {Issue一覧、またはなし}

## 成果物
- レポート: {output_dir}/report.md
- テスト結果: {output_dir}/results/
- 証跡: 起票した Issue に添付（スクリーンショット {数} 枚 / 録画 {数} 本）
- Issue一覧: {output_dir}/issues.md（起票した場合）

{全PASSの場合}
すべてのテストケースがPASSしました。

{FAILがある場合}
失敗したテストケースについて以下のIssueを起票しました:
- #{Issue番号}: {タイトル}（{分類}）
```

---

## セッション管理

サブエージェント間でブラウザが衝突しないよう、必ず `--session` で分離する。あわせて **`--restore` を必ず付ける**。付けないとブラウザ再起動で Cookie が失われ、検証中に突然ログイン画面へ戻される（Issue #960。詳細は `../_shared/references/agent-browser.md`）:

```bash
agent-browser --namespace {ns} --session verify-tc-001 --restore open http://localhost:{port}
agent-browser --namespace {ns} --session verify-tc-002 --restore open http://localhost:{port}/login
```

命名規則:
- `verify-tc-{番号}` — テストケース実行
- `headed-verify` — headed モード（デバッグ時）

テスト完了後は必ずセッションを閉じる:

```bash
agent-browser --namespace {ns} --session verify-tc-001 --restore close
```

## タイムアウト＆スタック対策

テストが無限に止まらないための仕組み。agent-browser は25秒のデフォルトタイムアウトを持つが、テストケース全体・サーバー起動にもガードが必要。

### コマンド単位のタイムアウト

agent-browser の各コマンドは `AGENT_BROWSER_DEFAULT_TIMEOUT`（Phase 1 で設定済み）に従う。個別に長い待機が必要な場合は `wait` コマンドで明示的に待つ:

```bash
# 特定テキストの出現を最大15秒待つ
agent-browser --namespace {ns} --session {s} --restore wait --text "読み込み完了" --timeout 15000

# ページの描画完了を待つ
agent-browser --namespace {ns} --session {s} --restore wait --load networkidle
```

### テストケース単位のタイムアウト

サブエージェントに「1テストケースあたり3分（180秒）を超えたら打ち切って結果を返す」と指示する。サブエージェントへの指示テンプレートに以下を含める:

```
## タイムアウト
- このテストケースの実行制限時間は3分（180秒）。
- 各 agent-browser コマンドが20秒以上応答しない場合は、そのステップを「無応答」と記録し、次のステップに進む。
- 3分を超過した場合は、残りのステップをすべて未実行と記録し、セッションを閉じて結果を返す。
```

### サーバー起動のタイムアウト

Phase 3 のヘルスチェックは60秒（30回×2秒）で十分。追加の安全策として Bash の timeout コマンドを使う:

```bash
timeout 90 bash -c 'for i in $(seq 1 30); do curl -s -o /dev/null -w "%{http_code}" http://localhost:{port}/ | grep -q "200\|301\|302" && exit 0; sleep 2; done; exit 1'
```

### スタック検出＆リカバリー

テスト実行中にサブエージェントが応答しなくなった場合のフォールバック:

1. メインエージェントはサブエージェントの完了を待つが、**5分**を目安に異常と判断する
2. 応答がない場合は `agent-browser --namespace {ns} close --all` でこの実行の全セッションを強制終了する
3. そのテストケースを TIMEOUT として記録し、次のテストケースに進む

### Phase 6 での確実なクリーンアップ

個別セッションの close に加え、最後にこの実行の全セッションを一括クリーンアップする:

```bash
# この実行のセッションを確実に閉じる
agent-browser --namespace {ns} close --all 2>/dev/null

# サーバー停止
kill $(cat {scratchpad}/server.pid) 2>/dev/null
rm {scratchpad}/server.pid {scratchpad}/server.log 2>/dev/null
```

## agent-browser コマンドリファレンス

```bash
# ナビゲーション
agent-browser --namespace {ns} --session {s} --restore open {url}
agent-browser --namespace {ns} --session {s} --restore back
agent-browser --namespace {ns} --session {s} --restore reload

# 調査
agent-browser --namespace {ns} --session {s} --restore snapshot -i -c
agent-browser --namespace {ns} --session {s} --restore snapshot --ref @e3
agent-browser --namespace {ns} --session {s} --restore screenshot {media_dir}/TC-{番号}.png    # 証跡。画像として Read しない
agent-browser --namespace {ns} --session {s} --restore record start {media_dir}/TC-{番号}.webm  # 録画開始（セッションを開いた直後）
agent-browser --namespace {ns} --session {s} --restore record stop                                       # 録画停止・保存
agent-browser --namespace {ns} --session {s} --restore get text --ref @e5
agent-browser --namespace {ns} --session {s} --restore get url
agent-browser --namespace {ns} --session {s} --restore get title

# 操作
agent-browser --namespace {ns} --session {s} --restore click @e2
agent-browser --namespace {ns} --session {s} --restore fill @e3 "test@example.com"
agent-browser --namespace {ns} --session {s} --restore select @e4 --value "option1"
agent-browser --namespace {ns} --session {s} --restore check @e5
agent-browser --namespace {ns} --session {s} --restore press Enter
agent-browser --namespace {ns} --session {s} --restore scroll down 500
agent-browser --namespace {ns} --session {s} --restore hover @e6

# バッチ実行（複数コマンドを1回で実行、効率的）
agent-browser --namespace {ns} --session {s} --restore batch "open {url}" "snapshot -i"
agent-browser --namespace {ns} --session {s} --restore batch --bail "fill @e1 'test'" "click @e2" "snapshot -i"  # --bail: エラーで中断

# 待機
agent-browser --namespace {ns} --session {s} --restore wait 2000                              # ミリ秒待機
agent-browser --namespace {ns} --session {s} --restore wait --text "読み込み完了" --timeout 15000  # テキスト出現待ち
agent-browser --namespace {ns} --session {s} --restore wait --load networkidle                # ネットワーク安定待ち
agent-browser --namespace {ns} --session {s} --restore wait --url "**/dashboard"              # URL パターン待ち

# 要素の発見
agent-browser --namespace {ns} --session {s} --restore find role "button"
agent-browser --namespace {ns} --session {s} --restore find text "ログイン"
agent-browser --namespace {ns} --session {s} --restore find placeholder "メールアドレス"

# 状態確認
agent-browser --namespace {ns} --session {s} --restore is visible @e3
agent-browser --namespace {ns} --session {s} --restore is enabled @e4

# セッション管理
agent-browser --namespace {ns} --session {s} --restore close
agent-browser --namespace {ns} close --all          # この実行の全セッション一括終了
agent-browser --namespace {ns} session list         # この実行のアクティブセッション一覧
```

ref（@e1, @e2...）は snapshot で取得できる。操作対象は ref で指定するのが基本。

### ページ遷移後の待機

`sleep 1` ではなく `wait` コマンドを使うこと。描画完了の判断がより正確になる:

```bash
# NG: sleep で固定時間待つ
sleep 1

# OK: ネットワークが落ち着くまで待つ
agent-browser --namespace {ns} --session {s} --restore wait --load networkidle

# OK: 特定要素の出現を待つ
agent-browser --namespace {ns} --session {s} --restore wait --text "ダッシュボード"
```

---

## 原則

- **テストソースに忠実に実行する** — 手順を勝手に変えたり省略したりしない
- **スクリーンショット・録画を画像として読み込まない** — 判断は実行ログと snapshot（テキスト）で行う。撮ったファイルを `Read` すると画像が以降の全ターンで context に残り続けるので、テキストで判断できないときだけ1枚読む。証跡の撮影はテストケースごとに終了時1枚・食い違い時1枚、録画は FAIL の再実行での1本に限り、`{media_dir}` に保存して PR・Issue に添付する。それ以外のステップでは撮らない
- **サーバーは必ず停止する** — テスト終了後（成功・失敗問わず）サーバーを停止し、ポートを解放する
- **コードは修正しない** — 失敗を検出したら原因分析とIssue起票に留め、修正は別のIssue対応フローに委ねる
- **メディアをローカルに残さない** — スクリーンショット・録画は `{media_dir}`（scratchpad 配下）に置き、PR・Issue に添付したら破棄する
- **環境を汚さない** — テストで作成したデータ・ファイルは記録し、必要なら後始末する
- **snapshot は `-i -c`**（操作可能な要素のみ・空要素を除去）で取る。`--max-output` は最後の手段で常用しない
- **判断を挟まない連続操作は `batch` でまとめる** — `wait` を単独で実行しない
- 委譲方式・並列実行・中断時の再委譲・委譲時のコンテキストは `../_shared/references/subagent-policy.md` に従う
