esbuild-jest
esbuild-jest copied to clipboard
Is breakpoints are not working or I'm the only one?
Hey, I try to set a breakpoint in the test but it never stops.
I run in-band etc. I'm using WebStorm functionality for that. Is it working with VSCode maybe? Anyone can confirm? What command are you using to achieve that?
I'm running the latest esbuild and esbuild-jest
@RIP21 it works on vscode i havent tried in webstorm, heres a repository https://github.com/aelbore/vs-code-jest-debug Please check launch.json for some comments
I can't get it to work on IntelliJ (which is the same thing as webstorm). I suspect sourcemaps since the tests run just viel. I thought it used to work.
what version you are using? if you are not using jest.mock just use [email protected]
i only tried vscode for break point and it works fine for me
vscode break point here https://github.com/aelbore/vs-code-jest-debug
After some experimenting, removing this line seems to partially fix debugging in IntelliJ (and should for Webstorm). Some of the mappings are wrong but it at least works inside test files.
map.sourcesContent = null;
I'm using a modified version of this package. Here's the full code I have working:
const esbuild = require('esbuild');
const path = require('path');
/**
* Jest ESBuild is a jest transformer that uses esbuild to compile .ts and .tsx
* into Node.js compatible JavaScript.
*
* Originally copied from the MIT licensed
* https://github.com/aelbore/esbuild-jest/
* @param {string} sourceText
* @param {string} sourcePath
* @param {import('@jest/types').Config} _config
* @param {import('@jest/transform/build/types').TransformOptions} _options
* @return {import('@jest/transform/build/types').TransformedSource}
*/
const process = (sourceText, sourcePath, _config, _options) => {
const loader = path.extname(sourcePath).slice(1);
if (loader !== 'ts' && loader !== 'tsx' && loader !== 'js' && loader !== 'jsx') {
throw new Error(`Unsupported extension type '${loader}' for esbuild Jest transformer on file: ${sourcePath}`);
}
const esbuildOpts = {
format: 'cjs',
target: 'esnext',
loader: loader,
sourcemap: true,
sourcesContent: false,
sourcefile: sourcePath
};
const result = esbuild.transformSync(sourceText, esbuildOpts);
if (result.map) {
// Add inline source maps so debugging works.
result.code += '\n//# sourceMappingURL=data:application/json;base64,';
result.code += Buffer.from(result.map).toString('base64');
}
return result
};
module.exports = {process};
whats your jest config? did you set the sourcemap to true? what esbuild you are using? maybe theres change on esbuild. it use to work before will check also thanks 👍
setting the sourcesContent: null before works fine but let me verify that one
Breakpoints work and mappings seem to have fixed themselves. That might have been changing sourcemap: true
to sourcemap: 'both'
.
whats your jest config? did you set the sourcemap to true?
Good thought, included below. I'm using a modified version of this package so the sourcemap config option is included in my jest-transform-js.js
modifications as sourcemap:'both'
.
Esbuild version: "esbuild": "^0.9.0",
jest-transform.js
const esbuild = require('esbuild');
const path = require('path');
/**
* Jest ESBuild is a jest transformer that uses esbuild to compile .ts and .tsx
* into Node.js compatible JavaScript.
*
* This file is JavaScript using commonjs modules (require instead of import)
* because it's the compiler for TypeScript files when running with jest. We
* want this file to run directly under Node to avoid bootstrapping.
*
* Originally copied from the MIT licensed
* https://github.com/aelbore/esbuild-jest/
* @param {string} sourceText
* @param {string} sourcePath
* @param {import('@jest/types').Config} _config
* @param {import('@jest/transform/build/types').TransformOptions} _options
* @return {import('@jest/transform/build/types').TransformedSource}
*/
const process = (sourceText, sourcePath, _config, _options) => {
const loader = path.extname(sourcePath).slice(1);
if (loader !== 'ts' && loader !== 'tsx' && loader !== 'js' && loader !== 'jsx') {
throw new Error(`Unsupported extension type '${loader}' for esbuild Jest transformer on file: ${sourcePath}`);
}
const esbuildOpts = {
format: 'cjs',
target: 'esnext',
loader: loader,
sourcemap: 'both',
sourcesContent: true,
sourcefile: sourcePath
};
return esbuild.transformSync(sourceText, esbuildOpts)
};
module.exports = {process};
jest.config.js
/** @type import('@jest/types/build/Config').InitialOptions */
module.exports = {
displayName: 'myapp',
errorOnDeprecated: true,
transform: {
'[.][jt]sx?$': "./testing/jest-transform-js.js",
'[.]css$': "./testing/jest-transform-css.js",
'[.]svg$': "./testing/jest-transform-svg.js",
},
setupFiles: ["./testing/jest-setup-polyfills.js"],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
rootDir: 'src',
testRegex: '_test[.]tsx?$',
// Place snapshots next to test files, like app_test.tsx.snap.
snapshotResolver: './testing/jest-snapshot-resolver.js',
};
@aelbore passing "both" to sourcemap
doesn't work if passed through the jest config as it will be overridden to become sourcemap: true
no matter the value you pass.
It will be passed correctly to babel transform for this ock(
hack.
Created a PR (from the Github UI don't blame me :D) https://github.com/aelbore/esbuild-jest/pull/28 Check it please as I'm not sure if sourcemap is passed properly.
I manually changed to both
and it doesn't help with WebStorm unfortunately.
Although esbuild-register
works fine with IntelliJ/WebStorm.
Check this code.
https://github.com/egoist/esbuild-register/blob/master/src/node.ts
Unsure if it's possible but maybe it will give some idea.
I can confirm that with the setup above of @jschaf it all works until there is a jest.mock
of course.
So it needs some fixes so it starts to work with this babel workaround for jest.mocks
Sorry for the spam... but here is the workaround for fellow WebStorm/IntelliJ users here. esbuild-jest.js
module.exports = require('esbuild-jest')
index.js (you may name it jest.config.js) but in my case it's a module that I'm sharing through the repo.
module.exports = {
roots: ['<rootDir>/src'],
transform: {
'^.+\\.tsx?$': require.resolve('./esbuild-jest.js'),
},
modulePaths: ['src'],
reporters: [require.resolve('jest-standard-reporter')],
coverageReporters: ['text-summary'],
collectCoverageFrom: ['src/**/*.{js,jsx,mjs,ts,tsx}'],
}
And breakpoints are working... Note that I'm using Rush.js and PNPM as a package manager, so it may be somehow related to that due to hard links and all that "magic" that PNPM does. And above is a module that I'm sharing.
I still think there are some bugs of some sort in the code due to this options
and opts
thingy that I'm unsure how they should work together. But other than that, this workaround works.
It stopped work again tho...
So here is my lifehack to you folks. If you want to speedup Jest with esbuild
, just don't, too many hacks to make mocks working :)
Just use this https://github.com/alangpierce/sucrase/tree/main/integrations/jest-plugin instead.
Surcrase is mega quick and is similar to Babel and works no problem with Jest via this plugin. It will require you to hoist jest.mock
calls yourself which is a bit annoying. But there is a PR opened that should fix that.
https://github.com/alangpierce/sucrase/pull/540
Hey @RIP21 any chance to share your config for Sucrase? I was trying to configure it with no luck 😞
@PatrykMilewski sure mate! :)
module.exports = {
roots: ['<rootDir>/src'],
transform: {
'^.+\\.tsx?$': require.resolve('@sucrase/jest-plugin'),
},
modulePaths: ['src'],
reporters: [require.resolve('jest-standard-reporter')],
coverageReporters: ['text-summary'],
collectCoverageFrom: ['src/**/*.{js,jsx,mjs,ts,tsx}'],
}
It has jest-standard-reporter
to work properly with Rush.js
so you can ignore this part :) But the rest should just work.
You can try latest version, the only thing that may be annoying tho is that you'll have to hoist up manually all jest.mock
calls above the import
s which is annoying :) Although it should change since this will be published https://github.com/alangpierce/sucrase/pull/540
{
"name": "@liveflow-io/config-jest",
"version": "0.0.1",
"description": "Jest config base",
"license": "MIT",
"main": "./index.js",
"dependencies": {
"@sucrase/jest-plugin": "~2.0.0",
"jest-standard-reporter": "~2.0.0"
},
"scripts": {
"build": ""
}
}
@RIP21 Thanks! It works great! Not sure what was wrong with my config lol
@PatrykMilewski proszę bardzo :P Miłego wieczoru :)
The issue seems to be that the altered map
contains sourcesContent: null
. When it is deleted (or set to undefined
), then breakpoints started working.
https://github.com/aelbore/esbuild-jest/blob/daa5847b3b382d9ddf6cc26e60ad949d202c4461/src/index.ts#L53-L57
Should be:
if (enableSourcemaps) {
map = {
...JSON.parse(result.map),
sourcesContent: undefined,
}
Also using sourcemap: 'both', sourcesContent: false
seems to not include sourcesContent
so I'm not sure why the manual manipulation.
const sourcemaps = enableSourcemaps ? {
sourcemap: 'both',
sourcesContent: false,
sourcefile: filename
} : {
};
Also, when changing any of this, the Jest cache in your temp directory needs deleted between runs.
@aelbore is there any chance to fix that? I would like to eventually use the same transpiler for both normal code and tests, as it's more consistent and safer. Right now I'm using Sucrase Jest plugin, as it's the only thing that I managed to configure to work with breakpoints.
@ngbrown, unfortunately, these changes don't make breakpoints work for me (Webstorm). Are there any other changes needed?
@ngbrown If you don't need decorators support, use @sucrase/jest-plugin jest plugin instead. It works great with Webstorm.
@PatrykMilewski I am working with ESM only currently and with @sucrase/jest-plugin
I get the following error, unfortunately:
Test suite failed to run
ReferenceError: require is not defined
@dan-lee I'm also using ESM, check out my minimal example here: https://github.com/PatrykMilewski/sucrase-test just bump the version of Sucrase plugin to the latest in package.json and it should work fine.
Thanks all for the suggestions to use @sucrase/jest-plugin instead, that fixed webstorm breakpoints in my tests!