Vue测试中Pinia Store状态未变更问题排查
问题描述
我想用Vitest测试submitEvaluation函数,预期调用disableSubmit(true)后,禁用状态设为true,此时submitEvaluation里的setIsLocked不应被执行。但实际调用disableSubmit(true)后,isDisabledSubmit始终是初始值false,导致setIsLocked仍被执行。我尝试通过wrapper.vm及直接导入useFormStore解决均无效,需排查问题原因。
相关代码
Pinia Store代码
lockStore
import { defineStore } from 'pinia'; export const useLockStore = defineStore("lockStore", { state: () => ({ isLocked: false }), actions: { setIsLocked(value: boolean): void { this.isLocked = value; } }, getters: { getIsLocked(state): boolean { return state.isLocked; } } });
formStore
import { defineStore } from 'pinia'; export const useFormStore = defineStore("formStore", () => { const preventSubmit = ref(false); function disableSubmit(val: boolean): void { preventSubmit.value = val; } function isDisabledSubmit(): boolean { return preventSubmit.value; } return { disableSubmit, isDisabledSubmit: isDisabledSubmit() }; });
Vue组件(Composition API Setup语法)待测试函数
const { disableSubmit, isDisabledSubmit } = useFormStore(); function submitEvaluation(): void { console.log(isDisabledSubmit); if (!isDisabledSubmit) { lockStore.setIsLocked(false); updateEvaluation(payload.value, closeDialog); } } defineExpose({ lockStore, loadDropDown, resubmissionDate, onDropDownReady, isOpenDialog, openDialog, closeDialog, cancelDialog, resetDataFields, dataFields, updateEvaluation, submitEvaluation, isDisabledSubmit, disableSubmit })
测试文件代码
beforeEach(() => { // 创建新的Pinia并设为活跃状态,useStore()会自动使用它,无需手动传入 setActivePinia(createPinia()); }); afterEach(() => { vi.clearAllMocks(); vi.restoreAllMocks() }); test.only('SubmitEvaluation_ifIsDisabledSubmitIsTrue_ExpectLockStoreSetLockedNotToBeCalled', async () => { const formStore = useFormStore(); const lockStore = useLockStore(); const spyOnFormStoreDisableSubmit = vi.fn(formStore.disableSubmit) formStore.disableSubmit = spyOnFormStoreDisableSubmit vi.spyOn(wrapper.vm, 'submitEvaluation') vi.spyOn(wrapper.vm, 'disableSubmit') vi.spyOn(formStore, 'disableSubmit') wrapper.vm.disableSubmit(true) wrapper.vm.isDisabledSubmit = vi.fn().mockReturnValue(true) as any console.log(wrapper.vm.isDisabledSubmit); formStore.disableSubmit(true) formStore.isDisabledSubmit = true wrapper.vm.isDisabledSubmit = vi.fn().mockReturnValue(true) as any wrapper.vm.submitEvaluation() // 当isDisabledSubmit为true时,setIsLocked不应被调用 expect(wrapper.vm.lockStore.setIsLocked).toBeCalledTimes(0) // expect(lockStore.setIsLocked).toBeCalledTimes(0) })
问题根源与修复方案
问题核心
- formStore定义错误:在
useFormStore中,isDisabledSubmit返回的是isDisabledSubmit()的执行结果(初始false),而非函数引用或响应式计算属性。这导致组件拿到的是一个固定布尔值,不会随preventSubmit的变化更新。 - 组件使用方式错误:组件解构出的
isDisabledSubmit是静态值,不是函数/响应式对象,因此submitEvaluation中的判断永远用初始值。 - 测试操作无效:测试中直接给
formStore.isDisabledSubmit或wrapper.vm.isDisabledSubmit赋值,无法同步组件内的静态值引用。
修复步骤
1. 修正formStore定义
选择以下两种方式之一:
- 使用响应式计算属性:
import { defineStore, ref, computed } from 'pinia'; export const useFormStore = defineStore("formStore", () => { const preventSubmit = ref(false); function disableSubmit(val: boolean): void { preventSubmit.value = val; } const isDisabledSubmit = computed(() => preventSubmit.value); return { disableSubmit, isDisabledSubmit }; });
- 返回函数引用:
import { defineStore, ref } from 'pinia'; export const useFormStore = defineStore("formStore", () => { const preventSubmit = ref(false); function disableSubmit(val: boolean): void { preventSubmit.value = val; } function isDisabledSubmit(): boolean { return preventSubmit.value; } return { disableSubmit, isDisabledSubmit }; // 不要加(),返回函数本身 });
2. 修正组件中的使用逻辑
- 若用计算属性:
const { disableSubmit, isDisabledSubmit } = useFormStore(); function submitEvaluation(): void { console.log(isDisabledSubmit.value); if (!isDisabledSubmit.value) { lockStore.setIsLocked(false); updateEvaluation(payload.value, closeDialog); } }
- 若用函数:
const { disableSubmit, isDisabledSubmit } = useFormStore(); function submitEvaluation(): void { console.log(isDisabledSubmit()); if (!isDisabledSubmit()) { lockStore.setIsLocked(false); updateEvaluation(payload.value, closeDialog); } }
3. 简化测试代码
test.only('SubmitEvaluation_whenDisabled_shouldNotCallSetIsLocked', async () => { const formStore = useFormStore(); const lockStore = useLockStore(); // 监听setIsLocked方法 const setIsLockedSpy = vi.spyOn(lockStore, 'setIsLocked'); // 设置禁用状态 formStore.disableSubmit(true); // 调用提交函数 wrapper.vm.submitEvaluation(); // 验证setIsLocked未被调用 expect(setIsLockedSpy).not.toHaveBeenCalled(); })
内容的提问来源于stack exchange,提问作者venndi
相关产品推荐
相关产品推荐

