Skip to content
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

Cannot read properties of undefined (reading 'endCol') #198

Open
valeneiko opened this issue Oct 27, 2022 · 24 comments
Open

Cannot read properties of undefined (reading 'endCol') #198

valeneiko opened this issue Oct 27, 2022 · 24 comments

Comments

@valeneiko
Copy link

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/v8-to-istanbul@9.0.1/node_modules/v8-to-istanbul/lib/range.js:30:54)
    at /workspace/node_modules/.pnpm/v8-to-istanbul@9.0.1/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:

_maybeRemapStartColEndCol (range) {

_maybeRemapStartColEndCol({
  count: 0,
  startOffset: 340,
  endOffset: 348
})

It receives object with all properties null from originalPositionFor here:

end = originalPositionFor(sourceMap, {

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"
}
@SimenB
Copy link
Member

SimenB commented Oct 27, 2022

@jridgewell can you tell if we're making wrong assumptions about source map shape here?

@jridgewell
Copy link
Contributor

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.

@valeneiko
Copy link
Author

"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}
}

@jridgewell
Copy link
Contributor

Sorry, I'm still missing the this.covSources field.

@valeneiko
Copy link
Author

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}

@jgeschwendt
Copy link

jgeschwendt commented Nov 1, 2022

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

@zaslow
Copy link

zaslow commented Nov 1, 2022

@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 🥇

@jridgewell
Copy link
Contributor

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:

Screen Shot 2022-11-05 at 1 44 42 PM

Screen Shot 2022-11-05 at 1 44 47 PM

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…

@aladinflux
Copy link

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.

@devcorraliza
Copy link

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.

@riku0202
Copy link

I lowered @swc/jest to version 2.20 and it worked!

@dyatko
Copy link

dyatko commented Dec 14, 2022

Tried 0.2.20 and it doesn't work

@zfben
Copy link

zfben commented Jan 4, 2023

I have the same issue

hurstindustries added a commit to hurstindustries/v8-to-istanbul that referenced this issue Jan 30, 2023
@bcoe
Copy link
Member

bcoe commented Feb 14, 2023

@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.

@mitestainer
Copy link

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 = () => {...}

🤷‍♂️

@wolandec
Copy link

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 :).

@clrtrm
Copy link

clrtrm commented Feb 22, 2023

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.

@benevbright
Copy link

    "@swc/core": "1.3.36",
    "@swc/jest": "0.2.24",

today's latest, doesn't work.

@brockross
Copy link

brockross commented Mar 10, 2023

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:

  1. isolate the one test in our suite that was throwing this error, and run it alone
  2. comment out every import in the file, and run again. Test fails, but coverage bug does not appear.
  3. 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.
  4. 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.
  5. If your import tree was as large as mine, indulge in your vice of choice

@koshic
Copy link

koshic commented Mar 10, 2023

@brockross it much easier to use small patch - #198 (comment). no any issues in very large (8000+ tests) repo since nov'22

@Nikkov17
Copy link

Nikkov17 commented May 3, 2023

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.

skorfmann added a commit to winglang/wing that referenced this issue Sep 10, 2023
@alexmarmon
Copy link

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);
  }
}

@big-kahuna-burger
Copy link

big-kahuna-burger commented Dec 20, 2023

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.

@reverbePrintemps
Copy link

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests