or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assertions.mdbenchmarking.mdbrowser-testing.mdconfiguration.mdindex.mdmocking.mdnode-apis.mdreporters.mdtest-definition.mdtimers.mdtype-testing.md
tile.json

tessl/npm-vitest

Next generation testing framework powered by Vite

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/vitest@4.0.x

To install, run

npx @tessl/cli install tessl/npm-vitest@4.0.0

index.mddocs/

Vitest

Vitest is a blazing fast unit test framework powered by Vite with native ES modules support, TypeScript integration, and Jest-compatible APIs.

Package Information

  • Package: vitest (npm)
  • Install: npm install -D vitest
  • Docs: https://vitest.dev

Quick Start

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

// Basic test
test('adds numbers', () => {
  expect(1 + 2).toBe(3);
});

// Suite with lifecycle
describe('Math', () => {
  beforeEach(() => { /* setup */ });
  afterEach(() => { /* cleanup */ });

  test('multiply', () => expect(2 * 3).toBe(6));
});

// Async test
test('async operation', async () => {
  await expect(Promise.resolve(42)).resolves.toBe(42);
});

// Mock function
test('with mock', () => {
  const fn = vi.fn(() => 'result');
  expect(fn()).toBe('result');
  expect(fn).toHaveBeenCalledTimes(1);
});

Entry Points

ImportUse Case
vitestTest APIs (test, expect, vi, etc.)
vitest/configConfiguration (defineConfig, defineProject)
vitest/nodeProgrammatic APIs (createVitest, reporters)
vitest/reportersReporter classes
vitest/browserBrowser testing utilities

Core Imports

// ESM
import { test, describe, expect, vi, beforeEach, afterEach } from 'vitest';

// Globals (with globals: true in config)
test('no import needed', () => expect(true).toBe(true));

API Quick Reference

Test Definition → Details

function test(name: string, fn: TestFunction, options?: TestOptions): void;
function describe(name: string, fn: () => void, options?: TestOptions): void;

// Modifiers
test.only | test.skip | test.todo | test.skipIf(cond) | test.runIf(cond)
test.concurrent | test.sequential | test.fails | test.each(cases)

// Lifecycle
function beforeEach(fn: () => void | Promise<void>, timeout?: number): void;
function afterEach(fn: () => void | Promise<void>, timeout?: number): void;
function beforeAll(fn: () => void | Promise<void>, timeout?: number): void;
function afterAll(fn: () => void | Promise<void>, timeout?: number): void;

Assertions → Details

function expect<T>(actual: T): Assertion<T>;
function createExpect(test?: TaskPopulated): ExpectStatic;

// Key methods
.toBe() | .toEqual() | .toStrictEqual()
.toBeTruthy() | .toBeFalsy() | .toBeDefined() | .toBeUndefined()
.toBeGreaterThan() | .toBeLessThan() | .toBeCloseTo()
.toMatch() | .toContain() | .toHaveLength() | .toHaveProperty()
.toThrow() | .toMatchObject()
.resolves | .rejects | .not

// Snapshots
.toMatchSnapshot() | .toMatchInlineSnapshot() | .toMatchFileSnapshot()

// Async
expect.poll(fn, options) | expect.soft(value)

Mocking → Details

vi.fn(impl?) // Create mock function
vi.spyOn(obj, method, accessType?) // Spy on method
vi.mock(path, factory?) // Mock module (hoisted)
vi.doMock(path, factory?) // Mock module (not hoisted)
vi.importActual(path) | vi.importMock(path)
vi.mocked(item, deep?) | vi.mockObject(obj, options?)

// Cleanup
vi.clearAllMocks() | vi.resetAllMocks() | vi.restoreAllMocks()

// Globals
vi.stubGlobal(name, value) | vi.stubEnv(name, value)
vi.unstubAllGlobals() | vi.unstubAllEnvs()

// Wait utilities
vi.waitFor(callback, options?) | vi.waitUntil(callback, options?)

Timers → Details

vi.useFakeTimers(config?) | vi.useRealTimers()
vi.advanceTimersByTime(ms) | vi.advanceTimersToNextTimer()
vi.runOnlyPendingTimers() | vi.runAllTimers() | vi.runAllTicks()
vi.setSystemTime(time) | vi.getMockedSystemTime() | vi.getRealSystemTime()
vi.getTimerCount() | vi.clearAllTimers()

Configuration → Details

import { defineConfig, defineProject } from 'vitest/config';

export default defineConfig({
  test: {
    globals: boolean;
    environment: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime';
    include: string[];
    exclude: string[];
    testTimeout: number;
    hookTimeout: number;
    setupFiles: string | string[];
    coverage: CoverageOptions;
    reporters: Array<Reporter>;
  }
});

Common Patterns

Test Organization

PatternCodeUse When
Single testtest('name', () => {...})Simple, isolated test
Test suitedescribe('name', () => {...})Grouping related tests
Nested suitesdescribe('A', () => describe('B', ...))Hierarchical organization
Shared setupbeforeEach(() => {...})Common test setup

Assertion Patterns

GoalMatcherExample
Exact equality.toBe()expect(x).toBe(5)
Deep equality.toEqual()expect(obj).toEqual({a: 1})
Truthiness.toBeTruthy()expect(value).toBeTruthy()
Array contains.toContain()expect([1,2]).toContain(1)
Object has prop.toHaveProperty()expect(obj).toHaveProperty('key')
Throws error.toThrow()expect(() => fn()).toThrow()
Async success.resolvesexpect(promise).resolves.toBe(x)
Async failure.rejectsexpect(promise).rejects.toThrow()

Mocking Strategies

ScenarioApproachCode
Track callsMock functionconst fn = vi.fn()
Keep originalSpyvi.spyOn(obj, 'method')
Replace moduleModule mockvi.mock('./module')
Partial mockImport actual + mockawait vi.importActual()
Global APIsStub globalvi.stubGlobal('fetch', mockFetch)

Time Control

NeedMethodUse Case
Control timevi.useFakeTimers()Deterministic testing
Jump forwardvi.advanceTimersByTime(ms)Skip delays
Next timervi.advanceTimersToNextTimer()Step through
Run allvi.runAllTimers()Complete all async
Set datevi.setSystemTime(date)Mock Date.now()

Advanced Features

Benchmarking → Details

import { bench } from 'vitest';

bench('operation', () => {
  // Code to benchmark
}, { time: 5000, iterations: 100 });

Type Testing → Details

import { expectTypeOf, assertType } from 'vitest';

expectTypeOf<string>().toBeString();
expectTypeOf(fn).returns.toBeNumber();
assertType<number>(value);

Browser Testing → Details

import { readFile, writeFile } from 'vitest/browser';

test('browser APIs', async () => {
  await writeFile('./test.txt', 'content');
  expect(await readFile('./test.txt')).toBe('content');
});

Reporters → Details

Built-in: default, verbose, dot, tree, json, junit, tap, github-actions

export default defineConfig({
  test: {
    reporters: ['default', 'json'],
    outputFile: './results.json'
  }
});

Node APIs → Details

import { createVitest } from 'vitest/node';

const vitest = await createVitest('test', { watch: false });
await vitest.start();
await vitest.close();

Configuration Defaults

configDefaults.include // ['**/*.{test,spec}.?(c|m)[jt]s?(x)']
configDefaults.exclude // ['**/node_modules/**', '**/dist/**', ...]
defaultBrowserPort // 63315

Decision Guides

When to Use

FeatureChoose When
test.onlyDebugging specific test
test.skipTemporarily disable test
test.concurrentIndependent tests that can run in parallel
test.sequentialTests with shared state
describe.skipDisable entire suite
beforeEachSetup needed for every test
beforeAllExpensive setup once per suite

Mocking Decision Tree

Need to track calls?
├─ Yes, keep original behavior?
│  └─ Yes: vi.spyOn(obj, 'method')
│  └─ No: vi.fn(newImpl)
└─ No, replace entire module?
   └─ Yes: vi.mock('./module')
   └─ No: Use real implementation

Environment Selection

EnvironmentUse CaseAPIs Available
nodeServer code, CLI toolsNode.js APIs
jsdomBrowser simulationDOM, window, document
happy-domFaster browser simulationDOM (lighter)
edge-runtimeEdge functionsSubset of Web APIs
Browser modeReal browser testingFull browser APIs

Common Gotchas

  1. Module mocks are hoisted - vi.mock() runs before imports
  2. Use vi.hoisted() for shared mock values
  3. vi.mock() is hoisted, vi.doMock() is not
  4. Restore mocks - Use afterEach(() => vi.restoreAllMocks())
  5. Async timers - Use *Async() versions with async code
  6. Globals require config - Set globals: true in config

Additional Exports

inject<T>(key: string | symbol): T // Dependency injection
chai, assert, should // Chai assertion library