E2Eテストの始め方 TestCafe① -導入編-

##TestCafeとは
アメリカのシステム開発会社が開発しているE2Eテストツール(2016年に登場した比較的新しいツール)
[公式ドキュメント](https://devexpress.github.io/testcafe/documentation/getting-started/)
###特徴
- **ES2017(async/await)を含む最新のJavascript機能をサポート、TypeScriptにも対応**
- **サポートブラウザが豊富**
    - Chrome、firefoxなどの主要ブラウザは網羅されており、IE11もサポートされています。
    - スマホやIEはテスト実行時に発行されるURLおよびQRコード(オプションで設定)を読み込むことで実機テストを行うことができる。 
- **非WebDriver依存**
    - 一昔前のE2Eテストツールは、各種ブラウザベンダ間の差異を吸収し抽象化して操作するためにWebDriverを使うのが常識でしたが、現在はブラウザ側がサポートするようになり、テストツール側が意識しなくてよくなりました。TestCafeもこれを前提に設計されています。
- **BDD([ビヘイベア駆動開発](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%98%E3%82%A4%E3%83%93%E3%82%A2%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA))に則ったテストコード**
    - UIテスト手順をメソッドチェーン形式で記述。これにより、ユーザー操作や外部仕様をまるで自然言語のようにコードで表現できるので、テストコードがそのままテスト仕様書となります。
- **BrowserStackとの連携をサポート**
    - E2Eテストの実行環境は開発マシンとは別に用意しておくことが望ましい。そうすることで開発（実装）と並行してテストを実行しやすくなります。
    - 参考：[BrowserStackを使ってブラウザテストに取り組んでいる知見](https://qiita.com/hotu_ta/items/759a64b1108860740894)
- **構築が簡単**
    - Seleniumではwebdriverのクライアントとテストを実行する各ブラウザのwebdriverのインストールが必要ですが、TestCafeはnpmでインストールするだけでOK。設定ファイルも必要なくテスト環境が整います。 

##セットアップ
npmもしくはyarnでtestcafeをインストール

```
$ npm install --save-dev testcafe
```
```
$ yarn add -D testcafe
```

##テストコードを書く
`test.js`など任意のファイルを用意しコードを書いていきます。
まずはtestcafeをインポート

```javascript:test.js
import {Selector} from 'testcafe’;
```

次に`fixture`メソッドでフィクスチャを宣言(定義)
**fixture**は**カテゴリ**のようなもので、テストケースをここで分類していきます。

```javascript:test.js
import {Selector} from 'testcafe’;

fixture('Getting started');
```
ちなみにタグ付きテンプレートリテラル構文でも書くことができます。

```
fixture`FormTest Start`;
```

次にfixtureメソッドの戻り値から`page`メソッドを実行します。
**page**はフィクスチャの**開始ページを宣言**するものです。こちらもテンプレートリテラルで書くことができます。

```javascript:test.js
import {Selector} from 'testcafe’;

fixture('FormTest Start');
  .page('https://example.com');
  // ↓テンプレートリテラル
  .page`https://example.com`;
```

###テストケースを書く
`test`メソッドでケース名とテスト内容(UI操作手順)を記述していきます。
第一引数にケース名を渡し、これが実行ログに表示されるので分かりやすい名前が良いです。
第二引数も記述することができ、テスト内容を関数として設定します。
**関数は戻り値がPromise型となっているのでasync/awaitを使います。**

```javascript:test.js
import {Selector} from 'testcafe’;

fixture('FormTest Start');
  .page('https://example.com');
  test('必須項目を入力し送信', async (t: TestController) => {
    const dataTarget = await Selector('[data-target-input]');
    const name = dataTarget.withAttribute('name', 'name');
    const mail = dataTarget.withAttribute('name', 'email');
    const phone = dataTarget.withAttribute('name', 'phone');
    const submitBtn = await Selector("button");
    
    await t
      .typeText(name, 'テスト名前')
      .typeText(mail, 'test_sample@gmail.com')
      .typeText(phone, '0312345678')
      .click(submitBtn.withExactText('送信'))
});
```
第二引数はなくてもOKです。その場合はこんな感じ

```
test('必須項目を入力し送信', async t => {
})
```

###セレクタについて
エレメントに関する情報を取得するには`Selector`を使用します。
ページ要素を識別し、それらに対してアクション(クリックやドラッグなど)を実行するか、アサーションでその状態を確認することができます。
今回は`withAttribute`メソッドを使い、指定したname属性と値が一致する要素を取得しています。
セレクタの詳細は次回の投稿で紹介します。

###画面操作について
今回の例として`click`と`typeText`を使用しています。
`click` ：クリックオプション
`typeText`：キー(テキスト)入力オプション
その他メソッドについても次回以降の記事で紹介します。

##テスト実行
package.jsonのscriptsにtestコマンドを追記し、コマンドラインから実行できるようにします。

```package.json
"scripts": {
  "formTest": "testcafe chrome e2e/test.js --page-load-timeout 5000 --speed 0.8",
}
```
コマンドに実行環境(ブラウザ)と実行ファイルのパスを指定します。※この2つは必須
今回はchromeを設定。
**インストールされている全てのブラウザ**でテストをする場合は`all`を指定します。

```package.json
"scripts": {
  "formTest": "testcafe all e2e/test.js --page-load-timeout 5000 --speed 0.8",
}
```

####オプション
`--page-load-timeout 5000`
　ページロード時のタイムアウト時間を指定できます。デフォルトは(3000ms)
`--speed 1`
　テスト実行速度を指定できます。デフォルトは最速(1)で実行されるので値を変更して遅くすることもできます。1が最速、0.01が最も遅い。**値を設定する際は1~0.01の間でなくてはいけません。**
`:headless`
　chrome、firefoxに対してこのパラメーターをつけるとUIシェルを表示せずにヘッドレスモードでテストが実行できます。


```
$ npm run formTest
```

コマンドを実行すると指定したブラウザが立ち上がりテストが実行されます。
<img width="1115" alt="スクリーンショット 2020-06-25 12.28.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174180/0605d079-1e76-2d92-1efe-72fa6bd509fb.png">

###リモートブラウザ上でテスト実行
ホストマシンがMacやLinuxの場合にIE11でテストを実行したい場合は、ブラウザに`remote`と指定することで**リモートアクセス用のURLを発行**できます。

```package.json
"scripts": {
  "formTest": "testcafe remote e2e/test.js",
}
```
同一のネットワーク上にいるマシンからであればOSやブラウザ問わずURLにアクセスすることでテストを行えます。
スマホ端末からアクセスする場合は、`--qr-code`オプションを指定することで**QRコードが発行**され、読み込むことでスマホからもテストができます。


```package.json
"scripts": {
  "formTest": "testcafe remote e2e/test.js --qr-code",
}
```


E2EテストツールというとSelenium、Puppeteerがよく聞きますが、他にないかなーと調べてTestCafeを知りました。(テストカフェ:coffee:って名前も可愛くて好きです:blush:)
まだまだ勉強中で基本的な使い方しか出来ていませんが、所感としては直感的に分かりやすいコードになるのでTestCafe良い感じです。
今回は備忘録としてセットアップをメインにまとめました。
オプションやセレクタ、メソッドはたくさんの種類があるので、よく使いそうなものを中心に今後の記事でまとめ、スクリーンショットを撮る方法についても書いていきたいと思います。

参考: [TestCafe で E2E テストを始めよう #1 - 概要説明 と Hello World](https://tech.recruit-mp.co.jp/front-end/post-20193/)