TestCafe超入門-マルチブラウザのE2Eをラクラク試す(WebDriver不要)

## 対象
- TestCafeについて興味がある方！
- マルチブラウザのE2Eを簡単に試したい方！
 
## TL;DR
```shell-session
$ npm install -g testcafe
$ vi test1.js
```

```javascript:test1.js
import { Selector } from 'testcafe'; // first import testcafe selectors 

fixture `Getting Started`// declare the fixture
  .page `https://devexpress.github.io/testcafe/example`;  // specify the start page

//then create a test and place your code there
test('My first test', async t => {
  await t
    .typeText('#developer-name', 'John Smith')
    .click('#submit-button')

    // Use the assertion to check if the actual header text is equal to the expected one
    .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');
});
```
`$ testcafe all test1.js`

## TestCafeとは
- エンドツーエンドのWebテストを自動化するNode.jsツール。
- TestCafeはWindows、MacOS、Linux上で動作
- デスクトップ、モバイル、リモート、クラウドの各ブラウザ（UIまたはヘッドレス）をサポート
- MITライセンスで自由に使用可能
- GitHubコミュニティで作成したプラグインを使用することも、独自のプラグインを作成することも可能

## どうしてTestCafeを使うのか？

##### 安定したテストと手動タイムアウトがなし
- テストが開始される前と各アクションの後に自動的にページの読み込みとXHRを待機
- ページエレメントが表示されるまで待機するアサーションあり
- 最大待ち時間の変更が可能で、テストのタイムアウトを設定できる

##### 最新のJSとTypeScriptのサポート
- ES2017（async / awaitなど）を含む最新のJavaScript機能をサポート
- TypeScriptを使用し厳密に型指定された言語でも開発ができる

##### コード内のJSエラーを検出する
- コード内のJSエラーを検出する(※ ただしテストは自動的にこける。これは無効にすることもできる)

##### テストを並列に実行可能
- 同じブラウザの複数のインスタンスを開いて並列テストを実行し、テスト実行時間を短縮できる

##### PageObjectパターンのサポート
- PageObjectパターンで読み取り可能なテストを実装することができる

##### 継続的な統合システムへの組み込みが容易
- TestCafeはコンソールから実行でき、継続的な統合システムへの組み込みが容易

## 実際に使ってみる

#### 1. インストール
`$ npm install -g testcafe`

#### 2. テストを作成
- `.js`のファイルか`.ts`のファイルを作成する必要がある  
  e.g., `$ vi test1.js`

```javascript:test1.js
import { Selector } from 'testcafe'; // first import testcafe selectors 

fixture `Getting Started`// declare the fixture
  .page `https://devexpress.github.io/testcafe/example`;  // specify the start page

//then create a test and place your code there
test('My first test', async t => {
  await t
    .typeText('#developer-name', 'John Smith')
    .click('#submit-button')

    // Use the assertion to check if the actual header text is equal to the expected one
    .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');
});
```

#### 3. テストを試す
`$ testcafe chrome test1.js`

参考:読み込み中
![スクリーンショット 2018-08-17 1.04.47.png](https://qiita-image-store.s3.amazonaws.com/0/210923/08501609-76ba-8310-f58d-d6ec83dfe340.png)

参考:テスト中
![スクリーンショット 2018-08-17 1.05.45.png](https://qiita-image-store.s3.amazonaws.com/0/210923/e1cb43b8-8274-9fc9-a1b9-d26ee643bebf.png)

アウトプット例:

```
 Running tests in:
 - Chrome 68.0.3440 / Mac OS X 10.13.4

 Getting Started
 ✓ My first test


 1 passed (4s)
✨  Done in 32.11s.
```


## 簡単にテストの構造と作り方を解説
1.　testcafeモジュールをimport
   
   ```
   import { Selector } from 'testcafe';
   ```
2.　フィクスチャ関数を使用してフィクスチャを宣言

   ```
   fixture `Getting Started
   ```

3.　page関数を用いてスタートページを指定

   ```
   fixture `Getting Started`
     .page `http://devexpress.github.io/testcafe/example`;
   ```

4.　次に、テストコードを入力できるテスト関数を作成します。

   ```
   import { Selector } from 'testcafe';

   fixture `Getting Started`
     .page `http://devexpress.github.io/testcafe/example`;

   test('My first test', async t => {
     // Test code
   });
   ```

## マルチブラウザで試す
- TestCafeにおいて、マルチブラウザの検証は、**ブラウザをカンマ区切りで指定するだけで良い**  
```
$ testcafe chrome,firefox test1.js
```

#### インストールされている全てのブラウザのテストを試す
- ブラウザ指定の部分で**all**を指定すれば  
  インストールされているすべてのブラウザでテストを実行可能

  ```
  $ testcafe all test1.js
  ```

#### パスで特定のブラウザを指定して実行も可能
```
$ testcafe 'path:`/Applications/Google Chrome.app`' test1.js
```

## ヘッドレスモードでのテスト
- Google ChromeまたはFirefoxでは`:headless`接尾辞を使用することで  
  ヘッドレスモードでテストを実行することが可能。

  ```
  testcafe 'firefox:headless' test1.js
  ```

## Chromeでのデバイスのエミュレーションモードの使用
- `:emulation` とデバイスパラメータを指定することで、  
   Chromeでのデバイスのエミュレーションモードでテストを実行することができる  
  
  ```
  testcafe "chrome:emulation:device=iphone 6" test1.js
  ```

## 引数付きブラウザの実行
- 指定したブラウザの引数を渡す必要がある場合は、  
  ブラウザのエイリアスの後に記述できる。  
  ※ ブラウザー呼び出しとその引き数を引用符で囲むこと

```
  test-chrome-add-option" : "testcafe 'chrome --start-fullscreen' test1.js
```