Playwrightとzxでブラウザ操作とCLIを連携する

タイトル以上の内容はあまりないのですが、やっていて面白かったのでメモ残し。
業務用ツールの画面上の値を取得してローカルPCの環境変数に設定しつつCLIでコマンドを実行する、ということをしていました。業務用ツールという性質上詳細は記載できないのですが、手順を残しておきます。

手順

使用したライブラリなど

名称 リンク 補足
Playwright https://playwright.dev/ E2Eテストを行うためのライブラリとして有名ですね。もちろんブラウザ操作の自動化だけでも有用です。
bun https://bun.sh/ JavaScriptのランタイム...というだけではなくall-in-oneのツールとのこと。TypeScriptを自分でトランスパイルしなくても実行してくれるのが嬉しい。肉まんかわいい。
zx https://github.com/google/zx JavaScriptでシェルをかけるツールです。バックドアが仕込まれていたのはxzです。
dprint https://dprint.dev/ Rust製のコードフォーマッターです。KAKEHASHIさんのテックブログで知りました。

実はzxははじめ使う予定はありませんでした。ブラウザ操作が必須だったのでPlaywrightを選択し、bun shellのアナウンスを耳にしていたのでランタイムにbunを選びました。しかし結局bunのみで実現ができそうになかった*1のでzxを使うことにした、という流れです*2

bun.sh

zxを利用すると、例えばjavascriptからaws cliを利用する、とかもできます。これまでだったら何のために?と感じたと思いますが、ブラウザ操作が前提にある場合は非常に便利と感じました。

dprintはおまけです。Biomeも少し気になっていますが、formatを自動かつサクッとやりたいだけなのでdprintを使いました。

なお筆者のPCはApple SiliconのMacBookです。

セットアップ

bun init

playwright

bun create playwright

playwrightの設定はデフォルトのままです。E2Eテストをしたいわけではないのでtests, test-examplesフォルダは削除します。そしてコードを生成するためにpackage.jsonにscriptを定義します。

{
  "scripts": {
    "record": "npx playwright codegen 対象のサイト",
  }
}

この状態でbun recordを実行すればブラウザが立ち上がり、操作が記録されます。こうして作成されたコードを元にスクリプトを作成します。ここではindex.tsとします。

注意点として、playwrightは新規でブラウザを起動するため、認証のセッションは維持できません。 Cookieによるセッション認証であればコード内でCookieを設定する必要があります。あるいはクライアント証明書が必要な場合は、別の工夫が必要です。

Cookieを設定する例

const context = await browser.newContext();
await context.addCookies([
  {
    name: cookie_name,
    value: cookie_value,
    domain: your_domain,
    path: path,
    expires: expire_period,
  },
]);

MacかつChromeの場合)クライアント認証を自動で選択する(AutoSelectCertificateForUrlsを設定する)ためには、以下のコマンドをCLIで実行します。

defaults write com.google.Chrome AutoSelectCertificateForUrls -array-add -string '{"pattern":"https://example.com","filter":{"ISSUER":{"CN":"Example CA"}}}'

参考:Mac OS XのChromeでAutoSelectCertificateForUrlsを設定する

zx

TypeScriptファイル内でシェルを実行するためにzxを用意します

bun add zx

シェルの実行は以下のように行います。

await $`echo "export ENV=${env}"`;
await $`echo "export MY_ENV=${my_env}" >> ~/.zshrc`;

なお、zxは新しい子プロセスでシェルコマンドを実行するため、スクリプトを実行しているシェルセッションには影響を与えません。したがって上記のようにecho "export ENV=${env}"をzxで実行しても親のセッションでは利用できません。利用できるようにするためには、.zshrcなどに書き込んだ上で、sourceするか新しいセッションを開始する必要があります。

dprint

bun add dprint --dev
{
  "scripts": {
    "fmt:init": "npx dprint init",
    "fmt": "npx dprint fmt",
  }
}

formatterの設定を初期化。

bun fmt:init

// 適当に必要なものを選択

formatを実行。

bun fmt

まとめ

TypeScriptでブラウザ操作もCLI操作もできるのありがたい!

参考まとめ

zx

google/zx

zxの紹介 〜 さよならシェルスクリプト そして伝説へ|Offers Tech Blog

zx を使って JavaScript でスクリプトを書いてみる - Webdelog

bun shell

$ Shell – API | Bun Docs

The Bun Shell | Bun Blog

Implement commands in Bun shell · Issue #9716 · oven-sh/bun · GitHub

Bun でクロスプラットフォームなシェルスクリプト

クライアント証明書

Mac OS XのChromeでAutoSelectCertificateForUrlsを設定する #MacOSX - Qiita

Chrome Enterprise のポリシーリストと管理 | ドキュメント

*1:bun shellで使用できるコマンドはIssueにまとまっています。Implement commands in Bun shell

*2:追っていないのですが、Denoにもdaxというのがあるようですね