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

Jest+testing-library如何动态Mock组件解决作用域报错

报错原因

Jest 执行测试时默认会把所有jest.mock()调用自动提升到当前文件最顶部,执行优先级高于所有import语句、变量声明和函数参数定义。你封装的mockComponent函数里传入的source、name属于函数作用域内的参数,在jest.mock被提升执行的时机还未完成初始化,工厂函数访问不到这些外部变量,就会抛出越权访问的错误。

可行解决方案

根据使用场景选对应方案即可:

方案1:封装通用动态mock函数(适配抽离公共逻辑的需求)

用不会被自动提升的jest.doMock替代jest.mock,同时配合模块缓存重置,保证mock结果生效,支持完全动态的参数传入:

export function mockComponent(source: string, name: string) {
  jest.doMock(source, () => ({
    // 保留模块原有其他导出,避免影响其他组件的正常使用
    ...jest.requireActual(source),
    [name]: (props: any) => {
      const ComponentMock = `${name}-mock`;
      // @ts-ignore
      return <ComponentMock {...props} />;
    },
  }));
  // 清除对应模块的缓存,保证后续导入时能拿到mock后的版本
  jest.resetModules();
}

注意事项:

  • 该函数必须在第一次导入被mock的模块之前调用,如果之前已经导入过模块,重置缓存后需要重新导入才能拿到mock结果。
  • 如果需要mock某个模块的多个导出组件,重复调用该函数传不同的name即可。

方案2:单文件内批量mock(无需封装工具的轻量场景)

Jest的mock工厂函数默认允许访问名字以mock开头的外部变量,可以直接在文件顶层用mock前缀的变量存要mock的模块名、组件名,不需要额外封装函数:

const mockRouterSource = 'react-router-dom';
const mockNavLinkName = 'NavLink';

jest.mock(mockRouterSource, () => ({
  ...jest.requireActual(mockRouterSource),
  [mockNavLinkName]: (props: any) => {
    const NavLinkMock = 'NavLink-Mock';
    // @ts-ignore
    return <NavLinkMock {...props} />;
  }
}));

方案3:全局公共mock(适配react-router-dom这类全项目通用依赖)

对于多个测试文件都要用到的公共依赖mock,不需要在每个文件写重复逻辑,直接在项目内建__mocks__目录维护固定mock实现即可:

  1. 在项目根目录新建__mocks__/react-router-dom.ts文件
  2. 写入固定mock逻辑:
const actualRouter = jest.requireActual('react-router-dom');

module.exports = {
  ...actualRouter,
  NavLink: (props: any) => {
    const NavLinkMock = 'NavLink-Mock';
    // @ts-ignore
    return <NavLinkMock {...props} />;
  }
}
  1. 所有测试文件里只要写一行jest.mock('react-router-dom'),Jest就会自动加载你写好的全局mock,不需要重复写实现。

内容的提问来源于stack exchange,提问作者Teehbow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:12:32