JavaのSeleniumラッパーの異常時挙動比較まとめ

JavaのSeleniumとSleniumラッパーの異常時の挙動の比較を行った結果をまとめました。
何かのご参考にどうぞ。
詳細なレポートについてはGitHubに[コード](https://github.com/kobanyan/selenium-wrapper-comparison)と[結果レポート](http://kobanyan.github.io/selenium-wrapper-comparison/#/)をアップしてあるので、そちらをご参照ください。

## 比較対象

- [Selenium](http://seleniumhq.org/) 2.48.2
- [Selenide](http://selenide.org/) 2.25
- [FluentLenium](http://www.fluentlenium.org/) 0.10.9

## 環境

- Mac OS X
- Chrome 47.0.2526.106
- ChromeDriver 2.20

## 比較内容

- 存在していないinputをクリアする
- 存在しているが見えないinput(`<input hidden>`)をクリアする
- 存在しているが有効でないinput(`<input disabled>`)をクリアする
- 存在しているが書き込み不可のinput(`<input readonly>`)をクリアする
- 存在していないinputが見えているかのアサーションを行う
- 存在しているが見えないinputが見えているかのアサーションを行う
- 存在していないinputが見えていないかのアサーションを行う

## コード

### クリアする

#### Selenium

```java
org.openqa.selenium.WebDriver driver;
driver.findElement(By.cssSelector("要素")).clear();
```

#### Selenide

```java
com.codeborne.selenide.Selenide.$("要素").clear();
```

#### FluentLenium

テストクラスは`org.fluentlenium.adapter.FluentTest`を継承しています。

```java
findFirst("要素").clear()
```

### 見えているかのアサーションを行う

#### Selenium

```java
org.openqa.selenium.WebDriver driver;
org.junit.Assert.assertTrue(driver.findElement(By.cssSelector("要素")).isDisplayed());
```

#### Selenide

```java
com.codeborne.selenide.Selenide.$("要素").shouldBe(com.codeborne.selenide.Condition.visible);
```

#### FluentLenium

テストクラスは`org.fluentlenium.adapter.FluentTest`を継承しています。

```java
org.fluentlenium.assertj.FluentLeniumAssertions.assertThat(findFirst("要素")).isDisplayed();
```

### 見えていないかのアサーションを行う

#### Selenium

```java
org.openqa.selenium.WebDriver driver;
org.junit.Assert.assertFalse(driver.findElement(By.cssSelector("要素")).isDisplayed());
```

#### Selenide

```java
com.codeborne.selenide.Selenide.$("要素").shouldNotBe(com.codeborne.selenide.Condition.visible);
```

#### FluentLenium

テストクラスは`org.fluentlenium.adapter.FluentTest`を継承しています。

```java
org.fluentlenium.assertj.FluentLeniumAssertions.assertThat(findFirst("要素")).isNotDisplayed();
```


## 結果

### 存在していないinputをクリアする

### Selenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
no such element: Unable to locate element: {"method":"css selector","selector":"存在していないinput"}
```

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.ElementNotFound`

#### 例外メッセージ

```
Element not found {存在していないinput}
Expected: exist
Screenshot: 
Timeout: 1 s.
```

### FluentLenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
Could not find element matching selector: 存在しないinput.
```

### 存在しているが見えないinput(`<input hidden>`)をクリアする

### Selenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element is not currently interactable and may not be manipulated
```

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.InvalidStateException`

#### 例外メッセージ

```
org.openqa.selenium.InvalidElementStateException: invalid element state: Element is not currently interactable and may not be manipulated
```

### FluentLenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element is not currently interactable and may not be manipulated
```

### 存在しているが有効でないinput(`<input disabled>`)をクリアする

### Selenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element is not currently interactable and may not be manipulated
```

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.InvalidStateException`

#### 例外メッセージ

```
org.openqa.selenium.InvalidStateException: InvalidElementStateException: invalid element state: Element is not currently interactable and may not be manipulated
```

### FluentLenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element is not currently interactable and may not be manipulated
```

### 存在しているが書き込み不可のinput(`<input readonly>`)をクリアする

### Selenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element must be user-editable in order to clear it.
```

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.InvalidStateException`

#### 例外メッセージ

```
org.openqa.selenium.InvalidStateException: InvalidElementStateException: invalid element state: Element must be user-editable in order to clear it.
```

### FluentLenium

#### 例外クラス

`org.openqa.selenium.InvalidElementStateException`

#### 例外メッセージ

```
invalid element state: Element must be user-editable in order to clear it.
```

### 存在していないinputが見えているかのアサーションを行う

### Selenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
no such element: Unable to locate element: {"method":"css selector","selector":"存在していないinput"}
```

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.ElementNotFound`

#### 例外メッセージ

```
Element not found {存在しないinput}
Expected: visible
Screenshot: 
Timeout: 1 s.
```

### FluentLenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
Could not find element matching selector: 存在しないinput.
```

### 存在しているが見えないinputが見えているかのアサーションを行う

### Selenium

#### 例外クラス

`java.lang.AssertionError`

#### 例外メッセージ

なし

### Selenide

#### 例外クラス

`com.codeborne.selenide.ex.ElementShould`

#### 例外メッセージ

```
Element should be visible {見えないinput}
Element: '<input type="text" displayed:false></input>'
Screenshot: 
Timeout: 1 s.
```

### FluentLenium

#### 例外クラス

`java.lang.AssertionError`

#### 例外メッセージ

```
Object is displayed
```

### 存在していないinputが見えていないかのアサーションを行う

### Selenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
no such element: Unable to locate element: {"method":"css selector","selector":"存在していないinput"}
```

### Selenide

成功

### FluentLenium

#### 例外クラス

`org.openqa.selenium.NoSuchElementException`

#### 例外メッセージ

```
Could not find element matching selector: 存在していないinput.
```

## まとめ

### Selenide

- Selenideが異常時に投げる例外はすべて `java.lang.Error` 系列のSelenideで定義している例外になる。
- 期待されている状態になるまでのウェイトがある。デフォルト4秒だが、`com.codeborne.selenide.Configuration.timeout`で変更可能。Selenideの[ウリ](https://github.com/codeborne/selenide/wiki/Selenide-vs-Selenium#5-ajax-support-waiting-for-some-event-to-happen)の一つ。
- 存在しない要素が表示されていないというアサーションは異常扱いされない。Selenideの[ウリ](https://github.com/codeborne/selenide/wiki/Selenide-vs-Selenium#9-assert-that-element-does-not-exist)の一つ。
- 異常時にスクリーンショットとhtmlがデフォルト保存される。`com.codeborne.selenide.Configuration.screenshots`で変更可能。保存先も`com.codeborne.selenide.Configuration.reportsFolder`で変更可能。Selenideの[ウリ](https://github.com/codeborne/selenide/wiki/Selenide-vs-Selenium#14-take-a-screenshot)の一つ。

### FluentLenium

- Seleniumと基本変わらないが、要素が見つからない時の例外のメッセージが若干異なる。
- Selenideと異なり異常時にデフォルトではスクリーンショットを取得しないが、テストクラスの`setSnapshotMode(org.fluentlenium.adapter.FluentTest.Mode mode)`で`TAKE_SNAPSHOT_ON_FAIL`をセットすることで取得可能。保存先は`setSnapshotPath(String path)`で変更可能。