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

使用Jest进行Vue单元测试时如何Mock $refs属性?

解决Vue组件Jest测试中$refs.tabRef的Mock问题

你遇到的TypeError: Cannot read property 'offsetParent' of null错误,本质是测试时组件挂载后$refs.tabRef默认是null,而且不能用mount配置里的mocks来Mock $refs——因为$refs是Vue实例的内部属性,不是全局注入的依赖,mocks只针对$router、$store这类全局对象。

下面是两种可行的Mock方案:

方案1:手动Mock DOM结构并触发mounted钩子

直接模拟$refs.tabRef及其层级结构,再手动执行mounted钩子:

import { mount } from '@vue/test-utils';
import YourComponent from '@/components/YourComponent.vue';

describe('YourComponent', () => {
  it('正确设置pageSize', () => {
    // 模拟最终的offsetParent元素,定义宽高
    const mockPageRef = {
      offsetWidth: 800,
      offsetHeight: 600
    };
    // 模拟tabRef的层级:tabRef -> offsetParent -> offsetParent -> mockPageRef
    const mockTabRef = {
      offsetParent: {
        offsetParent: mockPageRef
      }
    };

    const wrapper = mount(YourComponent);
    // 给组件实例的$refs赋值
    wrapper.vm.$refs.tabRef = mockTabRef;
    
    // 手动调用mounted钩子(因为组件挂载时已经执行过一次,现在重新执行)
    wrapper.vm.$options.mounted[0].call(wrapper.vm);

    // 断言pageSize是否符合预期
    expect(wrapper.vm.pageSize).toEqual({
      width: 800,
      height: 600
    });
  });
});

方案2:挂载到真实DOM并构建元素层级

如果需要更贴近真实渲染环境的测试,可以把组件挂载到真实DOM节点,手动构建offsetParent的层级:

import { mount } from '@vue/test-utils';
import YourComponent from '@/components/YourComponent.vue';

describe('YourComponent', () => {
  let container;

  beforeEach(() => {
    // 创建真实DOM容器并添加到页面
    container = document.createElement('div');
    document.body.appendChild(container);

    // 构建两层父元素作为offsetParent
    const parent1 = document.createElement('div');
    const parent2 = document.createElement('div');
    // 设置目标宽高
    parent2.style.width = '800px';
    parent2.style.height = '600px';
    parent1.appendChild(parent2);
    container.appendChild(parent1);

    // 创建tabRef对应的元素,放到parent2下(这样它的offsetParent就是parent1,再往上是parent2)
    const tabEl = document.createElement('div');
    parent2.appendChild(tabEl);
  });

  afterEach(() => {
    // 测试后清理DOM
    document.body.removeChild(container);
  });

  it('正确设置pageSize', () => {
    const wrapper = mount(YourComponent, {
      // 把组件挂载到我们创建的容器
      attachTo: container,
      // 直接指定$refs.tabRef对应的真实元素
      refs: {
        tabRef: container.querySelector('div')
      }
    });

    expect(wrapper.vm.pageSize).toEqual({
      width: 800,
      height: 600
    });
  });
});

注意事项

  • 永远不要用mocks配置Mock $refs,这是对mocks用途的误解。
  • 优先用方案1的Mock方式,避免真实DOM环境带来的跨平台测试差异。
  • 如果组件有多个mounted钩子,要注意调用对应索引的钩子函数,或者遍历执行所有mounted钩子。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:14:58