You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CommonJS的Node/TS项目中Jest使用ESM包file-type报错求助

CommonJS Node/TS后端项目中Jest测试ESM包file-type报错的解决办法

我在一个无Babel、Webpack及前端框架的Node/TS后端API项目(遵循CommonJS规范)中使用Jest编写测试用例,此前一切正常,直到引入ESM规范的npm包file-type。项目运行时API功能完全正常,但使用该包的测试用例(即使已mock)仍抛出如下错误:

Details:

/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/file-type/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as strtok3 from 'strtok3';
                                                                                  ^^^^^^

SyntaxError: Cannot use import statement outside a module

当前jest.config.ts配置:

reset: "ts-jest/presets/js-with-ts", // tries "ts-jest" and "ts-jest/presets/default-esm"
testEnvironment: "node",
transform: {
    "^.+\\.(ts|tsx)?$": "ts-jest"
  },
transformIgnorePatterns: [
    "node_modules/",
    "\\.pnp\\.[^\\/]+$"
  ],

执行测试命令:

npx jest path/to/my/file.test.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:

/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/file-type/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as strtok3 from 'strtok3';
                                                                                  ^^^^^^

SyntaxError: Cannot use import statement outside a module
    at new Script (node:vm:94:7)
    at Runtime.createScriptFromCode (/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/jest-runtime/build/index.js:1505:14)
    at Runtime._execModule (/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/jest-runtime/build/index.js:1399:25)
    at Runtime._loadModule (/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/jest-runtime/build/index.js:1022:12)
    at Runtime.requireModule (/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/jest-runtime/build/index.js:882:12)
    at Runtime.requireModuleOrMock (/home/bonjourjohn/projects/arpilabe/ged-backend/node_modules/jest-runtime/build/index.js:1048:21)
    at /home/bonjourjohn/projects/arpilabe/ged-backend/src/services/FileTypeService.ts:8:25
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

解决办法

方案一:让ts-jest转换file-type及其依赖(不改变项目模块规范)

核心是修改Jest配置,取消对file-type及其依赖的转换忽略,让ts-jest把这些ESM模块转成CommonJS格式:

export default {
  preset: "ts-jest/presets/js-with-ts",
  testEnvironment: "node",
  transform: {
    "^.+\\.(ts|tsx)?$": "ts-jest",
    // 对ESM的js文件也启用ts-jest转换
    "^.+\\.js$": "ts-jest"
  },
  transformIgnorePatterns: [
    // 排除node_modules中除file-type和strtok3之外的包(strtok3是file-type的依赖,同样是ESM)
    "/node_modules/(?!(file-type|strtok3)/)"
  ],
  globals: {
    "ts-jest": {
      useESM: false,
      tsconfig: "tsconfig.json" // 确保指向你的项目TS配置文件
    }
  }
};

方案二:切换Jest到ESM模式运行(适合逐步迁移到ESM的项目)

如果愿意调整项目的模块规范,可让Jest以ESM模式运行:

  1. 在package.json中添加"type": "module"
  2. 修改tsconfig.json:设置"module": "ESNext"、"moduleResolution": "Node16"
  3. 将jest.config.ts改为ESM格式(或重命名为jest.config.mjs),配置如下:
export default {
  preset: "ts-jest/presets/default-esm",
  testEnvironment: "node",
  extensionsToTreatAsEsm: [".ts"],
  moduleNameMapper: {
    "^(\\.{1,2}/.*)\\.js$": "$1" // 处理ESM导入时的后缀问题
  },
  transform: {
    "^.+\\.tsx?$": ["ts-jest", {
      useESM: true
    }]
  }
};

注意:此方案需要调整项目中所有的导入语句(比如去掉.ts后缀),适合长期迁移计划。

方案三:直接mock file-type模块(无需加载真实模块)

如果测试仅需验证调用逻辑,不需要file-type的真实功能,可直接mock整个模块:

在测试文件顶部添加:

jest.mock('file-type', () => ({
  // 根据你实际使用的方法来mock,示例为fileTypeFromBuffer
  fileTypeFromBuffer: jest.fn().mockResolvedValue({ ext: 'pdf', mime: 'application/pdf' })
}));

这样Jest不会加载真实的ESM模块文件,直接使用mock的实现,避免语法错误。

验证:修改配置后重新运行测试命令,即可解决报错。

内容的提问来源于stack exchange,提问作者Nicolas Espiau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:12:04