ほぼ表題の通りの内容で、Chrome拡張を作ってみた。
完成度としてはまだまだだけど、とりあえずざっくり触れる程度にはなったので公開した。
なんでこんなものを?
Capybaraのテストコードを書くのが面倒だなって感じることが多かったのが1つの理由。
TDD的に、先にテストコードを書いていけるのが理想だな〜とは思うものの、Webアプリケーションの開発をしていると、現実には一度は画面から一通り確認して、その後にfeature specを書く流れが多いように感じる。
そしてCapybaraでfeature specを書こうと思うと、
- 「これはテキストじゃなくてIDで選択しないとダメか〜」
- 「あ〜、これはfindしてからsetしないといけないのか〜」
という感じで、スムーズに書けない自分がいる。
そのあたりを都度試行錯誤しているのが面倒だな〜と思い始めて、「どうせ最初に一通り画面を触ってるんだから、そのときの操作がそのままfeature specとして出力できればいいじゃん!」と思って作り始めた。
あとは、Chrome拡張って興味があったけどなにげに作ったことがなかったので、やってみたかったというのもある。
つかったもの
- Vue
- Vuex
- events (https://github.com/Gozala/events)
ContentScript ⇔ Background ⇔ DevTools という流れでデータのやり取りを非同期で行う必要があった。
ごちゃごちゃしそうだったので、非同期になる箇所はすべてeventsでラップして、全データがDevTools上にVue&Vuexで構築たストアに集約するようにしたところ、わりとスッキリした。
役割としては、
- ContentScript : 操作の監視 & 情報を集約してeventsをpublish
- Background : ContentScriptとDevTools間を中継するのみ
- DevTools : ContentScriptのデータをsubscribeしCapybaraのコードを生成
みたいな感じになった。
できること
- テキストフォーム・テキストエリアの入力 → fill_in の生成
- ラジオボタンの選択 → choose の生成
- チェックボックスの選択 → check/uncheck の生成
- セレクトボックスの選択 → select の生成
- 要素クリック → find(xxx).click / click_link / click_button の生成
あたりはできている。
一番やりたかった部分として、何でその要素を特定できるかで生成コードが変わるようになってる。
fill_in '一意のラベル', with: '入力値' # ラベルで特定できる fill_in 'id', with: '入力値' # idで特定できる find('.class').set('入力値') # classで特定できる find(:xpath, '/div[1]/input[1]').set('入力値') # 上記全てが無理な場合はxpath
できないこと
まだまだ発展途上感がある。 現時点で以下は対応できていない。
- 画面遷移後の継続動作
visit
とかも作るfill_in
前の要素のclick
が不要なので省く- などなど..
というわけで
公開してあるので、興味のある方はどうぞ。
個人的には、label/id/class/xpathの自動判別が作れたのである程度満足しているけど、機能的にもっと充実させていきたい。
要望などがあればissueにもらえると嬉しいです。