如何解决CommonJS环境下Jest测试时的import语句语法错误?
解决Jest测试时「SyntaxError: Cannot use import statement outside a module」报错
问题说明
项目纯JS编写,正常运行无任何报错,但用Jest启动单元测试时,会弹出SyntaxError: Cannot use import statement outside a module错误,Stack Overflow现有方案未解决该问题。相关配置文件如下:
babel.config.js
module.exports = { retainLines: true, plugins: [ 'react-hot-loader/babel', '@babel/plugin-proposal-class-properties', '@babel/plugin-transform-modules-commonjs', 'babel-plugin-styled-components', ], presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'], env: { test: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'], }, development: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'], }, }, };
jest.config.js
module.exports = { verbose: true, transform: { '^.+\\.js$': '<rootDir>/node_modules/babel-jest', '^.+\\.jsx$': '<rootDir>/node_modules/babel-jest', }, globals: { NODE_ENV: 'development', }, setupFiles: ['@babel/polyfill', './jest.setup.js'], moduleDirectories: ['node_modules', 'src', 'src/client', 'src/client/components'], moduleNameMapper: { '^uuid$': require.resolve('uuid'), }, transformIgnorePatterns: [ '!node_modules/(?!@src/*.)', ], testEnvironment: 'jsdom', clearMocks: true, collectCoverage: true, collectCoverageFrom: [ 'src/**/*.js', '!**/node_modules/**', '!**/dist/**', '!**/coverage/**', ], coverageReporters: ['text-summary', 'lcov', 'cobertura'], reporters: ['default', 'jest-junit'], notify: true, };
package.json 测试脚本
"test": "NODE_ENV=development jest src --coverage -u --detectOpenHandles --verbose=true --forceExit"
问题根源
- Jest的transform配置中,
<rootDir>被错误转译为<rootDir>,导致babel-jest路径无效,ES模块语法未被转译 - 测试脚本设置
NODE_ENV=development,导致Babel加载开发环境配置,而非专门的test环境配置 - Babel全局配置硬加了
@babel/plugin-transform-modules-commonjs,可能与preset-env冲突,且test环境未针对性配置转译规则 - transformIgnorePatterns规则匹配错误,可能导致需要转译的模块被Jest跳过
修复步骤
1. 修正Jest的transform配置
将jest.config.js中的<rootDir>改回<rootDir>,同时简化规则:
module.exports = { // 其他配置保持不变 transform: { '^.+\\.(js|jsx)$': '<rootDir>/node_modules/babel-jest', }, // 其他配置保持不变 };
或者更简洁,直接使用babel-jest(Jest会自动查找对应依赖):
transform: { '^.+\\.(js|jsx)$': 'babel-jest', },
2. 调整测试脚本的NODE_ENV为test
修改package.json中的测试命令,让Babel加载test环境专属配置:
"test": "NODE_ENV=test jest src --coverage -u --detectOpenHandles --verbose=true --forceExit"
3. 优化Babel的test环境配置
删除babel.config.js全局plugins中的@babel/plugin-transform-modules-commonjs,在test环境中让preset-env自动转译为CommonJS:
module.exports = { retainLines: true, plugins: [ 'react-hot-loader/babel', '@babel/plugin-proposal-class-properties', 'babel-plugin-styled-components', ], presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'], env: { test: { presets: [ ['@babel/preset-env', { modules: 'commonjs' }], '@babel/preset-react', '@babel/preset-flow' ], }, development: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'], }, }, };
这样开发环境保留ES模块语法,测试环境转成CommonJS,避免环境冲突。
4. 修正transformIgnorePatterns规则
如果项目中没有@src开头的依赖包,直接删除原有规则;如果有需要转译的第三方模块(比如uuid),调整为:
transformIgnorePatterns: [ '/node_modules/(?!uuid)', ],
确保需要转译的模块不会被Jest忽略。
验证步骤
- 删除node_modules和package-lock.json,重新执行
npm install - 运行测试命令,检查错误是否消失
内容的提问来源于stack exchange,提问作者John Glabb
相关产品推荐
相关产品推荐

