jest: [Bug]: Unable to use ESM-only modules with TypeScript and babel-jest
Version
29.4.2
Steps to reproduce
Run yarn install
and yarn test
with the following package setup.
Note that react-dnd-html5-backend
is used as an example of an ESM-only package.
package.json:
{
"name": "jest-test",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "module",
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"devDependencies": {
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"babel-jest": "^29.4.2",
"jest": "^29.4.2",
"react-dnd-html5-backend": "^16.0.1",
"uuid": "^9.0.0"
}
}
babel.config.json:
{
"presets": [
["@babel/preset-env", { "targets": { "node": "current" }, "modules": false }],
"@babel/preset-typescript"
]
}
index.test.ts:
import {HTML5Backend} from 'react-dnd-html5-backend'
describe("example", ()=> {
it("works", ()=> {
console.log('backend', HTML5Backend)
expect.assertions(0);
})
})
Expected behavior
yarn test
should work.
Actual behavior
WITHOUT "modules": false
in @babel/preset-env
options, an error occurs because react-dnd-html5-backend
is an ESM-only package:
$ yarn test
yarn run v1.22.15
$ NODE_OPTIONS=--experimental-vm-modules jest
FAIL ./index.test.ts
● Test suite failed to run
Must use import to load ES Module: /Users/jacob/Desktop/jest-test/node_modules/react-dnd-html5-backend/dist/index.js
> 1 | import {HTML5Backend} from 'react-dnd-html5-backend'
| ^
2 |
3 | describe("example", ()=> {
4 | it("works", ()=> {
at Runtime.requireModule (node_modules/jest-runtime/build/index.js:817:21)
at Object.<anonymous> (index.test.ts:1:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.294 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
WITH "modules": false
in @babel/preset-env
options (to leave the ES module syntax alone, because we are using --experimental-vm-modules
), an error also occurs:
$ yarn test [1]
yarn run v1.22.15
$ NODE_OPTIONS=--experimental-vm-modules jest
FAIL ./index.test.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/jacob/Desktop/jest-test/index.test.ts:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { HTML5Backend } from 'react-dnd-html5-backend';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1449:14)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.289 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Additional context
No response
Environment
System:
OS: macOS 13.2
CPU: (10) arm64 Apple M1 Pro
Binaries:
Node: 16.15.1 - ~/.nvm/versions/node/v16.15.1/bin/node
Yarn: 1.22.15 - ~/.nvm/versions/node/v16.15.1/bin/yarn
npm: 8.11.0 - ~/.nvm/versions/node/v16.15.1/bin/npm
npmPackages:
jest: ^29.4.2 => 29.4.2
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 13
- Comments: 33 (5 by maintainers)
I’ve had similar problem and looked into it, and there are multiple points that can cause similar error message. It seems like the solution is different by whether if you use
--experimental-vm-modules
. (https://jestjs.io/docs/ecmascript-modules)If you use ‘–experimental-vm-modules’, it seems like Jest needs to decide each file’s module type (between ESM modules and CJS, just like Node.js does). For example, if Jest misdetects the module type, you’ll encounter “Must use import to load ES Module”, or “Cannot use import statement outside a module” error.
Furthermore, it seems like Jest sends the current module type to Babel, and Babel transpiles the code accordingly to fit the module type. For example, if Jest detects that the file is CJS, then Babel will use
module.exports
. But if it’s detected as ESM, Babel will keepimport
andexport
. For this reason, you don’t need to putmodules: false
in.babelrc
orbabel.config.js
if Jest is configured correctly.Therefore, It’d be crucial to make sure if the module type is detected correctly.
"type": "module"
inpackage.json
, as Node.js and Jest discerns the file type using it. Node.js Module System.ts
,.tsx
file as ESM module. This can be achieved by settingextensionsToTreatAsEsm: ['.ts', '.tsx']
injest.config.js
. #babel.config.js
, make sure that there is no"modules"
setting in"@babel/preset-env"
. It should still work if it’s set tofalse
, but you won’t really need it. #So, @jtbandes, can you check that
extensionsToTreatAsEsm
fixes your problem? @hubertlepicki, can you make sure that"type": "module"
is set in yourpackage.json
?If you don’t use ‘–experimental-vm-modules’, you have to make sure that babel can transpile all the files, including files in
node_modules
into CommonJS format. There are some points to check as well:babel.config.js
(orbabel.config.json
), NOT.babelrc
! Since Jest expects that everything is CommonJS, you need to transpile pure ESM packages as well.node_modules
as well. This can be achieved by settingtransformIgnorePatterns: []
insidejest.config.js
. #babel.config.js
, make sure that there is no"modules"
setting in"@babel/preset-env"
. #If you use
.babelrc
, Babel simply ignores the.babelrc
file when it’s insidenode_modules
directory. It’s because that Babel simply stops seeking the.babelrc
once it findspackage.json
. In other words,.babelrc
will keepimport
andexport
, which is unusable in Jest. Babel Config FilesHope I covered everything!
Sounds like this is still an issue.
Still happening with 29.4.2.
having the same problem, can’t seem to use the ESM module support. I get the same error whether or not I run using
node --experimental-vm-modules node_modules/jest/bin/jest.js
or justyarn jest
@lazarljubenovic Thanks for reproduction. In this case
ts-jest
is misconfigured. See ESM Support page in their docs. There is theuseESM
option and three ESM presets. All works if I use configuration from the page (did try the presets, not sure what are the differences between them).Also it is enough adding
extensionsToTreatAsEsm: ['.ts']
, removingtransform
from Jest config. And adding configuration for Babel (follow Getting Started guide to install required Babel dependencies):All works as documented, just read the docs (;
I have my package set to
"type": "module"
and everything but jest works, including webpack. For me removing"modules": false
from my babel config is not an option because it would essentially remove all the benefits of using using ES modules.However, because jest is using VM and ES modules are experimental with that feature, and jest has some outstanding issues to resolve (such as jest.requireActual -> jest.importActual), it’s OK with me just to disable modules just for jest and keep it enabled for everything else.
This is how you do it. Use this transform:
This will pull your existing babel config and override
"modules"
. Once jest resolves the issue you should be able to remove that from your jest config, and update mocks that likely can’t usejest.requireActual
anymore (as they probably will need to make an asyncjest.importActual
).This is happening for me as well. The stack is lacking TypeScript, but we have React, Babel and Jest.
When installing an ESM-only package to my project, like p-throttle version 5.0.0, and then runnig the tests with enabled experimental ESM modules support I get the following:
I believe this is the same problem @jtbandes is reporting.
I don’t quite understand the whole babel/jest build process, but it’s probably worth noting that the package builds and runs fine with ESM only package, the problem is only present when running tests.
I tried various combinations of settings mentioned here but nothing seems to have an effect. For example:
@SimenB This is still an issue. The problem is related to importing dependencies that are now ESM only and how jest handles those dependencies out of the box. It is solvable by telling babel-jest to transpile those dependencies (as shown above).
This is also somewhat related to https://github.com/jestjs/jest/issues/9430 which is still being worked on. Meaning one way to resolve this is by making your own package/app an ESM module. Depending on how you use jest, you may not be able to do this until that issue is solved. For my case I need importActual for my test setup to replace requireActual.
@yoo2001818 I followed these directions and got everything working perfectly. Thank you!
The reproduction you provided is very good example how to get the problem solved. Thanks for that once again!
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.