# フロントエンドに「ユニットテスト」を書く: chrome-use test 詳解

バックエンドのコードにはユニットテストが下支えとしてあり、1行変えても慌てません。ではフロントエンドはどうでしょうか。多くの場合、まだ「ページを開いて、何回かクリックして、正しいかちらっと見る」という段階にとどまっています。リリースのたびに手作業でもう一度やり直すのは退屈ですし、漏れも起きやすいです。

chrome-use には `test` コマンドがあります。これは、この一連の手作業を、繰り返し実行でき、CI に入れられるスイートとして固定化するものです。つまり、フロントエンド画面にユニットテストを書くようなものです。グループ内で使った人の原文は「とても使いやすい」だったので、これが何か、どう実現しているのか、そして実際にどう使うのかを、独立した記事としてきちんと説明します。

![ブラウザテストレポート: 2件成功、1件失敗し、現場スクリーンショット付き](https://img.leeguoo.com/media/f4b81fbd-e6c7-4202-b4e8-145d58eeeffd/chrome-use-test-cover.png)

## それは何か

ひと言でいうと、「どのページを開き、どんな操作をし、何を期待するか」を YAML で記述し、その後 `chrome-use test suite.yaml` で一気に実行するものです。全部グリーンなら問題なし、赤くなったらどのアサーションが落ちたかを教えてくれます。

最小構成のスイートはこんな感じです。

```yaml
# smoke.yaml
suite: chatgpt smoke
setup:
  - account: chatgpt/huayue          # 任意: cookie-use に保存済みのログイン状態を注入
cases:
  - name: ログイン状態つきでホームを開ける
    steps:
      - open: https://chatgpt.com/
      - wait: { load: networkidle }
    assert:
      - url: { contains: chatgpt.com }
      - visible: "#prompt-textarea"
  - name: 入力欄が文字を受け取れる
    steps:
      - fill: { sel: "#prompt-textarea", text: "hi" }
    assert:
      - text: { sel: "#prompt-textarea", contains: hi }
      - eval: "!!window.__NEXT_DATA__"
```

実行します。

```bash
chrome-use test smoke.yaml                     # 分離されたブラウザを起動し、実行後に自動で閉じる
chrome-use test smoke.yaml --session default   # あるいは接続中の実際の Chrome 上で直接実行する
```

出力はテストレポートです。

```
suite: chatgpt smoke  (session cu-test)
  ✓ ログイン状態つきでホームを開ける   1.2s
  ✗ 入力欄が文字を受け取れる           0.8s
      assert text "#prompt-textarea" contains "hi" → got ""
      ↳ cu-test-artifacts/composer-takes-text.png
2 cases · 1 passed · 1 failed
```

1件でも落ちれば終了コードは 0 以外になるので、そのまま CI に入れてゲートとして使えます。失敗したケースでは、その場のスクリーンショットも自動で `cu-test-artifacts/` に保存されるため、あとから当時の画面がどうなっていたか確認しやすくなります。

ステップで使える動詞は `open`、`click`、`fill`、`type`、`press`、`wait`、`scroll`、`eval` です。アサーションは `url`、`visible`、`hidden`、`text`、`count`、`eval` に対応しています。日常的な「操作 + 検証」のニーズはだいたいカバーできます。

## 原理: なぜここまで軽くできるのか

`test` の実装はごく薄いレイヤーだけで、テスト DSL エンジンを一から別に作っているわけではありません。うまく省力化しているポイントは 3 つあります。

![原理図: YAML スイートを runner に渡し、各ステップで chrome-use コマンドを 1 回 re-invoke し、常駐 daemon の socket 経由でブラウザへ送る。アサーションはすべて eval にコンパイルされ、true/false を読み戻す](https://img.leeguoo.com/media/e3a80e6a-503f-43f0-9f7d-09cf5f3f08aa/chrome-use-test-principle.png)

**第一に、各ステップは chrome-use 自身のコマンドを再利用します。** YAML 内の `open`、`click`、`fill` といったキーは、そのまま chrome-use 既存のサブコマンドに対応しています。runner があるステップまで進むと、そのステップのパラメータを使って chrome-use バイナリを 1 回 re-invoke します。利点は、launch モード、daemon、`@ref` 参照、各種 flag の意味をすべてそのまま継承でき、テスト層で再実装する必要がないことです。chrome-use 本体で対応していることは、スイート内ですぐに使えます。

**第二に、アサーションは最終的に truthy な `eval` にコンパイルされます。** `visible`、`text`、`count` のどれを書いても、runner はそれを JavaScript 式に変換してページ内で評価し、ブール値を読み戻します。真なら成功、偽なら失敗です。そのためアサーション体系に専用の判定ロジックを大量に持たせる必要はなく、1 本の `eval` チャネルですべてのチェックを統一できます。

**第三に、daemon は常駐し、各ステップは socket の往復 1 回だけです。** 1 つのスイートを走らせる間、ブラウザセッションは再利用されます。daemon は session 全体で起動したままで、各 step は daemon にコマンドを 1 つ送り、結果を受け取るだけです。非常に高速で、ステップごとにブラウザを再起動することはありません。

デフォルトの動作では、新しい隔離ブラウザ（`cu-test` セッション）を起動し、実行後に閉じます。これにより毎回クリーンな環境で実行でき、結果も再現しやすいため CI に向いています。実際のログイン状態でテストしたい場合は、`--session <name>` で、すでに接続済みの Chrome にアタッチできます（`chrome-use extension connect` と組み合わせます）。ログインが必要なサイトでは、`setup` に `account: <id>` と 1 行書けば、cookie-use に保存済みのログイン情報がテストセッションへ注入され、スイート全体をログイン状態のまま実行できます。

## 実際にどう使うか

これを本当に価値あるものにするのは、「一度に大量の用例を書く」ことではなく、普段やっている作業の中に組み込むことです。

1. **まず一度、手動で確認する。** `open` / `snapshot` / `eval` を使ってページを一通り操作し、ついでに selector も把握します。どの要素か、どんな文言か、どの URL か。
2. **1 つの case として書く。** 先ほどの操作と期待結果を、YAML の 1 つの用例として落とし込みます。
3. **実行して色を見る。** 緑ならその導線は通っています。赤なら、どの assertion が落ちたかを直接教えてくれ、スクリーンショットも 1 枚添付されます。
4. **以後、回帰に出会ったら 1 つ追加する。** bug を 1 つ直すたび、「前回は大丈夫だったのに今回は壊れた」を 1 つ見つけるたびに、対応する case を追加します。suite は使えば使うほど厚くなり、価値が増していく資産です。

ログイン状態の検証や、重要な flow（トップページに入れるか、入力欄が文字を受け付けるか、注文 flow が最後まで通るか）を頻繁に確認する場面では、この仕組みによって「リリース前に毎回手で一通りクリックする」を「CI の中で自動的に一通り実行する」に変えられます。節約できるのは、リリースのたびに発生していた、あの繰り返し作業の手間です。

## 複数アカウント: cookie-use と組み合わせて行き来する

多くの test は複数アカウントなしでは成り立ちません。管理者には見える設定項目が、一般メンバーには見えてはいけない。A ユーザーが投稿したものを、B ユーザー側で受け取れるか。chrome-use test はこの部分を [cookie-use](https://github.com/leeguooooo/cookie-use) に任せています。各サイトのログイン状態を暗号化されたローカル DB に保存し、いつでも取り出せる tool です。

suite の中で `account: <id>` という行を使うと、保存済みのログイン状態を test session に注入できます。書ける場所は 2 つあります。

- `setup` に書くと、suite 全体がそのアカウントで走ります。
- ある case の `steps` に書くと、その step に到達したところで別アカウントに切り替わります。切り替えは、その case 内の次の `open` / 遷移時に有効になります。これが「行き来する」ということです。1 つの suite の中で、ある用例は管理者、次は一般メンバー、さらに次は管理者に戻す、という使い方ができます。

```yaml
setup:
  - account: myapp/admin           # まず管理者として起動
cases:
  - name: 管理者は設定入口を見られる
    steps:
      - open: https://app.example.com/
    assert:
      - visible: "#settings-tab"
  - name: 一般メンバーには見えない
    steps:
      - account: myapp/member      # メンバーに切り替えてからページを開く
      - open: https://app.example.com/
    assert:
      - hidden: "#settings-tab"
  - name: 管理者に戻す
    steps:
      - account: myapp/admin
      - open: https://app.example.com/
    assert:
      - visible: "#settings-tab"
```

前提として、cookie-use がインストール済みで、アカウントも保存されている必要があります。切り替えに失敗した場合（id の書き間違い、cookie-use 未インストールなど）は、その case がその場で失敗し、理由も表示されます。黙って skip されることはありません。なお、`setup` での注入は `test` のリリース時点からあり、case 内での切り替えは v1.5.58 で追加されました。

## 現在の境界

現在のバージョン（v1）はまだかなり控えめです。アサーションはすべての step が走り終わったあとにまとめて評価され、単一 case のリトライ、並列 case、スクリーンショットのベースライン比較はまだありません（内容を比較したい場合は、当面 `eval` アサーションでしのいでください）。step は順番に実行され、どこかの step が失敗すると、その用例は即座に失敗します。これらは既知の境界であり、日常的な回帰には十分使えます。

完全なコマンド説明は `chrome-use skills get test` でローカルに取得できます。2 つのリポジトリがあります。chrome-use は [github.com/leeguooooo/chrome-use](https://github.com/leeguooooo/chrome-use)、複数アカウントで使う cookie-use は [github.com/leeguooooo/cookie-use](https://github.com/leeguooooo/cookie-use) です。

関連ドキュメント（英語）：[chrome-use · Testing & Dogfood](https://chrome-use.leeguoo.com/en/testing.html)、[インストール](https://chrome-use.leeguoo.com/en/install.html)。
