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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:14:20