Skip to main content

Vitest Guide

The complete reference for Vitest — the blazing-fast, Vite-native test runner with a Jest-compatible API. Covers setup, mocking, coverage, HMR watch mode, and in-source testing.

✓ Vite-native speed ✓ Jest-compatible API ✓ Native ESM support ✓ In-source testing ✓ V8 & Istanbul coverage

What is Vitest?

Vitest is a next-generation JavaScript testing framework built on top of Vite. Created by the Vite core team, it solves a fundamental problem: test tooling and build tooling used to be completely separate pipelines with different configuration, different module resolution, and different transform stacks. Vitest unifies them — your vite.config.ts is automatically reused by the test runner, including plugins, path aliases, and environment variables.

The result is dramatically faster test startup and a more consistent development experience. Vitest uses esbuild to transform TypeScript and JSX (the same as Vite's dev server), achieving sub-100ms cold starts on most projects. Its Jest-compatible API means most test suites can be migrated with minimal changes, making adoption low-risk.

Installation & Configuration

# Install Vitest
npm install --save-dev vitest

# Install coverage provider
npm install --save-dev @vitest/coverage-v8

# vitest.config.ts (or extend vite.config.ts)
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'jsdom',      // or 'node', 'happy-dom'
    globals: true,             // use describe/it without imports
    setupFiles: ['./tests/setup.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html'],
      thresholds: { lines: 80, branches: 70 },
    },
  },
});

Basic Test Syntax (Jest-compatible)

// With globals: true — no imports needed
describe('formatCurrency()', () => {
  it('formats USD correctly', () => {
    expect(formatCurrency(1234.5, 'USD')).toBe('$1,234.50');
  });

  it('handles zero', () => {
    expect(formatCurrency(0, 'EUR')).toBe('€0.00');
  });
});

// Without globals (explicit imports)
import { describe, it, expect, vi } from 'vitest';
import { fetchUser } from './api';

describe('fetchUser()', () => {
  it('returns user object', async () => {
    const user = await fetchUser(1);
    expect(user).toMatchObject({ id: 1, name: expect.any(String) });
  });
});

Mocking with vi (the Jest-equivalent)

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

// Mock a module
vi.mock('./emailService', () => ({
  sendEmail: vi.fn().mockResolvedValue({ success: true }),
}));

// Spy on a method
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});

// Mock timers
vi.useFakeTimers();

describe('RetryService', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('retries 3 times before failing', async () => {
    const mockFn = vi.fn()
      .mockRejectedValueOnce(new Error('fail'))
      .mockRejectedValueOnce(new Error('fail'))
      .mockResolvedValueOnce('success');

    const result = await retryWithBackoff(mockFn);
    expect(result).toBe('success');
    expect(mockFn).toHaveBeenCalledTimes(3);
  });
});

In-Source Testing

Vitest's unique in-source testing feature lets you colocate tests with your implementation code. The import.meta.vitest block is stripped from production builds automatically.

// utils/clamp.ts
export function clamp(value: number, min: number, max: number): number {
  return Math.min(Math.max(value, min), max);
}

// In-source tests — stripped in production builds
if (import.meta.vitest) {
  const { it, expect } = import.meta.vitest;

  it('clamps values within range', () => {
    expect(clamp(5, 0, 10)).toBe(5);
    expect(clamp(-5, 0, 10)).toBe(0);
    expect(clamp(15, 0, 10)).toBe(10);
  });
}

Running Coverage

# Run tests with coverage
npx vitest run --coverage

# Watch mode (re-runs affected tests on change)
npx vitest

# UI mode (browser-based test explorer)
npx vitest --ui

Key Features

Comparison: Vitest vs Alternatives

Feature Vitest Jest Node test runner
Startup speed Very fast (esbuild) Moderate (Babel/tsc) Fast (no transform)
Native ESM Full Partial/tricky Full
Mocking built-in Yes (vi.*) Yes (jest.*) No
Coverage V8 + Istanbul Istanbul V8 only
Snapshot testing Yes Yes No
UI mode Yes (@vitest/ui) No No
Vite plugin reuse Yes No No

Pros & Cons

Pros

  • Near-instant startup with esbuild transforms
  • Reuses Vite config — zero extra configuration for Vite projects
  • Full native ESM without experimental flags
  • Jest-compatible API — minimal migration effort
  • UI mode for interactive test exploration
  • In-source testing for colocation with implementation

Cons

  • Less mature ecosystem than Jest (fewer plugins)
  • Some Jest-specific features require workarounds
  • Smaller community and fewer Stack Overflow answers
  • Best value only for Vite-based projects
  • jsdom environment still not a real browser

Frequently Asked Questions

What is Vitest and how is it different from Jest?▼

Vitest is a Vite-native unit testing framework designed to reuse your Vite configuration for both the build pipeline and the test environment. Unlike Jest (which uses Babel/ts-jest and its own module resolver), Vitest uses Vite's esbuild-powered transform, giving near-instant startup times and full native ESM support. The API is intentionally Jest-compatible so migration is straightforward.

Can I use Vitest without Vite in my project?▼

Yes. Vitest works without an existing Vite project — it bundles its own Vite instance. However, the real benefit is for projects already using Vite (Vite + React, Vite + Vue, SvelteKit, Nuxt 3, Astro) because Vitest reuses vite.config.ts directly. For pure Node.js projects without Vite, Jest or Node's built-in test runner may be equally suitable.

How does Vitest handle Hot Module Replacement (HMR) in tests?▼

Vitest's watch mode uses Vite's HMR graph to understand which test files are affected by a source change. When you edit a file, only the tests that import it (directly or transitively) are re-run. This is dramatically faster than Jest's watch mode which uses a file-system watcher and runs all affected tests via a more conservative dependency scan.

What is in-source testing in Vitest?▼

In-source testing lets you write tests inside the same file as your implementation, similar to Rust's #[cfg(test)] pattern. Import and use import.meta.vitest inside an if (import.meta.vitest) block. When building for production, Vitest's Vite plugin strips these blocks via dead-code elimination, so tests never ship to users. This colocation style is great for small utility functions.

Does Vitest support code coverage?▼

Yes. Vitest supports V8 coverage (fast, based on Node.js's built-in) and Istanbul coverage (comprehensive, more accurate for branch coverage). Run vitest run --coverage after installing @vitest/coverage-v8 or @vitest/coverage-istanbul. Output formats include text, HTML, LCOV, and JSON — same as Jest's Istanbul integration. Coverage thresholds can be enforced in vitest.config.ts.

How do I migrate from Jest to Vitest?▼

For most projects: install vitest, replace jest.config.ts with vitest.config.ts, change test script from 'jest' to 'vitest run'. The API is nearly identical — describe, it, expect, beforeEach, afterEach, vi.fn() (instead of jest.fn()), vi.mock() etc. The main differences are: import from 'vitest' instead of globals, use vi instead of jest namespace, and ensure your vite.config.ts handles path aliases.

Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Related Articles

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →