HeadlessなLinux環境でNightmare(v2)を動かすためにしたこと


## はじめに
この記事を書こうと思った背景や動機を箇条書きにまとめると以下のようになります。

- Nightmare(v1)で書いたEnd-To-Endのテストコードがあり、CIサーバーで運用している
- Nightmare(v2)に移行したい
- Nightmare(v1)から(v2)でPhantomJSベースからElectronベースに大きく変わった
  - [Nightmare(v2) + mocha ベースに、ES6でE2Eテストを書く](http://qiita.com/imunew/items/06023f689c1a31aeddf9)
- HeadlessなLinux環境にて、そもそもElectronを動かそうとして、いろいろハマった

## 環境構築（CentOS7）

### CentOS6.xでは、Electronは動かない
正直、ここに気付くのに相当な時間を使ってしまいましたが、glibcのバージョンが古いため、CentOS6.xでは、Electronは動きません。

- [atom-shell not available on CentOS?](https://github.com/electron/electron/issues/1172)
- [Can't run on CentOS 6.5](https://github.com/LightTable/LightTable/issues/1842)

本家、Electronの[Supported Platforms](https://github.com/electron/electron/blob/master/docs/tutorial/supported-platforms.md)を見ても、CentOSについての記載がないので、はっきりしません。
が、ElectornベースのVisual Studio Codeの[Requirements for Visual Studio Code](https://code.visualstudio.com/Docs/supporting/requirements)を見ると、はっきりと下記のように記載があります。

#### Platforms
VS Code has been tested on the following platforms:

- OS X Yosemite
- Windows 7 (with .NET Framework 4.5), 8.0, 8.1 and 10 (32-bit and 64-bit)
- Linux (Debian): Ubuntu Desktop 14.04, Debian 7
- Linux (Red Hat): Red Hat Enterprise Linux 7, CentOS 7, Fedora 23

#### Additional Linux requirements

- GLIBCXX version 3.4.15 or later
- GLIBC version 2.15 or later


#### glibcのバージョン
尚、OSとglibcの初期バージョンをまとめると以下のようになります。

| OS | glibc | 
| --- | --- |
| RHEL / CentOS 7.x | 2.17 |
| RHEL / CentOS 6.x | 2.12 |
| RHEL / CentOS 5.x | 2.5 |
| AmazonLinux | 2.17 |
| Ubuntu 14.04 | 2.19 |
| Ubuntu 12.04 | 2.15 |

参考URL:

- [glibcの脆弱性(CVE-2015-7547)に関する注意 - このべん(ConoHa)](https://www.conoha.jp/conoben/archives/11014)
- [RedHat系でのglibcの脆弱性(GHOST)への対応方法](http://qiita.com/biatunky/items/231b673832a21f9f9524)

### CentOS7のインストール
ここでは、CentOS7のインストール手順については、割愛します。

### Xvfbのインストール
CUIベースのサーバーなど、GUIを持たない（＝ヘッドレス）サーバーにて、GUIを伴うテストを実行するために、仮想ディスプレイフレームバッファを使用します。

#### Xvfbとは
Xvfb そのものについては、下記を参照ください。
- [Xvfb - Wikipedia](https://en.wikipedia.org/wiki/Xvfb)

#### Xvfbに必要なライブラリのインストール
Xvfbに必要なライブラリをインストールします。

- gtk2
- atk
- pango
- gdk-pixbuf2
- libXrandr
- GConf2
- libXcursor
- libXcomposite
- libnotify
- libXtst
- cups-libs
- glib2-devel

参考URL:

- [Running Nightmare headlessly on Linux · Issue #224 · segmentio/nightmare](https://github.com/segmentio/nightmare/issues/224)
- [MockingBot - Using NightmareJS/Electron on Amazon Linux](https://mockingbot.com/posts/173)

#### Xvfbのインストール
Xvfb本体およびフォントセットをインストールします。

- xorg-x11-server-Xvfb
- xorg-x11-fonts*

#### 日本語フォントのインストール
日本語が化けてしまうので、IPAフォントをyumでインストールします。

- ipa-mincho-fonts
- ipa-gothic-fonts
- ipa-pmincho-fonts
- ipa-pgothic-fonts


### nodejsのインストール
#### nightmare v2.4からは、node v4.0以上が必要
PR #[579](https://github.com/segmentio/nightmare/pull/579)がmergeされた結果、nightmare v2.4からは、node v4.0 と `--harmony`オプション、または、node v5.0以上が必要になりました。

下記の[コード](https://github.com/segmentio/nightmare/pull/579/files#diff-895e00fa7fb2b0e7555fb1e9ce93b6c4R83)にて、`template literals`が使われていることが確認できます。
\`CALL_DATA_${id}\`の部分ですね。

```lib/ipc.js
    var id = callId++;
    var progress = new Emitter();

    emitter.on(`CALL_DATA_${id}`, function() {
      progress.emit.apply(progress, ['data'].concat(sliced(arguments)));
    });
```

`template literals`は、node v4.0+以上が必要なことは、[ECMAScript 6 compatibility table](https://kangax.github.io/compat-table/es6/)から分かります。

![es6_compability_table.png](https://qiita-image-store.s3.amazonaws.com/0/26422/579e8e03-50e1-26c3-0789-6f147df4ee72.png "es6_compability_table.png")

参考URL:

- [package should specify engine · Issue #621 · segmentio/nightmare](https://github.com/segmentio/nightmare/issues/621)


#### node v4.x をソースからインストールします。

```bash
$ curl -O https://nodejs.org/dist/v4.4.4/node-v4.4.4.tar.gz
$ sudo tar -zxvf node-v4.4.4.tar.gz
$ cd node-v4.4.4
$ ./configure
$ make
$ make install
```


## テストの実行

### exampleの作成
下記のように、exampleを作成します。

```test/example.js
require('mocha-generators').install();

var Nightmare = require('nightmare');
var config = require('../config');
var assert = require('assert');

describe('home', function() {

    this.timeout(config.mocha.timeout);

    it('execute example', function*() {

        var nightmare = Nightmare();
        yield nightmare
            .viewport(1024, 768)
            .goto('http://google.com')
            .wait(500)
            .screenshot('/path/to/screenshots/example-google.png')
            .end();
        ;
    });

});
```

### 実行時オプション
npm run コマンドから実行したいので、package.jsonの"scripts"に下記のように記述します。

```package.json
{
  "dependencies": {
    "mocha": "^2.3.3",
    "mocha-generators": "~1.2.0",
    "nightmare": "^2.3.4"
  },
  "scripts": {
  	"e2e-test:example": "DEBUG=nightmare:*,electron:* xvfb-run --server-args='-screen 0 1024x768x24' mocha --harmony test/example.js",
  }
}

```

参考URL:

- [Code 127 - you may not have electron installed correctly · Issue #602 · segmentio/nightmare](https://github.com/segmentio/nightmare/issues/602)
- [automated tests - Running NightmareJS with Mocha on server (Bamboo agent) - Stack Overflow](http://stackoverflow.com/questions/36641279/running-nightmarejs-with-mocha-on-server-bamboo-agent)


### npm run
作成したexampleを実行します。

```bash
$ npm run e2e-test:example

> example@0.0.1 e2e-test:example /path/to/app
> DEBUG=nightmare:*,electron:* xvfb-run --server-args='-screen 0 1024x768x24' mocha --harmony test/example.js

...(中略)...

  nightmare:actions .screenshot() +96ms
  nightmare:log subscribing to browser window frames +2ms
  nightmare:log altering page to force rendering +0ms
  nightmare:log unsubscribing from browser window frames +28ms
  nightmare:actions .screenshot() captured with length 32311 +80ms
    ✓ execute example (3743ms)


  1 passing (4s)

```

成功すれば、下記のようにスクリーンショットが保存されます。

![example-google.png](https://qiita-image-store.s3.amazonaws.com/0/26422/6af60994-86aa-0416-3b5f-c12bce85c611.png "example-google.png")

## CircleCIで動かすためにしたこと（2016-05-23追記）
### Xvfbはセットアップ済み
[公式のドキュメント](https://circleci.com/docs/build-image-precise/#browsers)にもあるとおり、Xvfbはセットアップ済みですので、`xvfb-run`コマンドがすぐに使えます。

```
CircleCI runs graphical programs in a virtual framebuffer, using xvfb.
```

### nodejsをv4に
```
machine:
  node:
    version: 4.2.2
```
しただけでは、切り替わらなかったので、

```
dependencies:
  override:
    - nvm use default
```
を追加しました

### xvfb-runの実行時オプションに`--auto-servernum`追加
```
xvfb-run: error: Xvfb failed to start
```
とエラーになったので、下記の記事などを参考に`--auto-servernum`を追加してみたところ、無事動作しました。

参考URL:

- [linux - Xvfb failed start error - Stack Overflow](http://stackoverflow.com/questions/16726227/xvfb-failed-start-error)

### `DEBUG=nightmare:*,electron:*`は削除
以前、「おわりに」の部分にて、「nightmare v2はそんなに早くない」、とか「まだまだ不安定」とか書いてましたが、`DEBUG=nightmare:*,electron:*`を削除したら、速度は改善（v1で15分かかっていたテストが5分程度に）し、途中で止まるようなこともなくなりました。
なので、CIでもデバッグモードなしで運用することをお勧めします。

## おわりに（2016-05-23更新）
以下、nightmare v2についての所感。

- nightmare v2は活発に開発が行われている
- ES6のFeatureも積極的に使われている
- 日本語の記事がおいついていない
- 結果、githubのissuesを確認するのが近道
- すでに、v3の仕様が検討されている模様
  - [Proposing nightmare v3 by Oceanswave · Pull Request #608 · segmentio/nightmare](https://github.com/segmentio/nightmare/pull/608)
  - v3では、メソッドチェーンから、promiseベースになる模様
- デバッグモード（`DEBUG=nightmare:*,electron:*`）は要注意
  - デバッグモードで動かすと、かなり動作が重くなり、仮想マシンごと止まったりする
  - 今のところ、普段づかいしないほうが良さそう


以上です。