Jest:同时模拟含默认导出与命名导出的ES6模块
Jest无法同时模拟ES6模块的默认导出和命名导出?这里有解决方案!
我之前也碰到过这个一模一样的坑!Jest处理ES6混合导出(同时有默认导出和命名导出)的时候,很容易因为模拟的语法细节没做对,导致默认导出依然走原模块的实现,只有命名导出被成功mock。别着急,咱们一步步解决这个问题:
先明确问题根源
Jest默认是按CommonJS模块的规则来处理mock的,而ES6模块的导出结构和CommonJS不一样——ES6的默认导出在模块对象里是default属性,但如果不告诉Jest这是个ES6模块,它会把这个default当成普通的命名导出,而不是你import的默认函数。所以核心就是要给mock对象加上__esModule: true标识。
解决方案1:直接mock整个模块(静态模拟)
假设你的myModule.js代码是这样的:
// myModule.js export default function defaultFunc() { return "原默认函数返回值"; } export function namedFunc() { return "原命名函数返回值"; }
那在测试文件里,你需要这么写mock:
// myModule.test.js // 关键:mock对象里必须加__esModule: true jest.mock('./myModule', () => ({ __esModule: true, default: jest.fn(() => "mock后的默认返回值"), namedFunc: jest.fn(() => "mock后的命名返回值") })); // 正常导入 import defaultFunc, { namedFunc } from './myModule'; test('同时mock默认和命名导出', () => { expect(defaultFunc()).toBe("mock后的默认返回值"); expect(namedFunc()).toBe("mock后的命名返回值"); });
这样写之后,默认导出和命名导出都会被正确mock,不会再走原模块的实现。
解决方案2:动态修改mock实现(保留部分原导出)
如果你需要在测试过程中动态修改默认导出的实现,或者只想mock部分导出、保留其他原模块的功能,可以用jest.requireActual先拿到原模块的完整结构,再替换需要mock的部分:
// myModule.test.js import defaultFunc, { namedFunc } from './myModule'; jest.mock('./myModule', () => { // 先获取原模块的所有导出 const originalModule = jest.requireActual('./myModule'); return { __esModule: true, // 保留原模块的其他导出(如果有的话) ...originalModule, // 替换默认导出为mock函数 default: jest.fn(), // 替换命名导出为mock函数 namedFunc: jest.fn(() => "固定mock的命名返回值") }; }); test('动态修改默认导出的实现', () => { // 测试中动态修改默认函数的返回值 defaultFunc.mockImplementation(() => "动态mock的默认返回值"); expect(defaultFunc()).toBe("动态mock的默认返回值"); expect(namedFunc()).toBe("固定mock的命名返回值"); });
额外技巧:用spyOn处理默认导出
如果你不想完全mock整个模块,只是想spy默认导出的调用情况,可以这么做:
// myModule.test.js // 把整个模块作为对象导入 import * as myModule from './myModule'; // 对模块的default属性创建spy const defaultFuncSpy = jest.spyOn(myModule, 'default'); defaultFuncSpy.mockImplementation(() => "spy后的默认返回值"); test('spy默认导出', () => { expect(myModule.default()).toBe("spy后的默认返回值"); // 还可以验证调用次数 expect(defaultFuncSpy).toHaveBeenCalledTimes(1); });
关键注意点总结
- 只要是mock ES6模块,一定要加
__esModule: true,这是让Jest正确识别ES6导出结构的核心 - mock对象里的
default属性对应模块的默认导出,其他属性对应命名导出,结构不能错 - 动态修改mock实现时,要确保mock的函数是
jest.fn()创建的,这样才能用mockImplementation修改
内容的提问来源于stack exchange,提问作者user2117153
相关产品推荐
相关产品推荐

