Jest: ES6 EcmaScript 6 Class coverage is generated for transpiled code

Created on 21 Mar 2016  路  31Comments  路  Source: facebook/jest

I am currently re-writing my https://github.com/Skelware/node-file-parser package with ES6, but I'm running into an issue where the test coverage appears to be run on the transpiled code, instead of the source code.

src/NodeFileParser.es6

class NodeFileParser {

    static test() {
        return 'dur';
    }
}

export default NodeFileParser;

spec/NodeFileParser.spec.es6:

jest.unmock('../src/NodeFileParser.es6');

import NodeFileParser from '../src/NodeFileParser.es6';

describe('NodeFileParser', () => {

    describe('#test', () => {

        it('should return "dur"', () => {
            expect(NodeFileParser.test()).toEqual('dur');
        });
    });
});

dist/NodeFileParser.js (generated by Babel):

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var NodeFileParser = function NodeFileParser() {
  _classCallCheck(this, NodeFileParser);
};

exports.default = NodeFileParser;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Ob2RlRmlsZVBhcnNlci5lczYiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7SUFBTTs7OztrQkFJUyIsImZpbGUiOiJOb2RlRmlsZVBhcnNlci5qcyIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIE5vZGVGaWxlUGFyc2VyIHtcblxufVxuXG5leHBvcnQgZGVmYXVsdCBOb2RlRmlsZVBhcnNlcjtcbiJdfQ==

package.json (excerpt):

{
  "main": "dist/NodeFileParser.js",
  "scripts": {
    "prepublish": "npm run build",
    "postinstall": "npm run build",
    "build": "babel src --out-dir dist --debug",
    "dev": "jest --verbose --watch",
    "test": "jest --no-cache --bail --verbose"
  },
  "devDependencies": {
    "babel-cli": "^6.6.5",
    "babel-jest": "^9.0.3",
    "babel-polyfill": "^6.7.2",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-stage-0": "^6.5.0",
    "jest-cli": "^0.9.2"
  },
  "jest": {
    "collectCoverage": true,
    "testDirectoryName": "spec",
    "testFileExtensions": [
      "js",
      "es6"
    ]
  },
  "babel": {
    "comments": false,
    "sourceMaps": "inline",
    "presets": [
      "es2015",
      "stage-0"
    ]
  }
}

Console output:

---------------------|----------|----------|----------|----------|----------------|
File                 |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
---------------------|----------|----------|----------|----------|----------------|
 src/                |    84.62 |       50 |    71.43 |      100 |                |
  NodeFileParser.es6 |    84.62 |       50 |    71.43 |      100 |                |
---------------------|----------|----------|----------|----------|----------------|
All files            |    84.62 |       50 |    71.43 |      100 |                |
---------------------|----------|----------|----------|----------|----------------|

Lcov html output:

class NodeFileParser { //1x EIE

    static test() {
        return 'dur'; //1x
    }
}

export default NodeFileParser;

I understand that the ES5 code is different from the ES6 code, and contains some boilerplate when transpiled, but it's really annoying when you're trying to cover all of your code, as you have to scroll through the file in your browser to check for any code that's not covered. I guess it's more accurate like this, but it's annoying.

Most helpful comment

Also happy to help talk to people on the babel side about this. Both issue seem to be simple fixes in Babel, so it should be easy to get them in.

All 31 comments

Further information on this issue from my own attempts to get this working...

I have a basic demo app that I've put together and I have successfully been able to write test and get code coverage working.

Except for one minor problem.

All of the code that use the class keyword from ES2015 end up emitting code at the top that looks like this:

/*istanbul ignore next*/'use strict';Object.defineProperty(exports, "__esModule", { value: true });var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();var /*istanbul ignore next*/_react = require('react'); /*istanbul ignore next*/var React = _interopRequireWildcard(_react);

It is a very long line, I'll save you the trouble of reading it.

There are a couple of problems.

First, the /istanbul ignore next/ should be /* istanbul ignore next */ with a space before and after the comment, otherwise istanbul does not properly apply it.

Second, even once you fix that, which I tried doing, there are functions in that string that don't get commented at all with the ignore comment. I'm assuming because the set of functions all get added at once so only one comment gets applied at the beginning.

My configuration for babel, both in package.json and .babelrc looks like this:

"presets": ["react","es2015"],
"comments": true,
"compact": false

I've also tried adding babel-plugin-transform-runtime as

"plugins": ["transform-runtime"]

both before and after the "presets" line but when I do that, I get errors that indicate the auto mocking is unable to read the metadata.

It seems that we need some sort of Babel plugin that adds in the comment for all of the transpiled code.

I finally came up with a solution which you can read about here http://blog.dmbcllc.com/es2015-code-coverage-and-jest-react-js-unit-testing/

That's quite ingenious

I would have submitted a pull request, but I'm not sure this is the BEST way of fixing this issue.

Well the only thing that's holding me back is the use of transform-runtime

Why?

It seems to me like these are things that should be fixed in babel instead of in Jest.

@DaveMBush It seems I was misinformed about the runtime transforms, as I just read the documentation again and it seems pretty good for my use-case.

I do agree with @cpojer that Babel should handle this better. I'll create an issue there and link to this one for reference. Perhaps babel-jest?

Also happy to help talk to people on the babel side about this. Both issue seem to be simple fixes in Babel, so it should be easy to get them in.

I'll help where I can. I'm still wrapping my head around React/Jest so I just didn't have time to try to figure out Babel and Syntax trees enough to build a Babel generic fix. I hope my article gives enough information that someone who understands Babel better can apply a generic enough fix.

Is https://github.com/jmcriffey/babel-istanbul relevant to this discussion?

Also this seems to be very recent and maybe a good addition? https://github.com/istanbuljs/babel-plugin-istanbul

I was having a similar issue where multiple files should've had 100% branch coverage but only had 75%. There was a weird behavior in that if I added an extra new line after my imports it would fix the branch coverage. Changing the es6 import statements to require statements also fixed this.

Trying to make a repo that recreates the bug so that I can post an issue, I realized that the problem went away when I ran Jest with --no-cache.

Can any of you having this problem try this as well and check if it works?

馃嵑

EDIT: I think it's worth mentioning that I tried deleting the cache and that didn't work either. Only using --no-cache fixes this for me.

@migueloller Can you have a look at https://github.com/facebook/jest/issues/1214? I had similar issues but with just ES5 code

@vvo, looks like another annoying issue. My problem is with branch coverage as opposed to statement coverage, though. 馃槙

It also seems you're using --no-cache and still getting an issue. Hopefully the improvements that @cpojer mentioned in #1214 will fix these. 馃槃

I'm assuming this is fixed now. @dmitriiabramov rewrote Jest's code coverage support. Please try with jest@test or [email protected] to see if this issue still persists. If it does, we'll reopen this issue.

image

This just made my day! @dmitriiabramov amazing work!!! 馃槃

nice!
thanks @migueloller

I've created a test repro, as the latest jest did not make a dent in the percentages for us.

https://github.com/a-c-m/react-jest-coverage-test

@a-c-m I've Added a pull request to your repo.

  • First remove all jest packages from your repo / clean install npm modules:
    rm -rf node_modules/*jest*

install jest@test and babel-jest@test

npm test will no longer work for your repo as the path to the jest executable is hardcoded.

Running npm test with scripts test changed to jest --no-cache will yield the correct result.

https://github.com/facebook/jest/issues/1425#issuecomment-240303564

@lPadier Many thanks, i've merged and also updated the readme.

@a-c-m I downloaded your project. After install [email protected] or jest@test I have the message "NO TESTS FOUND". At now jest@test is [email protected].

Try jest 15.

@cpojer I changed jest in my project to 15.1.1 and my tests is running now. But I have old problem with ES6 syntax. What other changes do I need to show the coverage of source files, as in Karma?

@ola-g86 are you using any custom preprocessors? is your project open sourced?

It is working now. My settings for this:
in package.json:
"jest": {
"coverageCollector": "jest-babel-istanbul",
}
in .babelrc:
"env": {
"test": {
"sourceMaps": "both"
}
}

Hi,
I am facing the same issue while performing testing using jest. My test never shows 100% for branching and statements covered.

I am using "jest": "20.1.0-delta.3", and "jest-css-modules": "^1.1.0" . Below is my jest configuration

"jest": {
"transform": {
".": "/node_modules/jest-css-modules"
},
"collectCoverageFrom": [
"!app/index.js",
"app//
.{js,jsx}",
"!
/node_modules/**"
],
"coverageThreshold": {
"global": {
"branches": 50,
"functions": 70,
"lines": 70,
"statements": 70
}
}
}

My .babelrc is as below

{
"presets": ["react", "es2015"]
}

Please help me to resolve my problem so that I can have 100% branching and statements in coverage report.

Thanks in advance

@bankimatglobant i think jest-css-modules is missing canInstrument transformer key ( see https://github.com/facebook/jest/blob/master/packages/babel-jest/src/index.js#L80) that makes instrumentation a separate process.

You can try to submit a PR to jess-css-modules to use createTransformer function that we export here https://github.com/facebook/jest/blob/master/packages/babel-jest/src/index.js#L132

I was running into this issue. Adding the transform-runtime and sourceMaps: both in my babelrc fixed it.

{
  "presets": ["es2015", "react", "stage-1"],
  "env": {
    "test": {
      "plugins": ["transform-runtime"],
      "sourceMaps": "both"
    }
  }
}

@mikeromano38 I have tried above configuration but it's not working. Just one query that what is "stage-1". My babelrc is as mentioned below:

{
"presets": ["es2015", "react"],
"env": {
"test": {
"plugins": ["transform-runtime"],
"sourceMaps": "both"
}
}
}

Was this page helpful?
0 / 5 - 0 ratings