如何Mock loadable.lib实现单元测试中同步加载依赖?
解决Jest中Mock Loadable.lib同步加载模块的问题
看起来你遇到的核心问题是:用loadable.lib懒加载react-toastify后,Jest测试因为无法等待异步加载完成,导致组件首次渲染返回null,快照匹配失败。我来给你几个可行的方案,核心思路是让loadable.lib的Mock版本同步返回已加载的模块,让组件能直接拿到依赖进行渲染。
方案一:针对性Mock react-toastify的加载
如果你的场景里loadable.lib主要用来加载react-toastify,可以直接在测试文件顶部添加这个Mock:
jest.mock('@loadable/component', () => ({ lib: jest.fn(() => { // 同步引入react-toastify的真实模块 const toastify = jest.requireActual('react-toastify'); // 返回一个组件,直接把模块传递给子函数 return ({ children }) => children(toastify); }), }));
为什么这个方案有效?
- 它跳过了
loadable.lib的异步加载逻辑,直接同步获取react-toastify模块 - 返回的组件会立即调用你传入的
children函数,把完整的toastify模块传进去,这样组件里的this.toast = toast能正常赋值,渲染不会出现null - 快照测试会捕获到完整的组件渲染内容,和旧快照匹配
方案二:通用型Mock(支持多个模块懒加载)
如果你的项目里还有其他模块用loadable.lib懒加载,可以用更通用的Mock,自动解析加载路径并同步引入:
jest.mock('@loadable/component', () => ({ lib: (loader) => { // 从loader函数的字符串中提取要加载的模块路径 const modulePathMatch = loader.toString().match(/import\(['"](.*)['"]\)/); if (!modulePathMatch) { throw new Error('无法解析loadable.lib的加载路径'); } const modulePath = modulePathMatch[1]; // 同步引入目标模块 const module = jest.requireActual(modulePath); // 返回同步渲染的组件 return ({ children }) => children(module); }, }));
这个方案会自动适配所有loadable.lib(() => import('xxx'))的写法,不用为每个模块单独写Mock。
为什么你之前的尝试失败了?
- 第一个Mock返回
{ toast: {} },但你的组件里解构的是default导出({ default: toast }),导致toast是undefined,组件渲染异常 - 第二个Mock用了
async/await,但Jest的组件渲染是同步的,首次渲染时模块还没加载完成,children函数拿到的是null,导致快照不匹配
额外优化:预加载模块(可选)
如果你不想Mockloadable.lib,也可以利用loadable组件提供的load()方法,在测试前预加载模块:
import LoadableToast from './path-to-your-loadable-toast-component'; beforeAll(async () => { // 预加载模块,确保测试时模块已加载完成 await LoadableToast.load(); });
不过这个方法需要在每个用到该组件的测试文件中添加,不如Mock方案高效。
内容的提问来源于stack exchange,提问作者silviubogan
相关产品推荐
相关产品推荐

