home / skills / eva813 / vue3-skills / vue-vite-testing
npx playbooks add skill eva813/vue3-skills --skill vue-vite-testingReview the files below or copy the command above to add this skill to your agents.
---
name: vue-vite-testing
description: Comprehensive unit testing guide for Vue 3 + Vite projects using Vitest and Vue Test Utils. Use when writing or reviewing unit tests for Vue components, composables, Pinia stores, or TypeScript/JavaScript utilities in Vite-based projects. Covers test structure, best practices, mocking strategies, and Vue-specific testing patterns.
---
# Vue + Vite Unit Testing
## Overview
Generate comprehensive, production-ready unit tests for Vue 3 + Vite projects using Vitest framework. Follow industry best practices for testing Vue components, composables, Pinia stores, and TypeScript utilities with proper isolation, mocking, and edge case coverage.
## Testing Framework Setup
**Primary Stack:**
- **Vitest**: Fast unit test framework built for Vite
- **Vue Test Utils**: Official testing utility library for Vue components
- **@vitest/ui**: Optional UI for test visualization
**Import pattern:**
```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { mount, shallowMount } from '@vue/test-utils';
```
## Testing Workflow
Follow this systematic approach for all testing tasks:
### 1. Code Analysis Phase
**Before writing any tests:**
- Analyze the code structure and identify all public interfaces
- Identify external dependencies (APIs, stores, composables, modules)
- Note all possible code paths, conditions, and edge cases
- Ask clarifying questions about:
- Missing type definitions or constants
- Unclear business logic or validation rules
- External API contracts or data structures
- Expected error handling behaviors
**Only proceed to writing tests after full code understanding.**
### 2. Test Design Phase
**Plan test coverage:**
- Happy path scenarios (expected inputs and outputs)
- Error handling and failure modes
- Edge cases (empty arrays, null values, boundary conditions)
- Async operations (loading, success, error states)
- User interactions (clicks, inputs, form submissions)
- Lifecycle hooks and reactivity
**For Vue components, identify:**
- Props validation and default values
- Emitted events and their payloads
- Slots usage and content projection
- Computed properties and watchers
- Component lifecycle behavior
**For composables, identify:**
- Input parameters and return values
- State management and reactivity
- Side effects (API calls, localStorage, timers)
- Cleanup requirements
## Test Structure Standards
### Standard Test Template
```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
describe('ModuleName or ComponentName', () => {
// Top-level test variables
let mockDependency: MockType;
beforeEach(() => {
// Reset state before each test
mockDependency = createMockDependency();
});
afterEach(() => {
// Cleanup after each test
vi.clearAllMocks();
});
describe('method or feature name', () => {
it('should handle happy path scenario', () => {
// Arrange: Set up test data and mocks
const input = { /* test data */ };
// Act: Execute the code under test
const result = functionUnderTest(input);
// Assert: Verify expected outcomes
expect(result).toBe(expectedValue);
});
it('should handle error case', async () => {
// Arrange
mockDependency.method.mockRejectedValue(new Error('test error'));
// Act & Assert
await expect(functionUnderTest()).rejects.toThrow('test error');
});
it('should handle edge case: empty input', () => {
// Test edge cases
expect(functionUnderTest([])).toEqual([]);
});
});
});
```
### AAA Pattern (Arrange-Act-Assert)
**Always structure individual tests using AAA:**
```typescript
it('should calculate total price correctly', () => {
// Arrange: Set up test data
const items = [
{ price: 100, quantity: 2 },
{ price: 50, quantity: 1 }
];
// Act: Execute the function
const total = calculateTotal(items);
// Assert: Verify the result
expect(total).toBe(250);
});
```
## Vue-Specific Testing Patterns
### 1. Component Testing
**Decide between mount vs shallowMount:**
- Use `mount()` for integration testing with child components
- Use `shallowMount()` for isolated unit testing (stubs child components)
```typescript
import { mount } from '@vue/test-utils';
import MyComponent from './MyComponent.vue';
describe('MyComponent', () => {
it('should render with props', () => {
const wrapper = mount(MyComponent, {
props: {
title: 'Test Title',
count: 5
}
});
expect(wrapper.find('h1').text()).toBe('Test Title');
expect(wrapper.find('.count').text()).toBe('5');
});
it('should emit event on button click', async () => {
const wrapper = mount(MyComponent);
await wrapper.find('button').trigger('click');
expect(wrapper.emitted('submit')).toBeTruthy();
expect(wrapper.emitted('submit')[0]).toEqual([{ data: 'value' }]);
});
it('should handle v-model binding', async () => {
const wrapper = mount(MyComponent, {
props: {
modelValue: 'initial'
}
});
await wrapper.find('input').setValue('updated');
expect(wrapper.emitted('update:modelValue')[0]).toEqual(['updated']);
});
});
```
**See `references/component-testing.md` for complete component testing patterns including slots, provide/inject, and async components.**
### 2. Composables Testing
```typescript
import { composableUnderTest } from './useFeature';
describe('useFeature composable', () => {
it('should initialize with default state', () => {
const { state, count } = composableUnderTest();
expect(state.value).toBe('idle');
expect(count.value).toBe(0);
});
it('should update reactive state', () => {
const { increment, count } = composableUnderTest();
increment();
expect(count.value).toBe(1);
});
it('should handle async operations', async () => {
const { fetchData, data, loading } = composableUnderTest();
expect(loading.value).toBe(false);
const promise = fetchData();
expect(loading.value).toBe(true);
await promise;
expect(loading.value).toBe(false);
expect(data.value).toBeDefined();
});
});
```
**See `references/composables-testing.md` for advanced composable testing patterns including side effects and cleanup.**
### 3. Pinia Store Testing
```typescript
import { setActivePinia, createPinia } from 'pinia';
import { useMyStore } from './myStore';
describe('myStore', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('should initialize with default state', () => {
const store = useMyStore();
expect(store.items).toEqual([]);
expect(store.loading).toBe(false);
});
it('should add item to store', () => {
const store = useMyStore();
const newItem = { id: 1, name: 'Test' };
store.addItem(newItem);
expect(store.items).toContainEqual(newItem);
});
it('should handle async actions', async () => {
const store = useMyStore();
await store.fetchItems();
expect(store.loading).toBe(false);
expect(store.items.length).toBeGreaterThan(0);
});
});
```
**See `references/store-testing.md` for Pinia store testing patterns including getters, mutations, and actions.**
## Mocking Strategies
### External Dependencies
```typescript
// Mock API calls
vi.mock('@/api/users', () => ({
fetchUsers: vi.fn(),
createUser: vi.fn()
}));
// Mock composables
vi.mock('@/composables/useAuth', () => ({
useAuth: vi.fn(() => ({
user: { id: 1, name: 'Test User' },
isAuthenticated: true,
login: vi.fn(),
logout: vi.fn()
}))
}));
// Mock Vue Router
const mockRouter = {
push: vi.fn(),
replace: vi.fn()
};
const wrapper = mount(Component, {
global: {
mocks: {
$router: mockRouter
}
}
});
```
### Timers and Delays
```typescript
import { vi } from 'vitest';
describe('setTimeout behavior', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it('should execute callback after delay', () => {
const callback = vi.fn();
setTimeout(callback, 1000);
expect(callback).not.toHaveBeenCalled();
vi.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalledOnce();
});
});
```
## Testing Best Practices
### 1. Test Isolation
- Each test should be independent and not rely on other tests
- Use `beforeEach` to reset state
- Clean up mocks with `vi.clearAllMocks()` or `vi.resetAllMocks()`
### 2. Descriptive Test Names
```typescript
// ✅ Good: Clear and descriptive
it('should display error message when API request fails', () => {});
// ❌ Bad: Vague and unclear
it('should work', () => {});
```
### 3. Avoid Test Logic
```typescript
// ❌ Bad: Contains loops and conditions
it('should validate all items', () => {
for (const item of items) {
if (item.type === 'special') {
expect(validate(item)).toBe(true);
}
}
});
// ✅ Good: Simple and direct
it('should validate special item', () => {
const specialItem = { type: 'special', value: 100 };
expect(validate(specialItem)).toBe(true);
});
it('should validate normal item', () => {
const normalItem = { type: 'normal', value: 50 };
expect(validate(normalItem)).toBe(true);
});
```
### 4. Test Coverage Priority
1. **Critical business logic** (payment, authentication, data validation)
2. **Complex algorithms** (calculations, transformations)
3. **Error handling** (edge cases, failure modes)
4. **User interactions** (forms, buttons, navigation)
5. **Integration points** (API calls, external services)
### 5. Async Testing
```typescript
// ✅ Properly handle async operations
it('should fetch data successfully', async () => {
const result = await fetchData();
expect(result).toBeDefined();
});
// ✅ Use resolves/rejects for promises
await expect(fetchData()).resolves.toEqual(expectedData);
await expect(failingOperation()).rejects.toThrow('Error message');
```
## Complete Test Deliverables
When generating tests, always provide:
1. **Complete test suites** - No placeholders or "// TODO" comments
2. **All edge cases covered** - Empty inputs, null values, boundaries
3. **Proper imports** - All necessary test utilities and dependencies
4. **Appropriate mocks** - For external dependencies and side effects
5. **Clear test descriptions** - Self-documenting test names
6. **Proper cleanup** - afterEach hooks where needed
## Reference Files
For detailed examples and advanced patterns:
- **`references/component-testing.md`** - Comprehensive component testing patterns (slots, teleport, provide/inject, async components)
- **`references/composables-testing.md`** - Advanced composable testing (side effects, watchers, cleanup)
- **`references/store-testing.md`** - Pinia store testing patterns (getters, actions, state management)