Implementing Code Coverage with Webpack v2

Upgrading to webpack v2 should be simple. And for the most part it is; the team has done an amazing job simplifying the exposed API and (more impressively) documenting the changes and providing upgrade paths.

It took me about 25 minutes to get one of my projects (which I’ve written about in the past) from webpack v1 => webpack2. I wasn’t doing a whole lot, using a handful of open-source loaders, with a different configuration for testing (using Karma, and karma-babel-prepocessor) to transpile my ES6/React into testable code (in the JSDOM environment). All in all, a pretty standard webpack setup for a React project.

So if it’s so simple, then why even write this blog post?

Two words: Code Coverage.

The merits of code coverage, whether it’s a flawed metric (it is), whether it tells you about the health of the system (it does), will not be discussed here, since that’s a much larger topic. The point of this article is simply about the implementation.

Like I said, for me, everything just worked after the upgrade — and I was able to remove a lot of the boilerplate required for v1, which v2 was able to abstract away or perform by default (requires, better globbing for excludes, etc). But code coverage didn’t work. At all. And not only did it not work — but it broke my entire testing workflow.

At the bottom I will link to the entire changeset that shows upgrading from v1 => v2, but I’ll mention the biggest gotcha.

With webpack v1, I was using two preloaders in order to implement code-coverage. A loader to transpile my code from React/ES6 to testable ES5, and a loader to actually instrument the code:

{
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.js$|\.jsx$/,
loader: 'isparta',
exclude: /node_modules|test/
}

However, since v2 now handles babel loader by default, and the mechanism that instruments the code is Bablyon (and not Babel) which does not use the .babelrc, when the code was getting to isparta-loader, it hadn’t transpiled my fancy React or ES6 — and of course, it broke immediately.

Here’s the new loader:

{
test: /\.js$|\.jsx$/,
enforce: 'post',
loader: 'istanbul-instrumenter-loader',
exclude: /node_modules|test/,
query: {
esModules: true
}
}

So now we only have a single loader, which gets executed at the post stage rather than pre, and at this point the code has already been transpiled, so we don’t need to worry about whether the code is in the correct format. Our loaders (and the corresponding presets) have taken care of that for us already.

And Voila! code coverage with webpack v2. I will link two changesets here, the first shows the upgrade path from v1 => v2, without removing a lot of the cruft not required by v2. The second changeset removes the no longer required code.

Changeset 1: Upgrade to Webpack 2

Changset 2: Cleanup after Upgrade