Vitest: an introduction

By

Vitest is the fast Vite-powered test runner with a Jest-compatible API, native ESM and TypeScript support, watch mode, and built-in mocking.

~~~

If you write JavaScript or TypeScript today, you need a test runner that understands modern modules. Vitest is what I reach for on new projects.

It’s a test runner built on Vite, using the same config, transforms, and plugins. If your app already runs on Vite, Astro, or another modern setup that uses it, Vitest picks up that pipeline automatically.

The API feels like Jest. You get describe, it, expect, and a vi namespace for mocks. Vitest runs native ESM and TypeScript without a separate transform step, so you do not need ts-jest or a Babel config just to run tests.

Vitest 5 is the current stable line as of September 2026. It needs Node.js 22.12 or newer, and Vite 6.4 or newer. Watch mode is fast. Coverage is built in. Monorepos get a projects config for running different test setups in one command.

Install and your first test

Install Vitest with npm as a dev dependency:

npm i -D vitest

Create a small function to test:

// sum.js
export function sum(a, b) {
  return a + b
}

Now write a test file next to it:

// sum.test.js
import { describe, it, expect } from 'vitest'
import { sum } from './sum.js'

describe('sum', () => {
  it('adds two numbers', () => {
    expect(sum(2, 3)).toBe(5)
  })
})

Run it:

npx vitest

Vitest finds files matching *.test.js or *.spec.js and runs them. You can use test() instead of it because they do the same thing.

Watch mode and the UI

When you run npx vitest locally with no flags, watch mode is on by default. In CI, Vitest detects the environment and runs once instead. Change a file locally, save it, and the related tests re-run instantly.

Want a one-off run without watching? Use run:

npx vitest run

For a visual dashboard, install the UI package and launch it:

npm i -D @vitest/ui
npx vitest --ui

It opens in the browser and shows your test files, results, and errors in one place.

Common matchers

Vitest uses Jest-compatible matchers. These four cover most of what you need:

MatcherWhat it checks
toBe(5)Strict equality (===)
toEqual({ a: 1 })Deep equality for objects and arrays
toContain('apple')Array or string includes a value
toThrow('message')Function throws an error

Example with a shopping cart:

const items = ['apple', 'bread', 'milk']

expect(items).toContain('bread')
expect(items.length).toBe(3)

Async tests

Testing async code is straightforward. Just await inside the test:

it('fetches the cart total', async () => {
  const total = await getCartTotal(['apple', 'bread'])
  expect(total).toBe(8.50)
})

Vitest waits for the promise to settle before marking the test done. If the promise rejects and you didn’t expect it, the test fails.

Mocking with vi

Vitest puts mocks under the vi namespace. vi.fn() creates a spy you can track:

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

it('calls the discount function', () => {
  const applyDiscount = vi.fn((total) => total * 0.9)

  checkout(100, applyDiscount)

  expect(applyDiscount).toHaveBeenCalledWith(100)
})

To replace an entire module, use vi.mock() at the top of the file:

vi.mock('./api.js', () => ({
  fetchCart: vi.fn(() => Promise.resolve([])),
}))

That’s enough to get started. Vitest also supports spies, timers, and module hoisting. The patterns are the same ones you’d use in Jest, with vi instead of jest.

Coverage

Install the coverage provider:

npm i -D @vitest/coverage-v8

Run tests with coverage enabled:

npx vitest run --coverage

Vitest prints a summary in the terminal. You can also configure reporters and thresholds in vitest.config.ts if you want coverage gates in CI.

TypeScript

Write your tests in .ts files and Vitest handles them. No extra setup.

Rename sum.test.js to sum.test.ts, add types to your function, and run the same command. Vitest reads your Vite config (or its own vitest.config.ts) and compiles TypeScript on the fly.

For monorepos, the projects option in config lets you define separate test setups with different environments and include patterns. You can run them all with one npx vitest command.

If you’re starting a new JavaScript or TypeScript project in 2026, my advice is to install Vitest before you write your second test file. Vitest is fast and its API is familiar. A project already using Vite needs almost no configuration.

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about js: