karma + babel + browserify + isparta を使って、es2015 で書いたフロントエンドテストのカバレッジを出す設定

こちらの記事も合わせて参考にしてください。
- [karma + babel + istanbul でフロントエンドのカバレッジを出す設定 2016年版](http://qiita.com/kt3k/items/4b5cdae2ad4c95b8ecb7)

---
フロントエンドで es2015 かつ browserify でバンドルしつつ書きたいという需要はそこそこ高まっているんじゃないかと思いますが、そのセッティングで開発した場合に、テストカバレッジってどうやって出したらいいの？という情報があまり出回っていない気がしたので、自分なりにミニマルだと思う設定の例をまとめてみました。

* なお、この記事では、テストランナーには、`karma`、バンドラには `browserify` を使う前提で書いています。ランナーで `testem` や、バンドラで `webpack` を使う場合は適宜置き換えて読んでください。

# まずは package.json を用意

```
npm init
```

npm の init コマンドの質問に適当に答えて、`package.json` を作ります。


# karma の設定ファイルを作成

```
npm install --save-dev karma
```
上のコマンドでまずは、karma をローカルにインストール

次に、

```
karma init
```

を実行して、karma の設定ファイル `karma.conf.js` を作成します。(karma-cli を持ってない場合は `npm install -g karma-cli` でグローバルにインストールする)

ここまでで、karma の基本的な runner と launcher などが自動で install されます。

# ビルド用の依存関係のインストール

## babel

```
npm install --save-dev babel-preset-es2015
```
上のコマンドで、es2015 のコンパイル用のプラグインのプリセットが落ちてきます。上のプリセットを isparta, babelify から使えるようにするために、
package.json の中に次のように記述します。

```json
{
  "name": "",
  ...
  "babel": {
    "presets": [
      "es2015"
    ]
  }
}
```

presets は複数形 (preset ではない) なので注意。

## karma-browserify

```
npm install --save-dev karma-browserify
```

Karma の中で browserify でビルドしながらファイルを読み込むために必要です。

## browserify-istanbul

```
npm install --save-dev browserify-istanbul
```

`browserify-istanbul` は browserify の追加のトランスフォームで、istanbul を使って、coverage 情報を付加しながらビルド出来るようになります。

## isparta

```
npm install --save-dev isparta
```

`isparta` は istanbul の Instrumenter を es6 向けに拡張したモジュールで、babel の変換と、coverage 情報の付加を同時にやってくれます。

## babelify

```
npm install --save-dev babelify
```

`babelify` は babel の変換をしながら browserify のビルドをするための追加の変換です。カバレッジを取りたいファイルは isparta で変換するので、そこでは babelify は不要ですが、カバレッジを取りたくないファイル (テストファイルなど) は、babel の変換だけをかけたいため、babelify が必要になります。

## karma-coverage

```
npm install --save-dev karma-coverage
```

`karma-coverage` はカバレッジのレポートを生成するのに使います。

# karma.conf.js の設定

## frameworks
使いたいフレームワークを複数指定します。browserify を使いたいので、browserify を含めるようにします。

例:

```js
frameworks: ['mocha', 'chai', 'browserify']
```

## files
読み込むファイルを設定します。browserify を使う場合は、実装ファイルは require (import) で取って来れるので、テストファイルだけの指定でも十分です。

例:

```js
files: ['spec/**/*.js']
```

ただし、対応するテストがないファイルがある場合など、カバレッジに漏れが出る可能性がある場合は、実装とテスト両方を指定しましょう。

例:

```js
files: [
  'src/**/*.js',
  'spec/**/*.js'
]
```

## preprocessor
すべてのファイルに browserify プリプロセッサーがかかる必要があるため、files で指定したパターンと同じパターンに browserify を指定します。browserify を使う場合は、karma-coverage のプリプロセッサーはうまく動かないため、coverage プリプロセッサーは指定しないようにします。

例:

```js
preprocessors: {
  'spec/**/*.js': ['browserify']
}
```

## browserify
一番肝になる設定部分ですが、transform に対して、まず、browserify-istanbul を指定して、その instrumenter を isparta で置き換えるという設定をします。その際、ignore オプションで、カバレッジを出したくないファイル (テストファイルなど) を指定します。この際、ignore に含まれたファイルは、カバレッジの変換だけでなく、babel の変換もスキップされてしまう (両方 isparta がやっているため) ため、babel 未変換のファイルを変換するため、babelify のトランスフォームも指定します。

```js
browserify: {
  debug: true,
  transform: [
    require('browserify-istanbul')({ // browserify のトランスフォームに browserify-istanbul を指定
      instrumenter: require('isparta'), // instrumenter を isparta で置き換える
      ignore: ['**/spec/**'] // spec/ ディレクトリにテストファイルがある場合
    }),
    'babelify' // 上のトランスフォームから漏れたもの (この場合 **/spec/** ) を babel で変換するため、babelify も設定する
  ]
}
```

なお、`package.json` で babel の設定をしていれば、babel-core モジュールが勝手に babel の設定を拾ってくれるため、babelify / isparta に明示的に babel オプションを渡す必要はありません。(babel のオプションを個別に明示的に設定するオプションについては、この記事のコメント参照)

注: ignore の設定で、一部の path ( `**/test/**` など) はデフォルトで含まれているので、その場合は、ignore 部分は必要ありません。詳しくは browserify-istanbul のドキュメント参照。

## reporters
reporters は複数指定が可能ですが、coverage を含める事で coverage report が出るようになります。

```js
reporters: ['progress', 'coverage']
```

## coverageReporter

とりあえず `type: lcov` だけ指定すれば大丈夫です。

```js
coverageReporter: {type: 'lcov'}
```

## まとめ

以上をまとめた、karma.conf.js の設定例です。

```js
module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['mocha', 'chai', 'browserify'],
    files: [
      'spec/**/*.js'
    ],
    exclude: [
    ],
    preprocessors: {
      'spec/**/*.js': ['browserify']
    },
    browserify: {
      debug: true,
      transform: [require('browserify-istanbul')({
        instrumenter: require('isparta'),
        ignore: ['**/spec/**']
      }), 'babelify']
    },
    reporters: ['progress', 'coverage'],
    coverageReporter: {
      type: 'lcov'
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome'],
    singleRun: true,
    concurrency: Infinity
  })
}
```


# テスト実行

ここまでの設定をすべて入れた上で、(テストと実装が最低1個づつある前提で)、次のコマンド実行で、karma を起動します。

    karma start karma.conf.js

上のコマンドで、`/coverage/ブラウザバージョン名` というディレクトリ以下に es2015 のコードに対するカバレッジレポートが出力されます。

例:
![スクリーンショット 2016-01-14 13.51.02.png](https://qiita-image-store.s3.amazonaws.com/0/13825/77c32805-1f76-8277-70de-7be185fb0cf1.png)

![スクリーンショット 2016-01-14 14.01.45.png](https://qiita-image-store.s3.amazonaws.com/0/13825/a756a7a5-b47a-99f1-e964-46495ed5affa.png)




# 実際に動いてる例

- https://github.com/kt3k/karma-browserify-isparta-example
  - 上記の設定をすべて入れた上で、Travis CI 上でカバレッジデータを生成して、Codecov.io 上でレポートをホストするように設定したレポジトリの例です。