Dockerコンテナでprotractorのテストを実行、キャプチャも撮りたい！


## はじめに

### きっかけ

ただいまフロント側を担当していますが、酷いコードでe2eテスト担当の方にご迷惑をおかけしています...。

e2eテストは、実行の際にはブラウザの起動（Selenium Webdriverなどなど) が必要になるので、テスト担当の方のローカル環境でテストを実施していただいてるのが現状。Commitの度にテストを自動で実行する...というのができたら、テスト担当の方も作業が楽になるはず^^; 

ただでさえ酷いコードでご迷惑かけているので、なにかもっと楽に実行して時間を他のことに使えるようにできないかな...と思ったのがきっかけです。

すでに世の中では、e2eテストももちろん自動化はされていると思うのですが、まだその知見がなかったこととe2eテストの知識も浅いため、[お手軽に利用できるようになった](http://qiita.com/akiko-pusu/items/a30db6332a77ed0ded09) Dockerを使ってやってみようと思った次第です。

## 今回やること / やらないこと

### やること

- dockerコンテナ上で、Seleniumを使ったe2eテストを実行させること
 - 実際には、protractorを利用します
 - コンテナ上での実行結果を可視化できるようにしてみます

### やらないこと

 - Dockerそのものについての説明
 - Docker用の環境構築 

Dockerの環境については、下記の通りです。

 - Dockerの実行環境には、Macbookを利用 (OS X)
  - Docker Toolboxを使って箱庭環境を用意しています
  - 関連：[Mac版 Docker Toolbox を使ってみました](http://qiita.com/akiko-pusu/items/a30db6332a77ed0ded09) 


## ヘッドレスでもブラウザ起動できるdockerイメージは？

ヘッドレスサーバであっても、xvfb関連が入っていれば実際はブラウザの起動 - Seleniumのテストができます。
Docker Hubで探してみると、有り難いことにそれっぽいものがありました！

ありがたいことに、使っているprotractorに必要なパッケージも組み込まれているイメージです。

- https://hub.docker.com/r/mjvdende/node-chrome-protractor/
 - nodeは4.x系が入ってます
 - Dockerfileを見れば分かる通り、xvfbが入ってます（この辺はUbuntuのほうがやりやすいです）

## 簡単なe2eテストを書いて動かしてみよう！

### テストコードの用意

e2eのテストコードは、[protractorのサンプルスクリプト](https://angular.github.io/protractor/#/page-objects )を利用してみます。

```source:JavaScript
describe('angularjs homepage', function() {
  it('should greet the named user', function() {
    browser.get('http://www.angularjs.org');

    element(by.model('yourName')).sendKeys('Julie');

    var greeting = element(by.binding('yourName'));

    expect(greeting.getText()).toEqual('Hello Julie!');
  });
  
  /* もうちょっと続きます */
 });
});  
```

まず、下記のようなテスト用ファイルを作成。（ここはローカルマシンでの実行のときと一緒）

```
$ tree protractor-test
├── Dockerfile
├── README.md
├── package.json
├── test
│   └── e2e
│       ├── config-docker.js
│       └── spec
│           └── example_spec.js
└── test.sh

```

dockerで実行する場合は、xvfbの起動が必要なため、シェルスクリプト経由でテストを実行させます。

```
$ cat test.sh
#!/usr/bin/env bash

xvfb-run --server-args="$DISPLAY -screen 0 1360x1020x24 -ac +extension RANDR" \
protractor test/e2e/config-docker.js --specs test/e2e/spec/example_spec.js 

```

上記の、 *xvfb-run --server-args="$DISPLAY -screen 0 1360x1020x24 -ac +extension RANDR"* の部分が、xvfbで仮装ディスプレイで起動するためのおまじないです。

### Mac上のソースをdockerコンテナ上とシェア

さて、Mac上にローカルに保持しているソースは、そのままではdockerコンテナ上にシェアできません。（リモートリポジトリにコミットしていれば、cloneなどでコピーできますが）

この点ですが、Docker Toolbox (boot2docker) を使っていると、デフォルトでMacとdockerホスト(boot2docker) との間でフォルダ共有がされています。

これを利用して、Mac - dockerホスト - dockerコンテナの間でファイルが共有できます。

- Macの場合: /Users/ 以下がDockerホストの /Users/ にマウントされる
 - $ docker-machine ssh default ls /Users といった感じで確認できる

```
$ docker run --rm -it mjvdende/node-chrome-protractor ls /Users/
ls: cannot access /Users/: No such file or directory
$ docker run --rm -it -v /Users:/Users mjvdende/node-chrome-protractor ls /Users/
Shared	akiko
```

上記の通り共有できるのが確認できたので、実際に動かしてみます。


## docker runしてみよう

dockerホストにシェアされたディレクトリを、さらに -v オプションでマウントさせ、テスト用のスクリプトを実行してみると....

```source:bash
$ docker run -it -v /Users/akiko/work/protractor-test:/test -w="/test" --rm mjvdende/node-chrome-protractor ./test.sh
Starting selenium standalone server...
[launcher] Running 1 instances of WebDriver
Selenium standalone server started at http://172.17.0.7:37219/wd/hub
...

Finished in 8.664 seconds
3 tests, 5 assertions, 0 failures

Shutting down selenium standalone server.
[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 passed

```

実行できました！

## ほんとに実行されているのか確認したい！

出力上は、テストも実行されて結果もFinishedになりました。
でも、GUIのテストがコンテナ側で実行されている様子をなんとか確認したい...。

ということで、キャプチャのコードを追加してみます。
スクリーンショット取得のために、こちらのモジュールを追加します。

- [protractor-html-screenshot-reporter](https://www.npmjs.com/package/protractor-screenshot-reporter)
 - テストコードのディレクトリにあるpackage.jsonに追加
 - protractor実行用のシェルスクリプトに、npm installを差し込み。
 - ドキュメントに従って、protractorの設定ファイルを修正。 

```source:JavaScript
  
  // protractorの設定から抜粋
  onPrepare: function() {
      // Add a screenshot reporter and store screenshots to `/tmp/screnshots`: 
      jasmine.getEnv().addReporter(new ScreenShotReporter({
         baseDirectory: 'screenshots'
      }));
   },

```

上記のみで、実際のテストコードには修正の必要はありません。再度docker runしてみると....。

```source:bash
bash-3.2$ docker run -it -v /Users/akiko/work/protractor-test:/test -w="/test"  --rm mjvdende/node-chrome-protractor ./test.sh
npm WARN EPACKAGEJSON iid-console-test-local@0.0.0 No repository 

-- [ 中略 ] ---

Shutting down selenium standalone server.
[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 passed
bash-3.2$ ls
Dockerfile	gulpfile.js	package.json	
README.md	node_modules	screenshots	test.sh

# Mac側から確認
# dockerコンテナ側が作成した、screenshots というディレクトリが出来ている
bash-3.2$ tree screenshots
screenshots
├── 006200c0-00b5-00db-00fb-00c90028002c.json
├── 006200c0-00b5-00db-00fb-00c90028002c.png
├── 00b600f6-00eb-0034-0075-00ac004500ad.json
├── 00b600f6-00eb-0034-0075-00ac004500ad.png
├── 00c4005a-0094-00cb-001b-005300fa00d5.json
└── 00c4005a-0094-00cb-001b-005300fa00d5.png
```

![protractor-screenshot.jpg](https://qiita-image-store.s3.amazonaws.com/0/27976/a485db5f-b1b1-7f1f-883a-5d41599d7f0a.jpeg "protractor-screenshot.jpg")

### テストをhtmlレポートで出したい！

キャプチャは撮れましたので、次はレポートを生成したい...！
ということで、方法はいろいろあるかと思いますが、以下の２つを使ってみます。

- jasmine-reporters
 - https://www.npmjs.com/package/jasmine-reporters
 - テスト結果をJUit形式のXMLに出力
- jasmine-xml2html-converter
　- https://www.npmjs.com/package/jasmine-xml2html-converter
　- XMLのテストレポートからhtmlを生成

JenkinsのようなCIツールを利用していれば、xmlのテストレポートをプラグインでHTMLに変換してくれますが、今回は単体ですので、htmlに変換するところまで実施。

実行すると、このようなレポートが出来ました。

![test-report-file.jpg](https://qiita-image-store.s3.amazonaws.com/0/27976/cfb5476b-3d3d-622c-0072-fc33bb61a1d3.jpeg "test-report-file.jpg")

## 日本語の表示のためにイメージ調整

さて、ヘッドレス環境でもprotractorのテストが通せることがわかりました。
環境を準備するのが一番大変だったりするので、手軽に環境を用意できるのは、大変ありがたいです！

また、DockerHubからイメージをpullするだけでなく、Dockerfileでどのようにイメージを作っているのかを見るのも、とても参考になります。

ですが、元にさせていただいた [mjvdende/node-chrome-protractor](https://hub.docker.com/r/mjvdende/node-chrome-protractor/) は、実は日本語フォントが入っていないので、日本語サイトを表示させようとすると、 **四角で文字化け** してしまいます（Webフォントなどを利用する場合は別）。

ということで、調整したDockerfileを作ってみました。
フォント追加のために500MBは容量が必要なので、ご注意ください。

- ベースのイメージ：1.3GB
- 日本語環境対応イメージ：1.9GB


```
FROM mjvdende/node-chrome-protractor
MAINTAINER @akiko_pusu (Akiko Takano)

USER root

#================================================
# ADD Repository
# NOTE: リポジトリを追加して日本語フォントをインストール
#================================================
RUN wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | apt-key add -
RUN wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | apt-key add -
RUN wget https://www.ubuntulinux.jp/sources.list.d/quantal.list -O /etc/apt/sources.list.d/ubuntu-ja.list
RUN apt-get -y update
RUN apt-get -y install ubuntu-defaults-ja

#========================
# For Caprure 
# NOTE: package.json側でローカルにnpm installなら要らない
#========================
RUN npm install -g protractor-screenshot-reporter
```

イメージのビルドは、以下のような感じ。（上記の通り、ベースも含めサイズが大きいのでご注意ください）

```
$ docker build -t akiko_pusu/protractor-screenshot-reporter-ja:1.0 .
```

## まとめ

以上、いつものように長めになってしまいましたが、なんとかヘッドレス + Dockerを利用してe2eテストが実行できました。

実際のテスト対象サイトでは、なかなか思った通りに実行されなかったり、同期・非同期の考慮があったりと大変だと思いますが、まずははじめの一歩として。

間違いや不備な点、こういう方法もあるよ、といった点をご指摘いただけると幸いです。

## サンプルコード

簡単なものになりますが、下記に置いてありますので、よかったらご覧ください。

- https://bitbucket.org/akiko_pusu/protractor-sample