Jest运行TypeScript测试遇意外令牌错误寻求解决方案
解决Jest测试中ES模块兼容问题
问题场景
开发目录结构:
. ├── README.md └── business ├── jest.config.ts ├── nodeLayer │ └── db │ ├── README.md │ ├── dist │ │ └── db │ │ ├── index.js │ │ └── index.js.map │ │ │ ├── package-lock.json │ ├── package.json │ ├── src │ └── index.ts │ └── hoge1 └── src ├── README.md ├── app │ └── app.ts ├── jest.config.ts ├── package-lock.json ├── package.json └── tests └── unit └── get.test.ts
执行npm run test时出现以下错误:
➤ npm run test > sync_app_info_to_aam_db@1.0.0 test > npm run unit > sync_app_info_to_aam_db@1.0.0 unit > NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.ts FAIL tests/unit/get.test.ts ● Test suite failed to run 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: /xxxxxxxx/business/nodeLayer/db/dist/db/index.js:2 import { createPool } from 'mysql2/promise'; ^^^^^^ SyntaxError: Cannot use import statement outside a module 5 | import { ConnectionArguments, Db, SelectArguments } from '/opt/nodejs/dist/db'; 6 | > 7 | export const lambdaHandler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => { | ^ 8 | const client = new SecretsManagerClient({ 9 | region: 'ap-northeast-1', 10 | }); at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1495:14) at Object.<anonymous> (app/app.ts:7:14) at Object.<anonymous> (tests/unit/get.test.ts:4:15)
app.ts中的导入代码:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { ConnectionArguments, Db, SelectArguments } from '/opt/nodejs/dist/db';
当前jest.config.ts配置:
export default { preset: 'ts-jest', clearMocks: true, collectCoverage: true, coverageDirectory: 'coverage', coverageProvider: 'v8', testMatch: ['**/tests/unit/*.test.ts'], testPathIgnorePatterns: ['cf/.aws-sam/build'], moduleNameMapper: { '^/opt/nodejs/dist/db$': '<rootDir>/nodeLayer/db/dist/db', }, };
问题核心:CommonJS模式下Jest无法处理dist目录中ES模块格式的import语句,需要切换到ES模块兼容配置。
解决方案
1. 标记项目为ES模块
在hoge1/src/package.json中添加"type": "module":
{ "name": "sync_app_info_to_aam_db", "version": "1.0.0", "type": "module", // 其他原有配置... }
2. 更新Jest配置
修改hoge1/src/jest.config.ts,适配ES模块:
export default { // 使用ts-jest的ES模块预设 preset: 'ts-jest/presets/default-esm', clearMocks: true, collectCoverage: true, coverageDirectory: 'coverage', coverageProvider: 'v8', testMatch: ['**/tests/unit/*.test.ts'], testPathIgnorePatterns: ['cf/.aws-sam/build'], moduleNameMapper: { // 直接导入TypeScript源文件,避免处理编译后的ES模块文件 '^/opt/nodejs/dist/db$': '<rootDir>/../nodeLayer/db/src/index.ts', }, // 告知Jest将.ts文件视为ES模块 extensionsToTreatAsEsm: ['.ts'], moduleFileExtensions: ['ts', 'js'], // 配置ts-jest以ES模块模式转译TypeScript transform: { '^.+\\.tsx?$': ['ts-jest', { useESM: true }], }, };
3. 调整TypeScript配置(若存在)
确保hoge1/src/tsconfig.json中启用ES模块相关配置:
{ "compilerOptions": { "module": "ESNext", "moduleResolution": "NodeNext", "target": "ES6", // 其他原有配置... } }
4. 修正导入注释(可选)
因为现在直接导入源文件,TypeScript可以识别类型,可移除@ts-ignore注释:
import { ConnectionArguments, Db, SelectArguments } from '/opt/nodejs/dist/db';
原理说明
- 标记
"type": "module"后,Node.js和Jest会默认以ES模块模式加载文件 - 使用
ts-jest/presets/default-esm预设,让ts-jest处理TypeScript到ES模块的转译 - 直接导入TypeScript源文件,跳过dist目录中已编译的ES模块文件,避免Jest以CommonJS模式加载时出现语法错误
内容的提问来源于stack exchange,提问作者kyoshida
相关产品推荐
相关产品推荐

