郭立 (leeguoo)

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

chrome-use test は、手作業のブラウザ点検を、繰り返し実行でき、CI に入れられる YAML スイートとして固定化するもので、フロントエンドにユニットテストを書くようなものです。それが何か、なぜ実装をここまで薄くできるのか、そして cookie-use と組み合わせて複数アカウントを行き来する方法を説明します。

2026年7月1日 · 記事 · 公開

このページの目次

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

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

ブラウザテストレポート: 2件成功、1件失敗し、現場スクリーンショット付き

それは何か

ひと言でいうと、「どのページを開き、どんな操作をし、何を期待するか」を 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/ に保存されるため、あとから当時の画面がどうなっていたか確認しやすくなります。

ステップで使える動詞は openclickfilltypepresswaitscrolleval です。アサーションは urlvisiblehiddentextcounteval に対応しています。日常的な「操作 + 検証」のニーズはだいたいカバーできます。

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

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

原理図: YAML スイートを runner に渡し、各ステップで chrome-use コマンドを 1 回 re-invoke し、常駐 daemon の socket 経由でブラウザへ送る。アサーションはすべて eval にコンパイルされ、true/false を読み戻す

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

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

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

デフォルトの動作では、新しい隔離ブラウザ(cu-test セッション)を起動し、実行後に閉じます。これにより毎回クリーンな環境で実行でき、結果も再現しやすいため CI に向いています。実際のログイン状態でテストしたい場合は、--session <name> で、すでに接続済みの Chrome にアタッチできます(chrome-use extension connect と組み合わせます)。ログインが必要なサイトでは、setupaccount: <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 の中で自動的に一通り実行する」に変えられます。節約できるのは、リリースのたびに発生していた、あの繰り返し作業の手間です。

多くの test は複数アカウントなしでは成り立ちません。管理者には見える設定項目が、一般メンバーには見えてはいけない。A ユーザーが投稿したものを、B ユーザー側で受け取れるか。chrome-use test はこの部分を 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、複数アカウントで使う cookie-use は github.com/leeguooooo/cookie-use です。

← 前の記事
ネットワークリクエストとレスポンスを変更する:chrome-use network route 詳解
次の記事 →
勤務中にこっそりWeChat、端末に移してdevツールに偽装する——その裏側の仕組み

コメント

コメントは即時公開されますが、ポリシー違反時は非表示になる場合があります。

最大 1000 文字。