Angular集成Jest开启测试覆盖率时因ES模块报错如何解决?
问题原因
两个报错本质都是Jest的ESM兼容配置覆盖不全,默认运行在CommonJS上下文导致的:
- 初始加
--coverage时报tslib的import错误,是因为覆盖率收集阶段会处理tslib依赖,但默认配置下Jest不会转换node_modules下的任何文件,ESM格式的tslib直接在CommonJS上下文执行就会抛出语法错误。 - 调整配置后报
.mjs文件错误有两个直接原因:- 你写的
transform规则只匹配.ts/.html/.svg后缀,.mjs文件不在转换范围内; transformIgnorePatterns仅白名单了tslib,@testing-library/angular这类Angular生态下发布为ESM格式的依赖,依然在默认跳过转换的列表里,Jest拿到原始ESM代码直接在CommonJS环境运行就会报错。
- 你写的
- 关于你提到的Node 16 + Jest 28自动识别
.mjs的认知是错的:Jest的ESM支持属于显式开启的特性,不会因为Node本身支持ESM就默认启用,没有全链路配置的情况下,所有ESM文件都会被当做CommonJS解析。
修复步骤
- 替换
jest.config.js为如下配置,不要手动移除预设配置自行实现全量转换规则,避免漏配:
// jest.config.js module.exports = { preset: "jest-preset-angular", setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"], globalSetup: "jest-preset-angular/global-setup", // 所有需要转换的ESM依赖都加入白名单 transformIgnorePatterns: [ "/node_modules/(?!(@angular|@testing-library/angular|tslib|rxjs)/)" ], // 补充mjs、js后缀的转换匹配 transform: { "^.+\\.(ts|mjs|js|html|svg)$": "jest-preset-angular" }, extensionsToTreatAsEsm: [".ts"], globals: { "ts-jest": { tsconfig: "<rootDir>/tsconfig.spec.json", stringifyContentPathRegex: "\\.html$", useESM: true, }, }, // 覆盖率收集阶段跳过不需要统计的文件,避免重复转换报错 coveragePathIgnorePatterns: [ "<rootDir>/node_modules/", "<rootDir>/setup-jest.ts", "<rootDir>/jest-global-mocks.ts" ] };
- 修改
package.json中的测试启动脚本,显式开启Node的ESM模块支持,适配Jest 28的ESM运行逻辑:
{ "scripts": { "test": "node --no-warnings=ExperimentalVmModules ./node_modules/jest/bin/jest.js" } }
配置完成后直接运行npm test -- --coverage即可正常执行测试并生成覆盖率报告。
注意事项
- 后续如果引入其他发布为ESM格式的第三方依赖,运行时如果出现同样的import语法错误,直接把依赖包名加到
transformIgnorePatterns的白名单列表里即可,多个包名用|分隔。 - 不要随意移除
preset: "jest-preset-angular"配置,该预设已经封装了绝大多数Angular + Jest适配的转换规则,手动重写全量transform逻辑很容易出现后缀漏配、编译参数错误的问题。
内容的提问来源于stack exchange,提问作者Ben Wainwright
相关产品推荐
相关产品推荐

