jBrowserDriverに挑んでみよう

この記事は[Selenium/Appium Advent Calendar 2016](http://qiita.com/advent-calendar/2016/selenium_and_appium)の1日目の記事です。

こんにちは！今年もSelenium/Appium界隈はいろいろありましたね！！
でもメジャーどころの話はみんな[12月18日の勉強会](https://seleniumjp.connpass.com/event/45208/)で話すことにします！！！
今年のAdvent Calendarは私はニッチな話しか書きませんよ！！！！

ところで皆さんPhantomJSDriverに███してませんか！！！！！
（~~Qiitaに消されないための配慮が生成されました~~）

Seleniumで常用できるヘッドレスブラウザーの選択肢ってもうちょっとあってもいいんじゃないかと思ったりするんですが、メジャーどころでは[Google Chromeがヘッドレス動作に対応するんだかしないんだか](http://qiita.com/devneko/items/51f2e114a7e0b3389435)という話があるくらいで、いまいち他の選択肢に欠けて、ちょっとした閉塞感ですよね。

私は最近になってようやく、jBrowserDriverなんてものもあるんだよ、ということを知って、今後の有力な選択肢にならないかなーと日々少しずつ調べて検討しています。
そんなわけでAdvent Calendarの1日目はjBrowserDriverに挑んでみます。

jBrowserDriverってなに？
=========================

https://github.com/MachinePublishers/jBrowserDriver

JavaFXに含まれるブラウザーコンポーネント「[WebView](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/web/WebView.html)」をブラウザーとして利用する、WebDriverの実装のひとつです。
最初のリリースは2015年2月で、わりと最近できたものです。

JavaFXに依存する都合上、Javaバインディングにしか対応していません。みんなJavaをやろう！！！！

jBrowserDriverのうれしいところ
==============================

## 環境構築が手軽

JavaFXがインストールされている環境であれば他にブラウザーなどインストールしなくてもすぐに使えるので、とかく手間がかかりがちなSelenium実行環境の構築で一手間も二手間も減らすことができます。

どういう状態なのか もう少しちゃんと言いますと、JavaFXはOracle JDKに同梱されていますので、JavaでSeleniumやりたいなーと思って自分のPCにOracle JDKをインストールした時点で既にjBrowserDriverの実行環境が構築できている、ということです。
手軽！！！

## ヘッドレスブラウザーとしての動作が可能

既定ではヘッドレスブラウザーとして動作します。CI環境での利用時も安心ですね。
しかも、指定すればGUIありのブラウザーとしても動作させることができます！
万能か！！！

## WebKitベース

JavaFXのWebViewコンポーネントはWebKitベースです。
独自仕様の少ない、ごく一般的なブラウザーとしての動作を期待できます。

## Actions対応

まだちゃんと全部確認できていませんが、Actionsにも対応しているようです。

jBrowserDriverやってみよう
===========================

では、能書きはこれくらいにして、試しに使ってみましょう。
jBrowserDriverの実行にはJava 8が必要になりますので注意してください。~~Java 7は捨てろ！！！！~~

Mavenプロジェクトであれば、次のような依存性設定を `pom.xml` に書いておけば利用可能になります。

```xml
<dependency>
    <groupId>com.machinepublishers</groupId>
    <artifactId>jbrowserdriver</artifactId>
    <version>0.17.1</version>
</dependency>
```

次に、Javaのコードを書いてみましょう。
既定値で実行する分には、特に他のWebDriver実装と変わりない感じで利用できます。

```java
JBrowserDriver driver = new JBrowserDriver();
```

いろいろと既定値以外の設定にしたい場合は、
他のWebDriver実装と同様に Capabilities をコンストラクターに食わせればOKです。便利クラスの[Settings.Builder](http://machinepublishers.github.io/jBrowserDriver/com/machinepublishers/jbrowserdriver/Settings.Builder.html)を使うと、メソッドチェーンでサクサクCapabilitiesを書けます！

```java
Capabilities capabilities = Settings.builder()
        .headless(true)
        .saveAttachments(true)
        .screen(new Dimension(1200, 700))
        .ssl("trustanything")
        .timezone(Timezone.ASIA_TOKYO)
        .buildCapabilities();
JBrowserDriver driver = new JBrowserDriver(capabilities);
```

jBrowserDriverのはまりどころ
===========================

## ファイルダウンロードにかなりクセがある

PhantomJSと違って、一応ファイルダウンロードに対応しています。
しかし、現状(v0.17.1)の実装は普通のブラウザーとかなり違っています。

* 元のファイル名と違う、metadataとcontentの2種類のファイルが出力されます。
    * metadataには、Content-typeやファイル名などが記載されています。
    * contentがファイル実体です。
* 上記の2種類のファイルは一時ファイルであり、実行プロセスが完了すると消えてしまいます。

なんだこりゃ！！！

## Linux環境での環境構築には注意が必要

LinuxでJDKをインストールしよう、となったとき、皆さんは無意識にOpenJDKのインストールで済ませているかもしれませんね。
しかし、OpenJDKにはJavaFXが含まれていません！なんらかJavaFXの実行環境も追加で構築する必要があります。

OpenJDKなんだから、JavaFXのオープンソース実装であるOpenJFXを使えばいいだろ、などと安直に考えてしまいます。たしかに [公式のREADME](https://github.com/MachinePublishers/jBrowserDriver/blob/master/README.md) にも案内がある通り、Ubuntu Linux 16.04以降であればOpenJFXのインストールはaptでできて簡単なのですが、Ubuntu Linux 14.04以前やRHEL/CentOSなどではソースコードからのビルドが必要になってしまいますので、けっこう環境を選んでしまいます。~~そんなOS捨ててしまえばいいんですよ~~

このような環境では、無理せずにOracle JDKのLinux版をインストールした方が手っ取り早いでしょう。

## 動作がかなり遅い

後述のベンチマークではっきりわかりますが、他のWebDriver実装に比べてダントツで動作が遅くてとても残念です！！
手軽さとのトレードオフですね...

## 微妙に動作不安定

繰り返し使っているうちに、たまに謎の例外を吐いて死んでしまうときがあります。
OpenJDK + OpenJFX環境よりも、Oracle JDK環境の方が不安定かも...？

## OS標準のフォントが使われなくて表示が微妙

これ、WebViewの設定しだいでどうにかなるはずなのですが、jBrowserDriverとしてどうやったらいいのか、私はいまのところよくわかっていません。

## GUIつき動作のときに、 `click()` でマウスポインターを持っていかれる

ぐぬぬ...
ヘッドレスブラウザーとして扱うのが本筋のようです。

ベンチマーク
=============

[日本Seleniumユーザーコミュニティの提供するサンプルページ](http://example.selenium.jp/reserveApp/)上で基本的なAPIを100回実行して、1回あたりの平均値を取得するだけの簡易ベンチマークをやりました。
https://github.com/hiroshitoda/WebDriverBenchmark

実行環境は手元のMacBook Pro実機で、スペックは次の通りです。

| | |
|:--|:--|
| CPU | Intel Core i5 2.5GHz |
| メモリー | 16Gbytes |
| OS | macOS Sierra 10.12 |
| JDK | 1.8.0_101-b13 |

結果は次の通りでした。
なんか...すげー遅くないか！？

| | | | | | |
|:--|:--|:--|:--|:--|:--|
| | jBrowserDriver | ChromeDriver | FirefoxDriver via GeckoDriver | PhantomJSDriver | SafariDriver |
| WebDriver.get | 1539ms | 289ms | 249ms | 49ms | 48ms |
| WebDriver.findElement(By.Id) | 4ms | 13ms | 10ms | 10ms | 7ms |
| WebDriver.findElement(By.cssSelector) | 3ms | 11ms | 9ms | 8ms | 5ms |
| WebElement.clear | 2ms | 64ms | 21ms | 21ms | 9ms |
| WebElement.sendKeys | 713ms | 70ms | 23ms | 32ms | 66ms |
| WebElement.click | 55ms | 55ms | 23ms | 39ms | 10ms |
| TakeScreenshot.getScreenshotAs | 419ms | 119ms | 45ms | 50ms | 24ms |

動作速度が問われるような環境には、現状では残念ながら導入が難しいですね。
今後に期待しつつ、使えるところでは使っていきましょう。

今回はここまで
===========================

次回はjugemixです。よろしくお願いします。
[Selenium/Appium Advent Calendar 2016](http://qiita.com/advent-calendar/2016/selenium_and_appium)はまだまだ君の挑戦を待っているぜ！