Jest with TypeScript and ES modules can't import "named imports" from cjs modules
See original GitHub issueš Bug Report
Using TS, exports from CJS modules can be imported with syntax as if they were named ES module exports, e.g.:
import { sync } from 'glob';
However, with Jest and ES modules, when this style of import is in a test file or in a dependency of a test file, it says SyntaxError: The requested module 'glob' does not provide an export named 'sync'
Going through all one by one and changing them to import glob from 'glob';
and then calling glob.sync()
seems to work, however when migrating some legacy stuff from another test runner to Jest this may not be an option, because there are a lot of those such imports in the codebase.
Is there a way around this, so that import { whatever } from 'whatever';
will work for CJS modules?
To Reproduce
Steps to reproduce the behavior:
Running jest with: node --experimental-vm-modules node_modules/jest/bin/jest.js
(as described in https://jestjs.io/docs/ecmascript-modules), and using Jest config:
resetMocks: true,
testEnvironment: "node",
testMatch: [
"**/src/**/*.(spec|test).[tj]s?(x)"
],
preset: 'ts-jest/presets/default-esm',
transform: {},
'extensionsToTreatAsEsm': [".ts", ".tsx"],
globals: {
'ts-jest': {
useESM: true,
tsconfig: {
allowSyntheticDefaultImports: true,
declaration: true,
esModuleInterop: true,
jsx: "react",
lib: ["esnext"],
module: "es2020",
moduleResolution: "node",
outDir: "build",
sourceMap: true,
strictNullChecks: true,
target: "ES2020",
}
},
}
Expected behavior
import { sync } from 'glob'
and similar imports from CJS modules work.
Link to repl or repo (highly encouraged)
https://github.com/themaskedavenger/tsjestcjerepro
envinfo
System:
OS: macOS 10.15.7
CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
Binaries:
Node: 15.14.0 - /usr/local/bin/node
Yarn: 1.22.0 - /usr/local/bin/yarn
npm: 7.7.6 - /usr/local/bin/npm
npmPackages:
jest: ^27.0.4 => 27.0.4
Issue Analytics
- State:
- Created 2 years ago
- Reactions:16
- Comments:7
Top GitHub Comments
Okay so dug into this a bit and hopefully my investigation helps whoever ends up fixing this on jestās side.
The first and important thing to note is that jest does not use nodejs to resolve files. This tripped me up a lot until I figured this out. Both jest and nodejs use
cjs-module-lexer
which uses basic regex to parse a contents of a file to determine what the exported functions are from a cjs library. The owner of that library had a great explanation that helped guide the rest of this investigation. Now what this means is the same package has the possibility of behaving differently between nodejs and jest and thatās really important because that gap between the two is going to cause lots of confusionā¦ so using a few examples letās take this package by packageā¦glob
Globās export code looks like
module.exports = glob
which would require an eval on the js code to determine what the exports are. This is whycjs-module-lexer
cannot determine the exports, because itās purely basing it off regex for performance reasons required by nodejs. This will fail in both nodejs and jest.enzyme
Enzymeās export code looks like
however it seems that
cjs-module-lexer
is only able to extract the first exported function. I commented about this bug in https://github.com/guybedford/cjs-module-lexer/issues/57 and provided a unit test for reproduction. Hopefully we can see it get fixed.tslib
tslib actually supports cjs, es6 through the
module
property (non-standard) and ESM through theexports
property (node compatible) so this should work.When running the following code in node in either cjs or esm there are no errors (as expected)
However when running the following test in Jest ESM:
Youāll get the following error:
Which means that jestās resolver isnāt resolving the same file that node js is resolving that eventually gets sent to
cjs-module-lexer
so that it can correctly determine the exports.Summary
Hopefully that gives some guidance to someone who investigates this and maybe we can at least fix this for tslib. To fix this for glob however, youāll need to fix it in
cjs-module-lexer
. Iād still leave this ticket open to hopefully fix it for tslib though.In hopes that it speeds things along and removes any question as to ownership, I forked the repository provided by @themaskedavenger and removed all typescript related stuff to show itās a jest issue.
https://github.com/k2snowman69/tsjestcjerepro
Hopefully this removes any doubt that this is a ts or a ts-jest issue
Tested with node 14.17.1 and node v16.1.0