Skip to content

Commit

Permalink
fix: Populate lastFileCoverage for already instrumented files (#470)
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyfarrell committed Sep 28, 2019
1 parent a629770 commit ea6d779
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 39 deletions.
29 changes: 29 additions & 0 deletions packages/istanbul-lib-instrument/src/default-opts.js
@@ -0,0 +1,29 @@
export default function defaultOpts() {
return {
coverageVariable: '__coverage__',
coverageGlobalScope: 'this',
coverageGlobalScopeFunc: true,
preserveComments: false,
compact: true,
esModules: false,
autoWrap: false,
produceSourceMap: false,
ignoreClassMethods: [],
sourceMapUrlCallback: null,
debug: false,
/* babel parser plugins are to be enabled when the feature is stage 3 and
* implemented in a released version of node.js */
plugins: [
'asyncGenerators',
'bigInt',
'classProperties',
'classPrivateProperties',
'dynamicImport',
'importMeta',
'objectRestSpread',
'optionalCatchBinding',
'flow',
'jsx'
]
};
}
3 changes: 2 additions & 1 deletion packages/istanbul-lib-instrument/src/index.js
@@ -1,4 +1,5 @@
import Instrumenter, { defaultOpts } from './instrumenter';
import Instrumenter from './instrumenter';
import defaultOpts from './default-opts';
import programVisitor from './visitor';
import readInitialCoverage from './read-coverage';

Expand Down
40 changes: 10 additions & 30 deletions packages/istanbul-lib-instrument/src/instrumenter.js
Expand Up @@ -7,36 +7,9 @@ import * as t from '@babel/types';
import traverse from '@babel/traverse';
import generate from '@babel/generator';
import programVisitor from './visitor';
import defaultOpts from './default-opts';
import readInitialCoverage from './read-coverage';

export function defaultOpts() {
return {
coverageVariable: '__coverage__',
coverageGlobalScope: 'this',
coverageGlobalScopeFunc: true,
preserveComments: false,
compact: true,
esModules: false,
autoWrap: false,
produceSourceMap: false,
ignoreClassMethods: [],
sourceMapUrlCallback: null,
debug: false,
/* babel parser plugins are to be enabled when the feature is stage 3 and
* implemented in a released version of node.js */
plugins: [
'asyncGenerators',
'bigInt',
'classProperties',
'classPrivateProperties',
'dynamicImport',
'importMeta',
'objectRestSpread',
'optionalCatchBinding',
'flow',
'jsx'
]
};
}
/**
* Instrumenter is the public API for the instrument library.
* It is typically used for ES5 code. For ES6 code that you
Expand Down Expand Up @@ -113,7 +86,14 @@ class Instrumenter {
sourceFileName: filename
};
const codeMap = generate(ast, generateOptions, code);
this.fileCoverage = output.fileCoverage;
if (output && output.fileCoverage) {
this.fileCoverage = output.fileCoverage;
} else {
const initialCoverage =
readInitialCoverage(ast) ||
/* istanbul ignore next: paranoid check */ {};
this.fileCoverage = initialCoverage.coverageData;
}
this.sourceMap = codeMap.map;
const cb = this.opts.sourceMapUrlCallback;
if (cb && output.sourceMappingURL) {
Expand Down
18 changes: 15 additions & 3 deletions packages/istanbul-lib-instrument/src/read-coverage.js
Expand Up @@ -2,21 +2,32 @@ import { parse } from '@babel/parser';
import traverse from '@babel/traverse';
import * as t from '@babel/types';
import { MAGIC_KEY, MAGIC_VALUE } from './constants';
import { defaultOpts } from './instrumenter';
import defaultOpts from './default-opts';

const astClass = parse('').constructor;

function getAst(code) {
if (code && code.constructor === astClass) {
// Already a babel ast
return code;
}

export default function readInitialCoverage(code) {
if (typeof code !== 'string') {
throw new Error('Code must be a string');
}

// Parse as leniently as possible
const ast = parse(code, {
return parse(code, {
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
sourceType: 'script',
plugins: defaultOpts().plugins
});
}

export default function readInitialCoverage(code) {
const ast = getAst(code);

let covScope;
traverse(ast, {
Expand Down Expand Up @@ -59,6 +70,7 @@ export default function readInitialCoverage(code) {
}

delete result.coverageData[MAGIC_KEY];
delete result.coverageData.hash;

return result;
}
2 changes: 1 addition & 1 deletion packages/istanbul-lib-instrument/src/visitor.js
Expand Up @@ -2,7 +2,7 @@ import { createHash } from 'crypto';
import template from '@babel/template';
import { SourceCoverage } from './source-coverage';
import { SHA, MAGIC_KEY, MAGIC_VALUE } from './constants';
import { defaultOpts } from './instrumenter';
import defaultOpts from './default-opts';

// pattern for istanbul to ignore a section
const COMMENT_RE = /^\s*istanbul\s+ignore\s+(if|else|next)(?=\W|$)/;
Expand Down
21 changes: 21 additions & 0 deletions packages/istanbul-lib-instrument/test/already-instrumented.test.js
@@ -0,0 +1,21 @@
/* globals it */

import { assert } from 'chai';
import Instrumenter from '../src/instrumenter';

function instrument(code) {
const instrumenter = new Instrumenter({});
const result = instrumenter.instrumentSync(code, __filename);
return {
code: result,
coverageData: instrumenter.lastFileCoverage(),
sourceMap: instrumenter.lastSourceMap()
};
}

const instrumented = instrument(`console.log('basic test');`);

it('should not alter already instrumented code', () => {
const result = instrument(instrumented.code);
assert.deepEqual(instrumented, result);
});
5 changes: 1 addition & 4 deletions packages/istanbul-lib-instrument/test/util/verifier.js
Expand Up @@ -73,10 +73,7 @@ class Verifier {
);
const initial = readInitialCoverage(this.getGeneratedCode());
assert.ok(initial);
assert.deepEqual(initial.coverageData, {
hash: initial.coverageData.hash,
...this.result.emptyCoverage
});
assert.deepEqual(initial.coverageData, this.result.emptyCoverage);
assert.ok(initial.path);
if (this.result.file) {
assert.equal(initial.path, this.result.file);
Expand Down

0 comments on commit ea6d779

Please sign in to comment.