如何在Jest中测试导入第三方ES6模块的ES6代码?
问题描述
环境:Node v19.6.0、Jest 29.5.0,代码及第三方依赖均采用ES6模块规范,仅配置文件为CommonJS。
具体情况:
- 有ES6模块A.js和对应的测试文件A.test.js
- 移除A.js中的导入语句时,测试能正常运行
- A.js中导入第三方ES6模块B(
import * as B from "packagename/b.js";)后,测试直接报错 - 正常运行代码(不用Jest)时,这个导入完全没问题
报错细节:
- 启动时加
NODE_OPTIONS=--experimental-vm-modules,报错:Must use import to load ES Module: - 不加这个参数,报错:
SyntaxError: Cannot use import statement outside a module
额外现象:把B模块从node_modules复制到src目录后,测试就能成功导入。
初始Jest配置:
"jest": { "preset": "react-native" }
临时方案的问题:
把package.json的type设为"module",并修改Jest配置为:
"jest": { "testEnvironment": "node", "transform": {} }
测试能正常跑,但CommonJS格式的配置文件会被当成ES模块处理,导致其他功能崩了,现在只能测试时临时改type,测完再改回去。
解决方案
不用全局设置type: "module"的解决方法有这几个:
方法1:通过Jest配置识别ES模块
在Jest配置里加几个参数,让它正确处理第三方ES模块:
"jest": { "preset": "react-native", "transformIgnorePatterns": [ "node_modules/(?!packagename/)" // 不对目标第三方包做转译 ], "moduleNameMapper": { "^packagename/b.js$": "<rootDir>/node_modules/packagename/b.js" // 明确指定模块路径 }, "extensionsToTreatAsEsm": [".js"] // 把.js文件当作ES模块处理 }
运行测试时必须加NODE_OPTIONS=--experimental-vm-modules,因为Jest处理原生ES模块需要依赖这个Node实验特性。
方法2:用Babel转译ES模块
如果方法1不好使,就用Babel把ES模块转成Jest能处理的格式:
- 先装依赖:
npm install --save-dev @babel/core @babel/preset-env babel-jest
- 创建
.babelrc配置文件:
{ "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]] }
- 修改Jest配置:
"jest": { "preset": "react-native", "transform": { "^.+\\.js$": "babel-jest" }, "transformIgnorePatterns": [ "node_modules/(?!packagename/)" ] }
这种方式不用加NODE_OPTIONS=--experimental-vm-modules,因为Babel已经把ES模块转成CommonJS了。
方法3:给测试相关文件改后缀
不想改全局配置的话,把A.js、A.test.js这类ES模块文件的后缀改成.mjs,Node会自动把它们识别为ES模块,Jest也能对应处理。同时调整Jest配置:
"jest": { "preset": "react-native", "moduleFileExtensions": ["mjs", "js", "json"], "extensionsToTreatAsEsm": [".mjs"] }
运行测试时还是要加NODE_OPTIONS=--experimental-vm-modules。
内容的提问来源于stack exchange,提问作者mushroom
相关产品推荐
相关产品推荐

