使用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
相关产品推荐
相关产品推荐

