testcafeを使ってみる


ブラウザの自動テストツール、testcafeを試したのでメモ。

## testcafeインストール

```bash
$ mkdir learning_testcafe
# 適当なフォルダを用意
$ cd learning_testcafe
$ npm init --yes
$ npm install testcafe
```

ちなみに、最初testcafeというフォルダ名にしたら、失敗した。
フォルダ名がパッケージ名と一緒だとダメっぽい？

参考：[npm install をしたら「npm ERR\! code ENOSELF npm ERR\! Refusing to install package with name "gulp" under a package」みたいに怒られたとき \- 約束の地](https://obel.hatenablog.jp/entry/20171122/1511321417)


## フォルダ構成

```bash
$ ls -1
node_modules
package-lock.json
package.json
test.js
```

なお、あとで出てくる `takeScreenshot` を使った場合は、
自動的に `./screenshot` というフォルダができます。

## package.json編集

testcafeを走らせる際に、scriptsの中に ` "testcafe": "testcafe",` の一文を追加します。

```diff

{
  "name": "learning_testcafe",
  "version": "1.0.0",                                                                                                  
  "main": "index.js",
  "scripts": {
+    "testcafe": "testcafe",
    "test": "echo \"Error: no test specified\" && exit 1"
  },  
  "keywords": [], 
  "author": "", 
  "license": "ISC",
  "description": "", 
  "dependencies": {
    "testcafe": "^1.6.0"
  }
}

```

## testcafeのコードを書く

画面テストのコードを書きます。

```js:test.js
import "testcafe";
import {Selector} from "testcafe";

// 最初に行くサイトを指定
fixture("Google Search")
    .page("https://www.google.com/");

// テストケース1
let testPattern = "Googleで検索できること";
test(testPattern, async (t) => {
    let googleSearchTextArea = Selector(".gLFyf")
    let googleSearchButton   = Selector(".gNO89b")
    // テスト開始
    await t
      // 基本的な検索をしてみる
      .typeText(googleSearchTextArea, "TestCafe")
      .click(googleSearchButton)
      // アサーション。titleタグのテキストがイコールだったらテストOK
      .expect(Selector("title").innerText).eql('TestCafe - Google 検索')
      // 結果をスクショする
      // pathの指定が無ければ、.screenshots/ の作成される
      .takeScreenshot(testPattern + '.png')
});

// テストケース2
let testPattern2 = "2回続けて検索できること";
test(testPattern2, async (t) => {
    let googleSearchTextArea = Selector(".gLFyf");
    let googleSearchButton   = Selector(".gNO89b");
    let googleSearchButtonNotFirstSite = Selector(".rINcab");

    // テスト開始
    await t
      // -------------------
      // 最初の画面で検索
      // -------------------
      // 検索実施
      .typeText(googleSearchTextArea, "TestCafe selenium")
      .click(googleSearchButton)
      .expect(Selector("title").innerText).eql('TestCafe selenium - Google 検索')
      .takeScreenshot(testPattern2 + '_1.png')

      // -------------------
      // 検索後の画面で検索条件を変えて検索
      // -------------------
      // この２行で一度入力欄をクリア
      .click(googleSearchTextArea)
      .pressKey('ctrl+a delete')
      // 検索実施
      .typeText(googleSearchTextArea, "コッペパン カレーパン 比較")
      .click(googleSearchButtonNotFirstSite)
      .expect(Selector("title").innerText).eql('コッペパン カレーパン 比較 - Google 検索')
      .takeScreenshot(testPattern2 + '_2.png')
});

```

test関数が1つのテストケースとなります。
expectはアサーションです。

[Selector](https://devexpress.github.io/testcafe/documentation/test-api/selecting-page-elements/selectors/
)ではclassやid、titleタグなどを指定して要素を取得することができます。


## 実行

下記コマンドを叩くと、testcafeでのE2Eテストが実行できます。
`chrome` のところは、好きなブラウザを指定。
最後はテストコードのファイルを指定。


```bash
$ npm run testcafe chrome ./test.js 
```

ブラウザのエイリアスは、[testcafeのドキュメント](https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/browsers/browser-support.html#locally-installed-browsers)に記載されています。
※主要なブラウザは基本サポートされている模様です。


実行をすると、ブラウザが勝手に立ち上がり、テストコード通りに実行されます。

![Nov-05-2019 23-46-07.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168063/e47c94f5-a2d2-d12e-8ce3-a30313f10fd5.gif)

全テスト実行後、コンソールに結果が表示されます。

```bash:実行結果

> learning_testcafe@1.0.0 testcafe /Users/user/Projects/learning_testcafe
> testcafe "chrome" "./test.js"

 Running tests in:
 - Chrome 78.0.3904 / Mac OS X 10.14.6

 Google Search
 ✓ Googleで検索できること (screenshots:
 /Users/user/Projects/learning_testcafe/screenshots/Googleで検索できること.png)
 ✓ 2回続けて検索できること (screenshots: /Users/user/Projects/learning_testcafe/screenshots)


 2 passed (23s)


```

失敗した場合は、具体的にアサーションが失敗した箇所と、
expectとactualの値が表示されるのでわかりやすいです。


```bash:エラーの場合
 Google Search
 ✖ Googleで検索できること

   1) AssertionError: expected 'TestCafe - Google 検索' to deeply equal 'Cafe - Google 検索'

      Browser: Chrome 78.0.3904 / Mac OS X 10.14.6

         14 |    await t
         15 |      // 基本的な検索をしてみる
         16 |      .typeText(googleSearchTextArea, "TestCafe")
         17 |      .click(googleSearchButton)
         18 |      // アサーション titleタグのテキストがイコールだったらテストOK
       > 19 |      .expect(Selector("title").innerText).eql('Cafe - Google 検索')
         20 |      // 結果をスクショする
         21 |      .takeScreenshot(testPattern + '.png')
         22 |});
         23 |
         24 |let testPattern2 = "2回続けて検索できること";

```

ちょっと面白そうなので、しばらく触って遊んでみようと思います。



## 参考

[TestCafe入門](https://tech.pjin.jp/blog/2019/06/19/testcafe_tutorial/)
[Test Code Structure \| TestCafe](https://devexpress.github.io/testcafe/documentation/test-api/test-code-structure.html)
[Press Key \| TestCafe](https://devexpress.github.io/testcafe/documentation/test-api/actions/press-key.html)