vitest

Vitest - Modern Test Framework

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "vitest" with this command: npx skills add jezweb/claude-skills/jezweb-claude-skills-vitest

Vitest - Modern Test Framework

Status: Production Ready Last Updated: 2026-02-06 Vitest Version: 4.x Vite Compatibility: 6.x

Quick Start

Install

pnpm add -D vitest

Add to package.json

{ "scripts": { "test": "vitest", "test:run": "vitest run", "test:coverage": "vitest run --coverage" } }

Configuration

Minimal Config (vitest.config.ts)

import { defineConfig } from 'vitest/config';

export default defineConfig({ test: { globals: true, environment: 'node', }, });

React Config

import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react';

export default defineConfig({ plugins: [react()], test: { globals: true, environment: 'jsdom', setupFiles: ['./src/test/setup.ts'], css: true, }, });

Cloudflare Workers Config

import { defineConfig } from 'vitest/config'; import { cloudflare } from '@cloudflare/vite-plugin';

export default defineConfig({ plugins: [cloudflare()], test: { globals: true, environment: 'node', // Workers tests often need longer timeouts for D1/KV testTimeout: 10000, }, });

Mocking Patterns

vi.mock - Module Mocking

import { vi, describe, it, expect } from 'vitest'; import { fetchUser } from './api';

// Mock entire module vi.mock('./api', () => ({ fetchUser: vi.fn(), }));

describe('User component', () => { it('fetches user data', async () => { // Type-safe mock implementation vi.mocked(fetchUser).mockResolvedValue({ id: 1, name: 'Test' });

// ... test code

expect(fetchUser).toHaveBeenCalledWith(1);

}); });

vi.spyOn - Spy on Methods

import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';

describe('Date handling', () => { beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-01-01')); });

afterEach(() => { vi.useRealTimers(); });

it('uses mocked date', () => { expect(new Date().getFullYear()).toBe(2026); }); });

vi.stubGlobal - Global Mocks

import { vi, describe, it, expect } from 'vitest';

describe('Environment', () => { it('mocks fetch globally', async () => { const mockFetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ data: 'test' }), });

vi.stubGlobal('fetch', mockFetch);

const response = await fetch('/api/test');
expect(mockFetch).toHaveBeenCalledWith('/api/test');

vi.unstubAllGlobals();

}); });

Snapshot Testing

Basic Snapshots

import { describe, it, expect } from 'vitest';

describe('Component output', () => { it('matches snapshot', () => { const result = renderComponent({ title: 'Hello' }); expect(result).toMatchSnapshot(); });

it('matches inline snapshot', () => { const result = { name: 'test', count: 42 }; expect(result).toMatchInlineSnapshot( { "count": 42, "name": "test", } ); }); });

Update Snapshots

Update all snapshots

vitest run --update

Interactive update

vitest --ui

In-Source Testing

Test code directly in source files (tree-shaken in production):

// src/utils/math.ts export function add(a: number, b: number): number { return a + b; }

// In-source test block if (import.meta.vitest) { const { describe, it, expect } = import.meta.vitest;

describe('add', () => { it('adds two numbers', () => { expect(add(1, 2)).toBe(3); }); }); }

Config for in-source testing:

// vitest.config.ts export default defineConfig({ test: { includeSource: ['src/**/*.{js,ts}'], }, define: { 'import.meta.vitest': 'undefined', // Tree-shake in production }, });

Workspace Configuration (Monorepos)

// vitest.workspace.ts import { defineWorkspace } from 'vitest/config';

export default defineWorkspace([ // Each package can have its own config 'packages/*/vitest.config.ts',

// Or define inline { test: { name: 'unit', include: ['src//*.test.ts'], environment: 'node', }, }, { test: { name: 'browser', include: ['src//*.browser.test.ts'], browser: { enabled: true, provider: 'playwright', name: 'chromium', }, }, }, ]);

Browser Mode Testing

// vitest.config.ts export default defineConfig({ test: { browser: { enabled: true, provider: 'playwright', // or 'webdriverio' name: 'chromium', headless: true, }, }, });

Install browser provider

pnpm add -D @vitest/browser playwright

Coverage

Install coverage provider

pnpm add -D @vitest/coverage-v8

Run with coverage

vitest run --coverage

// vitest.config.ts export default defineConfig({ test: { coverage: { provider: 'v8', reporter: ['text', 'html', 'lcov'], exclude: [ 'node_modules/', 'src/test/', '**/*.d.ts', ], thresholds: { statements: 80, branches: 80, functions: 80, lines: 80, }, }, }, });

Jest Migration

Key Differences

Jest Vitest

jest.fn()

vi.fn()

jest.mock()

vi.mock()

jest.spyOn()

vi.spyOn()

jest.useFakeTimers()

vi.useFakeTimers()

jest.clearAllMocks()

vi.clearAllMocks()

@jest/globals

vitest

Migration Steps

  • Replace imports:

// Before (Jest) import { jest } from '@jest/globals';

// After (Vitest) import { vi } from 'vitest';

  • Update config:

// jest.config.js → vitest.config.ts export default defineConfig({ test: { globals: true, // Enables describe/it/expect without imports environment: 'jsdom', }, });

  • Replace jest. with vi.:

Quick replace (review changes carefully)

find src -name "*.test.ts" -exec sed -i 's/jest./vi./g' {} ;

Common Patterns

Testing Async Code

import { describe, it, expect } from 'vitest';

describe('async operations', () => { it('resolves promise', async () => { const result = await fetchData(); expect(result).toBeDefined(); });

it('rejects with error', async () => { await expect(failingOperation()).rejects.toThrow('Expected error'); }); });

Testing with Fixtures

import { describe, it, expect, beforeEach } from 'vitest';

describe('with fixtures', () => { let testData: TestData;

beforeEach(() => { testData = createTestFixture(); });

it('uses fixture', () => { expect(testData.id).toBeDefined(); }); });

Parameterized Tests

import { describe, it, expect } from 'vitest';

describe.each([ { input: 1, expected: 2 }, { input: 2, expected: 4 }, { input: 3, expected: 6 }, ])('double($input)', ({ input, expected }) => { it(returns ${expected}, () => { expect(double(input)).toBe(expected); }); });

Debugging

Run Single Test

vitest run -t "test name" vitest run src/specific.test.ts

Debug Mode

With Node inspector

node --inspect-brk ./node_modules/vitest/vitest.mjs run

Or use Vitest UI

vitest --ui

Watch Mode

vitest # Watch mode (default) vitest run # Single run vitest watch # Explicit watch

Troubleshooting

"Cannot find module" in mocks

// Ensure mock path matches import path exactly vi.mock('./api'); // Matches: import { x } from './api' vi.mock('../api'); // Different! Won't work for './api' imports

ESM/CJS Issues

// vitest.config.ts - for CJS dependencies export default defineConfig({ test: { deps: { inline: ['problematic-cjs-package'], }, }, });

Globals Not Defined

// If using globals: true but TypeScript complains // Add to tsconfig.json: { "compilerOptions": { "types": ["vitest/globals"] } }

See Also

  • testing-patterns skill - General testing patterns

  • testing-library skill - React Testing Library integration

  • Official docs: https://vitest.dev

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwind-v4-shadcn

No summary provided by upstream source.

Repository SourceNeeds Review
2.7K-jezweb
General

tanstack-query

No summary provided by upstream source.

Repository SourceNeeds Review
2.5K-jezweb
General

fastapi

No summary provided by upstream source.

Repository SourceNeeds Review
General

zustand-state-management

No summary provided by upstream source.

Repository SourceNeeds Review
1.2K-jezweb