TechSetupGuides
Intermediatetestingvitestvitejestunit-testingcomponent-testingtypescriptnodeesmbrowser

Vitest - Next Generation Testing Framework

Next generation testing framework powered by Vite for fast unit testing, component testing, and browser testing.

  1. Step 1

    Overview

    Vitest is a next-generation testing framework powered by Vite. It offers an intuitive developer experience with fast test execution, native code coverage, snapshot testing, and Jest-compatible APIs. Vitest is designed for modern web development with ESM-first architecture, top-level await, and out-of-the-box TypeScript and JSX support.

  2. Step 2

    Technology Stack

    Vitest is built with the following technologies:

    Language: TypeScript
    License: MIT
    Stars: ~16,590
    Owner: vitest-dev
    Repo: https://github.com/vitest-dev/vitest
    Website: https://vitest.dev
    
    Core Dependencies:
    - Vite (>=6.4.0) - Build tool and bundler
    - Node.js (>=22.12.0) - Runtime environment
    - Chai - Assertion library with Jest-compatible APIs
    - Jest Snapshot - Snapshot testing integration
    - JSDOM / Happy-DOM - DOM and browser API mocking
    - Tinybench - Benchmarking support
    - expect-type - Type-level testing
    
    Key Features:
    - Vite's config, transformers, resolvers, and plugins
    - Smart & instant watch mode (HMR for tests)
    - Native code coverage (v8 and Istanbul)
    - Jest-compatible mocking, stubbing, and spies
    - Browser Mode for component testing
    - Component testing (Vue, React, Svelte, Solid, Lit, Marko)
    - ESM first, top level await
    - Out-of-the-box TypeScript/JSX support
  3. Step 3

    Installation

    Install Vitest using your preferred package manager.

    npm install -D vitest
    yarn add -D vitest
    pnpm add -D vitest
    bun add -D vitest
    
    # For coverage
    pnpm add -D @vitest/coverage-v8
    
    # For UI
    pnpm add -D @vitest/ui
  4. Step 4

    Basic Configuration

    Vitest automatically detects and uses your Vite configuration.

    // vitest.config.ts
    import { defineConfig } from 'vitest/config'
    
    export default defineConfig({
      test: {
        include: ['src/**/*.test.{ts,js}'],
        exclude: ['**/node_modules/**', '**/dist/**'],
        environment: 'node',
        coverage: {
          provider: 'v8',
          reporter: ['text', 'json', 'html']
        },
        testTimeout: 5000,
        globals: true,
        watch: true
      }
    })
  5. Step 5

    Running Tests

    Run tests using npx or your package.json scripts.

    npx vitest                    # Basic test run (watch mode)
    npx vitest run                 # Run without watch mode
    npx vitest run --coverage      # Run with coverage
    npx vitest --ui               # Run with UI
    npx vitest run -u             # Update snapshots
    npx vitest run src/math.test.ts  # Specific test file
    npx vitest --testNamePattern "should"  # Filter by name
  6. Step 6

    Writing Tests

    Create test files with .test.ts, .spec.ts, or .test.js extensions.

    // math.test.ts
    import { describe, it, expect } from 'vitest'
    
    describe('Math operations', () => {
      it('adds numbers correctly', () => {
        expect(1 + 1).toBe(2)
      })
    
      it('handles async operations', async () => {
        const result = await Promise.resolve(42)
        expect(result).toBe(42)
      })
    
      it.skip('skipped test', () => {})
      
      it.only('only runs this test', () => {
        expect(1).toBe(1)
      })
    })
  7. Step 7

    Using Matchers

    Vitest provides matchers inspired by Jest and Chai.

    import { describe, it, expect } from 'vitest'
    
    describe('Matchers', () => {
      it('equality', () => {
        expect(1).toBe(1)           // Identity
        expect({ a: 1 }).toEqual({ a: 1 }) // Deep equality
      })
    
      it('truthiness', () => {
        expect('hello').toBeTruthy()
        expect('').toBeFalsy()
        expect(null).toBeNull()
      })
    
      it('types', () => {
        expect(42).toBeNumber()
        expect('text').toBeString()
        expect([1, 2]).toBeArray()
      })
    
      it('arrays/strings', () => {
        expect([1, 2, 3]).toContain(2)
        expect('hello').toMatch(/ll/)
      })
    
      it('async', async () => {
        await expect(Promise.resolve(1)).resolves.toBe(1)
      })
    })
  8. Step 8

    Mocking Functions

    Use vi.fn() to create mock functions.

    import { describe, it, expect, vi } from 'vitest'
    
    const mockFn = vi.fn()
    mockFn()
    mockFn(1)
    mockFn(1, 2)
    
    describe('Mock Functions', () => {
      it('tracks calls', () => {
        expect(mockFn).toHaveBeenCalledTimes(3)
        expect(mockFn).toHaveBeenCalledWith(1)
      })
    
      it('mocks with implementation', () => {
        const mockFn = vi.fn((a, b) => a + b)
        expect(mockFn(1, 2)).toBe(3)
      })
    
      it('async mocks', async () => {
        const mockFn = vi.fn().mockResolvedValue(42)
        expect(await mockFn()).toBe(42)
      })
    })
  9. Step 9

    Mocking Modules

    Mock entire modules using vi.mock().

    import { describe, it, expect, vi } from 'vitest'
    
    // Mock before importing
    vi.mock('./myModule', () => ({
      fetchData: vi.fn().mockResolvedValue({ id: 1, name: 'test' }),
      processData: vi.fn((input: string) => input.toUpperCase())
    }))
    
    describe('Mocked Module', () => {
      it('uses mocked implementation', async () => {
        const myModule = await import('./myModule')
        const data = await myModule.fetchData()
        expect(data).toEqual({ id: 1, name: 'test' })
      })
    })
    
    // Unmock: vi.unmock('./myModule')
    // Partial: await vi.importActual('./myModule')
  10. Step 10

    Snapshot Testing

    Vitest supports Jest-compatible snapshot testing.

    import { describe, it, expect } from 'vitest'
    
    describe('Snapshots', () => {
      it('inline snapshot', () => {
        expect({ a: 1, b: 2 }).toMatchInlineSnapshot(`
          {
            "a": 1,
            "b": 2,
          }
        `)
      })
    
      it('file snapshot', () => {
        expect({ foo: 'bar' }).toMatchSnapshot()
      })
    })
    
    # Update snapshots:
    npx vitest run -u
  11. Step 11

    Browser Mode

    Run tests in real browsers with Playwright or WebDriverIO.

    # Install browser testing
    pnpm add -D @vitest/browser playwright
    
    // vitest.config.ts
    export default defineConfig({
      test: {
        browser: {
          enabled: true,
          headless: true,
          provider: 'playwright',
          instances: [{ browser: 'chromium' }]
        }
      }
    })
    
    npx vitest --browser
    ⚠ Heads up: Requires Playwright or WebDriverIO installed.
  12. Step 12

    Component Testing

    Test Vue, React, Svelte components.

    // Counter.test.ts
    import { mount } from '@vue/test-utils'
    import { describe, it, expect } from 'vitest'
    import Counter from './Counter.vue'
    
    describe('Counter', () => {
      it('renders initial count', () => {
        const wrapper = mount(Counter)
        expect(wrapper.text()).toContain('Count is 0')
      })
    
      it('increments on click', async () => {
        const wrapper = mount(Counter)
        await wrapper.get('button').trigger('click')
        expect(wrapper.text()).toContain('Count is 1')
      })
    })
  13. Step 13

    Environments

    Use different test environments.

    // vitest.config.ts
    export default defineConfig({
      test: {
        environment: 'jsdom', // or 'node', 'happy-dom', 'edge', 'browser'
        environmentOptions: {
          jsdom: { url: 'http://localhost', pretendToBeVisual: true }
        },
        projects: [
          { test: { name: 'node', environment: 'node', include: ['tests/node/**/*.test.ts'] } },
          { test: { name: 'browser', environment: 'jsdom', include: ['tests/browser/**/*.test.ts'] } }
        ]
      }
    })
  14. Step 14

    Test Coverage

    Native code coverage through v8 or Istanbul.

    pnpm add -D @vitest/coverage-v8
    
    // vitest.config.ts
    export default defineConfig({
      test: {
        coverage: {
          provider: 'v8',
          reporter: ['text', 'html', 'json'],
          thresholds: { global: { lines: 80, functions: 80 } }
        }
      }
    })
    
    npx vitest run --coverage
  15. Step 15

    Watch Mode & Filtering

    Smart watch mode and filtering.

    npx vitest                      # Watch mode (default)
    
    npx vitest --testNamePattern "should"  # Filter by name
    npx vitest src/auth.test.ts        # Filter by file
    npx vitest --changed              # Only changed tests
    npx vitest --no-file-parallelism  # Sequential
    npx vitest --maxWorkers 4         # Limit workers
  16. Step 16

    Multi-project

    Run tests across multiple projects.

    // vitest.config.ts
    export default defineConfig({
      test: {
        projects: [
          { extends: './apps/api/vite.config.ts', test: { name: 'api', environment: 'node' } },
          { extends: './apps/web/vite.config.ts', test: { name: 'web', environment: 'jsdom' } }
        ]
      }
    })
    
    npx vitest --project api
  17. Step 17

    Vitest UI

    Interactive browser UI for tests.

    pnpm add -D @vitest/ui
    
    // vitest.config.ts
    export default defineConfig({
      test: {
        ui: true,
        open: true
      }
    })
    
    npx vitest --ui
    # Available at http://localhost:51204
  18. Step 18

    Test Utilities (vi API)

    Advanced control with vi utility.

    import { vi } from 'vitest'
    
    vi.clearAllMocks()      # Clear mocks
    vi.restoreAllMocks()    # Restore mocks
    vi.resetModules()       # Reset modules
    await vi.importActual('./module')  # Import real
    
    vi.useFakeTimers()      # Mock timers
    vi.advanceTimersByTime(1000)
    vi.setSystemTime(new Date('2024-01-01'))
    
    vi.stubEnv('NODE_ENV', 'test')    # Stub env
    
    await vi.waitFor(() => expect(count.value).toBe(5), { timeout: 3000 })
  19. Step 19

    Custom Matchers

    Extend expect with custom matchers.

    import { expect } from 'vitest'
    
    declare module 'vitest' {
      interface Assertion {
        toContainKey(key: string): void
        toBeEmptyArray(): void
      }
    }
    
    expect.extend({
      toContainKey(received: object, key: string) {
        const pass = key in received
        return { message: () => `expected key`, pass }
      }
    })
    
    expect({ a: 1 }).toContainKey('a')
  20. Step 20

    Key Features

    Vitest capabilities:

    1. Fast Execution: Vite-powered
    2. Watch Mode: Smart HMR
    3. Code Coverage: v8/Istanbul
    4. Snapshot Testing: Jest-compatible
    5. Browser Mode: Real browsers
    6. Component Testing: Vue/React/Svelte
    7. TypeScript: Native support
    8. ESM First: Top-level await
    9. Mocking: vi.* API
    10. Projects: Multi-project
    11. UI: Interactive runner
    12. CI Friendly: Parallel
    13. Benchmarking: Tinybench
    14. Type Testing: expect-type
    15. Extensible: Custom plugins
  21. Step 21

    Use Cases

    Vitest is ideal for:

    1. Unit Testing: Fast isolated tests
    2. Component Testing: Framework components
    3. Integration Testing: API mocking
    4. Library Testing: Cross-framework
    5. Microservices: Per-service tests
    6. TypeScript: Native TS
    7. Vite Projects: Zero-config
    8. CI/CD: Fast parallel
    9. Development: Instant feedback
    10. Benchmarks: Performance
    11. Coverage: Thresholds
    12. Type-Safe: Runtime assertions
    13. Browser: Real browser tests
    14. ESM-only: Native ESM
  22. Step 22

    Migration from Jest

    Migrate from Jest to Vitest:

    Step 1: pnpm add -D vitest @vitest/ui
    Step 2: "test": "vitest"
    Step 3: jest.config.js -> vitest.config.ts
    Step 4: import "vitest", vi.fn(), vi.mock()
    Step 5: Matchers compatible
    Step 6: setupFiles / globalSetup
    Step 7: coverage provider: 'v8'
  23. Step 23

    Resources

    Additional resources:

    Documentation: https://vitest.dev
    GitHub: https://github.com/vitest-dev/vitest
    Discord: https://chat.vitest.dev
    API: https://vitest.dev/api/
    Config: https://vitest.dev/config/
    Migration: https://vitest.dev/guide/migration
    Examples: https://github.com/vitest-dev/vitest/tree/main/examples
  24. Step 24

    File Locations

    Key files:

    vitest.config.ts        - Vitest config
    vite.config.ts          - Vite config
    coverage/               - Coverage reports
    __snapshots__/          - Snapshots
    node_modules/.vitest/   - Cache

Feature requests

Sign in to suggest features or vote on existing ones.

No feature requests yet.

Discussion

0 people marked this as worked·Sign in to mark your own.

Sign in to join the discussion.

No comments yet.