まだまだやる事はあるのですが、とりあえず動いたので公開。
What
件名の通り。結果から言うと下図のようにしてくれるやつです。
Why
PhantomJSでページに注釈を付けてスクリーンショット撮るやつ - hitode909の日記 という素晴しい記事とツールを発見したのですが 仕事では Capybara 使っている (driver は selenium-webdriver or poltergeist) ので、Capybara から使えると便利だなと思ったので作ってみました。
How (for User)
examples にもあるやつです。
visit 'http://www.apple.com/jp/' within(:css, 'div.text') do page.attention_here page.attention_to(find(:css, 'img', match: :first)) end within(:css, 'aside') do within(:css, 'li.first-child') do page.attention_here end within(:css, 'li.third-child') do page.attention_to(find(:css, 'img')) end end
attention_here
- 現在いるスコープ (
<div>
だったり<pre>
だったり) に対して枠を付ける用途
- 現在いるスコープ (
attention_to(element)
- find した element (
button
だったり<input>
だったり) に対して枠を付ける用途
- find した element (
上のコードで、先程見せた図のように各要素へ赤枠をつけます。ここら辺の css は web-overlay を参考にしてます。
How (for Developer)
実装方法いろいろ試して今の形になったんですが、他によさそうな道筋があれば教えてください!!
attention
が呼ばれた場所(もしくは指定した node)の locator (xpath or css selector) を取得- 1 でゲットした locator を使い、
jQuery.find(locator).css(properties)
を実行 - 枠できた
現在のスコープの取得方法
ネストした within とか、そのスコープ内で指定した node の path ってどうやればわかるんだろうって思って、
最終的には Capybara::Node::Element
が持っていた @query (Capybara::Query)
を使用しました。
Capybara::Query は within や find した際の locator を持っているので、
例えば nested within の場合も、全ての within で指定された locator を連結してやればどうにかなるんじゃないかなーってことでこの方法でいきました。
ちなみに「全ての within」については Capybara::Session#scopes
を利用しました。
ちなみに、finder では基本 xpath or css で指定するため、混ざっていると単純に連結するだけでは動かないです。 これについては jQuery に加えて jquery-xpath を使っています。
xpath
→jQuery.xpath
css
→jQuery.find
みたいに切り替えてます。
枠の付け方
これも web-overlay をパク‥‥参考にしてるんですが、「赤枠」「若干透けてる背景色」「指定のノードの幅・高さ・位置」を持つ div を作成し、
$(document.body).append(div)
してるだけです。簡単!!
こっからはもう execute_script
無双です。
「そもそも jQuery や jquery-xpath をロードしてないサイトの場合どうすんの」という時は、リポジトリに置いてる2つの js を読み込ませてます。
※ 今気づいたけど p e
が残ってる…
Problem
いくつかやること残ってます
- おそらく within 範囲外(つまりトップレベル) で
attention_here
するとエラーになるはず - js を読み込んでくれない時のエラー処理
- selenium-webdriver の場合、ブラウザによって読んでくれない理由がまちまち。どれがどれか忘れました
- Poltergeist だと結構安定して動いてる模様
Capybara::Node::Finders#all
で取得したやつらをattention_to
すると先頭のやつの所にしか枠が付かない- 例えば
all(:css, 'img.profile')
とすると、全ての要素が持つ Capybara::Query はどれもimg.profile
を返すから。 - Capybara::Result とか弄くって順番情報持たせればどうにかなるかもしれないけど、まあ考え中
- 例えば
Conclusion
本当の目的は gnawrnip の画像で、どこを注目していいか一目でわかるようにしたいなーって思ってて、 Failed 時の current scope からある程度絞り込めるんじゃないかなーって妄想してるところです。動くといいですね。