In this tutorial I'll walk you through setting up test coverage for your fancy pants ES2015+ JavaScript projects. We'll cover two topics: instrumenting native JavaScript code, and writing backwards compatible ES2015+ code using babel.
For this tutorial, feel free to follow along in the repository bcoe/es2015-coverage
@babel/preset-env
ES2015+ is composed of a daunting array of JavaScript language features. Babel comes to the rescue, providing collections of plugins that track the standardization process.
For this tutorial we will be using the env preset, a collection of Babel plugins that encompass many of the exciting features currently in the pipeline for JavaScript.
By relying on the preset, there are only a few dependencies that we need to add test coverage to our ES2015 project:
npm i @babel/cli @babel/register babel-plugin-istanbul @babel/preset-env cross-env mocha chai nyc --save-dev
@babel/cli
: is the command-line interface for babel; we use it during the build step.@babel/register
: automatically compiles ES2015+ JavaScript as it's required in your
tests.babel-plugin-istanbul
: this plugin adds coverage instrumentation to your ES2015+ code
as it's compiled.nyc
: outputs the coverage information to disk, and handles running reports.cross-env
: used to set NODE_ENV=test
in a cross-platform compatible way.mocha
/chai
: the test framework that I happen to be using for this tutorial..babelrc
We place a .babelrc
in the root of our project which is used by @babel/cli
to apply the compilation process:
{
"presets": [
"@babel/preset-env"
],
"env": {
"test": {
"plugins": [
"istanbul"
]
}
}
}
presets
: indicates that we should load the @babel/preset-env
set of plugins, which is kept up to date for us.env.test.plugins.istanbul
: indicates that we should run the babel-plugin-istanbul
plugin only when NODE_ENV=test
.package.json: configuring nyc
{
"nyc": {
"require": [
"@babel/register"
],
"reporter": [
"lcov",
"text"
],
"sourceMap": false,
"instrument": false
}
}
nyc.require.@babel/register
: indicates that we should automatically run
require('@babel/register')
as nyc
loads our tests. This allows us to
write ES2015+ code in our tests without running a build step (code is automatically
compiled by babel as it is loaded).nyc.sourceMap=false
/nyc.instrument=false
: indicates that we should not use
nyc
for instrumenting tests with coverage or handling source-maps; this
logic is instead handled by babel
and babel-plugin-istanbul
.nyc.reporter
: A list of reporters that you can use, all of which come from
istanbul. In this case we telling nyc to ask for an lcov
which gives you
a set of html reports for each file instrumented as well as an lcov.info
file which can
be sent to coverage services like coveralls.io or codecov.io. The text
reporter gives
a table summary of each file's coverage in the terminal.package.json: script stanza
{
"scripts": {
"build": "babel index.js -d src",
"test": "cross-env NODE_ENV=test nyc mocha test.js",
"prepublish": "npm run build"
}
}
scripts.test
:
cross-env NODE_ENV=test
: sets the NODE_ENV
environment variable resulting in the babel-plugin-istanbul
plugin being loaded.nyc
: indicates that nyc should be used to run mocha
.mocha test.js
: it doesn't get much simpler than this; use mocha
to run
test.js
.scripts.build
: this script uses babel-cli
to compile your ES2015+ code.scripts.prepublish
: we automatically run the build step before publishing our
package to npm.Because nyc
automatically loads @babel/register
there is no
build step necessary for your tests. Just write your tests using
ES2015+ syntax and require()
the pre-compiled ES2015+ JavaScript files:
import CoverageBabel from './index'
require('chai').should()
describe('CoverageBabel', function () {
it('returns hello world message', function () {
const cls = new CoverageBabel('Ben')
cls.helloMessage().should.equal('hello Ben')
})
})
When it's time to publish your code to npm, simply use @babel/cli
to compile
your ES2015+ JavaScript into ES5 compatible code:
babel index.js -d src
This command will read in your ES2015+ ./index.js
file and output the ES5
./src/index.js
file. Only ./src/index.js
should be published to npm, which
can be achieved by adding a files
stanza to your package.json:
{
"files": [
"src/index.js"
]
}
If you're using newer versions's of Node.js various ES2015+ features are already supported. node.green provides a useful chart for viewing compatibility information.
nyc uses the same parser underneath the hood as babel and understands native ES2015+ constructs; with zero configuration you can start instrumenting your ES2015+ code!