SmartHR Advent Calendar 2024、14日目の記事です。昨日のご担当は tnagatomi さんでした!
株式会社SmartHRのプロダクトエンジニア @udzura です。労務基本機能を開発するチームで働いています。
今日は最近知った JXA で、Macのちょっとしたブラウザ操作を自動化する例をご紹介します。
JXA とは?
Macにはマシン上の操作を自動化するためのフレームワークが同梱されています。
例えばAutomatorのようなアプリを使って仕事を自動化するのですが、 AppleScript という言語もよく知られていました。このスクリプト言語を用いて特定のアプリケーションやウィンドウを操作したり、システム設定などの変更を記述することができます。
以下は開いているFinderの最初のウィンドウをドックに格納するスクリプトです。
tell application "Finder" set collapsed of Finder window 1 to true end tell
上記のスクリプトをファイルに保存して osascript というコマンドに渡せば実行ができます。
ですが、ご覧の通りAppleScriptはやや癖があり、覚えるのが結構大変なものでした。そこで満を持してなのか、JavaScriptで同様の操作が可能になる JXA (JavaScript for Automation) が登場しました。2014年に出たOS X Yosemiteから使えるようになったそうです。
以下は、先ほどのFinderをドックに格納するためのスクリプトをJavaScriptで書き直したものです。
const finder = Application("Finder"); const window = finder.windows[0]; window.collapsed = true;
これを osascript -l JavaScript とオプション付きのコマンドに渡して実行すればOKです。ちなみに、 osascript -l JavaScript -i というコマンドを打つことでREPLも立ち上げられるので、ちょっとした確認や作業にとても便利です。
JXAでSlackに貼るためのリンクを取得してみる
もう少し具体的な応用例をお見せします。
Slackでリンクを貼ると、OGPなどを取得してタイトルや画像を展開してくれます。しかし、社内向けサイトなんかの場合はSlackのクローラからアクセスができなくて、そういった自動展開が使えないことってありますよね。
そういう時単にリンクだけ貼っても不親切なので、例えば頑張ってタイトルを貼る... みたいな運用でカバーをしたりしがちです。
この問題へのアプローチ、色々方法はあるとは思うのですが、シンプルに「タイトルとリンクを取得してまとめてクリップボードに格納し、そのまま貼れるようにする」というスクリプトを書いてみます。
以下が実装例です。
#!/usr/bin/osascript -l JavaScript const chrome = Application("Google Chrome"); chrome.includeStandardAdditions = true; let w = chrome.windows[0]; let title = w.activeTab.title(); let url = w.activeTab.url(); chrome.setTheClipboardTo(`:github: [**${title}**](${url})`);
少しだけコードの補足をすると、まず、 includeStandardAdditions = true をしてあげると、ダイアログの表示、クリップボードやテキストスピーチ周りの操作などの便利命令の集合体(StandardAdditions.osax と呼ばれるもの)が使えるようになるそうで、ほぼ定型句的にセットしています。
WindowやTabの取り方はメソッド名で推測できると思いますが、 setTheClipboardTo() というメソッドも chrome インスタンスから呼んでいます。クリップボードに関する命令ではありますが、StandardAdditionsで有効にした命令はアプリから呼べるようです。
ES2015の文字列展開など最近の普通のJavaScriptを使えるので、だいぶ生産性が高そうな感じですね。
実際動かしてみると、こういう感じの文字列がクリップボードに入るので、
:github: [**Fix miscounting childrenNum in node16's shrink by udzura · Pull Request #28 · plar/go-adaptive-radix-tree**](https://github.com/plar/go-adaptive-radix-tree/pull/28)
あとはこれをそのままSlackに貼り付ければ、ちょっと親切にリンクを共有できます。
また、これは一つのスクリプトにまとめてどこからでも実行できますので、例えば Raycast のコマンド登録なんかとも相性がいいと思います。
JXAでフォームを自動入力する
もう少し凝ったことをしてみます。
例えばWebアプリケーションを開発していると、入力フォームの動作確認をしたり、定型作業をしたいことがあります。画面を立ち上げてポチポチと値を埋め続けるのも趣深いのですが、手作りの暖かさが不要ならば自動化したいところです。
以下は、 smarthr-ui を用いて作った、従業員情報の登録だけができる謎のアプリの画面です。
このアプリで一通り値を入れて送信するとか、あるいは失敗するという動作を目視で確認したい*1のですが、いろんな値のパターンがあってポチポチするのも大変...。みたいな検証の場面を想像してみてください。
JXAを使うとブラウザ上で任意のJavaScriptを動かせるので、フォームの値を自動入力することができます。
以下のようなJXAスクリプトを書いてみました*2。このスクリプトを実行すると、従業員情報入力画面を自動で開き、姓と名の値を自動入力します。
#!/usr/bin/osascript -l JavaScript const app = Application("Google Chrome"); app.includeStandardAdditions = true; var win = app.Window().make() win.tabs()[0].url = "http://localhost:3000/"; delay(1); win.activeTab.execute({ javascript: `document.getElementById("last_name").value = "従業院"; document.getElementById("first_name").value = "流水";` }); "OK";
このスクリプトを実行すると、ちゃんと従業員の「姓」と「名」を埋めることができることを確認できます。
他にも、クリックやキーボード入力なども動作させることができるそうです。色々とハックが捗りそうなツールだなと思いました。
最後にお断り的に書かせていただきますが、ウェブアプリケーションの画面のDOM構造を前提に自動操作をするのは、一般的にはアプリの都合で壊れやすかったり難しい面もあると思いますので、あくまでテストの補助用途や、自己責任での自動化にお使いください。
Macの各種操作を自動化するためのスクリプト JXA を紹介しました。いかがでしたか? 日々の生産性向上にご活用ください。
明日はd-haseさんの記事の予定です!