Jest: Empty coverage

Created on 14 Jul 2015  ยท  29Comments  ยท  Source: facebook/jest

I'm struggling to get code coverage with Jest.

Here's a sample component I'm running tests on:

var React = require('react');

var Input = React.createClass({
  render: function() {
    var placeholder = this.props.placeholder,
        value = this.props.value,
        name = this.props.name;

    return React.DOM.div({
      className: 'field'
    }, [
      React.DOM.label({
        htmlFor: name
      }),
      React.DOM.input({
        name: name,
        value: value,
        type: 'text',
        placeholder: placeholder
      })
    ]);
  }
});

module.exports = Input;

And here's a test file:

jest.dontMock('../../../components/input');

var React, TestUtils, Input;

var input;

var placeholder = 'placeholder',
    name = 'name',
    value = 'value';

describe('Input', function() {

  it('should render props', function() {

    React = require('react/addons');
    TestUtils = React.addons.TestUtils;
    Input = require('../../../components/input');

    input = TestUtils.renderIntoDocument(
      React.createElement(Input, {
        name: name,
        value: value,
        placeholder: placeholder
      }));

    var inputTag = TestUtils.findRenderedDOMComponentWithTag(input, 'input')
          .getDOMNode();

    expect(inputTag.getAttribute('placeholder')).toEqual(placeholder);
    expect(inputTag.getAttribute('name')).toEqual(name);
    expect(inputTag.getAttribute('value')).toEqual(value);
  });
});

And also Jest settings from package.json:

 {
    "collectCoverage": true,
    "testDirectoryName": "test/unit",
    "rootDir": "./src",
    "unmockedModulePathPatterns": [
      "./node_modules/react"
    ]
  }

All paths a valid. I've been debugging Jest and found out that moduleLoader.getDependenciesFromPath(testFilePath) returns empty array. So for some reason it can not get dependencies of the test file.

Most helpful comment

@cpojer This is still a bug in 0.9.2.

Steps to reproduce within a set of code with zero tests.

  1. run jest --coverage and see that it shows coverage errors.
  2. set a "testPathDirs": [ ... ] to your src files
  3. run jest --coverage

The second run will result with zero files untested. While it still should since there are plenty of files within src that doesn't have any tests.

All 29 comments

I found that if you don't add in the moduleFileExtensions param in package.json it will not collect coverage on anything but js files. Or maybe I'm misunderstanding your question.

    "moduleFileExtensions": [
      "js",
      "jsx"
    ],

@browniefed Didn't help :(

I'm also getting empty coverage results, but I'm not sure if it is a jest, babel-jest or even istanbul issue. I'm using Jest 0.5.x with ES6 imports and auto-mock off, and the following configuration:

"jest": {
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "testPathDirs": [
    "<rootDir>/src"
  ],
  "testDirectoryName": "spec",
  "testFileExtensions": [
    "js",
    "jsx"
  ],
  "moduleFileExtensions": [
    "js",
    "json"
  ],
  "unmockedModulePathPatterns": [
    "<rootDir>/node_modules/react"
  ]
}

This is the Jest output:

> iojs ./node_modules/jest-cli/bin/jest.js --coverage

Using Jest CLI v0.4.17
 PASS  src/tests/spec/DurationFormatter-test.js (1.751s)
1 test passed (1 total)
Run time: 2.435s
----------|----------|----------|----------|----------|----------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------|----------|----------|----------|----------|----------------|
----------|----------|----------|----------|----------|----------------|
All files |      100 |      100 |      100 |      100 |                |
----------|----------|----------|----------|----------|----------------|

All reports generated

And coverage/clover.xml contents:

<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1438265018003" clover="3.2.0">
  <project timestamp="1438265018003"  name="All Files" >
    <metrics statements="0"  coveredstatements="0"  conditionals="0"  coveredconditionals="0"  methods="0"  coveredmethods="0"  elements="0"  coveredelements="0"  complexity="0"  packages="0"  files="0"  classes="0"  loc="0"  ncloc="0" />
  </project>
</coverage>

I get exactly the same output as @rbardini. I don't use babel-jest, I transpile the files before running jest from the 0.5 branch on them.

preprocessor.js just replaces require('./styles.scss') with {}.

"jest": {
    "scriptPreprocessor": "<rootDir>/preprocessor.js",
    "testDirectoryName": "build",
    "testPathDirs": [
      "build"
    ],
    "testFileExtensions": [
      "spec.js"
    ],
    "moduleFileExtensions": [
      "js",
      "jsx"
    ],
    "unmockedModulePathPatterns": [
      "/node_modules/"
    ]
  }

And the output:

Using Jest CLI v0.4.17
 PASS  build/components/Paper/tests.spec.js (0.47s)
 PASS  build/components/Button/tests.spec.js (0.572s)
Warning: Returning `false` from an event handler is deprecated and will be ignored in a future release. Instead, manually call e.stopPropagation() or e.preventDefault(), as appropriate.
2 tests passed (2 total)
Run time: 1.603s
----------|----------|----------|----------|----------|----------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------|----------|----------|----------|----------|----------------|
----------|----------|----------|----------|----------|----------------|
All files |      100 |      100 |      100 |      100 |                |
----------|----------|----------|----------|----------|----------------|

All reports generated

I fixed this by including every file in collectCoverageOnlyFrom:

"jest": {
    "scriptPreprocessor": "<rootDir>/preprocessor.js",
    "testDirectoryName": "build",
    "testPathDirs": [
      "build"
    ],
    "testFileExtensions": [
      "spec.js"
    ],
    "unmockedModulePathPatterns": [
      "/node_modules/"
    ],
    "collectCoverageOnlyFrom": {
      "build/components/Paper/index.js": true,
      "build/components/Button/index.js": true
    }
  }

cc @rbardini

Thanks @Aluxian, your solution also worked for me, although I find it a little impractical to list all the desired files in package.json as time goes on and the number of tested components increase. I don't know if that's feasible, but perhaps we could have a jest.collectCoverage(moduleName) method?

Besides that, I've noticed that my test fails if I list the file in collectCoverageOnlyFrom but do not tell Jest to collect coverage information either via the --coverage flag or the collectCoverage option:

> iojs ./node_modules/jest-cli/bin/jest.js

Using Jest CLI v0.4.17
 FAIL  src/tests/spec/DurationFormatter-test.js
TypeError: src/tests/spec/DurationFormatter-test.js: undefined is not a function
  at Loader._execModule (node_modules/jest-cli/src/HasteModuleLoader/HasteModuleLoader.js:222:9)
  at Loader.requireModule (node_modules/jest-cli/src/HasteModuleLoader/HasteModuleLoader.js:905:12)
  at Loader.requireModuleOrMock (node_modules/jest-cli/src/HasteModuleLoader/HasteModuleLoader.js:926:17)
  at Object.<anonymous> (src/tests/spec/DurationFormatter-test.js:2:258)
  at Object.runContentWithLocalBindings (node_modules/jest-cli/src/lib/utils.js:495:17)
  at Loader._execModule (node_modules/jest-cli/src/HasteModuleLoader/HasteModuleLoader.js:236:9)
  at Loader.requireModule (node_modules/jest-cli/src/HasteModuleLoader/HasteModuleLoader.js:905:12)
  at jasmineTestRunner (node_modules/jest-cli/src/jasmineTestRunner/jasmineTestRunner.js:283:16)
  at node_modules/jest-cli/src/TestRunner.js:376:12
  at tryCatcher (node_modules/jest-cli/node_modules/bluebird/js/main/util.js:26:23)
  at Promise._settlePromiseFromHandler (node_modules/jest-cli/node_modules/bluebird/js/main/promise.js:503:31)
  at Promise._settlePromiseAt (node_modules/jest-cli/node_modules/bluebird/js/main/promise.js:577:18)
  at Promise._settlePromises (node_modules/jest-cli/node_modules/bluebird/js/main/promise.js:693:14)
  at Async._drainQueue (node_modules/jest-cli/node_modules/bluebird/js/main/async.js:123:16)
  at Async._drainQueues (node_modules/jest-cli/node_modules/bluebird/js/main/async.js:133:10)
  at Immediate.Async.drainQueues [as _onImmediate] (node_modules/jest-cli/node_modules/bluebird/js/main/async.js:15:14)
  at processImmediate [as _immediateCallback] (timers.js:371:17)
1 test failed, 0 tests passed (1 total)
Run time: 2.253s
npm ERR! Test failed.  See above for more details.

Otherwise it works as expected:

> iojs ./node_modules/jest-cli/bin/jest.js --coverage

Using Jest CLI v0.4.17
 PASS  src/tests/spec/DurationFormatter-test.js (1.473s)
1 test passed (1 total)
Run time: 2.004s
-----------------------|----------|----------|----------|----------|----------------|
File                   |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
-----------------------|----------|----------|----------|----------|----------------|
 components/           |      100 |      100 |      100 |      100 |                |
  DurationFormatter.js |      100 |      100 |      100 |      100 |                |
-----------------------|----------|----------|----------|----------|----------------|
All files              |      100 |      100 |      100 |      100 |                |
-----------------------|----------|----------|----------|----------|----------------|

All reports generated

Same for me ^ I enabled coverage by default now.

And yeah, I know it's impractical, but hey โ€“ at least it works. Now that we know what's wrong is much easier to find a viable solution.

Did someone found solution? I have lot of tests, so it's impractical to add them using collectCoverageOnlyFrom. Thank you.

+1

I found out that using testPathDirs breaks the coverage output. If I remove testPathDirs from config and use testPathIgnorePatterns instead to ignore tests from unwanted directories, I get real coverage output.

@roman01la I think you need to put your test under __test__ folder in order to get coverage report. And my also get rid the line "testDirectoryName": "test/unit",
I got that suggest from http://blog.redradix.com/get-coverage-reports-with-jest-js-react/ and was able to get report.

My problem is I get the report only from the files I tested, or list them in collectCoverageOnlyFrom. If my test does not touch a file in the test folder, I wish the report show 0% for that file, but it is not reported at all.

Should I raise separate issue?

same like @akheron, as soon as i add testPathDirs it's over with the coverage, only the coverage of the first file is shown.. and i already have the tests within a __test__ directory.

Using testPathDirs speeds up my initialization routine by far.. from 1 minute 17 seconds to 14 seconds.. but without coverage this is useless...

Same issue here. I only get coverage if I add manually files in collectCoverageOnlyFrom.

as workaround you can create fake __tests__/package.json with {} inside. In this case node-haste create correct requiredModules and you will see coverage for all files (_direct_ dependent from test file).

@hourliert That was my finding as well. Annoying, but it works...

@hourliert, @yaycmyk +1

Am also having this issue. Coverage only working when files added to collectCoverageOnlyFrom.

[email protected]
I found that one of the reasons for getting empty coverage is require.requireActual your test object, although it works fine during testing process.

By changing to syntax:
jest.dontMock('./test object');
const TestObject = require('./test object');
problem bypassed.

Another reason is using a custom structure to organise tests and mocks.
It works fine by using
"testPathDirs": [ "app/"],
and following tutorial to use the default structure:
/app
โ””โ”€โ”€ __mocks__
โ””โ”€โ”€ components

       โ””โ”€โ”€ __tests__
                    โ””โ”€โ”€ testObject.<testFileExtension>
       โ””โ”€โ”€ testObject.js

While this won't work (even using dontMock instead of require.requireActual):
/app
โ””โ”€โ”€ __mocks__
โ””โ”€โ”€ __tests__

       โ””โ”€โ”€ components
                    โ””โ”€โ”€ testObject.<testFileExtension>

โ””โ”€โ”€ components

       โ””โ”€โ”€ testObject.js

This should be fixed in 0.9.0, currently as alpha release tagged with jest-cli@next. Let me know if this still doesn't work and I will reopen this issue.

@cpojer This is still a bug in 0.9.2.

Steps to reproduce within a set of code with zero tests.

  1. run jest --coverage and see that it shows coverage errors.
  2. set a "testPathDirs": [ ... ] to your src files
  3. run jest --coverage

The second run will result with zero files untested. While it still should since there are plenty of files within src that doesn't have any tests.

@blainekasten can you provide a repo that highlights this issue so we can add it as an integration test and fix it?

In my case I get an empty coverage when I try to put test files in the same directory as source files. I found it useful to stick a breakpoint in this line https://github.com/facebook/jest/blob/master/src/Runtime/Runtime.js#L296 and found out that the whole test directory is excluded from coverage. My fix is to check if the file does not have test extension (I use 'spec.test') rather than being in the test directory.

Oh you are right, it's because we don't collect coverage information from tests. I'm not entirely sure what the best behavior here should be โ€“ I believe when we fix the test path pattern to be based on the full path rather than just the directory name, this bug will resolve itself :) Soon!

There are so many different issues listed in this ticket that I'm having a hard time following what is actually still a problem.

@cpojer I did make a repo with the one issue I currently still see here

The issue i'm still seeing:

  • Files not touched by jest aren't reported in coverage

That said, I would gladly enjoy anyone else putting up PR's in that repo for other configurations that are having issues so we can try to keep these centrally located.

I think this should be fine now. If there are issues that are still unresolved with Jest 12.1, please open individual new issues.

@cpojer, i can confirm this is still an issue.

  • here you will see that coverage is requested. on npm test, indeed, jest shows the coverage report
  • the report in stdout shows 100% coverage, yet the coverage/lcov* and coverage/*.xml show as 0% coverage. hence, there is an easily reproducible discrepancy between outputs

jest 17.x. thx!

I am using jest version 24, and this is still an issue!!!

What is the proper jest config to have it report untouched source files?? Insane that this hasn't been fixed yet... ๐Ÿ˜ข

Not sure if it's still relevant for someone, but I fixed it by adding this to my package.json file:

"jest": {
    "preset": "react-native",
    "testMatch": [
      "**/__tests__/**/?(*.)+(spec|test).[tj]s?(x)"
    ],
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx"
    ],
    "collectCoverageFrom": [
      "src/**/*.{ts,tsx,js,jsx}"
    ]
  }
Was this page helpful?
0 / 5 - 0 ratings