1 |
|
2 | babel-plugin-\_\_coverage\_\_
|
3 | =============================
|
4 |
|
5 | [![Build Status](https://travis-ci.org/dtinth/babel-plugin-__coverage__.svg?branch=master)](https://travis-ci.org/dtinth/babel-plugin-__coverage__)
|
6 | [![codecov.io](https://codecov.io/github/dtinth/babel-plugin-__coverage__/coverage.svg?branch=master)](https://codecov.io/github/dtinth/babel-plugin-__coverage__?branch=master)
|
7 |
|
8 | A Babel plugin that instruments your code with `__coverage__` variable.
|
9 | The resulting `__coverage__` object is compatible with Istanbul.
|
10 |
|
11 | __Note:__ This plugin does not generate any report or save any data to any file;
|
12 | it only adds instrumenting code to your JavaScript source code.
|
13 | To integrate with testing tools, please see the [Integrations](#integrations) section.
|
14 |
|
15 |
|
16 | ## Usage
|
17 |
|
18 | Install it:
|
19 |
|
20 | ```
|
21 | npm install --save-dev babel-plugin-__coverage__
|
22 | ```
|
23 |
|
24 | Add it to `.babelrc` in test mode:
|
25 |
|
26 | ```js
|
27 | {
|
28 | "env": {
|
29 | "test": {
|
30 | "plugins": [ "__coverage__" ]
|
31 | }
|
32 | }
|
33 | }
|
34 | ```
|
35 |
|
36 |
|
37 | ## Integrations
|
38 |
|
39 | ### karma
|
40 |
|
41 | It _just works_ with Karma. First, make sure that the code is already transpiled by Babel (either using `karma-babel-preprocessor`, `karma-webpack`, or `karma-browserify`). Then, simply set up [karma-coverage](https://github.com/karma-runner/karma-coverage) according to the docs, but __don’t add the `coverage` preprocessor.__ This plugin has already instrumented your code, and Karma should pick it up automatically.
|
42 |
|
43 | It has been tested with [bemusic/bemuse](https://codecov.io/github/bemusic/bemuse) project, which contains ~2400 statements.
|
44 |
|
45 |
|
46 | ### node.js (using nyc)
|
47 |
|
48 | Configure Mocha to transpile JavaScript code using Babel, then you can run your tests with [`nyc`](https://github.com/bcoe/nyc), which will collect all the coverage report. You need to __configure NYC not to instrument your code__ by adding setting this in your `package.json`:
|
49 |
|
50 | ```js
|
51 | "nyc": {
|
52 | "include": [ "/" ]
|
53 | },
|
54 | ```
|
55 |
|
56 |
|
57 | ## Canned Answers
|
58 |
|
59 | ### There’s already Isparta. Why another coverage tool?
|
60 |
|
61 | Isparta is the de-facto tool for measuring coverage against ES6 code, which extends Istanbul with ES6 support. But it did not go that smoothly.
|
62 |
|
63 | So I’ve been trying to get webpack 2 to work with Istanbul/Isparta.
|
64 | To benefit from [webpack 2’s with tree shaking](http://www.2ality.com/2015/12/webpack-tree-shaking.html), I need to keep `import` and `export` statements in JavaScript file intact. I can’t get code coverage to work. Inspecting Isparta’s [source code](https://github.com/douglasduteil/isparta/blob/749862a7d1810dd25b8c62c9e613720b57d36da1/src/instrumenter.js), here’s what it does:
|
65 |
|
66 | 1. It uses Babel to transpile ES6 back into ES5, saving the source map.
|
67 | 2. It uses Istanbul to instrument the transpiled source code. This produces some initial metadata (in a global variable called `__coverage__`) which contains the location of each statement, branch, and function. Unfortunately, the location is mapped to the transpiled code. Therefore,
|
68 | 3. The metadata is processed using source map obtained from step 1 to map the location in transpiled code back to the location in the original source code.
|
69 | 4. The final instrumented code in ES5 is generated. This code shouldn’t be processed through Babel again, or it will be redundant and leads to slower builds.
|
70 |
|
71 | Since transforming `import`/`export` statements has now been disabled, instrumentation now dies at step 2.
|
72 |
|
73 | So I looked for something else, and I found [babel-plugin-transform-adana](https://github.com/adana-coverage/babel-plugin-transform-adana). I tried it out immediately.
|
74 | It turns out that although adana also generates the `__coverage__` variable, it is in its own format. This means that most tools that works with Istanbul-format coverage data (including `karma-coverage` and `nyc`) will not work with this. Tools need to be reinvented for each test harness.
|
75 |
|
76 | Now, with lots of tools to help developers author Babel 6 plugins,
|
77 | such as [the Babel Handbook](https://github.com/thejameskyle/babel-handbook) and [the AST Explorer](https://astexplorer.net/), it’s not that hard to create Babel plugins today. So I gave it a shot. This is my first Babel plugin.
|
78 |
|
79 | It turns out that I can create a rudimentary instrumenter with Babel 6 in roughly 300 lines of code (compare to 1,000 in Istanbul). Babel has A LOT of cool stuff to make transpilation easy, from [babel-template](https://github.com/babel/babel/tree/master/packages/babel-template) to [babel-traverse](https://github.com/babel/babel/tree/master/packages/babel-traverse) to [babel-helper-function-name](https://github.com/babel/babel/tree/master/packages/babel-helper-function-name). Babel’s convenient API also handles a lot of edge cases automatically. For example, if a function begins with `'use strict'` statement, prepending a statement into its body will insert it _after_ the `'use strict'` statement. It also automatically convert `if`/`while`/`for` body into a `BlockStatement` when a statement is inserted before the body.
|
80 |
|
81 |
|
82 | ### Is it stable?
|
83 |
|
84 | Well, I wrote most of it in two nights and have only tested some basic stuffs.
|
85 | So speaking in terms of maturity, this one is very new.
|
86 |
|
87 | However, I tried using them in some bigger projects, such as [bemusic/bemuse](https://github.com/bemusic/bemuse) (contains around 2400 statements) without much problem, and it works fine.
|
88 |
|
89 |
|
90 | ### How do I ignore branches/statements?
|
91 |
|
92 | I haven’t implemented it. I once [posted an issue on Isparta](https://github.com/douglasduteil/isparta/issues/24) asking about ignoring statements in Isparta (which is now fixed). But later, I just think that “coverage is just a number.” Also, I don’t have time to implement it.
|
93 |
|
94 | Pull requests are welcome!
|
95 |
|
96 |
|
97 | ### How do I ignore certain files?
|
98 |
|
99 | Well, [Codecov](https://codecov.io/) allows you to ignore files from their web interface, so if you’re using that, then that’s the easiest way!
|
100 |
|
101 | Oh yeah if you use webpack, you can set up two loaders.
|
102 | One for your production code (with this plugin enabled), and another for your test code (without this plugin).
|
103 |
|
104 | And if you’re using Babel, you can precompile your production code with coverage enabled into another directory like `babel src --plugins __coverage__ -d lib-cov` and tell your tests to redirect to that instead.
|
105 |
|
106 | But if you’re using something like `browserify` or `babel-register` where you can only enable or disable this plugin for every source file, then sorry, I haven’t implemented it yet, because I don’t need it now. If you want it, pull requests are welcome!
|