Seleniumでクリックするやりかたがわかりません！ 教えてください！！

こんにちは！
わかりますか！！
わかりません！！！

わからないものは調べましょう、わかるようになります。

Seleniumでクリックするやりかた
================================

Seleniumは、Webブラウザーに標準的なREST APIっぽいのがあって自動操作できたらいいな、という感じのフレームワークでして、たとえばクリックするときの処理はクライアント側としては `/session/{session id}/element/{element id}/click` にHTTP POSTするだけです。詳細はW3C文書の説明をみてね！
https://www.w3.org/TR/webdriver/#element-click

![ブラウザ太郎](https://qiita-image-store.s3.amazonaws.com/0/33963/b22aada2-c069-1f95-914f-2d2b11f1bfe8.png)

ただ、一般的なWebブラウザーがもともとそんなAPIを持っているわけなくて、大方の場合はブラウザー固有の自動操作方式との相互変換を行ってくれるプロキシーを間にかますことになります。
 `chromedriver` とか `geckodriver` とか呼ばれるアイツらのことですね。話のわかるヤツだ。

![話のわかるアイツ](https://qiita-image-store.s3.amazonaws.com/0/33963/0a5cb69c-9507-5b7b-78be-f361f8f4299d.png)


アイツらのクリックするやりかた
===========================

じゃあ、そのアイツらがやっている「ブラウザー固有の実装」とやらでは、クリックはどうやってるんでしょうね？
わかりますか？ わかりません！！ 調べてみましょう！！！

オープンソースのものは、詳細に調べることができます。

## chromedriver

[Chrome DevTools Protocolの Input.dispatchMouseEvent](https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchMouseEvent) で、 `mousePressed` と `mouseReleased` を順に投げているだけです。
https://cs.chromium.org/chromium/src/chrome/test/chromedriver/chrome/web_view_impl.cc?sq=package:chromium&dr=C&l=408

`Input.dispatchMouseEvent` を受け取ったChrome側では、最終的にはBlinkのマウスイベント処理を呼び出しているようです。

## geckodriver

Marionette Protocolで `clickElement` を投げているだけです。
https://github.com/mozilla/geckodriver/blob/v0.20.0/src/marionette.rs#L1090

`clickElement` を受け取ったFirefox側では、最終的には [clickイベント](https://developer.mozilla.org/ja/docs/Web/Reference/Events/click) を発生させているだけのようです。

## IEDriverServer

デフォルトではWindowsのネイティブAPI [SendInput](https://msdn.microsoft.com/ja-jp/library/cc411004.aspx) で `MOUSEEVENTF_LEFTDOWN` と `MOUSEEVENTF_LEFTUP` を送信しています。
https://github.com/SeleniumHQ/selenium/blob/master/cpp/iedriver/CommandHandlers/ClickElementCommandHandler.cpp#L86-L87

capabilitiesで `nativeEvent` をfalseにすると動作が変わり、JavaScriptで [clickイベント](https://developer.mozilla.org/ja/docs/Web/Reference/Events/click) を発生させるようになるようです。
https://github.com/SeleniumHQ/selenium/blob/master/cpp/iedriver/CommandHandlers/ClickElementCommandHandler.cpp#L163-L167

## jBrowserDriver

[JavaFXの方のRobotクラス](http://hg.openjdk.java.net/openjfx/10-dev/rt/file/tip/modules/javafx.graphics/src/main/java/com/sun/glass/ui/Robot.java) の `mousePress` と `mouseRelease` を実行しているだけのようです。
https://github.com/MachinePublishers/jBrowserDriver/blob/master/src/com/machinepublishers/jbrowserdriver/Robot.java#L520-L521


やりかたはいろいろあっていい
===========================

オープンソースのものだけでも、やりかたは千差万別であることがわかります。でも、インターフェースとしてのWebDriverは規格化され揃っているので、ブラウザ側の実装の違いは隠蔽され意識しなくてもいいようになっています。

WebDriver規格に準拠していればいい、というところを活かして、もっとブラウザドライバ側の実装に多様性が生まれても良いよね、と最近思い始めています。
例えば、Internet Explorerに関してです。ほんとうに厳密な意味でユーザー操作をエミュレートしたいのか、単に [Trident](https://ja.wikipedia.org/wiki/Trident) でのレンダリング結果を得たいのか、どうにかしてヘッドレス動作させたいのか、などなど、本来ニーズは様々にあるかと思われる一方で、IEDriverServerだけではすべてのニーズに答えられていないのかもしれません。
実際、SeleniumからIEを扱うときにヘッドレス動作させたい、という人向けに、WindowsのCreateDesktop APIを利用した仮想デスクトップでヘッドレス風に実装してみた [Headless Selenium for Windows](https://github.com/kybu/headless-selenium-for-win) なんてものも作る人があらわれています。私はこの実装だけでは不足があると思っていますが、考え方の方向性としてはとても良くて、もっとこういうアプローチを取れる人が増えると良いなと思っています。

これじゃ足りないよな、というところに対して、なんとなく主語が大きくなってSeleniumダメだよねという結論に終わるのでなく、様々なアイディアが形になっていくことが当たり前になっていくと良いですね！