WebdriverIO検証

[WebdriverIO](https://webdriver.io/)を使ったE2Eテスト自動化の検討メモ

##### TypeScriptとasync/awaitのサポート

TypeScriptは[公式にサポートされている](https://webdriver.io/docs/typescript.html)。

[async/await にも対応している](https://webdriver.io/docs/api.html)が、コードを単純化するために[同期的に実装することが推奨されている](https://webdriver.io/docs/gettingstarted.html)。

* WebdriverIOのメソッドは `function() {}` 内で呼び出されると同期的に実行され、 `async function() {}` 内で呼び出されると非同期になる（ `Promise` を返却する）。
* 同期的な実装をサポートするために、`Promise` を返却する非同期メソッドを同期的に実行できる [browser.call](https://webdriver.io/docs/api/browser/call.html) メソッドが提供されている。

##### ひな型プロジェクト（Boilarplate Project）

[Boilerplate Project](https://webdriver.io/docs/boilerplate.html)をベースにプロジェクトを作成すると、TypeScriptやReportingライブラリを1からセットアップする手間が省ける。

WebdriverIO v5対応していてTypeScript + Mochaの組み合わせのものは以下の通り。

* https://github.com/jpolley/WebdriverIO_v5_TypeScript
* https://github.com/WillLuce/WebdriverIO_Typescript
* https://github.com/dalenguyen/WebdriverIO-TypeScript-Boilerplate

##### ローカルマシンで各ブラウザを使ってテストを実行する

[@wdio/selenium-standalone-service](https://www.npmjs.com/package/@wdio/selenium-standalone-service)を使うとnpmでWebDriverをインストールでき、テスト開始前にSeleniumサーバーを起動してくれる。

* インストールするWebDriverはwdio.conf.jsに設定する。
* Windows 10環境でChrome、Firefox、InternetExplorerを使う場合の設定例：

    ```javascript
    {
      services: ['selenium-standalone'],
      seleniumArgs: {
        drivers: {
          chrome: {},
          firefox: {},
          // Use ia32 version of IEDriver as x64 version is not stable.
          ie: { arch: "ia32" }
        }
      },
      seleniumInstallArgs: {
        drivers: {
          chrome: {},
          firefox: {},
          ie: { arch: "ia32" },
        }
      }
    }
    ```

    ※ 64bit版 IEDriverを使うとフォームへの文字列入力が遅くなるため、32bit版を指定している。

##### テスト開始前に処理を入れる

WebdriverIOの[Hooks](https://webdriver.io/docs/options.html#hooks)を定義するか、（テストランナーにMochaを使っている場合）[Root-level hook](https://mochajs.org/#root-level-hooks)を使えばよい。

ただし、MochaのRoot-level hookはspecファイルごとに実行される。（[参考](https://github.com/mochajs/mocha/issues/1460)）

##### スクリーンショットの比較による回帰検査を実装する

[Stack Overflow](https://stackoverflow.com/questions/37055507/webdriverio-take-full-page-screenshot)で議論されているライブラリはメンテされていなくWebdriverIO v5未対応のため、現状は自力でスクリーンショットを取得して比較する必要がある。

* [wdio-visual-regression-service](http://v4.webdriver.io/guide/services/visual-regression.html)：v4時点で開発が停止している。
* [webdrivercss](https://github.com/webdriverio-boneyard/webdrivercss)：v3以降対応していない。

WebDriverの[Take Screenshot](https://www.w3.org/TR/webdriver/#take-screenshot)では表示領域のみのスクリーンショットしか取得できないため、表示領域よりもページのサイズが大きい場合は、スクロールをしながらスクリーンショットを取る必要がある。

* 表示領域・ページサイズの取得：WebDriverのAPIでは取れないのでJavaScriptで取得する

  ```typescript
  const size = browser.execute(function() {
    return { 
      viewWidth: document.documentElement.clientWidth,
      viewHeight: document.documentElement.clientHeight,
      pageWidth: document.body.scrollWidth,
      pageHeight: document.body.scrollHeight,
    };
  });
  ```

* スクロール：サイズ取得同様にJavaScriptで実装する

  ```typescript
  browser.execute(function (x, y) {
    window.scrollTo(x, y);
  }, x, y);
  ```

  ※ Internet ExplorerでJavaScriptを実行する際は `browser.execute(() => {});` のようにアロー関数を使うとエラーになることに注意すること。


取得したスクリーンショットを比較は、[resemblejs](https://www.npmjs.com/package/resemblejs)を使うと不一致率を計算できる。