pinia-store-mocking.md
3.73 KB
title: Mocking Pinia Stores with Vitest
impact: HIGH
impactDescription: properly mocks Pinia stores in component tests
type: efficiency
tags: pinia, vitest, testing, mock, createTestingPinia, store
Mocking Pinia Stores with Vitest
Impact: HIGH - properly mocks Pinia stores in component tests
Developers struggle to properly mock Pinia stores: createTestingPinia requires explicit createSpy configuration, and "injection Symbol(pinia) not found" errors occur without proper setup.
Important (@pinia/testing 1.0+): The
createSpyoption is REQUIRED, not optional. Omitting it throws an error: "You must configure thecreateSpyoption."
Symptoms
- "injection Symbol(pinia) not found" error
- "You must configure the
createSpyoption" error - Actions not properly mocked
- Store state not reset between tests
Fix
Pattern 1: Basic setup with createTestingPinia
import { mount } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'
import { vi } from 'vitest'
import MyComponent from './MyComponent.vue'
import { useCounterStore } from '@/stores/counter'
test('component uses store', async () => {
const wrapper = mount(MyComponent, {
global: {
plugins: [
createTestingPinia({
createSpy: vi.fn, // REQUIRED in @pinia/testing 1.0+
initialState: {
counter: { count: 10 } // Set initial state
}
})
]
}
})
// Get the store instance AFTER mounting
const store = useCounterStore()
// Actions are automatically stubbed
await wrapper.find('button').trigger('click')
expect(store.increment).toHaveBeenCalled()
})
Pattern 2: Customize action behavior
test('component handles async action', async () => {
const wrapper = mount(MyComponent, {
global: {
plugins: [
createTestingPinia({
createSpy: vi.fn,
stubActions: false // Don't stub, use real actions
})
]
}
})
const store = useCounterStore()
// Override specific action
store.fetchData = vi.fn().mockResolvedValue({ items: [] })
await wrapper.find('.load-button').trigger('click')
expect(store.fetchData).toHaveBeenCalled()
})
Pattern 3: Testing store directly
import { setActivePinia, createPinia } from 'pinia'
import { useCounterStore } from '@/stores/counter'
describe('Counter Store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
test('increments count', () => {
const store = useCounterStore()
expect(store.count).toBe(0)
store.increment()
expect(store.count).toBe(1)
})
})
Setup Store with Vitest
// stores/counter.ts - Setup store syntax
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
// Test file
test('setup store works', async () => {
const pinia = createTestingPinia({
createSpy: vi.fn,
initialState: {
counter: { count: 5 }
}
})
const wrapper = mount(MyComponent, {
global: { plugins: [pinia] }
})
const store = useCounterStore()
expect(store.count).toBe(5)
expect(store.doubleCount).toBe(10)
})
Reset Between Tests
describe('Store Tests', () => {
let pinia: Pinia
beforeEach(() => {
pinia = createTestingPinia({
createSpy: vi.fn
})
})
afterEach(() => {
vi.clearAllMocks()
})
test('test 1', () => { /* ... */ })
test('test 2', () => { /* ... */ })
})