解决Jest测试中setup-jest.ts的import语句模块报错问题
解决Jest+TypeScript+Angular测试中的"Cannot use import statement outside a module"错误
问题描述
运行npm test时触发报错:SyntaxError: Cannot use import statement outside a module,报错指向setup-jest.ts第一行。详细报错信息如下:
Jest encountered an unexpected token Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax. Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration. By default "node_modules" folder is ignored by transformers. Here's what you can do: • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it. • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config. • If you need a custom transformation specify a "transform" option in your config. • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option. You'll find more details and examples of these config options in the docs: https://jestjs.io/docs/configuration For information about custom transformations, see: https://jestjs.io/docs/code-transformation Details: D:\Angular\ng-frontend\node_modules\@angular\core\fesm2022\testing.mjs:7 import { ɵDeferBlockState, ɵtriggerResourceLoading, ɵrenderDeferBlockState, ɵCONTAINER_HEADER_OFFSET, ɵgetDeferBlocks, ɵDeferBlockBehavior, InjectionToken, inject as inject$1, ɵNoopNgZone, NgZone, ɵEffectScheduler, ApplicationRef, ɵPendingTasks, getDebugNode, RendererFactory2, ɵdetectChangesInViewIfRequired, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetAsyncClassMetadataFn, ɵgenerateStandaloneInDeclarationsError, ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ɵdepsTracker, ɵgetInjectableDef, resolveForwardRef, ɵNG_COMP_DEF, ɵisComponentDefPendingResolution, ɵresolveComponentResources, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, ɵclearResolutionOfComponentResourcesQueue, ɵrestoreComponentResolutionQueue, ɵinternalProvideZoneChangeDetection, ɵChangeDetectionScheduler, ɵChangeDetectionSchedulerImpl, Compiler, ɵDEFER_BLOCK_CONFIG, COMPILER_OPTIONS, Injector, ɵisEnvironmentProviders, ɵNgModuleFactory, ModuleWithComponentFactories, ɵconvertToBitFlags, InjectFlags, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, runInInjectionContext, EnvironmentInjector, ɵZONELESS_ENABLED, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core'; ^^^^^^ SyntaxError: Cannot use import statement outside a module > 1 | import 'jest-preset-angular/setup-jest'; | ^ 2 | import './jest-global-mocks'; at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14) at Object.<anonymous> (node_modules/jest-preset-angular/setup-jest.js:3:24) at Object.<anonymous> (setup-jest.ts:1:1)
已尝试的解决措施:
- 调整Jest配置以支持ES模块,但报错未解决;
- 完全移除并重新安装所有项目依赖;
- 查阅类似问题及官方文档,未找到有效方案;
- 参考不同指南重建测试环境,问题依旧;
- 参考相关Stack Overflow方案,仍未解决。
相关配置文件:
jest.config.js
const { pathsToModuleNameMapper } = require('ts-jest'); const { paths } = require('./tsconfig.json').compilerOptions; /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ module.exports = { preset: 'jest-preset-angular', moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: '<rootDir>' }), setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], transformIgnorePatterns: [ "/node_modules/", "<rootDir>/src/app/Config", ], };
setup-jest.ts
import 'jest-preset-angular/setup-jest'; import './jest-global-mocks';
babel.config.js
module.exports = { presets: [ ['@babel/preset-env', { targets: { node: 'current', }, },], '@babel/preset-typescript', ], plugins: [ ["@babel/plugin-proposal-decorators", { "legacy": true }] ] };
解决方案
这个错误的核心原因是Jest无法解析Angular核心库中的ESM模块,默认配置会忽略node_modules目录下的文件转换,而Angular的fesm2022格式模块需要被jest-preset-angular处理。以下是针对性的解决步骤:
1. 修改Jest配置,允许转换Angular相关模块
当前transformIgnorePatterns排除了所有node_modules,需要调整为不忽略Angular和jest-preset-angular相关包:
module.exports = { preset: 'jest-preset-angular', moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: '<rootDir>' }), setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], // 只忽略非Angular/jest-preset-angular的node_modules包 transformIgnorePatterns: [ 'node_modules/(?!@angular|jest-preset-angular)', '<rootDir>/src/app/Config', ], };
2. 检查并修正tsconfig.json配置
确保TypeScript编译配置符合Jest要求,特别是模块和目标版本:
{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, // 保留其他原有配置 }, "include": ["src/**/*", "setup-jest.ts"] }
3. 调整Babel配置避免冲突
jest-preset-angular已内置TypeScript转换逻辑,额外的Babel配置可能导致冲突。可以:
- 暂时重命名
babel.config.js为babel.config.js.backup,重新运行测试验证是否解决问题; - 若必须保留Babel,优先使用
jest-preset-angular的预设:
module.exports = { presets: [ 'jest-preset-angular', ['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript', ], plugins: [["@babel/plugin-proposal-decorators", { "legacy": true }]] };
4. 确保setup-jest.ts被正确转换
在Jest配置中明确指定转换规则,确保TypeScript文件被处理:
module.exports = { // 其他配置... transform: { '^.+\\.(ts|js|mjs)$': 'jest-preset-angular', }, };
5. 检查依赖版本兼容性
确保jest、ts-jest、jest-preset-angular与Angular版本匹配,例如Angular 16+建议使用:
{ "devDependencies": { "jest": "^29.7.0", "ts-jest": "^29.1.1", "jest-preset-angular": "^13.1.1" } }
更新后运行npm install重新安装依赖。
内容的提问来源于stack exchange,提问作者sudhanshu
相关产品推荐
相关产品推荐

