From b7d89397710c746eec8595f79cc9fa8182144b17 Mon Sep 17 00:00:00 2001 From: meng lin Date: Mon, 24 Dec 2018 07:47:24 -0500 Subject: [PATCH] Incorrect empty file coverage (#7388) --- CHANGELOG.md | 1 + .../generateEmptyCoverage.test.js.snap | 2 +- .../__tests__/generateEmptyCoverage.test.js | 27 ++++++++++++++++--- .../jest-cli/src/generateEmptyCoverage.js | 20 +++++++------- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 602f57bd5183..f84e2a276a8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ ### Fixes +- `[jest-cli]` Fix empty coverage data for untested files ([#7388](https://github.com/facebook/jest/pull/7388)) - `[jest-cli]` [**BREAKING**] Do not use `text-summary` coverage reporter by default if other reporters are configured ([#7058](https://github.com/facebook/jest/pull/7058)) - `[jest-mock]` [**BREAKING**] Fix bugs with mock/spy result tracking of recursive functions ([#6381](https://github.com/facebook/jest/pull/6381)) - `[jest-haste-map]` [**BREAKING**] Recover files correctly after haste name collisions are fixed ([#7329](https://github.com/facebook/jest/pull/7329)) diff --git a/packages/jest-cli/src/__tests__/__snapshots__/generateEmptyCoverage.test.js.snap b/packages/jest-cli/src/__tests__/__snapshots__/generateEmptyCoverage.test.js.snap index 2ca9e8f4e4f6..87cafc2da6c5 100644 --- a/packages/jest-cli/src/__tests__/__snapshots__/generateEmptyCoverage.test.js.snap +++ b/packages/jest-cli/src/__tests__/__snapshots__/generateEmptyCoverage.test.js.snap @@ -75,7 +75,7 @@ Object { "name": "(anonymous_0)", }, }, - "path": "/sum.js", + "path": "/tmp/sum.js", "s": Object { "0": 0, "1": 0, diff --git a/packages/jest-cli/src/__tests__/generateEmptyCoverage.test.js b/packages/jest-cli/src/__tests__/generateEmptyCoverage.test.js index d84db796d90a..2466804e0550 100644 --- a/packages/jest-cli/src/__tests__/generateEmptyCoverage.test.js +++ b/packages/jest-cli/src/__tests__/generateEmptyCoverage.test.js @@ -8,9 +8,12 @@ */ 'use strict'; +import istanbulCoverage from 'istanbul-lib-coverage'; +import libSourceMaps from 'istanbul-lib-source-maps'; import generateEmptyCoverage from '../generateEmptyCoverage'; import Runtime from 'jest-runtime'; +const path = require('path'); const os = require('os'); const {makeGlobalConfig, makeProjectConfig} = require('../../../../TestUtils'); @@ -32,14 +35,32 @@ module.exports = { };`; it('generates an empty coverage object for a file without running it', () => { + const coverageMap = istanbulCoverage.createCoverageMap({}); + const sourceMapStore = libSourceMaps.createSourceMapStore(); + const rootDir = '/tmp'; + const filepath = path.join(rootDir, './sum.js'); + const emptyCoverage = generateEmptyCoverage( src, - '/sum.js', + filepath, makeGlobalConfig(), makeProjectConfig({ cacheDirectory: os.tmpdir(), - rootDir: os.tmpdir(), + rootDir, + transform: [['^.+\\.js$', require.resolve('babel-jest')]], }), ); - expect(emptyCoverage && emptyCoverage.coverage).toMatchSnapshot(); + + expect(typeof emptyCoverage).toBe('object'); + + let coverage = emptyCoverage && emptyCoverage.coverage; + + if (emptyCoverage && emptyCoverage.sourceMapPath) { + coverageMap.addFileCoverage(emptyCoverage.coverage); + sourceMapStore.registerURL(filepath, emptyCoverage.sourceMapPath); + + coverage = sourceMapStore.transformCoverage(coverageMap).map; + } + + expect(coverage).toMatchSnapshot(); }); diff --git a/packages/jest-cli/src/generateEmptyCoverage.js b/packages/jest-cli/src/generateEmptyCoverage.js index 87be42cf3656..19c537e7025f 100644 --- a/packages/jest-cli/src/generateEmptyCoverage.js +++ b/packages/jest-cli/src/generateEmptyCoverage.js @@ -9,7 +9,8 @@ import type {GlobalConfig, ProjectConfig, Path} from 'types/Config'; -import {createInstrumenter} from 'istanbul-lib-instrument'; +import {readInitialCoverage} from 'istanbul-lib-instrument'; +import {classes} from 'istanbul-lib-coverage'; import Runtime from 'jest-runtime'; export type CoverageWorkerResult = {| @@ -17,6 +18,8 @@ export type CoverageWorkerResult = {| sourceMapPath: ?string, |}; +const {FileCoverage} = classes; + export default function( source: string, filename: Path, @@ -29,16 +32,15 @@ export default function( collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, }; if (Runtime.shouldInstrument(filename, coverageOptions, config)) { - // Transform file without instrumentation first, to make sure produced - // source code is ES6 (no flowtypes etc.) and can be instrumented - const transformResult = new Runtime.ScriptTransformer( + // Transform file with instrumentation to make sure initial coverage data is well mapped to original code. + const {code, mapCoverage, sourceMapPath} = new Runtime.ScriptTransformer( config, - ).transformSource(filename, source, false); - const instrumenter = createInstrumenter(); - instrumenter.instrumentSync(transformResult.code, filename); + ).transformSource(filename, source, true); + const extracted = readInitialCoverage(code); + return { - coverage: instrumenter.fileCoverage, - sourceMapPath: transformResult.sourceMapPath, + coverage: new FileCoverage(extracted.coverageData), + sourceMapPath: mapCoverage ? sourceMapPath : null, }; } else { return null;