v8-to-istanbul
v8-to-istanbul copied to clipboard
Cannot read properties of undefined (reading 'endCol')
I am getting Cannot read properties of undefined (reading 'endCol')
when trying to generate coverage after a jest
test run when using @swc/jest
as a transformer.
Error
TypeError: Cannot read properties of undefined (reading 'endCol')
at module.exports.sliceRange (/workspace/node_modules/.pnpm/[email protected]/node_modules/v8-to-istanbul/lib/range.js:30:54)
at /workspace/node_modules/.pnpm/[email protected]/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:139:19
at Array.forEach (<anonymous>)
at /workspace/node_modules/.pnpm/[email protected]/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:125:20
at Array.forEach (<anonymous>)
at V8ToIstanbul.applyCoverage (/workspace/node_modules/.pnpm/[email protected]/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:124:12)
Details
During this call: https://github.com/istanbuljs/v8-to-istanbul/blob/b5ecd8242cf64389c9a656d78530bd0428edf195/lib/v8-to-istanbul.js#L205
_maybeRemapStartColEndCol({
count: 0,
startOffset: 340,
endOffset: 348
})
It receives object with all properties null
from originalPositionFor
here: https://github.com/istanbuljs/v8-to-istanbul/blob/b5ecd8242cf64389c9a656d78530bd0428edf195/lib/source.js#L105
Which causes it to fail somewhere down the line.
Source File
export const noop = () => Promise.resolve();
export const noopSync = () => {
/* noop */
};
Transformed File
If I transform it with @swc
with source maps enabled, I get this:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
noop: ()=>noop,
noopSync: ()=>noopSync
});
const noop = ()=>Promise.resolve();
const noopSync = ()=>{
/* noop */ };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi93b3Jrc3BhY2Uvc3JjL3V0aWxzL2Z1bmN0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBub29wID0gKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCk7XG5leHBvcnQgY29uc3Qgbm9vcFN5bmMgPSAoKSA9PiB7XG4gIC8qIG5vb3AgKi9cbn07XG4iXSwibmFtZXMiOlsibm9vcCIsIm5vb3BTeW5jIiwiUHJvbWlzZSIsInJlc29sdmUiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7OztJQUFhQSxJQUFJLE1BQUpBO0lBQ0FDLFFBQVEsTUFBUkE7O0FBRE4sTUFBTUQsT0FBTyxJQUFNRSxRQUFRQyxPQUFPO0FBQ2xDLE1BQU1GLFdBQVcsSUFBTTtBQUM1QixRQUFRLEdBQ1YifQ==
Source map
{
"version": 3,
"sources": [
"/workspace/src/utils/function.ts"
],
"sourcesContent": [
"export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n"
],
"names": [
"noop",
"noopSync",
"Promise",
"resolve"
],
"mappings": "AAAA;;;;;;;;;;;IAAaA,IAAI,MAAJA;IACAC,QAAQ,MAARA;;AADN,MAAMD,OAAO,IAAME,QAAQC,OAAO;AAClC,MAAMF,WAAW,IAAM;AAC5B,QAAQ,GACV"
}
@jridgewell can you tell if we're making wrong assumptions about source map shape here?
I'd need a proper reproduction repo to fully debug. Or, if you could provide me with the arguments passed to the offsetToOriginalRelative
call (I don't know what the value of sourceTranspiled.wrapperLength
to calculate it based on the _maybeRemapStartColEndCol
call).
My initial thought is that we're hitting one of the unmapped regions in the map (everything that's not highlighted). If that's the case, then we do return an all-null InvalidOriginalMapping
.
"wrapperLength":77
Here is the full JSON.stringify()
:
{
"sourceMap": {"version":3,"file":"/workspace/src/utils/function.ts","names":["noop","noopSync","Promise","resolve"],"sources":["/workspace/src/utils/function.ts"],"sourcesContent":["export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n"],"resolvedSources":["/workspace/src/utils/function.ts"],"_encoded":"AAAA;;;;;;;;;;;IAAaA,IAAI,MAAJA;IACAC,QAAQ,MAARA;;AADN,MAAMD,OAAO,IAAME,QAAQC,OAAO;AAClC,MAAMF,WAAW,IAAM;AAC5B,QAAQ,GACV","_decoded":[[[0,0,0,0]],[],[],[],[],[],[],[],[],[],[],[[4,0,0,13,0],[8,0,0,17],[14,0,0,13,0]],[[4,0,1,13,1],[12,0,1,21],[18,0,1,13,1]],[],[[0,0,0,7],[6,0,0,13,0],[13,0,0,20],[17,0,0,26,2],[25,0,0,34,3],[32,0,0,41]],[[0,0,1,7],[6,0,1,13,1],[17,0,1,24],[21,0,1,30]],[[0,0,2,2],[8,0,2,10],[11,0,3,0]]],"_decodedMemo":{"lastKey":5,"lastNeedle":0,"lastIndex":-1}},
"startCol": 263,
"endCol": 271,
"this": {"lines":[{"line":1,"startCol":0,"endCol":13,"count":1,"ignore":false},{"line":2,"startCol":14,"endCol":60,"count":1,"ignore":false},{"line":3,"startCol":61,"endCol":76,"count":1,"ignore":false},{"line":4,"startCol":77,"endCol":80,"count":1,"ignore":false},{"line":5,"startCol":81,"endCol":112,"count":1,"ignore":false},{"line":6,"startCol":113,"endCol":174,"count":1,"ignore":false},{"line":7,"startCol":175,"endCol":200,"count":1,"ignore":false},{"line":8,"startCol":201,"endCol":223,"count":1,"ignore":false},{"line":9,"startCol":224,"endCol":231,"count":1,"ignore":false},{"line":10,"startCol":232,"endCol":233,"count":1,"ignore":false},{"line":11,"startCol":234,"endCol":252,"count":1,"ignore":false},{"line":12,"startCol":253,"endCol":272,"count":1,"ignore":false},{"line":13,"startCol":273,"endCol":299,"count":1,"ignore":false},{"line":14,"startCol":300,"endCol":303,"count":1,"ignore":false},{"line":15,"startCol":304,"endCol":339,"count":1,"ignore":false},{"line":16,"startCol":340,"endCol":362,"count":1,"ignore":false},{"line":17,"startCol":363,"endCol":376,"count":1,"ignore":false},{"line":18,"startCol":377,"endCol":377,"count":1,"ignore":false},{"line":19,"startCol":378,"endCol":944,"count":1,"ignore":false}],"eof":944,"shebangLength":0,"wrapperLength":77}
}
Sorry, I'm still missing the this.covSources
field.
Previously I sent this
from offsetToOriginalRelative
, that's way it wasn't there. Here is this
from _maybeRemapStartColEndCol
:
{"path":"/workspace/src/utils/function.ts","wrapperLength":77,"sources":{"originalSource":"export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n","source":"\"use strict\";\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nfunction _export(target, all) {\n for(var name in all)Object.defineProperty(target, name, {\n enumerable: true,\n get: all[name]\n });\n}\n_export(exports, {\n noop: ()=>noop,\n noopSync: ()=>noopSync\n});\nconst noop = ()=>Promise.resolve();\nconst noopSync = ()=>{\n/* noop */ };\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi93b3Jrc3BhY2Uvc3JjL3V0aWxzL2Z1bmN0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBub29wID0gKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCk7XG5leHBvcnQgY29uc3Qgbm9vcFN5bmMgPSAoKSA9PiB7XG4gIC8qIG5vb3AgKi9cbn07XG4iXSwibmFtZXMiOlsibm9vcCIsIm5vb3BTeW5jIiwiUHJvbWlzZSIsInJlc29sdmUiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7OztJQUFhQSxJQUFJLE1BQUpBO0lBQ0FDLFFBQVEsTUFBUkE7O0FBRE4sTUFBTUQsT0FBTyxJQUFNRSxRQUFRQyxPQUFPO0FBQ2xDLE1BQU1GLFdBQVcsSUFBTTtBQUM1QixRQUFRLEdBQ1YifQ==","sourceMap":{"sourcemap":{"file":"/workspace/src/utils/function.ts","version":3,"sources":["/workspace/src/utils/function.ts"],"sourcesContent":["export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n"],"names":["noop","noopSync","Promise","resolve"],"mappings":"AAAA;;;;;;;;;;;IAAaA,IAAI,MAAJA;IACAC,QAAQ,MAARA;;AADN,MAAMD,OAAO,IAAME,QAAQC,OAAO;AAClC,MAAMF,WAAW,IAAM;AAC5B,QAAQ,GACV"}}},"generatedLines":[],"branches":{},"functions":{},"covSources":[{"source":{"lines":[{"line":1,"startCol":0,"endCol":44,"count":1,"ignore":false},{"line":2,"startCol":45,"endCol":76,"count":1,"ignore":false},{"line":3,"startCol":77,"endCol":89,"count":1,"ignore":false},{"line":4,"startCol":90,"endCol":92,"count":1,"ignore":false}],"eof":92,"shebangLength":0,"wrapperLength":77},"path":"/workspace/src/utils/function.ts"}],"rawSourceMap":{"sourcemap":{"file":"/workspace/src/utils/function.ts","version":3,"sources":["/workspace/src/utils/function.ts"],"sourcesContent":["export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n"],"names":["noop","noopSync","Promise","resolve"],"mappings":"AAAA;;;;;;;;;;;IAAaA,IAAI,MAAJA;IACAC,QAAQ,MAARA;;AADN,MAAMD,OAAO,IAAME,QAAQC,OAAO;AAClC,MAAMF,WAAW,IAAM;AAC5B,QAAQ,GACV"}},"sourceMap":{"version":3,"file":"/workspace/src/utils/function.ts","names":["noop","noopSync","Promise","resolve"],"sources":["/workspace/src/utils/function.ts"],"sourcesContent":["export const noop = () => Promise.resolve();\nexport const noopSync = () => {\n /* noop */\n};\n"],"resolvedSources":["/workspace/src/utils/function.ts"],"_encoded":"AAAA;;;;;;;;;;;IAAaA,IAAI,MAAJA;IACAC,QAAQ,MAARA;;AADN,MAAMD,OAAO,IAAME,QAAQC,OAAO;AAClC,MAAMF,WAAW,IAAM;AAC5B,QAAQ,GACV","_decoded":[[[0,0,0,0]],[],[],[],[],[],[],[],[],[],[],[[4,0,0,13,0],[8,0,0,17],[14,0,0,13,0]],[[4,0,1,13,1],[12,0,1,21],[18,0,1,13,1]],[],[[0,0,0,7],[6,0,0,13,0],[13,0,0,20],[17,0,0,26,2],[25,0,0,34,3],[32,0,0,41]],[[0,0,1,7],[6,0,1,13,1],[17,0,1,24],[21,0,1,30]],[[0,0,2,2],[8,0,2,10],[11,0,3,0]]],"_decodedMemo":{"lastKey":5,"lastNeedle":0,"lastIndex":-1}},"sourceTranspiled":{"lines":[{"line":1,"startCol":0,"endCol":13,"count":1,"ignore":false},{"line":2,"startCol":14,"endCol":60,"count":1,"ignore":false},{"line":3,"startCol":61,"endCol":76,"count":1,"ignore":false},{"line":4,"startCol":77,"endCol":80,"count":1,"ignore":false},{"line":5,"startCol":81,"endCol":112,"count":1,"ignore":false},{"line":6,"startCol":113,"endCol":174,"count":1,"ignore":false},{"line":7,"startCol":175,"endCol":200,"count":1,"ignore":false},{"line":8,"startCol":201,"endCol":223,"count":1,"ignore":false},{"line":9,"startCol":224,"endCol":231,"count":1,"ignore":false},{"line":10,"startCol":232,"endCol":233,"count":1,"ignore":false},{"line":11,"startCol":234,"endCol":252,"count":1,"ignore":false},{"line":12,"startCol":253,"endCol":272,"count":1,"ignore":false},{"line":13,"startCol":273,"endCol":299,"count":1,"ignore":false},{"line":14,"startCol":300,"endCol":303,"count":1,"ignore":false},{"line":15,"startCol":304,"endCol":339,"count":1,"ignore":false},{"line":16,"startCol":340,"endCol":362,"count":1,"ignore":false},{"line":17,"startCol":363,"endCol":376,"count":1,"ignore":false},{"line":18,"startCol":377,"endCol":377,"count":1,"ignore":false},{"line":19,"startCol":378,"endCol":944,"count":1,"ignore":false}],"eof":944,"shebangLength":0,"wrapperLength":77},"all":false}
i've run into this too, i've pinned @swc/core
at 1.3.3
, every patch release after that seems to cause this error
@jgeschwendt I tried about 500 different upgrades/resolutions within my package.json today with no luck until I stumbled upon this comment, so thank you 🥇
Ok, so the relevant call to offsetToOriginalRelative
has the params (sourceMap, 263, 271)
, and if we sliceRange(lines, 263, 271, true)
we get [{ "line": 12, "startCol": 253, "endCol": 272, "count": 1, "ignore": false }]
.
That's a single line (0-based) matching line 13: ····noopSync: ()=>noopSync,
. Our start = originalPositionTryBoth(sourceMap, 12, 10)
returns { source '…', line: 2, column: 13, name: '…' }
(1-based) and end = originalEndPositionFor(sourceMap, 12, 18)
returns the same { source '…', line: 2, column: 13, name: '…' }
. This totally valid, and if we look at the sourcemap visualizer, we see this:


This is a valid transform and sourcemap.
So we hit end = originalPositionFor(sourceMap, 12, 18, LEAST_UPPER_BOUND)
, and this returns the all-null { source: null, line: null, column null, name: null }
. Again, correct, there's no other segments after that on this line to return with an upper bound search. We don't guard this call with a !(end && end.source)
check, and we get the bug.
I'm not sure why we're performing that second end = originalPositionFor(…)
call…
Not sure if this will help anyone, but I encountered the same issue, the file was exporting constants only:
export const XXXXXXX = 'something'
export const YYYYYYY = 'something'
After tracking down the issue, I figured out the solution, I just added one space above the very first export
, so my file became:
// Constants
export const XXXXXXX = 'something'
export const YYYYYYY = 'something'
I guessed it because in the file range.js
, I found that the end
variable was -1
, so by adding that comment line on top of the file, the issue went away.
Hi, same issue experienced here. Independently to a proper and source based fix we have an easy patch applied at @jest/reporters/v8-to-istanbul@^9.0.1
diff --git a/lib/range.js b/lib/range.js
index 4abdfe78be6c8fab30225d65970cf66cb055f941..901722bcee414924eafe8b4585d2f0522ba8681e 100644
--- a/lib/range.js
+++ b/lib/range.js
@@ -16,7 +16,7 @@ module.exports.sliceRange = (lines, startCol, endCol, inclusive = false) => {
if (startCol >= lines[mid].endCol) {
start = mid + 1
} else if (endCol < lines[mid].startCol) {
- end = mid - 1
+ end = Math.max(mid - 1, start);
} else {
end = mid
while (mid >= 0 && startCol < lines[mid].endCol && endCol >= lines[mid].startCol) {
That makes end not go beneath start position. I would suggest to add that to a PR but knowing that is not a fix of the problem creator but a problem stopper.
I lowered @swc/jest to version 2.20 and it worked!
Tried 0.2.20 and it doesn't work
I have the same issue
@hurstindustries curious why you closed your PR (apologies for the slow review 😄 , I'm guessing that might be the reasoning).
I'll keep an eye out for a patch for this issue.
Having an export const
in the first line of the file was the problem for me. Adding a comment in line 1 and a return in line 2 as @aladinflux did worked for me.
1 // leave this line here so the test coverage won't break
2
3 export const func = () => {...}
🤷♂️
The simplest and safest way is to change the endCol
reading on line 30 in range.js to lines[end]?.endCol
. At least this allows doing not patch lib to have a working coverage :).
As @aladinflux and @mitestainer, adding a comment in line 1 of a file that was only exporting constants solved the issue (which was previously encountered in another project, and back then strangely resolved by lowering axios from 1.2.3 to 1.1.3). Quite curious as to why it happens.
"@swc/core": "1.3.36",
"@swc/jest": "0.2.24",
today's latest, doesn't work.
Ran into this same issue, and pinning the @swc/jest
version didn't work. @aladinflux, thank you for the idea to check for top-line exports; that ended up being the problem.
For other folks' reference, I had to:
- isolate the one test in our suite that was throwing this error, and run it alone
- comment out every import in the file, and run again. Test fails, but coverage bug does not appear.
- one by one, uncomment an import and run the test again. If the coverage bug still does not appear, uncomment the next import and run again. If you uncomment an import and the coverage bug reappears, you'll know the issue is somewhere in the import tree of that file. Open it.
- Repeat steps 2 and 3 until you reach the leaf node(s) of your problem. Pay particular attention to any files whose first line is an export--add a comment and newline to the top of the file. Keep going til it's fixed.
- If your import tree was as large as mine, indulge in your vice of choice
@brockross it much easier to use small patch - https://github.com/istanbuljs/v8-to-istanbul/issues/198#issuecomment-1310007608. no any issues in very large (8000+ tests) repo since nov'22
Hello, seems that the issue is still not fixed. As for me personally i wasnt able to find which test breaks the coverage collection process, so maybe really the easiest way is to add lines[end]**?**.endCol
on line 30 in range.js ?
Edit: issue is caused by the first line export, so adding anything at the top of the file (for example comment) helps.
I ran into this today as well and really appreciate all the suggestions here but have to many tests to go one by one. In order to find the file that had export const
at the top I modified ./node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:146
. Wrapping the call site in a try/catch and logging the path shows you which file is the issue. Hope it helps until a fix can be merged 👍
} else {
try {
lines = sliceRange(covSource.lines, startCol, endCol)
} catch (e) {
console.log(path);
console.log(e);
}
}
Having an
export const
in the first line of the file was the problem for me. Adding a comment in line 1 and a return in line 2 as @aladinflux did worked for me.1 // leave this line here so the test coverage won't break 2 3 export const func = () => {...}
🤷♂️
Bro... thanks, I've hit the same error with vitest --coverage
, concluded this same thing, and found your comment here.
Idk what to think of it really, but this fixed my own case.
Also running into this issue when running some tests using Jest. Tried pinning @swc/core
to 1.3.3
, as suggested, and verified I have no exported const at the top of my test file, both to no avail.
TypeError: Cannot read properties of undefined (reading 'endCol')
at module.exports.sliceRange (/workspace/node_modules/v8-to-istanbul/lib/range.js:30:54)
at workspace/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:145:19
at Array.forEach (<anonymous>)
at workspace/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:130:20
at Array.forEach (<anonymous>)
at V8ToIstanbul.applyCoverage (workspace/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:129:12)
at workspace/node_modules/@jest/reporters/build/CoverageReporter.js:531:21
at async Promise.all (index 5)
at async CoverageReporter._getCoverageResult (workspace/node_modules/@jest/reporters/build/CoverageReporter.js:500:35)
at async CoverageReporter.onRunComplete (workspace/node_modules/@jest/reporters/build/CoverageReporter.js:172:34)
at async ReporterDispatcher.onRunComplete (workspace/node_modules/@jest/core/build/ReporterDispatcher.js:71:9)
at async TestScheduler.scheduleTests (workspace/node_modules/@jest/core/build/TestScheduler.js:306:5)
at async runJest (workspace/node_modules/@jest/core/build/runJest.js:367:19)
at async _run10000 (workspace/node_modules/@jest/core/build/cli/index.js:343:7)
at async runCLI (workspace/node_modules/@jest/core/build/cli/index.js:198:3)
at async Object.run (workspace/node_modules/jest-cli/build/run.js:130:37)
husky - pre-commit hook exited with code 1 (error)