使用Jest测试嵌套Pinia Store Action遇类型错误求助
测试嵌套Pinia Store Action时的Jest Mock问题
在使用Jest测试嵌套Pinia Store的Action时遇到类型错误:
TypeError: foodStore.getSnack.mockReturnValue is not a function
取消注释测试代码里的// foodStore.getSnack = jest.fn()后测试可通过,但这种写法不够优雅。想知道Pinia有没有官方的Action Mock方式,还是必须在Store实例创建后重新Mock Action?
错误信息
● useMamaStore › should make a snack if food store has snacks available TypeError: foodStore.getSnack.mockReturnValue is not a function 58 | it('should make a snack if food store has snacks available', () => { 59 | // Mock food store to return a valid snack > 60 | foodStore.getSnack.mockReturnValue(true) | ^ 61 | mamaStore.makeSnack() 62 | expect(foodStore.getSnack).toHaveBeenCalled() 63 | expect(mamaStore.snackMade).toBe(true) at Object.mockReturnValue (test/jest/__tests__/stores/mama.jest.spec.js:60:24)
测试代码
import { setActivePinia, createPinia, getActivePinia } from 'pinia' import { useMamaStore } from 'src/stores/mama' import { useFoodStore } from 'src/stores/food' export const getStore = (name) => { const store = getActivePinia()?._s.get(name) if (!store) throw new Error(`${name} store does not exist`) return store } jest.mock( 'src/stores/food', () => { const { defineStore } = require('pinia') const useFoodStore = defineStore('food', { state: () => ({ snacks: 10 }), actions: { getSnack: jest.fn(), }, }) return { useFoodStore } }, ) describe('useMamaStore', () => { let mamaStore let foodStore beforeEach(() => { const pinia = createPinia() setActivePinia(pinia) foodStore = useFoodStore(pinia) // foodStore.getSnack = jest.fn() mamaStore = useMamaStore(pinia) jest.clearAllMocks() }) it('should make a snack if food store has snacks available', () => { // Mock food store to return a valid snack foodStore.getSnack.mockReturnValue(true) mamaStore.makeSnack() expect(foodStore.getSnack).toHaveBeenCalled() expect(mamaStore.snackMade).toBe(true) }) })
相关Store代码
src/stores/mama.js
import { defineStore } from 'pinia' import { useFoodStore } from './food' export const useMamaStore = defineStore('mama', { state: () => ({ loving: true, caring: true, snackMade: false, }), getters: { timeForSnack(state) { return state.snackMade }, }, actions: { makeSnack() { const foodStore = useFoodStore() const snack = foodStore.getSnack() this.snackMade = snack }, }, })
src/stores/food.js
import { defineStore } from 'pinia' export const useFoodStore = defineStore('food', { state: { delicious: true, snacks: 10, }, getters, actions: { getSnack() { if (this.snacks === 0) { return false } this.snacks = this.snacks - 1 return true }, }, })
解决方案
问题根源
你在jest.mock里定义的getSnack: jest.fn()会被Pinia做一层包装,绑定store的上下文,导致原来的jest mock函数实例被覆盖,无法访问mockReturnValue等方法。
方案一:暴露Mock函数到模块外部
修改jest.mock的实现,把mock函数单独赋值,再暴露出来,这样可以直接在测试中操作这个原始mock:
jest.mock( 'src/stores/food', () => { const { defineStore } = require('pinia') // 单独定义mock函数 const mockGetSnack = jest.fn() const useFoodStore = defineStore('food', { state: () => ({ snacks: 10 }), actions: { getSnack: mockGetSnack, }, }) // 暴露mock函数 return { useFoodStore, mockGetSnack } }, )
测试中直接使用暴露的mock:
import { mockGetSnack } from 'src/stores/food' it('should make a snack if food store has snacks available', () => { mockGetSnack.mockReturnValue(true) mamaStore.makeSnack() expect(mockGetSnack).toHaveBeenCalled() expect(mamaStore.snackMade).toBe(true) })
方案二:使用Pinia官方测试工具(推荐)
Pinia提供了@pinia/testing工具,可以自动处理action的mock,无需手动mock整个模块:
- 安装依赖:
npm install -D @pinia/testing - 修改测试代码:
import { setActivePinia } from 'pinia' import { createTestingPinia } from '@pinia/testing' import { useMamaStore } from 'src/stores/mama' import { useFoodStore } from 'src/stores/food' describe('useMamaStore', () => { let mamaStore let foodStore beforeEach(() => { // 创建测试用Pinia实例,自动mock所有actions const pinia = createTestingPinia({ createSpy: jest.fn, // 指定用Jest创建mock函数 }) setActivePinia(pinia) foodStore = useFoodStore(pinia) mamaStore = useMamaStore(pinia) }) it('should make a snack if food store has snacks available', () => { foodStore.getSnack.mockReturnValue(true) mamaStore.makeSnack() expect(foodStore.getSnack).toHaveBeenCalled() expect(mamaStore.snackMade).toBe(true) }) })
这种方式会自动把所有store的action替换为Jest mock函数,同时保留store的其他逻辑,是Pinia官方推荐的测试方式。
内容的提问来源于stack exchange,提问作者whoacowboy
相关产品推荐
相关产品推荐

