Skip to content

Jest 测试中解决 "Cannot use import statement outside a module" 错误

问题分析

当在 Jest 测试环境中使用 Axios 1.x+ 版本时,常会遇到 Cannot use import statement outside a module 错误。这是因为:

  1. Axios 1.0+ 将模块系统从 CommonJS 切换为 ECMAScript Modules (ESM)
  2. Jest 运行在 Node.js 环境,默认使用 CommonJS 模块系统
  3. Jest 默认忽略 node_modules 目录的代码转换

错误原因

Axios 1.x 的入口文件使用 ESM 语法:

js
import axios from './lib/axios.js'; // Axios 1.x 的入口文件语法
export default axios;

而 Jest 无法直接执行 ESM 语法,导致测试失败。

解决方案

方法一:配置 moduleNameMapper 指向 CommonJS 版本(推荐)

修改 Jest 配置,强制使用 Axios 的 CommonJS 版本:

js
module.exports = {
  // 其他配置...
  moduleNameMapper: {
    '^axios$': 'axios/dist/node/axios.cjs'
  }
};
json
{
  "jest": {
    "moduleNameMapper": {
      "^axios$": "axios/dist/node/axios.cjs"
    }
  }
}

方法二:配置 transformIgnorePatterns 转换 Axios 模块

允许 Jest 转换 Axios 模块,忽略其他 node_modules

js
module.exports = {
  transformIgnorePatterns: [
    'node_modules/(?!axios)'  // 排除 axios 的忽略规则
  ]
};
json
{
  "jest": {
    "transformIgnorePatterns": [
      "node_modules/(?!axios)"
    ]
  }
}

方法三:在测试脚本中直接指定配置

通过命令行传递 transformIgnorePatterns 参数:

json
{
  "scripts": {
    "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\""
  }
}

正则表达式解释

node_modules/(?!axios) 表示:"排除所有 node_modules 目录,但 axios 除外"

方法四:更新 Jest 和相关依赖

较旧的 Jest 版本可能不兼容新的模块系统,更新依赖:

bash
npm install --save-dev jest@29 ts-jest@29

特殊情况处理

使用 axios-mock-adapter 时的处理

当配合 axios-mock-adapter 使用时,推荐使用 transformIgnorePatterns 方案:

js
// jest.config.js
module.exports = {
  transformIgnorePatterns: [
    "/node_modules/(?!(axios)/)"
  ]
};

清除 Jest 缓存

如果配置修改未生效,尝试清除缓存:

bash
npm test -- --clearCache

不推荐的方案:直接修改导入路径

虽然可行,但不建议在项目代码中直接指定 Axios 构建路径:

js
// 不推荐 - 侵入代码实现细节
import axios from 'axios/dist/browser/axios.cjs';

最佳实践总结

  1. 首选方案:使用 moduleNameMapper 指向 CommonJS 版本
  2. 通用方案:配置 transformIgnorePatterns 允许转换 Axios
  3. 及时更新:保持 Jest 和测试相关依赖为最新版本
  4. 注意缓存:修改配置后清除 Jest 缓存确保生效

重要提醒

在 Vue 项目中,避免添加 "type": "module"package.json,这可能导致其他配置文件(如 vue.config.js)出现兼容性问题。

方案对比表

方案优势缺点适用场景
moduleNameMapper直接使用 CJS 版本,无需转换与某些库(如 axios-mock-adapter)兼容性问题简单项目,无需复杂模拟
transformIgnorePatterns正确转换 ESM 模块稍微降低测试速度通用解决方案,兼容性更好
命令行参数无需修改配置文件,快速验证只能应用在脚本调用时临时解决方案或简单项目
更新 Jest解决根本性兼容问题需要更新多个相关依赖使用较旧 Jest 版本的项目

选择最适合您项目情况的解决方案即可解决 Axios 在 Jest 测试中的导入错误问题。