click するとどうなるのか
DESCRIPTION
capybara + poltergeist な構成で、各種ブラウザへのイベントはどのように phantom js へ送られるかをソースコードを追って見る。TRANSCRIPT
![Page 1: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/1.jpg)
click 呼ぶとどうなるん?capybara + poltergeist ( + phantomjs ) の場合
![Page 2: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/2.jpg)
自己紹介
• Crowdworks
• 元々はテストエンジニア
• ちょっと前まではゲーム作ってた
• 興味ある技術: prolog, Haxe, elm-lang
![Page 3: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/3.jpg)
ネタバレ・このバグの誰か直して…
![Page 4: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/4.jpg)
いつも RSpec 中などでこんな風に使っている click や visit と言ったメソッド群は
![Page 5: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/5.jpg)
Capybara::Session の定数として NODE, DOCUMENt, SESSION のメソッドをまとめた
DSL_METHOD って名前で登録されていて
![Page 6: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/6.jpg)
Capybara::DSL でこんな風にメソッド作られているので
![Page 7: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/7.jpg)
include すると使えます。
![Page 8: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/8.jpg)
で、やっていることは、 current_session の同名メソッド呼び出しです。
![Page 9: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/9.jpg)
current_session は capybara.rb に実装されていますが、 app は rack アプリ current_driver は Capybara::Driver のインスタンスです。
と、いうわけで Capybara::Session のインスタンスが visit や click を持っている訳ですね。
![Page 10: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/10.jpg)
ちなみに Session は初期化のタイミングでテスト対象のラックアプリを立ち上げます。
![Page 11: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/11.jpg)
まぁ、こんな感じで。
![Page 12: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/12.jpg)
さて、実際のところ、Capybara::Session は DSL_METHODS のうち SESSION_METHOD のみを実装してます。
NODE_METHODS と DOCUMENT_METHODS は
![Page 13: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/13.jpg)
こんな風にして、インスタンス変数へ送ってやっています。 ここの current_scope と document は各ドライバのインスタンスですね。
![Page 14: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/14.jpg)
こんな感じで、ドライバは node を実装しているので、 ここから先は driver の話となります。
![Page 15: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/15.jpg)
いきなり Capybara::Poltergeist::Node にいきたいのですが、 その前に Poltergeist::Driver の初期化について。
Poltergeist ドライバは内部に app, server, client とかが見えるとおもいます。 app は rack アプリですが、 server や client は
Poltergeist 独自のもの。
![Page 16: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/16.jpg)
server はこんな感じ。 Poltergeist は中で WebSocketServer を立ち上げます。
![Page 17: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/17.jpg)
client は PhantomJS をラップした javascript アプリケーション
![Page 18: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/18.jpg)
つまり、Capybara::Driver の実装である Poltergeist は、click とかを呼ばれると
![Page 19: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/19.jpg)
こんな風に、Polteregesit 内部の WebSocket サーバーに click というコマンドを積んで
![Page 20: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/20.jpg)
PhantomJS を操る javascript アプリケーションがそれを受け取り
![Page 21: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/21.jpg)
なんやかんやで js のこの辺に行き着くと言う訳です。 で、やることは scroll して、
絶対座標をとって、ブラウザの絶対座標に click イベントを送る、と。
![Page 22: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/22.jpg)
mouseEvent はこんな感じで、 マウスの座標を動かして、実際のイベントを送る
![Page 23: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/23.jpg)
sendEvent はこう実装されていて、 ここの this._native が phantomJS なので、イベントが発火する訳です。
![Page 24: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/24.jpg)
さて、先ほどみた mouseEvent 。 この 47 行目と 51 行目の間にノードがアニメーションして、
位置がずれているケースがあります。 この場合、座標に基づく click は成功しますが、ノードへの click は失敗します。 このケースは、capybara, poltergeist, phantomjs のデバッグログを見ても、 全て正常に見えますが、直接 console.log を挟んで座標を見るとわかります。
![Page 25: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/25.jpg)
そんな訳で、昨年3月くらいからレアケースとしてこんなバグがありますが、 まだ解決していません。
![Page 26: click するとどうなるのか](https://reader033.vdocuments.net/reader033/viewer/2022042501/559b35e21a28ab2f638b47d4/html5/thumbnails/26.jpg)
crowdworks では、このバグを直せるエンジニアを募集しております。