Pinia stores are easy to test because they're just functions. You can test them in isolation or with components.
Setup for Testing
typescript// vitest.config.ts or jest setup import { beforeEach } from 'vitest' import { setActivePinia, createPinia } from 'pinia' beforeEach(() => { // Create a fresh pinia for each test setActivePinia(createPinia()) })
Testing State
typescriptimport { describe, it, expect, beforeEach } from 'vitest' import { setActivePinia, createPinia } from 'pinia' import { useCounterStore } from '@/stores/counter' describe('Counter Store', () => { beforeEach(() => { setActivePinia(createPinia()) }) it('has initial state', () => { const store = useCounterStore() expect(store.count).toBe(0) expect(store.name).toBe('Counter') }) it('can modify state directly', () => { const store = useCounterStore() store.count = 10 expect(store.count).toBe(10) }) })
Testing Actions
typescriptimport { describe, it, expect, vi, beforeEach } from 'vitest' import { setActivePinia, createPinia } from 'pinia' import { useCartStore } from '@/stores/cart' describe('Cart Store Actions', () => { beforeEach(() => { setActivePinia(createPinia()) }) it('adds item to cart', () => { const store = useCartStore() store.addItem({ id: 1, name: 'Product', price: 10 }) expect(store.items).toHaveLength(1) expect(store.items[0].name).toBe('Product') }) it('removes item from cart', () => { const store = useCartStore() store.items = [{ id: 1, name: 'Product', price: 10 }] store.removeItem(1) expect(store.items).toHaveLength(0) }) it('clears cart', () => { const store = useCartStore() store.items = [ { id: 1, name: 'A', price: 10 }, { id: 2, name: 'B', price: 20 } ] store.clearCart() expect(store.items).toHaveLength(0) }) })
Testing Getters
typescriptdescribe('Cart Store Getters', () => { beforeEach(() => { setActivePinia(createPinia()) }) it('calculates total correctly', () => { const store = useCartStore() store.items = [ { id: 1, name: 'A', price: 10, quantity: 2 }, { id: 2, name: 'B', price: 5, quantity: 3 } ] expect(store.total).toBe(35) // 10*2 + 5*3 }) it('returns empty total for empty cart', () => { const store = useCartStore() expect(store.total).toBe(0) }) it('counts items correctly', () => { const store = useCartStore() store.items = [ { id: 1, quantity: 2 }, { id: 2, quantity: 3 } ] expect(store.itemCount).toBe(5) }) })
Testing Async Actions
typescriptimport { vi } from 'vitest' describe('Async Actions', () => { beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() }) it('fetches data successfully', async () => { const mockData = [{ id: 1, name: 'Product' }] global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockData) }) const store = useProductStore() await store.fetchProducts() expect(store.products).toEqual(mockData) expect(store.loading).toBe(false) expect(store.error).toBeNull() }) it('handles fetch error', async () => { global.fetch = vi.fn().mockRejectedValue(new Error('Network error')) const store = useProductStore() await expect(store.fetchProducts()).rejects.toThrow() expect(store.error).toBe('Network error') expect(store.loading).toBe(false) }) it('sets loading state during fetch', async () => { let resolvePromise: Function const promise = new Promise(resolve => { resolvePromise = resolve }) global.fetch = vi.fn().mockReturnValue({ ok: true, json: () => promise }) const store = useProductStore() const fetchPromise = store.fetchProducts() expect(store.loading).toBe(true) resolvePromise!([]) await fetchPromise expect(store.loading).toBe(false) }) })
Testing with Components
typescriptimport { mount } from '@vue/test-utils' import { createTestingPinia } from '@pinia/testing' import Counter from '@/components/Counter.vue' describe('Counter Component', () => { it('displays count from store', () => { const wrapper = mount(Counter, { global: { plugins: [ createTestingPinia({ initialState: { counter: { count: 42 } } }) ] } }) expect(wrapper.text()).toContain('42') }) it('calls increment action on click', async () => { const wrapper = mount(Counter, { global: { plugins: [createTestingPinia()] } }) const store = useCounterStore() await wrapper.find('button').trigger('click') expect(store.increment).toHaveBeenCalled() }) })
@pinia/testing Options
typescriptimport { createTestingPinia } from '@pinia/testing' createTestingPinia({ // Initial state for stores initialState: { counter: { count: 10 }, user: { name: 'Test User' } }, // Stub all actions (default: true) stubActions: true, // Create spies for actions (default: true with vitest/jest) createSpy: vi.fn, // Plugins to use plugins: [myPlugin] })