-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrect branch coverage when loaders used #325
Comments
@coderaiser thanks for the bug report. I'm not super familiar with the loader API, so not sure where this bug might be cropping up -- it could be as simple as coverage reports not being output by Node.js in one edge case (which would be relatively easy to fix). If the problem is missing lines of coverage in v8 itself, this tends to be more difficult to fix. If you beat me to the punch, and are excited to dig into this, where I would start looking would be in the raw v8 output:
These files contain the raw output from v8 (which is written to disk by Node.js on exit):
☝️ my guess is that we'll see output that's slightly off startOffets/endOffset values for code using the loaders. |
Just landed ability to generate Generated file looks this way: const hello = 'world';
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImhlbGxvLmpzIl0sIm5 hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyx DQUFDIiwiZmlsZSI6ImhlbGxvLm1hcCIsInNvdXJjZXNDb250ZW50IjpbImNvbnN0IGhlbGxvID0gJ3dvcmxkJzsiXX0= And it works good in the browser. The question is: does Could you please help me to get source map working? |
Looks like istrumenting with Happy holidays 🎉 ! |
@coderaiser If I understand correctly, you're using |
@bcoe Unfortunately it shows full coverage every time, so it’s useless. Could you please tell me is it possible to make Source file is changed inside of loader, and it has different name(with |
Looks like it can be related to But they are needed to |
Looks like this is
We should merge all changes that we find using different source maps (for each test when |
Hey @coderaiser, can you figure out a minimal failing test case? that demonstrates how truncating the query string causes this bug? I think we could probably figure out an approach to keep the suffix longer, until the source map lookup occurs, if that's the root of the problem (I think I'm not yet fully understanding, what do the entries for sourcemaps look like In the cache, they include the query string?) |
Hey @bcoe, OK, right now I have 3 tests.
Sourcemap doesn't includes When const {
readFile: readFile
} = global.__mockImportCache.get('fs/promises');
import {
execSync,
} from 'child_process';
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztpQ0FFTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7SUFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDWixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0FBRXRCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDeEIsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRW5CLENBQUMsRUFBRSxDQUFDLENBQUM7VUFDRCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztNQUVyQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNoQixDQUFDIiwiZmlsZSI6ImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcy5tYXAiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIHJlYWRGaWxlLFxufSBmcm9tICdmcy9wcm9taXNlcyc7XG5cbmltcG9ydCB7XG4gICAgZXhlY1N5bmMsXG59IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuXG5leHBvcnQgZGVmYXVsdCAoYSwgYiwgYykgPT4ge1xuICAgIGlmIChhKVxuICAgICAgICByZXR1cm4gcmVhZEZpbGUoKTtcbiAgICAgXG4gICAgICBpZiAoYylcbiAgICAgICAgICByZXR1cm4gZXhlY1N5bmMoKTtcbiAgICAgIFxuICAgICAgcmV0dXJuICdkJztcbn07XG5cbiJdfQ== Here is version {
"version": 3,
"sources": [
"file:///Users/coderaiser/c8-reproduce/lib/changelog.js"
],
"names": [],
"mappings": ";;iCAEO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEnB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACZ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEtB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACxB,CAAC,EAAE,CAAC,CAAC;QACD,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;MAEnB,CAAC,EAAE,CAAC,CAAC;UACD,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;MAErB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChB,CAAC",
"file": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js.map",
"sourcesContent": [
"import {\\n readFile,\\n} from 'fs/promises';\\n\\nimport {\\n execSync,\\n} from 'child_process';\\n\\nexport default (a, b, c) => {\\n if (a)\\n return readFile();\\n \\n if (c)\\n return execSync();\\n \\n return 'd';\\n};\\n\\n"
]
} When import {
readFile,
} from 'fs/promises';
const {
execSync: execSync
} = global.__mockImportCache.get('child_process');
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOzs7O2lDQUliLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFckIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUN4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ0QsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7TUFFbkIsQ0FBQyxFQUFFLENBQUMsQ0FBQztVQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRXJCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2hCLENBQUMiLCJmaWxlIjoiZmlsZTovLy9Vc2Vycy9jb2RlcmFpc2VyL2M4LXJlcHJvZHVjZS9saWIvY2hhbmdlbG9nLmpzLm1hcCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgcmVhZEZpbGUsXG59IGZyb20gJ2ZzL3Byb21pc2VzJztcblxuaW1wb3J0IHtcbiAgICBleGVjU3luYyxcbn0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChhLCBiLCBjKSA9PiB7XG4gICAgaWYgKGEpXG4gICAgICAgIHJldHVybiByZWFkRmlsZSgpO1xuICAgICBcbiAgICAgIGlmIChjKVxuICAgICAgICAgIHJldHVybiBleGVjU3luYygpO1xuICAgICAgXG4gICAgICByZXR1cm4gJ2QnO1xufTtcblxuIl19 When nothing mocked: import {
readFile,
} from 'fs/promises';
import {
execSync,
} from 'child_process';
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztBQUVwQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFdEIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUN4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ0QsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7TUFFbkIsQ0FBQyxFQUFFLENBQUMsQ0FBQztVQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRXJCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2hCLENBQUMiLCJmaWxlIjoiZmlsZTovLy9Vc2Vycy9jb2RlcmFpc2VyL2M4LXJlcHJvZHVjZS9saWIvY2hhbmdlbG9nLmpzLm1hcCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgcmVhZEZpbGUsXG59IGZyb20gJ2ZzL3Byb21pc2VzJztcblxuaW1wb3J0IHtcbiAgICBleGVjU3luYyxcbn0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChhLCBiLCBjKSA9PiB7XG4gICAgaWYgKGEpXG4gICAgICAgIHJldHVybiByZWFkRmlsZSgpO1xuICAgICBcbiAgICAgIGlmIChjKVxuICAgICAgICAgIHJldHVybiBleGVjU3luYygpO1xuICAgICAgXG4gICAgICByZXR1cm4gJ2QnO1xufTtcblxuIl19
Here is repository and test, to get things working run: git clone https://github.com/coderaiser/c8-reproduce
cd c8-reproduce
npm i
npm run coverage You can use And you will see that coverage information is not full: changelog.js | 100 | 20 | 100 | 100 | 11-14 Here is #345. |
Here is offsets I receive in {
"result": [
{
"scriptId": "0",
"url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=1",
"functions": [
{
"functionName": "",
"ranges": [
{
"startOffset": 0,
"endOffset": 1824,
"count": 1
}
],
"isBlockCoverage": true
},
{
"functionName": "default",
"ranges": [
{
"startOffset": 144,
"endOffset": 271,
"count": 1
},
{
"startOffset": 196,
"endOffset": 270,
"count": 0
}
],
"isBlockCoverage": true
}
]
},
{
"scriptId": "1",
"url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=2",
"functions": [
{
"functionName": "",
"ranges": [
{
"startOffset": 0,
"endOffset": 1820,
"count": 1
}
],
"isBlockCoverage": true
},
{
"functionName": "default",
"ranges": [
{
"startOffset": 144,
"endOffset": 271,
"count": 1
},
{
"startOffset": 178,
"endOffset": 196,
"count": 0
},
{
"startOffset": 244,
"endOffset": 270,
"count": 0
}
],
"isBlockCoverage": true
}
]
},
{
"scriptId": "2",
"url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=3",
"functions": [
{
"functionName": "",
"ranges": [
{
"startOffset": 0,
"endOffset": 1929,
"count": 1
}
],
"isBlockCoverage": true
},
{
"functionName": "default",
"ranges": [
{
"startOffset": 109,
"endOffset": 236,
"count": 1
},
{
"startOffset": 143,
"endOffset": 161,
"count": 0
},
{
"startOffset": 191,
"endOffset": 209,
"count": 0
}
],
"isBlockCoverage": true
}
]
}]
} And they are passed to applyCoverage from |
I dug into the problem a bit more, the root of the problem is essentially that the three Here's an example of why this would cause trouble merging:
vs.,
Note that in To address this problem, I think you would need to:
There's a question of whether the Istanbul format output will merge cleanly, I haven't tried this before. |
I hacked together an approach that merges three coverage reports at the end, rather than merging the However, it has trouble merging branches, this isn't unexpected because SourceMaps provide sparse data, so trying to combine two source maps can be like comparing apples and oranges. A better way to fix your problem, I think, would be to figure out where the 30 byte discrepancy is happening in |
I don't quite understand, right now each files is converted: Lines 93 to 102 in eaf8456
it goes to import {
readFile,
} from 'fs/promises';
import {
execSync,
} from 'child_process';
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
}; Then for some reason Then .......
......................
................................................
........
.............
.......................
.............................
..........
..........................
.....
............
............................
......
.................
..
............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ And than saves value of {
"lines": [
{
"line": 1,
"startCol": 0,
"endCol": 7,
"count": 1,
"ignore": false
},
{
"line": 2,
"startCol": 8,
"endCol": 30,
"count": 1,
"ignore": false
},
{
"line": 3,
"startCol": 31,
"endCol": 79,
"count": 1,
"ignore": false
},
{
"line": 4,
"startCol": 80,
"endCol": 80,
"count": 1,
"ignore": false
},
{
"line": 5,
"startCol": 81,
"endCol": 89,
"count": 1,
"ignore": false
},
{
"line": 6,
"startCol": 90,
"endCol": 103,
"count": 1,
"ignore": false
},
{
"line": 7,
"startCol": 104,
"endCol": 127,
"count": 1,
"ignore": false
},
{
"line": 8,
"startCol": 128,
"endCol": 128,
"count": 1,
"ignore": false
},
{
"line": 9,
"startCol": 129,
"endCol": 158,
"count": 1,
"ignore": false
},
{
"line": 10,
"startCol": 159,
"endCol": 169,
"count": 1,
"ignore": false
},
{
"line": 11,
"startCol": 170,
"endCol": 196,
"count": 1,
"ignore": false
},
{
"line": 12,
"startCol": 197,
"endCol": 202,
"count": 1,
"ignore": false
},
{
"line": 13,
"startCol": 203,
"endCol": 215,
"count": 1,
"ignore": false
},
{
"line": 14,
"startCol": 216,
"endCol": 244,
"count": 1,
"ignore": false
},
{
"line": 15,
"startCol": 245,
"endCol": 251,
"count": 1,
"ignore": false
},
{
"line": 16,
"startCol": 252,
"endCol": 269,
"count": 1,
"ignore": false
},
{
"line": 17,
"startCol": 270,
"endCol": 272,
"count": 1,
"ignore": false
},
{
"line": 18,
"startCol": 273,
"endCol": 273,
"count": 1,
"ignore": false
},
{
"line": 19,
"startCol": 274,
"endCol": 274,
"count": 1,
"ignore": false
},
{
"line": 20,
"startCol": 275,
"endCol": 1823,
"count": 1,
"ignore": false
}
],
"eof": 1823,
"shebangLength": 0,
"wrapperLength": 0
}
That's right, this is 3 different files: const {
readFile: readFile
} = global.__mockImportCache.get('fs/promises');
import {
execSync,
} from 'child_process';
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztpQ0FFTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7SUFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDWixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O0FBRXRCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDeEIsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRW5CLENBQUMsRUFBRSxDQUFDLENBQUM7VUFDRCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztNQUVyQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNoQixDQUFDIiwiZmlsZSI6ImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcy5tYXAiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIHJlYWRGaWxlLFxufSBmcm9tICdmcy9wcm9taXNlcyc7XG5cbmltcG9ydCB7XG4gICAgZXhlY1N5bmMsXG59IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuXG5leHBvcnQgZGVmYXVsdCAoYSwgYiwgYykgPT4ge1xuICAgIGlmIChhKVxuICAgICAgICByZXR1cm4gcmVhZEZpbGUoKTtcbiAgICAgXG4gICAgICBpZiAoYylcbiAgICAgICAgICByZXR1cm4gZXhlY1N5bmMoKTtcbiAgICAgIFxuICAgICAgcmV0dXJuICdkJztcbn07XG5cbiJdfQ== Second: import {
readFile,
} from 'fs/promises';
const {
execSync: execSync
} = global.__mockImportCache.get('child_process');
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOzs7O2lDQUliLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFckIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUN4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ0QsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7TUFFbkIsQ0FBQyxFQUFFLENBQUMsQ0FBQztVQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRXJCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2hCLENBQUMiLCJmaWxlIjoiZmlsZTovLy9Vc2Vycy9jb2RlcmFpc2VyL2M4LXJlcHJvZHVjZS9saWIvY2hhbmdlbG9nLmpzLm1hcCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgcmVhZEZpbGUsXG59IGZyb20gJ2ZzL3Byb21pc2VzJztcblxuaW1wb3J0IHtcbiAgICBleGVjU3luYyxcbn0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChhLCBiLCBjKSA9PiB7XG4gICAgaWYgKGEpXG4gICAgICAgIHJldHVybiByZWFkRmlsZSgpO1xuICAgICBcbiAgICAgIGlmIChjKVxuICAgICAgICAgIHJldHVybiBleGVjU3luYygpO1xuICAgICAgXG4gICAgICByZXR1cm4gJ2QnO1xufTtcblxuIl19 And third: import {
readFile,
} from 'fs/promises';
import {
execSync,
} from 'child_process';
export default (a, b, c) => {
if (a)
return readFile();
if (c)
return execSync();
return 'd';
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvY29kZXJhaXNlci9jOC1yZXByb2R1Y2UvbGliL2NoYW5nZWxvZy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztBQUVwQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtJQUNILENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7QUFFdEIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUN4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ0QsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7TUFFbkIsQ0FBQyxFQUFFLENBQUMsQ0FBQztVQUNELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7O01BRXJCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2hCLENBQUMiLCJmaWxlIjoiZmlsZTovLy9Vc2Vycy9jb2RlcmFpc2VyL2M4LXJlcHJvZHVjZS9saWIvY2hhbmdlbG9nLmpzLm1hcCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgcmVhZEZpbGUsXG59IGZyb20gJ2ZzL3Byb21pc2VzJztcblxuaW1wb3J0IHtcbiAgICBleGVjU3luYyxcbn0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChhLCBiLCBjKSA9PiB7XG4gICAgaWYgKGEpXG4gICAgICAgIHJldHVybiByZWFkRmlsZSgpO1xuICAgICBcbiAgICAgIGlmIChjKVxuICAgICAgICAgIHJldHVybiBleGVjU3luYygpO1xuICAgICAgXG4gICAgICByZXR1cm4gJ2QnO1xufTtcblxuIl19
3-rd file is the same as original, but it still has sourcemap added by changelog.js | 100 | 42.85 | 100 | 100 | 11-14
This is amazing! Would be great if you add this to |
Yes I'd be open to adding this functionality, the only issue is it does draw attention to the fact that merging multiple istanbul reports is a bit buggy. The function and line coverage should be pretty accurate, I think, but as demonstrated by the yellow blocks in the report I shared, branch coverage is a bit off. All I did was stop dropping the diff --git a/lib/report.js b/lib/report.js
index d3c8806..41edabf 100644
--- a/lib/report.js
+++ b/lib/report.js
@@ -117,6 +117,7 @@ class Report {
map.merge(converter.toIstanbul())
}
} catch (err) {
+ console.info(err)
debuglog(`file: ${v8ScriptCov.url} error: ${err.stack}`)
}
}
@@ -143,7 +144,12 @@ class Report {
*/
_getSourceMap (v8ScriptCov) {
const sources = {}
- const sourceMapAndLineLengths = this.sourceMapCache[pathToFileURL(v8ScriptCov.url).href]
+ let suffix = '';
+ const match = v8ScriptCov.url.match(/(?<query>\?.*)$/)
+ if (match) {
+ suffix = match.groups.query;
+ }
+ const sourceMapAndLineLengths = this.sourceMapCache['file://' + v8ScriptCov.url]
if (sourceMapAndLineLengths) {
// See: https://github.com/nodejs/node/pull/34305
if (!sourceMapAndLineLengths.data) return
@@ -279,15 +285,22 @@ class Report {
}
if (/^file:\/\//.test(v8ScriptCov.url)) {
try {
- v8ScriptCov.url = fileURLToPath(v8ScriptCov.url)
- fileIndex.add(v8ScriptCov.url)
+ let suffix = '';
+ const match = v8ScriptCov.url.match(/(?<query>\?.*)$/)
+ if (match) {
+ suffix = match.groups.query;
+ }
+ const normalized = fileURLToPath(v8ScriptCov.url)
+ v8ScriptCov.url = normalized + suffix;
+ fileIndex.add(normalized)
} catch (err) {
debuglog(`${err.stack}`)
continue
}
}
if ((!this.omitRelative || isAbsolute(v8ScriptCov.url))) {
- if (this.excludeAfterRemap || this.exclude.shouldInstrument(v8ScriptCov.url)) {
+ const url = v8ScriptCov.url.split('?')[0]
+ if (this.excludeAfterRemap || this.exclude.shouldInstrument(url)) {
result.push(v8ScriptCov)
}
}
@@ -307,7 +320,12 @@ class Report {
_normalizeSourceMapCache (v8SourceMapCache) {
const cache = {}
for (const fileURL of Object.keys(v8SourceMapCache)) {
- cache[pathToFileURL(fileURLToPath(fileURL)).href] = v8SourceMapCache[fileURL]
+ let suffix = '';
+ const match = fileURL.match(/(?<query>\?.*)$/)
+ if (match) {
+ suffix = match.groups.query;
+ }
+ cache[pathToFileURL(fileURLToPath(fileURL)).href + suffix] = v8SourceMapCache[fileURL]
}
return cache
} The approach should be fleshed out more with tests, and using a helper rather than repeated code -- also it fails if no source is found right now, since |
It would be outstanding if c8 would differentiate moduleIds requested with query string to provide accurate coverage results. |
@iambumblehead agreed. Would happily accept a patch for this, or even a failing test. |
|
Maintainer of several test frameworks here. Since query strings are really the only way to invalidate imports when running tests in esm, this is really not great. Would really appreciate if someone could pick this up again! Cheers |
This is happening to me as well, but only on dynamic imports. |
c8
shows uncovered lines, but the whole file is covered.Version: output of
node -v
16.9.0Platform: output of
uname -a
DarwinRepository https://github.com/coderaiser/c8-reproduce
When I'm using loaders to mock
imports
the coverage I see is broken.Code:
Tests:
What mock-import does is converts source to:
And
imports
it as./changelog.js?count=1
on first test, then on second test:File
imported
as./changelog.js?count=2
, and then on third assertion code isn't changed.The text was updated successfully, but these errors were encountered: