nyc: unable to get correct nyc/istanbul coverage report for typescript

Please use the template provided below, when reporting bugs:

Expected Behavior

get correct coverage report for typescript project

Observed Behavior

coverage is not correct for typescript files. i.e. html coverage map is miss-aligned with the source also coverage numbers seem to not be correct (and sometimes non deterministic

I’ve described my issue in https://stackoverflow.com/questions/44701991/getting-nyc-istanbul-coverage-report-to-work-with-typescript

copy-pasting the info here:

nyc relevant config in package.json

"scripts": {
    "test:coverage": "nyc npm run test:unit",
    "test:unit": "gulp mocha"
}
"nyc": {
    "check-coverage": true,
    "all": true,
    "extension": [
      ".js",
      ".jsx",
      ".ts",
      ".tsx"
    ],
    "include": [
      "src/**/!(*.test.*).[tj]s?(x)"
    ],
    "reporter": [
      "html",
      "lcov",
      "text",
      "text-summary"
    ],
    "report-dir": "docs/reports/coverage"
  }

gulpfile.js mocha relevant part

const SRC_DIR = path.join(__dirname, 'src');
const SRC_FILES = path.join(SRC_DIR, '**', '*.[jt]s?(x)');
const TEST_FILES = path.join(SRC_DIR, '**', '*.test.[jt]s?(x)');
const MOCHA_CONFIG = {
    src: [
        TEST_FILES
    ],
    watchSrc: [
        SRC_FILES,
        TEST_FILES
    ],
    mocha: {
        // compilers: [
        //     'ts:ts-node/register',
        //     'tsx:ts-node/register'
        // ],
        require: [
            './tests/setup.js',
            'ignore-styles',
            'source-map-support/register'
        ]
    }
};
gulp.task('mocha', mocha(MOCHA_CONFIG));

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./",
    "rootDir": "./src",
    "outDir": "./build",
    "allowJs": true,
    "module": "commonjs",
    "target": "es5",
    "lib": ["es5", "es6", "dom"],
    "sourceMap": true,
    "inlineSourceMap": false,
    "inlineSources": false,
    "experimentalDecorators": true,
    "noUnusedParameters": true,
    "noUnusedLocals": true,
    "jsx": "react",
    "moduleResolution": "node"
  },
  "exclude": [
    "docs",
    "tests",
    "**/*.test.js",
    "**/*.test.jsx",
    "**/*.test.ts",
    "**/*.test.tsx",
    "tools",
    "gulpfile.js",
    "node_modules",
    "build",
    "typings/main",
    "typings/main.d.ts"
  ],
  "awesomeTypescriptLoaderOptions": {
    "useCache": true,
    "useBabel": true
  }
}

I’ve tried a number of approaches, some of them seem to be unable to use source maps and other fails due to ts-node/tsc errors.

With the above setup coverage produces results for all the files but they are incorrect for TS files most probably due to source maps not being used (i.e. report shows no coverage for lines which are comments and the numbers seems to be wrong as well).

With a number of variant approaches tried with no success one of the most commonly suggested is to add "require": ["ts-node/register"] to nyc configuration yet then I’m getting errors complaining about i.e. gulpfile.js, docs/reports/coverage/lcov-report/prettify.js and number of other JS files to be not under 'rootDir' which is correct yet it is not clear why ts-node tries to process all the files out of src even if they are excluded in tsconfig.json (still the configuration gets really complex).

Forensic Information

Operating System: macOS 10.12.4 Environment Information: node v7.2.0 npm v3.10.9 nyc v11.0.1

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 35
  • Comments: 22 (8 by maintainers)

Commits related to this issue

Most upvoted comments

There is a tutorial on how to use Istanbul with TypeScript & mocha but is there also a tutorial that explains how to use it with Jasmine?

I guess that it would be possible to instrument the compiled JavaScript code to get code coverage from TypeScript code?

By the way, do not know if this is related, but I noticed the removeComments option, in tsconfig.json, if enabled will remove Istanbul ignore tags and so actual coverage will be different from the expected one.

This is my command to launch coverage: nyc mocha 'test/**/*.ts'.

mocha.opts:

--require ts-node/register
--require source-map-support/register
--ui bdd
--timeout 60000

.nycrc:

{
  "extension": [
      ".ts"
  ],
  "require": [
      "ts-node/register"
  ],
  "include": [
      "src/**/*.ts"
  ],
  "exclude": [
      "**/*.d.ts"
  ],
  "reporter": [
      "html"
  ],
  "all": true
}

I think it would be worthy to add this detail in the Istanbul + Typescript configuration tutorial.

Thanks for pointing me in the right direction. I added the require statement to my package.json which contained the all:true.

We had problems with this require stanza before, producing vague error messages: ts.Debug.assert(outputText !== undefined, "Output generation failed". I found out that this could be fixed this by adding "**/*.d.ts" to our excludes. (nyc seems to consider file.d.ts to have a .ts extension)

@johan-gorter as indicated in the initial post, make sure that nyc has a require stanza that pulls in "ts-node/register" for you. This is required because the --all step functions by pre-instrumenting all of the files, and pulling out the coverage information.

If nyc itself is not the process performing the instrumentation, then there will be a discrepancy between the line count retrieved during the fake instrumentation applied by --all and the instrumentation applied when running tests that exercise the file.

tldr; if you’re using --all, the nyc process needs to control the instrumentation of the files; feel free to share your package.json with me, and something might jump out.

I’m also seeing this issue. I’ve created a repository to demonstrate the issue. In that repository, I created two files with identical contents. One has a .ts extension and the other has a .tsx extension. Interestingly, the coverage highlighting seems accurate in the .ts file, but not in the .tsx file:

fooTs fooTsx

This suggests that there is some sort of issue with the source map, but I don’t know enough to tell whether it’s an issue with the generation of the source map or one of the libraries that are processing it.

I hope this helps.

upgrading to latest nyc, ts-node did not change anything for me. Yet just found that using "target": "es5" as compilerOptions in tsconfig.conf seems to solve the issue (need to confirm though if coverage report is fully correct). Also if you need es5 target in production there is still an option to use TS_NODE_COMPILER_OPTIONS='{"target":"es6"}' nyc ... i.e. in package.json’s scripts section

see: https://github.com/Microsoft/TypeScript/issues/24993 I would like for us to better document a happy path for TypeScript and nyc.

I still have this issue on .ts code, I tried everything mentioned above, switching to es6 or es2017 using inlineSourceMap. none of them solved my issue. when I run the test, 3 json files are generated in my .nyc_output. But their statementMap are different. if nyc analyze one of the json first, the result is correct, but if it analyze the other file fist, and then try to merge the good one into it, the result would be broken.

my work around: run nyc twice with 2 different nycrc, the second one with

  "sourceMap": false,
  "instrument": false

that makes the second nycrc always output correct result, but it rely on the cache generated by the first run

I found that using "inlineSourceMap": true in tsconfig.json and inline-source-map for devtool in my Webpack conf (Because I’m doing Typescript -> ES6 -> Babel -> ES5), seems to have fixed the alignment of my TS source in coverage. I am also requiring source-map-support/register with mocha’s -r switch.

Hopefully, this helps put anyone on the right track. I understand you may not be using the same setup as me (As I’ve Webpack in the middle) so our circumstance may be different.