Vue Test Utils:如何动态Mock带参数的命名空间Getter返回值
问题描述
需要Mock Vuex命名空间app下的带参数Getter myGetter,使其动态返回测试参数,以此控制页面元素的可见性。原Getter为柯里化结构,目前尝试的多种Mock方式均未成功。
原Getter代码(位于app模块)
const getters = { myGetter: (state) => (getterArg) => { return state.someStateVariable === true ? valueForTrue : valueForFalse; } };
测试代码及失败尝试
import { cloneDeep } from "lodash"; import { createLocalVue, shallowMount } from "@vue/test-utils"; import MyComponent from "@/views/MyComponent.vue"; import { storeConfig } from "@/store"; import Vuex from "vuex"; describe("My test", () => { let localVue; let store; let wrapper; beforeEach(() => { localVue = createLocalVue(); localVue.use(Vuex); }); test.each([[false], [true]])( "Test param: '%s'", (testParam) => { store = new Vuex.Store({ modules: { app: { namespaced: true, ...cloneDeep(storeConfig.modules.app), state: { ...cloneDeep(storeConfig.modules.app.state), }, getters: { ...cloneDeep(storeConfig.modules.app.getters), // 已定义getter,但未使用测试参数 // myGetter: jest.fn().mockReturnValue(jest.fn()) // 带Mock返回值的getter变体(测试失败) // myGetter: jest.fn().mockReturnValue(jest.fn().mockReturnValue(testParam)) // 带组件传入参数和Mock返回值的getter变体(测试失败) // myGetter: jest.fn("getterArg").mockReturnValue(jest.fn().mockReturnValue(testParam)) } } } }); wrapper = shallowMount(MyComponent, { localVue, store }); expect(wrapper.find("#my-element").exists()).toBe(testParam); } ); });
额外失败尝试(创建wrapper后修改)
// 测试失败,getter未定义 Object.defineProperty(wrapper.vm, "app/myGetter", { value: () => { return testParam; } }); // 测试失败,getter未定义 Object.defineProperty(wrapper.vm, "app/myGetter", { value: ("getterArg") => { return testParam; } });
解决方案
原Getter是柯里化函数((state) => (getterArg) => 返回值),Mock时必须匹配这个嵌套函数结构,以下是两种可行方案:
方案1:直接定义匹配结构的函数(最简方式)
在创建store时,重写myGetter为忽略参数、直接返回测试参数的柯里化函数:
store = new Vuex.Store({ modules: { app: { namespaced: true, ...cloneDeep(storeConfig.modules.app), state: { ...cloneDeep(storeConfig.modules.app.state), }, getters: { ...cloneDeep(storeConfig.modules.app.getters), // 核心:返回嵌套函数,最终返回测试参数 myGetter: () => () => testParam } } } });
方案2:使用jest.fn()模拟(支持调用断言)
如果需要验证myGetter的调用情况(比如调用次数、传入参数),可以用jest模拟嵌套函数:
getters: { ...cloneDeep(storeConfig.modules.app.getters), myGetter: jest.fn().mockReturnValue(jest.fn().mockReturnValue(testParam)) }
注意:确保测试代码中只保留这一行
myGetter定义,避免多定义冲突导致失败。
为什么修改vm属性的方式失败?
Vuex命名空间Getter不会直接挂载到组件实例vm上,而是通过$store.getters['app/myGetter']访问。如果必须在创建wrapper后修改,可以直接操作store并强制组件更新:
// 修改store中的getter store.getters['app/myGetter'] = () => testParam; // 触发组件重新渲染 wrapper.vm.$forceUpdate();
不过优先推荐在创建store时完成Mock,避免状态不一致问题。
内容的提问来源于stack exchange,提问作者Growth Mindset
相关产品推荐
相关产品推荐

