jest模拟es模块默认导出需显式设置__esmodule: true和default属性。正确方式是jest.mock('./module', () => ({ __esmodule: true, default: {...} })),避免require().default为undefined;可动态修改require('./module').default.method,或结合jest.requireactual()部分mock。

在 Jest 中模拟 ES 模块的默认导出,核心是使用 jest.mock() 配合 __esModule: true 和 default 属性来构造一个符合 ESM 默认导出行为的模拟对象。
明确模拟目标:ESM 默认导出本质是 export default xxx
ES 模块中 export default foo 实际会生成一个具有 default 属性的对象(即 { __esModule: true, default: foo })。Jest 的自动模拟(auto-mock)默认不设 __esModule: true,所以直接写 jest.mock('./module') 后用 require('./module').default 可能为 undefined —— 这是常见陷阱。
正确方式:手动提供带 default 和 __esModule 的模拟实现
推荐在 jest.mock() 的第二个参数(factory)中显式返回符合 ESM 语义的对象:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
// 假设被测文件 import api from './api.js'
jest.mock('./api.js', () => ({
__esModule: true,
default: {
fetchUser: jest.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
postOrder: jest.fn().mockResolvedValue({ orderId: 'ORD-001' })
}
}));
这样导入时 import api from './api.js' 就能正确解构到 api.fetchUser,无需写 api.default.fetchUser。
进阶:动态修改默认导出方法(如重置 mock 或替换返回值)
如果需要在测试中控制行为(例如不同 test case 返回不同数据),可先 mock,再通过 require 获取模块并修改其 default 属性:
- 在
beforeEach中重置:require('./api.js').default.fetchUser.mockReset() - 临时替换方法:
require('./api.js').default.fetchUser = jest.fn().mockReturnValue({ id: 2 }); - 注意:需确保该模块尚未被其他文件
import过(否则缓存生效),建议在jest.mock后、首次import前操作
替代方案:使用 jest.requireActual() 保留部分真实逻辑
若只想 mock 其中一个方法,其余保持原样,可以结合真实模块和覆盖:
jest.mock('./api.js', () => {
const actual = jest.requireActual('./api.js');
return {
__esModule: true,
default: {
...actual.default,
fetchUser: jest.fn().mockResolvedValue({ id: 999, name: 'Mocked' })
}
};
});
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










