Espresso webview support

[Espresso](https://code.google.com/p/android-test-kit/)の2.2からひっそりとespresso-webというWebViewサポートのモジュールが追加されているのですが、公式のドキュメントもサンプルもなかったので調査しました。
[サンプル](https://github.com/hotchemi/espresso-tasting/blob/master/app/src/androidTest/java/espresso/tasting/webview/ShowWebViewActivityTest.java)はこちら。

> 公式のドキュメントとサンプルが出たらそちらを正として考えてください。

## dependency

```groovy
dependencies {
    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile 'com.android.support.test:rules:0.3'
    androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2'
}
```

## package

`android.support.test.espresso.web`パッケージ以下に配置されています。

## overview

espresso本体の方では原則として

`onView(ViewMatcher).perform(ViewAction).check(ViewAssertion);`

という形式でコードを書いていくようなAPI設計になっており、espresso-webでもこれを踏襲した形式となっています。

`onWebView(ViewMatcher(※ここはoption)).withElement(Atom<R>).perform(Atom<E>).check(WebAssertion<E>);`

WebViewを指定し、更に内部でDOMのelementを指定し、performしてcheckという流れです。他にもできるのかもしれませんがミニマムな使い方としてはこれでいいのではないかと思います。
[Atom](https://developer.android.com/intl/ko/reference/android/support/test/espresso/web/model/Atom.html)というクラスが多用されていますがこれはJavaScriptのラッパーオブジェクトという事なので、JavaScriptを用いて動作や検証を実現しているという事が推測できます。

## withElement

`withElement(Atom<R>)`でelementを指定していきますが、[DriverAtoms](https://developer.android.com/intl/ko/reference/android/support/test/espresso/web/webdriver/DriverAtoms.html)にutil的なメソッドがあり、`findElement(Locator locator, String value)`や`findMultipleElements(Locator locator, String value)`等が利用できそうです。

```java
onWebView().withElement(findElement(Locator.ID, "email_input"))
```

## perform

同じく[DriverAtoms](https://developer.android.com/intl/ko/reference/android/support/test/espresso/web/webdriver/DriverAtoms.html)のメソッドを利用できそうです。`clearElement()`、`webClick()`、`webKeys(String text)`があります。これだけだと複雑な操作はできないので、今後追加されていくのでしょうか。

```java
private static final String EMAIL_TO_BE_TYPED = "email_to_be_typed";
onWebView().withElement(findElement(Locator.ID, "email_input")).perform(webKeys(EMAIL_TO_BE_TYPED));
```

余談ですが操作するメソッドの中身はどうなっているのかと思って調べてみると、

```java
    public static Atom<Evaluation> webKeys(final String text) {
        Preconditions.checkNotNull(text);
        return new SimpleAtom(WebDriverAtomScripts.SEND_KEYS_ANDROID) {
            public void handleNoElementReference() {
                throw new RuntimeException("webKeys: Need an element to type on!");
            }

            public List<Object> getNonContextualArguments() {
                return Lists.newArrayList(new Object[]{text});
            }
        };
    }
```
となっていて、`WebDriverAtomScripts.SEND_KEYS_ANDROID`の中を覗くと大量のJavaScriptがStringで定義されていて怖くなって閉じました。

## check

`Web.WebInteraction.check`はWebAssersitonを引数にとります。[WebAssersitons](https://developer.android.com/intl/ko/reference/android/support/test/espresso/web/assertion/WebViewAssertions.html)のwebContentメソッドが`Matcher<Document>`をWebAssersitonに変換してくれるので、[DomMatchers](https://developer.android.com/intl/ko/reference/android/support/test/espresso/web/matcher/DomMatchers.html)と併用して使います。

```java
onWebView().check(webContent(hasElementWithId("email_input")));
```

## まとめ

仕事でアプリを開発しているとWebViewというのはどうしても避けられない事もあるので地味に嬉しい機能です。競合のrobotiumは2年程前からサポートしていたので、乗り換えに当ってのハードルも低くなったと思います。
気になったのはcoreの方だとユーザーがCustomMatcherを定義できたりカスタマイズ性が高い印象ですが、espresso-web側は頑張ろうとするとJavaScriptをゴリゴリ定義しないといけなさそうで辛そうな印象でした(小並感)。