Dockerを使ってTestCafeを動かす

## はじめに

Dockerを使ってTestCafe（TypeScriptで記述）を動かします。TestCafeのDockerイメージに含まれている**Chromium, FireFox**を使った簡易な方法です。

クロスブラウザテストや、docker-composeを使って複数のコンテナを構築、といった内容は含まれませんのでご容赦ください。

**使用するツール**

[Docker](https://docs.docker.com/engine/install/)、[Node.js](https://nodejs.org/ja/download/)はインストール済のものとします。

- Windows 10 Pro
- Docker
- Node.js
- TestCafe
- TypeScript

**ディレクトリ構成**

大まかにこんな感じ。

```text
.
└── testcafe
    ├── Dockerfile
    ├── .testcaferc.json
    ├── package.json
    ├── node_modules
    ├── datadriven     # データ駆動テスト用のデータ
    ├── pages          # ページモジュール
    └── features       # テストスクリプト（.ts）
```

## 手順

１．TestCafeとTypeScriptをインストール
２．テストスクリプトを用意
３．TestCafeのDockerイメージをpull
４．Dockerイメージからコンテナを作成・実行
５．（おまけ）Dockerfileを書いてTestCafeを動かす

## TestCafeとTypeScriptをインストール

今回はnpmを使いました。ローカルインストールするために`--save-dev`のオプションを付けています。

```
npm install --save-dev testcafe
```

```
npm install --save-dev typescript
```

## テストスクリプトを用意

[TestCafeサンプルサイト](https://devexpress.github.io/testcafe/example/)のh1要素のテキストを確認する簡易なもの。
ローカルだと`npx testcafe chrome .\features\test.ts`等で実行できます。ローカルインストールとグローバルインストールのコマンド詳細は[Install TestCafe](https://testcafe.io/documentation/402834/guides/basic-guides/install-testcafe)。

```ts:test.ts
import { Selector } from 'testcafe';

fixture('TestCafe tutorials')
    .page('https://devexpress.github.io/testcafe/example/');

test('h1 text is Example', async (t) => {
    const h1 = Selector('h1');
    await t.expect(h1.innerText).eql('Example');
});
```

## TestCafeのDockerイメージをpull

[TestCafeのDockerイメージ](https://hub.docker.com/r/testcafe/testcafe/)をpullします。

```
docker pull testcafe/testcafe
```

## Dockerイメージからコンテナを作成・実行

TestCafeのDockerイメージには、ChromiumとFirefoxがインストールされているのでこれを使います。それ以外のブラウザを使う場合は別途インストールが必要です。

```
docker run -v ${TEST_FOLDER}:/tests -it testcafe/testcafe ${TESTCAFE_ARGS}
```

**パラメタ**

- `-v ${TEST_FOLDER}:/tests`
  - ホスト側の`TEST_FOLDER`をコンテナ内の`/tests`ディレクトリにマウントします
- `-it testcafe/testcafe`
  - インタラクティブモードでTestCafeを実行します
- `${TESTCAFE_ARGS}`
  - testcafeコマンドに渡す引数
  - TestCafeの[Command Line Interface](https://testcafe.io/documentation/402639/reference/command-line-interface)が使えます

この時、テストに必要なファイル（Pageモジュール、Node.jsモジュール等）はホストディレクトリかそのサブディレクトリに配置します。それ以外に配置すると、コンテナからアクセスできません。

実際のコマンドはこんな感じ。testcafeディレクトリまで`cd`で移動して実行。実行後にコンテナを削除したいので`--rm`を追加しています。

```
docker run -v ${PWD}:/tests -it --rm testcafe/testcafe chromium /tests/features/test.ts
```

実行結果はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/5969fba2-9c71-ccf5-c062-19482c7f3b55.png)

FireFoxでも動きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/f4a43fbe-6de6-97b2-ee24-4b5cdda3da3b.png)


## Dockerfileを書いてTestCafeを動かす

先ほどと同様に、TestCafeのDockerイメージを使います。各行の詳細は以下に書きますが、Dockerイメージからコンテナを起動した後に、テストを実行するようになっています。

```Dockerfile:Dockerfile
# testcafeイメージを取得し、ベースイメージとする
FROM testcafe/testcafe

# Dockerコンテナ内に作業用フォルダを作成する
WORKDIR /tests

# ローカルのtestcafeディレクトリ下をDockerコンテナ内の作業フォルダ直下にコピー
COPY ./ /tests

# テストを実行
CMD ["chromium", "/tests/features/test.ts"]
```

Dockerfileを使ってDockerイメージをビルドします。適当に名前とタグを付けました。

```
docker build ./ -t testcafe/testcafe:1.0
```

実行するとステータスが流れます。

```
> docker build ./ -t testcafe/testcafe:1.0
[+] Building 43.0s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                              0.0s 
 => => transferring dockerfile: 549B                                              0.0s 
...略
```

Dockerイメージが生成されていることを確認しておきます。

```
docker image ls
```

Dockerイメージを指定して、コンテナを起動。ここでも使い捨てるために`--rm`を付けています。

```
docker run --rm testcafe/testcafe:1.0
```

実行すると、通常と同様にテスト結果が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548627/ab502604-9264-c550-d057-c3d4e354d4b6.png)


## 参考

- [Use TestCafe Docker Image | TestCafe](https://testcafe.io/documentation/402838/guides/advanced-guides/use-testcafe-docker-image)
- [TestCafeを使ってCircleCI上でE2Eテスト - Qiita](https://qiita.com/nju33/items/e7da2198c5aa64e85aea#testcafe)
- [Nuxt on Dockerにtestcafeを導入する](https://zenn.dev/at946/articles/af6cec6fc9c8f1)