babel, webpack, karmaでnode_modulesを除いてカバレッジを計測する

 

f:id:shogonir:20170529011413p:plain

 

目次

  1. この記事の目的
  2. テスト対象のコードを準備する
  3. karmaとbabel, webpack
  4. karmaでカバレッジを測定する
  5. テストを実行します
  6. まとめ

 

1. この記事の目的

最近、babel, webpackを使っていてkarmaでテストを書いています。

カバレッジの測定をしたくてkarma-coverageを使ってあれこれしていました。
しかしどうも依存するライブラリまでカバレッジ対象になってしまいます。
そこで今回はistanbulを使った解決策を紹介します。

ソースコードGithubに上げました。

github.com

 

2. テスト対象のコードを準備する

今回はthree.jsに依存するCanvasController.jsを準備します。
最終的に、このCanvasController.jsをテストするコードを書き、three.jsを除いたカバレッジを計測します。

まずは、必要なパッケージを導入します。

yarn add three
yarn add --dev \
    babel-core \
    babel-loader \
    babel-preset-es2015 \
    babel-preset-es2016 \
    webpack

 
次にwebpackの設定ファイルを準備します。

module.exports = {
  context: __dirname + '/src',
  entry: {
    'application': './application',
  },
  output: {
    path: __dirname + '/dist',
    filename: 'app.js'
  },
  module: {
    loaders: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/, 
        loader: "babel-loader", 
        query:{
          presets: ['es2015', 'es2016']
        }
      }
    ]
  }
};

 
次にエントリーポイントのsrc/application.jsを次のように保存します。

export { default as CanvasController } from './CanvasController';

 
次にsrc/CanvasController.jsを下記の通り保存します。

import * as THREE from 'three';

export default class CanvasController {
  
  constructor(canvasId) {
    let canvas = document.getElementById(canvasId);
    let renderer = new THREE.WebGLRenderer({canvas});
  }
}

 
これで、canvasのHTML要素を探して、three.jsのWebGLRendererを初期化するコードができました。
ではこれからはkarmaを使って、このCanvasController.jsをテストしていきます。
しかし、three.jsはカバレッジの対象外にするようにしていきます。

 

3. karmaとbabel, webpack

まず前提として、karmaでテストを実行するには、テストコードとテスト対象のコードがes5のJSである必要があります。
しかし、babelを使ってes2016などの記法で開発を進めている方も多いかと思います。
そこで、preprocessorという仕組みを使って、テスト実行前の処理を指定します。

今回はwebpackをpreprocessorとすることで、テストができるようにします。
この際のwebpackのloaderにbabelを指定することで、es2016->es5に変換してからwebpackに渡します。
webpackが最終的に1つのファイルにまとめたものをkarmaに渡し、テストを実行します。

まずは必要なパッケージを導入しましょう。 \

yarn add --dev \
    assert \
    karma \
    karma-chrome-launcher \
    karma-mocha \
    karma-webpack \
    mocha

 
次にkarmaの設定ファイルkarma.conf.jsを次のように保存します。

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    browsers: ['Chrome'],
    singleRun: true,
    logLevel: config.LOG_INFO,
    
    plugins: [
      'karma-chrome-launcher',
      'karma-mocha',
      'karma-webpack'
    ],
    
    files: [
      './test/**/*.js'
    ],
    preprocessors: {
      './test/**/*.js': ['webpack']
    },
    
    webpack: {
      module: {
        loaders: [
          {
            loader: 'babel-loader',
            exclude: /node_modules/,
            query: {
              presets: ['es2015', 'es2016']
            }
          }
        ]
      }
    },
  });
};

 
これで、babel -> webpack -> karmaという順番でテスト実行できるようになりました。
次にテストコードを書きます。test/CanvasController.karma.jsを次の通り保存します。

import assert from 'assert';

import CanvasController from '../src/CanvasController';

describe('CanvasController', () => {
  describe('constructor', () => {
    it('no throw', () => {
      let canvas = document.createElement('canvas');
      canvas.id = 'canvas';
      document.body.appendChild(canvas);
      let canvasController = new CanvasController('canvas');
    });
  });
});

 
今回はカバレッジが本質なのでテストコードの書き方については省略します。
この状態でpackage.jsonのscripts.test: “karma start"として、yarn testを実行するとテストが走るはずです。

 

4. karmaでカバレッジを測定する

karmaでカバレッジを測定するために下記のパッケージを導入していきます。

  • istanbul-instrumenter-loader
    • 渡されたコードにinstrumentを仕込むローダー
    • instrument: その場所をテスト実行時に通ったか測定するセンサー
  • karma-coverage-istanbul-reporter

 
実際にパッケージを導入するコマンドは下記の通りです。

yarn add --dev \
    istanbul-instrumenter-loader \
    karma-coverage-istanbul-reporter

 
次にkarmaの設定ファイルkarma.conf.jsを修正します。

module.exports = function(config) {
  config.set({
    ...
    plugins: [
      'karma-chrome-launcher',
      'karma-coverage-istanbul-reporter',
      'karma-mocha',
      'karma-webpack',
      'istanbul-instrumenter-loader'
    ],
    ...
    webpack: {
      module: {
        loaders: [
          {
            loader: 'babel-loader',
            exclude: /node_modules/,
            query: {
              presets: ['es2015', 'es2016']
            }
          },
          {
            loader: 'istanbul-instrumenter-loader',
            exclude: /node_modules/,
            include: /src/,
            enforce: 'post'
          }
        ]
      }
    },
    reporters: ['progress', 'coverage-istanbul'],
    coverageIstanbulReporter: {
      reports: ['text-summary']
    }
  });
};

 
修正したことは下記の通りです。

  • pluginsを追加
  • loadersにistanbul-instrumenter-loaderを追加
    • node_modulesを除外してsrc配下のソースのみ測定対象にします
    • enforce: ‘post'としてbabelより後になるようにしています
      • このローダーもes5のjsファイルにのみ対応していたはず
  • reportersにistanbulを追加

 

5. テストを実行します

yarn testを実行すると、テストが実行され、カバレッジが出力されます。

f:id:shogonir:20170529021653p:plain

 

6. まとめ

今回はbabel, webpack, karmaを使ってテストのカバレッジを測定する方法を紹介しました。
ポイントはistanbul-instrumenter-loaderでnode_modulesをカバレッジ測定対象外にしている点です。
さて、これでブラウザでテストが動きますし、カバレッジも測定できます。
テストを書きつつモダンな環境でどんどん開発していきましょう。