如何测试Vue 2.7组件中基于外部可组合式计算属性的watch监听
解决方案:Vue 2.7测试中模拟可组合式的Computed并触发Watch
问题核心是你mock的computed是只读的,无法手动修改值触发watch回调,但又必须符合原函数返回的ComputedRef类型。以下是两种可行方案:
方案一:基于可修改的Ref创建Computed
通过一个可手动控制的ref作为底层依赖,再基于它创建computed,修改ref的值就能让computed更新,进而触发watch:
// 测试文件 import { ref, computed, nextTick } from 'vue'; import composables from '@/composables/usePromotionProducts'; // 定义可修改的ref作为computed的依赖 const mockIsLoadingRef = ref(false); // mock可组合式函数 jest.spyOn(composables, 'usePromotionProducts').mockReturnValue({ isLoading: computed(() => mockIsLoadingRef.value) }); // 测试逻辑 test('watch triggers when isLoading changes', async () => { const wrapper = mount(YourComponent); expect(doSomething).not.toHaveBeenCalled(); // 修改ref的值,触发computed更新 mockIsLoadingRef.value = true; // 等待Vue更新watch回调 await nextTick(); // 断言doSomething被触发 expect(doSomething).toHaveBeenCalled(); });
方案二:手动模拟符合类型的ComputedRef对象
直接构造一个符合ComputedRef类型的对象,让它的value属性可读写,同时保留响应式标记:
// 测试文件 import { ComputedRef, nextTick } from 'vue'; import composables from '@/composables/usePromotionProducts'; // 构造模拟的ComputedRef const mockIsLoading = { _value: false, get value() { return this._value; }, set value(val) { this._value = val; }, __v_isRef: true, __v_isComputed: true, __v_isReadonly: false // 标记为非只读,确保watch能监听变化 } as ComputedRef<boolean>; // mock可组合式函数 jest.spyOn(composables, 'usePromotionProducts').mockReturnValue({ isLoading: mockIsLoading }); // 测试逻辑 test('watch triggers when isLoading changes', async () => { const wrapper = mount(YourComponent); expect(doSomething).not.toHaveBeenCalled(); // 直接修改模拟computed的value mockIsLoading.value = true; await nextTick(); expect(doSomething).toHaveBeenCalled(); });
注意事项
- 方案一更贴近真实业务场景,因为实际
computed也是依赖响应式数据计算而来,测试逻辑更符合生产环境的运行机制。 - 方案二需要确保模拟对象的类型与
ComputedRef完全匹配,避免TypeScript类型报错,手动断言类型是必要的。 - Vue 2.7的
watch监听computed时,依赖的是其value的响应式变化,只要能触发这个值的更新并让Vue检测到,就能触发watch回调。
内容的提问来源于stack exchange,提问作者Corentin DELANNOY
相关产品推荐
相关产品推荐

