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

Breakpoints & sourcemaps do not work with a react native setup in Webstorm #209

Closed
GeeWee opened this issue May 11, 2017 · 21 comments
Closed

Comments

@GeeWee
Copy link
Collaborator

GeeWee commented May 11, 2017

  • Issue

When running a react native configuration, it is impossible for me to get any breakpoints to register in Webstorm.
Debugger statements work but do not break at the correct line.

I have a suspicion that the sourcemaps are to blame. This is an example of it breaking before the debugger statement:
billede

However when I remove the typescript interface it breaks like this:
billede

My thoughts are, that it is using an es6 sourcemap, and not the typescript sourcemaps.
My tsconfig is set to enable inline sourcemaps, and looks like this:

{
    "compilerOptions": {
        "jsx": "react",
        "allowSyntheticDefaultImports": true,
        "target": "es2015",
        "moduleResolution": "node",
        "inlineSourceMap": true
    },
    "exclude": [
        "node_modules"
    ]
}

and jest config looks like this:

	"jest": {
		"preset": "react-native",
		"transform": {
			"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
			".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
		},
		"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
		"moduleFileExtensions": [
			"ts",
			"tsx",
			"js",
			"json"
		],
		"globals": {
			"__DEV__": true
		}
	}

I do not know if this is a webstorm or jest regression, or whether the react native build setup has anything to do with it.

  • Expected behavior

I expect to be able to set breakpoints, and that the debugger statements stop at the correct place.

  • Link to a minimal repo that reproduces this issue

This is a minimal repo that reproduces the issue. Simply go to the some-test.test.tsx, and in webstorm left click on the test and click debug.
https://github.com/GeeWee/rn-typescript-example/tree/ts-loader-bug

I'm not sure how to set up any test cases for this particular bug.

@kulshekhar
Copy link
Owner

I was able to get the debugger to stop at the breakpoint with the following changes:

  • comment out allowSyntheticDefaultImports from tsconfig.json
  • use jest 20.0.0
  • add the following in jest config:
"testPathIgnorePatterns": ["/node_modules/", "<rootDir>/src/some-test.test.js"],
"mapCoverage": true,

@GeeWee
Copy link
Collaborator Author

GeeWee commented May 11, 2017

Great stuff, I was as well! Thanks a lot for the quick reply @kulshekhar .
The only thing that was actually needed was commenting out the allowSyntheticDefaultImports

However, my codebase makes quite a bit of use of default imports, e.g. import React from 'react'
My tests work with these, if allowSyntheticDefaultImports is on.
I figured I could simply run the test suite with allowSyntheticDefaultImports - as tsc explicitly states it only has to do with typechecking, not code emission, as that would let the breakpoints work.

However - it's not quite that simple. My tests actually start breaking when it is turned off, even when doing a lot of the workarounds described in #92.

I've updated the repo at https://github.com/GeeWee/rn-typescript-example/tree/ts-loader-bug to display this new issue. If you run it out of the box, with allowSyntheticDefaultImports: true the tests will pass, and the breakpoints will not work, but if you run it with allowSyntheticDefaultImports: false the breakpoints will work, but the test imports will fail.

Note that you'll need to run the webstorm configuration with --no-cache to provoke it reliably.

@kulshekhar
Copy link
Owner

I don't really use babel or synthetic imports so I'm not sure what needs to be done here.

When allowSyntheticDefaultImports is set, ts-jest uses babel-jest internally to process typescript compiler's output. I suspect this is probably where the fix would go. I'm not sure though.

Maybe @ds300 can chime in?

@GeeWee
Copy link
Collaborator Author

GeeWee commented May 11, 2017

Yes that makes perfect sense! Because babel-jest ( at least with the react native preset ) creates synthetic default exports that typescript can grab.

It seems like the problem here would be that if the ts files are passed to babel-jest, the sourcemaps are not included.

I have set sourceMaps: "inline" in my .babelrc and it seems to allow me to set breakpoints and not fail my tests.
I've updated my repo - can you see if it works for you?

I would be willing to do a PR explaining a more detailed react-native setup guide. (e.g. someone should really mention it pipes it through babel-jest if you use allowSyntheticDefaultImports - I spent quite a bit of time on a preprocessor that would do essentially the same thing)

@kulshekhar
Copy link
Owner

@GeeWee that worked! A PR with the explanation would be very welcome :)

@GeeWee
Copy link
Collaborator Author

GeeWee commented May 11, 2017

Wonderful! I'll definitely get a PR up and rolling, though I'll want to make sure the same setup works in VSCode as well :)

@GeeWee
Copy link
Collaborator Author

GeeWee commented May 14, 2017

@kulshekhar - this setup also works in VSCode. At least almost.
I have debugger statements working, and it shows the correct source code, so the sourcemaps work.
However, I'm unable to set breakpoints - vscode seems to ignore those handily.
I'd love to get a PR in explaining both editors, but I'm a little hindered right now - I'm not very good with VSCode.
Do you have any ideas? Would you like me to open a new issue?

@kulshekhar
Copy link
Owner

@GeeWee It might be best to add instructions for Webstorm/IDEA (since we have that working) and open a new issue for VS Code.

@shlomiassaf
Copy link

@kulshekhar This workaround does work, however it is an issue since now the test code after compilation does not match the actual code after compilation.

For example:

import * as pathToRegexp from 'path-to-regexp';

The library above requires "allowSyntheticDefaultImports": true.
When so, the value of pathToRegexp is a function.

When running in test I get an error since the imported module pathToRegexp is not a function, it is an object with a default property that is the function.

This creates an inconsistent behaviour

@kulshekhar
Copy link
Owner

@shlomiassaf are you referring to this workaround?

@shlomiassaf
Copy link

Actually I used the other one but it's the same.

@kulshekhar
Copy link
Owner

@shlomiassaf those two aren't the same. If there seems to be a problem, can you create & share a minimal repo specific to your case?

@GeeWee
Copy link
Collaborator Author

GeeWee commented May 14, 2017

I have created #212 for the VSCode issue.

@shlomiassaf
Copy link

@kulshekhar

https://github.com/shlomiassaf/ts-jest-issue-209

npm run start will execute a ts file

import * as pathToRegexp from 'path-to-regexp';

console.log(`Type of module alias import of "path-to-regexp" is ${typeof pathToRegexp}`);

This should show that pathToRegexp is a function

Then npm run test will execute unit testing with jest and ts-jest

import * as pathToRegexp from 'path-to-regexp';

describe('TEST', () => {
  it('module alias import of "path-to-regexp" should be a function', () => {
    // if this fails it means that pathToRegexp is an object with a "default" property that is the expected function
    expect(typeof pathToRegexp).toEqual('function');
  });
});

It will fail since pathToRegexp is now an object with a default property referencing the function.
This is an expected behaviour when allowSyntheticDefaultImports": false, which is not the case.

Note that both tsconfig files are identical

You can remove the .babelrc file, it will still fail the test.

@kulshekhar
Copy link
Owner

@shlomiassaf I'm slightly confused here. How is this relevant to the proposed solution (which sets allowSyntheticDefaultImports to true)?

@shlomiassaf
Copy link

shlomiassaf commented May 14, 2017

@kulshekhar If you look at the code you will see that for the same code compiled with TS, ts-jest emits a different output.

  • Both tsconfig file are identical (one for regular TS compilation, one for ts-jest)
  • allowSyntheticDefaultImports set to true.

When using this statement:

import * as pathToRegexp from 'path-to-regexp';

In TS compilation without ts-jest pathToRegexp is a function
In TS compilation with ts-jest pathToRegexp is an object.

It's not deterministic, different outcome for the same TS compilation process

@kulshekhar
Copy link
Owner

@shlomiassaf that's because when allowSyntheticDefaultImports is set to true, ts-jest processes the output of the typescript compiler with babel. This is required because Jest can only process ES5 code. There's no way around this.

This is also unrelated to this issue. If you think there needs to be a discussion on this here, it might be better to open a new issue so that we can focus better.

@shlomiassaf
Copy link

@kulshekhar I'll open an issue, just to understand, why would you need babel for that? you can use TS compiler to emit ES5 code.

@kulshekhar