Reputation: 4403
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.
/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 |
Using env
setup in babel.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.
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?
Upvotes: 190
Views: 275941
Reputation: 380
I had similar problem after migrating to NX monorepo v18, but with node_modules/@angular/core/fesm2022/testing.mjs
file.
Angular library Jest config was not migrated/updated, here is config that worked for me:
Root jest.config.js
/** @type {import('jest').Config} */
const config = {
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
transform: {
'^.+\\.[tj]sx?$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
resolver: '@nx/jest/plugins/resolver',
coverageReporters: ['html'],
testEnvironment: 'jsdom',
preset: 'ts-jest/presets/js-with-ts',
};
module.exports = config;
Angular Library jest.config.js
/** @type {import('jest').Config} */
const config = {
displayName: 'tests',
preset: '../../jest.config.js',
setupFilesAfterEnv: ['./src/test-setup.ts'],
coverageDirectory: '../../coverage/libs/tests',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
};
module.exports = config;
Also used following commands to clear cache: npx nx reset
and npx jest --clearCache
.
Upvotes: 0
Reputation: 459
I was using ts-jest and encountered this error. The key is that jest was still trying to use the JavaScript files that had been generated from the TypeScript tests. Once I deleted those, I was good to go.
Here's how I solved it.
package.json
contains this line{
...
"type": "module"
}
// jest.config.ts
import type { JestConfigWithTsJest } from 'ts-jest'
const jestConfig: JestConfigWithTsJest = {
// [...]
preset: 'ts-jest/presets/default-esm', // or other ESM presets
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
// '^.+\\.[tj]sx?$' to process js/ts with `ts-jest`
// '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest`
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
},
],
},
}
export default jestConfig
tests
directory(take care not to delete any of your own js files)
$ rm tests/*.js
bun run jest
Source: https://kulshekhar.github.io/ts-jest/docs/guides/esm-support
Upvotes: 0
Reputation: 2076
Update the test
property in the package.json file (the default is react-scripts test
):
"scripts": {
"test": "jest"
}
Upvotes: 0
Reputation: 81
I encountered the same issue when I was trying to test my app and some functions were using the file-type library.
I did jest configuration as below in my package.json
"jest": {
"moduleFileExtensions": [
"js",
"json",
"jsx",
"node",
"mjs"
],
"transformIgnorePatterns": []
},
I think the important thing is to only use "transformIgnorePatterns": [].
Setting transformIgnorePatterns to an empty array means Jest will transform every imported module using the specified transformer, in this case, babel-jest. By default, Jest does not transform anything in node_modules, which can lead to issues when a module (or its dependencies) uses ES6 imports.
If you only encounter this issue with a subset of modules, you can further refine transformIgnorePatterns to exclude only those specific modules from being ignored, but if the empty array works well and does not introduce other complications, you can stick with that.
Upvotes: 6
Reputation: 5965
I encountered the same issue when installing NestJS following this documentation: https://docs.nestjs.com/first-steps.
The fix was adding the missing "preset": "ts-jest",
in the package.json
file under "jest"
configuration:
"jest": {
...
"preset": "ts-jest",
...
}
Upvotes: 0
Reputation: 1486
Right now ts-jest version 28 & 29 is broken. I don't know all of the versions it affects, but it at least affects 28.1.3
- 29.1.0
. It is documented here: https://github.com/nodkz/mongodb-memory-server/issues/679
The bug is that specifying moduleDirectories: ["node_modules", "src"]
breaks jest in unexpected ways, including being essentially super mad at you for imports and exports. The fix is to change the line to moduleDirectories: ["node_modules", "<rootdir>/src/"]
or remove it entirely. Note: these solutions do not permit the original functionality
The reason one might include this line is to allow direct paths so instead of import { minute } from "../../../utils";
you can write import { minute } from "utils";
In my opinion this is very convenient. The above fixes will allow you to compile, but you will probably still get errors like cannot find module "utils" in /some/directory/path
The only fix I was able to find to get back my desired behaviour is using the moduleNameMapper option like so:
"moduleNameMapper": {
'^utils(.*)$': '<rootDir>/src/utils$1',
},
credit to answer https://stackoverflow.com/a/67667249
This means that you now have to explicitly specify which files you will reference with absolute imports. While not ideal, I could not get anything else to work
For reference, here is my complete jest.config.js file:
/* eslint-disable import/no-commonjs */
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: "ts-jest/presets/js-with-ts",
testEnvironment: "node",
roots: ["<rootDir>/src"],
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
],
testPathIgnorePatterns: ["<rootDir>/dist/", "node_modules"],
moduleDirectories: ["node_modules", "<rootdir>/src/"],
setupFiles: ['dotenv/config'],
collectCoverage: true,
coverageDirectory: "coverage",
extensionsToTreatAsEsm: ['.ts'],
"moduleNameMapper": {
"/src/(.*)": "<rootDir>/src/$1",
'^utils(.*)$': '<rootDir>/src/utils$1',
},
"transform": {
"node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"
},
};
For your tsconfig.json
, you may want to consider the following settings:
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "Node",
"module": "ESNext",
"target": "ES2020",
``
Upvotes: 0
Reputation: 455
This worked for me.
npm i ts-jest -D
Create jest.config.js in your root dir
Then add this to it:
module.exports = {
"roots": [
"<rootDir>/src"
],
"testMatch": [
"**/__tests__/**/*.+(ts|tsx|js)",
"**/?(*.)+(spec|test).+(ts|tsx|js)"
],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
}
Upvotes: 9
Reputation: 2496
Use Vitest.
I have tried most of the suggestions made here. I found Jest to be quite painful to install correctly, whereas Vitest works out of the box without any config. This is my personal experience. It took me days to get Jest to sort-of work. I had Vitest working immediately after installation.
I don't want to hate on Jest, I actually think it's a wonderful and intuitive testing tool. But ultimately Vitest "Just Works" (tm), and you can use the same simple Jest style API we all have come to love.
Steps (I use pnpm, but of course you could do the same with yarn or npm):
pnpm remove jest ts-jest @types/jest
pnpm add -D vite vitest
Delete jest.config.js
, and create vite.config.ts
:
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
/* for example, use global to avoid globals imports (describe, test, expect): */
// globals: true,
},
})
Add to your tests:
import { assert, expect, test } from 'vitest'
Update your package.json:
"test": "vitest",
Upvotes: 35
Reputation: 1354
I tried a lot of answers here, but nothing worked for me. I was about to give up on jest
but found a solution. I will document the steps as a checklist.
First, make sure jest
is installed:
npm install --save-dev jest
Second, enable ESM in your package.json
file:
{
...
"type": "module"
}
Third, update the test
property in the package.json
file:
"scripts": {
"test": "node --experimental-vm-modules ./node_modules/.bin/jest"
}
Following that, create the jest.config.js
and add the following contents:
export default { transform: {} };
With that, run the jest again:
npm test
Upvotes: 1
Reputation: 1630
By accident I found a hack to let pre-processor
process the whole node_modules
what is usually forbidden:
By default "node_modules" folder is ignored by transformers.
transformIgnorePatterns:
[
'node_modules'
]
Using this pattern seems to bypass the Jest internal check.
transformIgnorePatterns:
[
'//node_modules'
]
It this a hack? Yes! Is this slow? Yes! But properly it can help someone who needs a quick fix.
Upvotes: 6
Reputation: 2531
For people suffering from this due to antd framework.
You override antd DatePicker to use day js instead of default moment js.
You followed the instructions here
Now if you run your test, it will have that dreaded error
SyntaxError: Cannot use import statement outside a module
The reason for that is because of this
import generatePicker from "antd/es/date-picker/generatePicker";
import "antd/es/date-picker/style/index";
Specifically it is caused because of importing from antd/es/
The fix is to import from antd/lib/ instead.
import generatePicker from "antd/lib/date-picker/generatePicker";
import "antd/lib/date-picker/style/index";
This fixes the test error, however, another problem that would arise is that this code have a bug. The DatePicker component now will not respect locales.
So the final solution is to add
moduleNameMapper: {
... other mappings here ...
// Add this to fix the problem!
"^antd/es/(.*)$": "antd/lib/$1",
}
in your jest.config.js file
This will let you use antd/es/ in your code but will replace it with antd/lib/ on your tests.
Reference here
Hope this helps anyone, this took me a while to figure out.
Upvotes: 3
Reputation: 402
Solved mine by adding "modules": "commonjs"
inside .babelrc -> presets -> @babel/preset-env
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": "commonjs"
}
],
"@babel/preset-react"
]
}
package.json
"jest": {
"verbose": true,
"moduleDirectories": ["node_modules", "src"],
"testEnvironment": "node",
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
],
"transform": {
"^.+\\.jsx?$": "babel-jest"
}
}
Upvotes: 2
Reputation: 489
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
Upvotes: 38
Reputation: 88
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.
Upvotes: 1
Reputation: 445
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'
}
Upvotes: 10
Reputation: 266
tl;dr: tsconfig.spec.json >
{ "compilerOptions": { "allowJs": true } }
Did everything else mentioned here:
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 whileallowJs
option is not set totrue
(file: {{path}}). To fix this:
- if you want TypeScript to process JS files, set
allowJs
totrue
in your TypeScript config (usually tsconfig.json)- if you do not want TypeScript to process your
.js
files, in your Jest config change thetransform
key which value ists-jest
so that it does not match.js
files anymore
(see: ts-jest-transformer.ts)
Upvotes: 1
Reputation: 494
You don't necessarily need to change the transformer from babel-jest to ts-jest.
Instead:
Rename your .babelrc
to babel.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.
Upvotes: 5
Reputation: 73
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.
jest.config.ts
.node_modules
, including cache, and reinstalled them.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.
Upvotes: 2
Reputation: 4403
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/.*)"
]
},
transform
and transformIgnorePatterns
together.babel-jest
as the transformer instead of ts-jest
(I guess that is a problem when the preset of jest is defined as ts-jest
. Because if I change it to be babel-jest
it throws the same error again.):--- "node_modules/variables/.+\\.(j|t)sx?$": "babel-jest"
+++ "node_modules/variables/.+\\.(j|t)sx?$": "ts-jest"
Upvotes: 119
Reputation: 338
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).
Upvotes: 2