3.8 KiB
3.8 KiB
name, description
| name | description |
|---|---|
| testing | Unit testing stores and components with @pinia/testing |
Testing Stores
Unit Testing Stores
Create a fresh pinia instance for each test:
import { setActivePinia, createPinia } from 'pinia';
import { useCounterStore } from '../src/stores/counter';
describe('Counter Store', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('increments', () => {
const counter = useCounterStore();
expect(counter.n).toBe(0);
counter.increment();
expect(counter.n).toBe(1);
});
});
With Plugins
import { setActivePinia, createPinia } from 'pinia';
import { createApp } from 'vue';
import { somePlugin } from '../src/stores/plugin';
const app = createApp({});
beforeEach(() => {
const pinia = createPinia().use(somePlugin);
app.use(pinia);
setActivePinia(pinia);
});
Testing Components
Install @pinia/testing:
npm i -D @pinia/testing
Use createTestingPinia():
import { mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { useSomeStore } from '@/stores/myStore';
const wrapper = mount(Counter, {
global: {
plugins: [createTestingPinia()],
},
});
const store = useSomeStore();
// Manipulate state directly
store.name = 'new name';
store.$patch({ name: 'new name' });
// Actions are stubbed by default
store.someAction();
expect(store.someAction).toHaveBeenCalledTimes(1);
Initial State
Set initial state for tests:
const wrapper = mount(Counter, {
global: {
plugins: [
createTestingPinia({
initialState: {
counter: { n: 20 }, // Store name → initial state
},
}),
],
},
});
Action Stubbing
Execute Real Actions
createTestingPinia({ stubActions: false });
Selective Stubbing
// Only stub specific actions
createTestingPinia({
stubActions: ['increment', 'reset'],
});
// Or use a function
createTestingPinia({
stubActions: (actionName, store) => {
if (actionName.startsWith('set')) return true;
return false;
},
});
Mock Action Return Values
import type { Mock } from 'vitest';
// After getting store
store.someAction.mockResolvedValue('mocked value');
Mocking Getters
Getters are writable in tests:
const pinia = createTestingPinia();
const counter = useCounterStore(pinia);
counter.double = 3; // Override computed value
// Reset to default behavior
counter.double = undefined;
counter.double; // Now computed normally
Custom Spy Function
If not using Jest/Vitest with globals:
import { vi } from 'vitest';
createTestingPinia({
createSpy: vi.fn,
});
With Sinon:
import sinon from 'sinon';
createTestingPinia({
createSpy: sinon.spy,
});
Pinia Plugins in Tests
Pass plugins to createTestingPinia():
import { somePlugin } from '../src/stores/plugin';
createTestingPinia({
stubActions: false,
plugins: [somePlugin],
});
Don't use testingPinia.use(MyPlugin) - pass plugins in options.
Type-Safe Mocked Store
import type { Mock } from 'vitest';
import type { Store, StoreDefinition } from 'pinia';
function mockedStore<TStoreDef extends () => unknown>(
useStore: TStoreDef,
): TStoreDef extends StoreDefinition<infer Id, infer State, infer Getters, infer Actions>
? Store<
Id,
State,
Record<string, never>,
{
[K in keyof Actions]: Actions[K] extends (...args: any[]) => any
? Mock<Actions[K]>
: Actions[K];
}
>
: ReturnType<TStoreDef> {
return useStore() as any;
}
// Usage
const store = mockedStore(useSomeStore);
store.someAction.mockResolvedValue('value'); // Typed!
E2E Tests
No special handling needed - Pinia works normally.