Vitest Configuration
Master Vitest configuration, Vite integration, workspace setup, and test environment configuration for modern testing. This skill covers comprehensive configuration strategies for Vitest, the blazing-fast unit test framework powered by Vite.
Installation and Setup
Basic Installation
npm install -D vitest
or
yarn add -D vitest
or
pnpm add -D vitest
Additional Packages
UI for vitest
npm install -D @vitest/ui
Browser mode
npm install -D @vitest/browser playwright
Coverage
npm install -D @vitest/coverage-v8
or
npm install -D @vitest/coverage-istanbul
Configuration Files
vitest.config.ts (Recommended)
import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { // Test environment environment: 'node', // 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime'
// Global test files
globals: true,
setupFiles: ['./vitest.setup.ts'],
// Include/exclude patterns
include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],
// Coverage configuration
coverage: {
provider: 'v8', // 'v8' | 'istanbul'
reporter: ['text', 'json', 'html'],
include: ['src/**/*.{js,ts,jsx,tsx}'],
exclude: [
'node_modules/',
'src/**/*.test.{js,ts,jsx,tsx}',
'src/**/*.spec.{js,ts,jsx,tsx}',
'src/**/__tests__/**'
],
thresholds: {
lines: 80,
functions: 80,
branches: 80,
statements: 80
}
},
// Performance
pool: 'threads', // 'threads' | 'forks' | 'vmThreads'
poolOptions: {
threads: {
singleThread: false,
minThreads: 1,
maxThreads: 4
}
},
// Timeouts
testTimeout: 10000,
hookTimeout: 10000,
// Watch options
watch: false,
watchExclude: ['**/node_modules/**', '**/dist/**'],
// Reporters
reporters: ['default'],
// Mock options
mockReset: true,
restoreMocks: true,
clearMocks: true
} });
Extending Vite Config
import { defineConfig, mergeConfig } from 'vitest/config'; import viteConfig from './vite.config';
export default mergeConfig( viteConfig, defineConfig({ test: { // Vitest-specific configuration } }) );
Workspace Configuration
// vitest.workspace.ts import { defineWorkspace } from 'vitest/config';
export default defineWorkspace([ // Multiple projects { extends: './vitest.config.ts', test: { name: 'unit', include: ['src//*.test.ts'], environment: 'node' } }, { extends: './vitest.config.ts', test: { name: 'browser', include: ['src//.browser.test.ts'], environment: 'jsdom' } }, { extends: './vitest.config.ts', test: { name: 'integration', include: ['tests/integration/**/.test.ts'], environment: 'node' } } ]);
Environment Configuration
Node Environment
// vitest.config.ts export default defineConfig({ test: { environment: 'node', environmentOptions: { // Node-specific options } } });
JSDOM Environment
// vitest.config.ts export default defineConfig({ test: { environment: 'jsdom', environmentOptions: { jsdom: { resources: 'usable', url: 'http://localhost:3000' } } } });
Happy DOM Environment
// vitest.config.ts export default defineConfig({ test: { environment: 'happy-dom', environmentOptions: { happyDOM: { width: 1024, height: 768 } } } });
Custom Environment
// custom-environment.ts import type { Environment } from 'vitest';
export default <Environment>{ name: 'custom', transformMode: 'ssr', setup() { // Setup custom environment return { teardown() { // Cleanup } }; } };
// vitest.config.ts export default defineConfig({ test: { environment: './custom-environment.ts' } });
Setup Files
vitest.setup.ts
import { expect, afterEach, vi } from 'vitest'; import { cleanup } from '@testing-library/react'; import matchers from '@testing-library/jest-dom/matchers';
// Extend Vitest matchers expect.extend(matchers);
// Cleanup after each test afterEach(() => { cleanup(); });
// Mock global objects global.fetch = vi.fn();
// Setup global test utilities global.testUtils = { // Custom test utilities };
// Configure test environment beforeAll(() => { // Global setup });
afterAll(() => { // Global teardown });
Setup for React Testing
import { expect, afterEach } from 'vitest'; import { cleanup } from '@testing-library/react'; import * as matchers from '@testing-library/jest-dom/matchers';
expect.extend(matchers);
afterEach(() => { cleanup(); });
// Mock window.matchMedia Object.defineProperty(window, 'matchMedia', { writable: true, value: vi.fn().mockImplementation(query => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn() })) });
Coverage Configuration
V8 Provider
export default defineConfig({ test: { coverage: { provider: 'v8', reporter: ['text', 'json', 'html', 'lcov'], reportsDirectory: './coverage', include: ['src//*.ts'], exclude: [ '/.test.ts', '**/.spec.ts', '/types/', '**/*.d.ts' ], thresholds: { lines: 80, functions: 80, branches: 80, statements: 80, perFile: true }, all: true, clean: true, cleanOnRerun: true } } });
Istanbul Provider
export default defineConfig({ test: { coverage: { provider: 'istanbul', reporter: ['text', 'json', 'html'], watermarks: { lines: [80, 95], functions: [80, 95], branches: [80, 95], statements: [80, 95] } } } });
Module Resolution
Path Aliases
import { defineConfig } from 'vitest/config'; import path from 'path';
export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './src'), '@components': path.resolve(__dirname, './src/components'), '@utils': path.resolve(__dirname, './src/utils'), '@hooks': path.resolve(__dirname, './src/hooks'), '@services': path.resolve(__dirname, './src/services') } }, test: { // Test configuration } });
External Dependencies
export default defineConfig({ test: { // Don't externalize these packages deps: { inline: ['package-to-inline'] }, // Externalize these packages server: { deps: { external: ['package-to-external'] } } } });
Package.json Scripts
{ "scripts": { "test": "vitest", "test:ui": "vitest --ui", "test:run": "vitest run", "test:coverage": "vitest run --coverage", "test:watch": "vitest watch", "test:ci": "vitest run --coverage --reporter=json --reporter=default" } }
Advanced Configuration
Browser Mode
export default defineConfig({ test: { browser: { enabled: true, name: 'chrome', // 'chrome' | 'firefox' | 'safari' provider: 'playwright', // 'playwright' | 'webdriverio' headless: true, screenshotFailures: true } } });
Performance Optimization
export default defineConfig({ test: { // Use threads for parallel execution pool: 'threads', poolOptions: { threads: { singleThread: false, minThreads: 1, maxThreads: 4, useAtomics: true } },
// Isolate tests
isolate: true,
// Sequence tests
sequence: {
shuffle: false,
concurrent: false
},
// File parallelism
fileParallelism: true,
// Max concurrency
maxConcurrency: 5,
// Bail on failure
bail: 1
} });
Type Checking
export default defineConfig({ test: { typecheck: { enabled: true, checker: 'tsc', // 'tsc' | 'vue-tsc' tsconfig: './tsconfig.json', include: ['**/*.{test,spec}-d.ts'] } } });
Best Practices
-
Use TypeScript configuration - Leverage type safety in configuration files
-
Configure appropriate environments - Choose the right environment for your tests (node vs jsdom)
-
Set up coverage thresholds - Define realistic coverage goals
-
Use workspace for monorepos - Leverage workspace config for multiple projects
-
Configure path aliases - Match your application's import paths
-
Optimize thread usage - Balance parallelism with system resources
-
Use globals sparingly - Prefer explicit imports for better tree-shaking
-
Configure appropriate timeouts - Set realistic timeouts for async operations
-
Enable coverage reporting - Track test coverage consistently
-
Use setup files effectively - Centralize common setup logic
Common Pitfalls
-
Incorrect environment selection - Using wrong environment causes undefined errors
-
Missing path aliases - Forgetting to configure aliases from vite.config
-
Overly aggressive coverage thresholds - Unrealistic goals discourage testing
-
Not configuring globals - Leads to verbose imports in every test file
-
Incorrect thread configuration - Too many threads overwhelm system
-
Missing setup files - Repetitive boilerplate in every test
-
Wrong coverage provider - V8 vs Istanbul have different capabilities
-
Not cleaning mocks - Shared mock state causes flaky tests
-
Ignoring watch exclude - Unnecessary file watching slows development
-
Misconfigured module resolution - Import errors in test files
When to Use This Skill
-
Setting up Vitest in a new Vite project
-
Migrating from Jest to Vitest
-
Configuring Vitest for TypeScript projects
-
Setting up testing in monorepos with workspaces
-
Optimizing test performance for large codebases
-
Configuring browser testing with Playwright
-
Setting up coverage reporting for CI/CD
-
Debugging module resolution issues
-
Implementing custom test environments
-
Configuring type checking for tests