Jest won't transform the module - SyntaxError: Cannot use import statement outside a module
TypescriptJestjsBabel JestTs JestTypescript Problem Overview
I couldn't get rid of this SyntaxError: Cannot use import statement outside a module
error no matter what I have tried and it got so frustrating. Is there anybody out here solved this issue? I have read a million stackoverflow and github issue threads. No clear solutions.
This is a React, Typescript, Webpack project. I am trying to test a module. But Jest won't transform the module to plain javascript somehow.
The error I get is
/Users/me/dev/Project/project/node_modules/variables/src/variables.js:12
import './main.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
17 |
18 | */
> 19 | import { GlobalVars } from 'variables'
| ^
20 |
21 | export const Vars = new GlobalVars()
22 |
What I have tried to solve this (and didn't work):
-
Using
env
setup inbabel.config
:env.test.preset: ['@babel/plugin-transform-modules-commonjs']
-
modifying
transform
setup in Jest configuration as'^.+\\.jsx?$': 'babel-jest', '^.+\\.tsx?$': 'ts-jest'
and all other possibilities around this. -
In Jest configuration,
testPathIgnorePatterns
,transformIgnorePatterns
-
Using
.babel.config.js
instead of.babelrc.js
...and more.
I have this setup:
package.json
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
}
.babelrc.js
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-react',
'@babel/preset-typescript',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/proposal-class-properties',
'@babel/transform-regenerator',
'@babel/plugin-transform-template-literals',
'react-hot-loader/babel',
],
}
variables.ts
import { GlobalVars } from 'variables'
export const Vars = new GlobalVars()
variables.spec.ts
import { Vars } from './variables.ts'
describe('Test The Package', () => {
it('Should accept new variables', () => {
Vars.newVariable = 'new variable'
expect(Vars.newVariable).toEqual('new variable')
})
})
Any idea on how to resolve this problem?
Typescript Solutions
Solution 1 - Typescript
Even though I have tried them separately, I haven't tried them together (transform
and transformIgnorePatterns
). So this jest configuration solved my issue:
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"transform": {
"node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"
},
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
]
},
My mistakes were:
- Not using
transform
andtransformIgnorePatterns
together. - And defining
babel-jest
as the transformer instead ofts-jest
(I guess that is a problem when the preset of jest is defined asts-jest
. Because if I change it to bebabel-jest
it throws the same error again.):
--- "node_modules/variables/.+\\.(j|t)sx?$": "babel-jest"
+++ "node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"
Solution 2 - Typescript
Since Jest is not working with esmodules well, you need to add these configurations in jest.config.js
to tell Jest to use commonJS
builds instead
moduleNameMapper: {
'^variables$': 'variables/dist/cjs',
'^[NAME OF MODULE YOU WANT TO IMPORT]$': '[NAME OF MODULE YOU WANT TO IMPORT]/dist/cjs'
}
Solution 3 - Typescript
My issue was different in a way that jest
would stumle on .js
files from one of the dependencies in node_modules
with SyntaxError: Cannot use import statement outside a module
.
I had to make sure, that ts-jest
wouldn't ignore (when transforming) .js
files in troublesome dependency.
After reading carefully about presets, I realized, that it leaves them 'as-is' with preset: 'ts-jest'
. I changed it to preset: 'ts-jest/presets/js-with-ts'
and set "allowJs": true
in tsconfig.json
.
To not mess up my project's tsconfig.json
, I have a separate one for jest
.
In the end, my jest.config.js
looks mainly like this:
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: "node",
globals: {
'ts-jest': {
tsconfig: '<rootDir>/test/tsconfig.json',
},
},
transformIgnorePatterns: [
"node_modules/(?!troublesome-dependency/.*)",
],
}
P.S. I didn't need a transform
field, since the preset is already on it.
P.P.S. I didn't need to introduce any babel
configuration
Solution 4 - Typescript
I got stuck in the same situation. Due to I had a private untranspiled package which is based on TypeScript, and all my source files and test files were all applied with ECMA ( import syntax ), I encountered the following error as well.
> SyntaxError: Cannot use import statement outside a module
The solutions I have tried.
- The above answers, such as use transform, transformIgnorePatterns, moduleNameMapper in
jest.config.ts
. - Followed JEST official document, Configuration Jest#transformignorepatterns-arraystring, I used exactly the same method and even referred to the use case from React Native Guide.
- Removed all
node_modules
, including cache, and reinstalled them. - Used react-scripts and downgrade jest and babel-jest to 26 from 27. There was another issue that occurred.
After all, I found ECMAScript Modules from the JEST official document, the four steps perfectly solved my problem. I pasted their instructions here, however, you should take a look at the document itself.
- Ensure you either disable code transforms by passing transform: {} or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS).
- Execute node with --experimental-vm-modules, e.g. node --experimental-vm-modules node_modules/.bin/jest or NODE_OPTIONS=--experimental-vm-modules npx jest etc.. On Windows, you can use cross-env to be able to set environment variables.
- Beyond that, we attempt to follow node's logic for activating "ESM mode" (such as looking at type in package.json or mjs files), see their docs for details.
- If you want to treat other file extensions (such as ts) as ESM, please use the extensionsToTreatAsEsm option.
Solution 5 - Typescript
You don't necessarily need to change the transformer from babel-jest to ts-jest.
Instead:
-
Rename your
.babelrc
tobabel.config.json
https://babeljs.io/docs/en/configuration#whats-your-use-case -
Add transformIgnorePatterns:
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
]
This solved similar problem to me without need to add additional transform patterns. .babelrc
is local to your project so it won't be applied to node_modules
in Jest.
Solution 6 - Typescript
> tl;dr: tsconfig.spec.json > { "compilerOptions": { "allowJs": true } }
Did everything else mentioned here:
- transformIgnorePatterns
- add an additional pattern to the transform section
- ... much more that I reverted afterwards
Then I debugged into the transformer. First think I realized: the preconfigured workspace does not log anything, not even into ts-jest.log, not with --verbose
or --debug
and not even the warning, that would have been:
> Got a .js
file to compile while allowJs
option is not set to true
(file: {{path}}). To fix this:
> - if you want TypeScript to process JS files, set allowJs
to true
in your TypeScript config (usually tsconfig.json)
> - if you do not want TypeScript to process your .js
files, in your Jest config change the transform
key which value is ts-jest
so that it does not match .js
files anymore
(see: ts-jest-transformer.ts)
Solution 7 - Typescript
Another way to solve it is and possible other subsequent issues regarding babel and typescript is to use ts-jest, quoted from Jest's getting started
> However, there are some caveats to using TypeScript with Babel. Because TypeScript support in Babel is purely transpilation, Jest will not type-check your tests as they are run. If you want that, you can use ts-jest instead, or just run the TypeScript compiler tsc separately (or as part of your build process).
Solution 8 - Typescript
A simple solution would be to use a different preset in your jest.config.js
file.
Instead of using the default "preset": "ts-jest"
, try use presets like "preset": "ts-jest/presets/js-with-ts"
. Based on the documentation, it will:
> ts-jest/presets/js-with-ts > > TypeScript and JavaScript files (.ts, .tsx, .js, .jsx) will be transformed by ts-jest to CommonJS syntax. You'll need to set allowJs to true in your tsconfig.json file.