kulshekhar / ts-jest

A Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.

Home Page:https://kulshekhar.github.io/ts-jest

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Line numbers aren't mapped correctly in TSX files when using Node 8 AND React 16

jimthedev opened this issue · comments

  • Issue

When using Node version 8 tsx-errors.spec.ts fails with:

Summary of all failing tests
 FAIL  tests/__tests__/tsx-errors.spec.ts
  ● TSX Errors › should show the correct error locations in the typescript files

    expect(string).toContain(value)

    Expected string:
      "FAIL __tests__/Button.test.tsx
      ✓ Button renders correctly (13ms)
      ✕ BadButton should throw an error on line 18 (6ms)

      ● BadButton should throw an error on line 18

        Error in Bad button

          at BadButton.Object.<anonymous>.BadButton.render (Button.tsx:34:15)
          at Object.<anonymous> (__tests__/Button.test.tsx:11:14)
              at Promise (<anonymous>)
              at <anonymous>
          at process._tickCallback (internal/process/next_tick.js:188:7)

    Test Suites: 1 failed, 1 total
    Tests:       1 failed, 1 passed, 2 total
    Snapshots:   1 passed, 1 total
    Time:        2.75s
    Ran all test suites.
    "
    To contain value:
      "Button.tsx:18:17"

      at Object.<anonymous> (tests/__tests__/tsx-errors.spec.ts:10:20)
          at Promise (<anonymous>)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)


Test Suites: 1 failed, 22 passed, 23 total
Tests:       1 failed, 67 passed, 68 total
Snapshots:   2 passed, 2 total
Time:        23.794s
Ran all test suites matching /^(?!(.*watch.spec.ts$)).*/i.
npm ERR! Test failed.  See above for more details.
  • Expected behavior

I expect the test to pass.

  • Link to a minimal repo that reproduces this issue

This test is in the ts-jest repo so reproducing just involves upgrading to node 8 via nvm, n or some other method.

Thanks for reporting this. I was able to reproduce this issue. It looks related to react 16 in some way.

Yes I think you're correct. I would be happy to help on this if you point me in the right direction of what in React 16 might have changed the error line mappings?

I've pushed an additional change to your PR which should, hopefully, result in a failed build. It'll be good to have a common point of reference when debugging this issue.

I would be happy to help on this if you point me in the right direction of what in React 16 might have changed the error line mappings?

The issue appears to arise due to some changes in react-test-renderer

Sounds good!

Yeah react-test-renderer is where I got to and then figured I was out of my element since I wasn't sure what it did.

This is probably being caused due to the new error handling mechanism that React has. I'm not sure how this can be fixed in ts-jest.

I wonder if we can add in a custom log output in componentDidCatch that captures the right line.

componentDidCatch doesn't contain any line numbers

:( Dang.

they have some sort of a plugin for those using Babel but it won't help here
https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html#component-stack-traces

If this is due to the react code - can we just throw our errors in non-react code?

commented

We just read <div />._source.lineNumber. I don’t know where it comes from for TypeScript users. If you use Babel, babel-plugin-transform-react-jsx-source generates it as part of JSX.

So to fix it, you would need to either remove babel-plugin-transform-react-jsx-source (assuming you somehow use it after running TS), or add source metainformation at TypeScript level.

@GeeWee

If this is due to the react code - can we just throw our errors in non-react code?

I'm not sure I understand. Could you please elaborate?

@gaearon

We just read <div />._source.lineNumber

that's set by the babel-plugin-transform-react-jsx-source plugin.

I don’t know where it comes from for TypeScript users.

It isn't available at the moment the TypeScript file is processed. It wasn't required prior to v16 as all errors in .tsx files were displayed with the correct line numbers.

So to fix it, you would need to either remove babel-plugin-transform-react-jsx-source (assuming you somehow use it after running TS)

We don't currently use it but I actually think otherwise. We might need to use it if we can't find any solution. In that case as well, the plugin should be capable of using sourcemaps (that are emitted after we process .tsx files) to display the correct line numbers. Does the plugin handle sourcemaps?

or add source metainformation at TypeScript level

In the worst case, this might be the way to go.

Curiously, it only fails in node version 8. I was able to reproduce this as part of #333

I'm not sure I understood it right the first time around. Do we still think this is due to react error boundaries?

It only failing in node 8 says no to me, but it's very curious.

commented

It wasn't required prior to v16 as all errors in .tsx files were displayed with the correct line numbers.

React 16 didn't change anything in how line numbers are associated with JSX. There are only two things that changed:

  • React now catches errors during rendering before rethrowing them.
  • React adds extra information in the form of component stack when JSX line numbers are available.

React can't possibly affect the line numbers from JavaScript stack. Those are reported by the JavaScript engine. I now see that your report was about JS line numbers so my previous comments about JSX transform were not relevant.

I'm going to try and find some time to dive deeper into this but in case someone else is looking at it, here's what the situation looks like:

  • This issue seems to affect only projects that use React 16 AND Node 8.
  • Projects using React 16 with an older version of node aren't affected
  • Projects using an earlier version of React with node 8 aren't affected

Some debugging threw up this error message:

    Error
        console.error ../../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2055
          The above error occurred in the <BadButton> component:
              in BadButton
              in BadButtonBoundary
          
          React will try to recreate this component tree from scratch using the error boundary you provided, BadButtonBoundary.
      
        console.error ../../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2055
          The above error occurred in the <BadButtonBoundary> component:
              in BadButtonBoundary

I have a suspicion that some code in react is throwing the built-up error and in the process (directly or indirectly) suppressing the stack trace

@gaearon

React 16 didn't change anything in how line numbers are associated with JSX. There are only two things that changed:

  • React now catches errors during rendering before rethrowing them.
  • React adds extra information in the form of component stack when JSX line numbers are available.

React can't possibly affect the line numbers from JavaScript stack. Those are reported by the JavaScript engine. I now see that your report was about JS line numbers so my previous comments about JSX transform were not relevant.

Thanks for the insights.

The absence of a stack trace is the likely cause of this issue.

Is it possible that some edge case handler (or some branch of code) in the renderer is suppressing the stack trace? The reason I think this might be the case is because this fails only on Node 8 and not on the earlier versions.

commented

Where do you see the stack trace being suppressed?

Sorry about that!

That was the result of some changes that I had made while debugging. Please disregard my previous comment (updated)

I've spent some time on this and don't think this is an issue with ts-jest. ts-jest is processing the tsx files correctly and is adding the sourcemap as well as the code to use source-map-support.

There's not much we can do about this here, I'm afraid.

The readme needs to be updated with a note about react 16 + node 8.

I noticed that I get correct source-mapping in thrown Errors when I set "useBabelrc": false, in the package.json["jest"]["globals"]["ts-jest"] config block (alongside "mapCoverage": true)

(To be clear, this doesn't mean I got correct code-coverage, just that errors thrown in TS files needed ts-jst to avoid babel).

Maybe this helps?

I was wondering if there is any more information or progress on this? I'm trying to set up Jest for the first time and stack trace line numbers are incorrect as per this issue. It's a little different for me:

  1. We are on React 15
  2. Node version has no effect (tried 6, 7, 8, 9)
  3. Source maps work perfectly when I debug in VS Code, so it seems unrelated to sourcemaps themselves.

I've sought support via Discord and there are unanswered Stack Overflow questions with the same issue, there doesn't seems to be any resolution or workaround. This seems like a pretty big problem.

Does anyone more familiar with Jest & this issue know if this is affecting everyone using Jest + TypeScript or just isolated cases? It seems odd that it's been going on so long unresolved if it's affecting a large number of people. I'm not sure how I can make a case that we should be adopting Jest if I can't get source maps working correctly, but i've been working on this for several days and nothing seems to work so I'm pretty baffled. I've tried various workarounds from older issues, e.g. turn on mapCoverage, disableSourceMapSupport option, nothing makes any difference.

I fixed it by adding the --mapCoverage flag

react-scripts test --env=jsdom --coverage --mapCoverage

Tried adding mapCoverage, it's been deprecated as of 22.4.0. I've tried literally every possible combination of options - useBabelrc, disableSourceMapSupport, in babelrc "sourceMap": "inline", nothing makes any difference.

Not sure what magic it is.
We also have this problem. However, running the tests with --mapCoverage flag fixed this.
versions:
ts-jest: 22.4.5
node: v9.10.1
react: v16.0.0

@jamietre Did you try the CLI flag --mapCoverage or the config option? I did both test and strangely, only the command line flag --mapCoverage works. Using mapCoverage: true is not working.

That's really strange :(

@maoueh ! -- that's a big catch. I was only using the config option. I haven't tested the CLI flag. I don't know when I'll get to experiment with implementing that in our repo, but that's really key.

For people coming to this issue from the FAQ, mapCoverage is removed in later versions of Jest as it's not needed anymore.

(that won't help create-react-app I suppose, as that's on an older version of jest)

@jamietre @6220119 @maoueh @fbartho you can try the beta release of ts-jest (see #697). It should fix your coverage/line-mapping issues.

@SimenB I'd love to chat about jest+ts-jest. We now have our slack channel so let's chat there if you can.

@huafu sorry, missed your message. I'm already a member of way too many Slacks, but you can join us over on Reactiflux? https://discord.gg/MWRhKCj

Same problem for non-react projects - invalid stack trace line number.

Node v12.16.1
ts-jest@25.2.1
jest@25.1.0

(it is showing .ts file but line number isn't mapped to original ts file)

@fider-apptimia I had the same problem in non-react project when I was using async/await. Changing target in tsconfig.json to ES2019 fixed it for me.

This is how my tsconfig.json looks like (only target is edited, the rest are default tsc --init values):

{
  "compilerOptions": {
    "target": "ES2019",                       /* ES2019 is rquired to display proper stack trace when using async/await and '?.' operator */
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}

@adambbn here is my full tsconfig:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "noImplicitAny": true,
    "module": "CommonJS",
    "moduleResolution": "node",
    "allowJs": true,
    "strict": true,
    "isolatedModules": true,
    "pretty": true,
    "sourceMap": true,
    "target": "ES2019",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "rootDir": "./",
    "outDir": "./dist"
  },
  "exclude": ["dist", "node_modules"]
}

Still invalid stack trace with ES2019 - stack traces of errors throwed from my .ts file wrapped by jest are still not mapped.

Just in case someone stumbles on this issue in the future.
I've hit that issue again recently.
While I was trying to make a minimal repro, I was struggling to do it in a controlled environment.
After much reducing in my main project I finally identified the culprit.
There was a ts-node import and register which caused bad line numbers

I managed to make a minimal repro here
https://github.com/Cellule/ts-jest-line-numbers

I doubt this is something that ts-jest should handle/fix ? But if that can help another than I'm glad