Vitest
Anthony FuCommunityCreated by Anthony Fu
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Vitest is a testing framework built for the Vite ecosystem. It provides a Jest-compatible API and supports ESM, TypeScript, and JSX by default. It shares configuration, transformers, and plugins with Vite applications, allowing for integrated testing workflows. The framework includes features for mocking, snapshot testing, code coverage, and multi-threaded test execution.
What it does
- Provides a Jest-compatible API for writing and running unit tests
- Supports native ESM, TypeScript, and JSX without additional configuration
- Enables mocking of functions, modules, timers, and dates
- Offers built-in code coverage reporting using V8 or Istanbul
- Supports multi-project workspaces and varied test environments like Node, jsdom, and happy-dom
- Includes utilities for snapshot testing, test filtering, and benchmarking
When to use it
- When you need a testing framework that integrates directly with your Vite configuration
- When migrating existing test suites that rely on Jest-compatible APIs
- When you require specific test environments like jsdom or happy-dom for DOM-related testing
- When managing complex test setups across monorepos or multiple projects
Advantages
- Shares configuration and plugins with Vite projects
- Supports parallel test execution via multi-threaded workers
- Provides flexible test environment configuration per file or project
- Includes built-in support for snapshot testing and mocking utilities
Usage examples
- “How do I configure Vitest to use the jsdom environment for my tests?”
- The agent provides the vitest.config.ts configuration snippet using the environment: 'jsdom' property and explains how to install the necessary jsdom package.
- “Can I run different test configurations in the same Vitest process?”
- The agent explains how to use the projects field in the vitest.config.ts file to define multiple test suites with different environments or include patterns.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/antfu/vitest/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip vitest.zip -d .agents/skills
Documentation by Anthony Fu
Vitest is a next-generation testing framework powered by Vite. It provides a Jest-compatible API with native ESM, TypeScript, and JSX support out of the box. Vitest shares the same config, transformers, resolvers, and plugins with your Vite app.
Key Features:
Vite-native: Uses Vite's transformation pipeline for fast HMR-like test updates
Jest-compatible: Drop-in replacement for most Jest test suites
Smart watch mode: Only reruns affected tests based on module graph
Native ESM, TypeScript, JSX support without configuration
Multi-threaded workers for parallel test execution
Built-in coverage via V8 or Istanbul
Snapshot testing, mocking, and spy utilities
The skill is based on Vitest 5.1.0-beta.1, generated at 2026-10-23.
Core
| Topic | Description | Reference |
|---|---|---|
| Configuration | Vitest and Vite config integration, defineConfig usage | core-config |
| CLI | Command line interface, commands and options | core-cli |
| Test API | test/it function, modifiers like skip, only, concurrent | core-test-api |
| Describe API | describe/suite for grouping tests and nested suites | core-describe |
| Expect API | Assertions with toBe, toEqual, matchers and asymmetric matchers | core-expect |
| Hooks | beforeEach, afterEach, beforeAll, afterAll, aroundEach | core-hooks |
Features
| Topic | Description | Reference |
|---|---|---|
| Mocking | Mock functions, modules, timers, dates with vi utilities | features-mocking |
| Snapshots | Snapshot testing with toMatchSnapshot and inline snapshots | features-snapshots |
| Coverage | Code coverage with V8 or Istanbul providers | features-coverage |
| Test Context | Test fixtures, context.expect, test.extend for custom fixtures | features-context |
| Concurrency | Concurrent tests, parallel execution, sharding | features-concurrency |
| Filtering | Filter tests by name, file patterns, tags | features-filtering |
| Test Tags | Label tests with tags to filter runs and apply shared options | features-test-tags |
| Reporters | Built-in reporters, default selection, CI/output config | features-reporters |
| Benchmarking | Write benchmarks with the bench fixture (Tinybench) | features-benchmarking |
Advanced
| Topic | Description | Reference |
|---|---|---|
| Vi Utilities | vi helper: mock, spyOn, fake timers, hoisted, waitFor | advanced-vi |
| Environments | Test environments: node, jsdom, happy-dom, custom | advanced-environments |
| Type Testing | Type-level testing with expectTypeOf and assertType | advanced-type-testing |
| Projects | Multi-project workspaces, different configs per project | advanced-projects |
Files
- ATTRIBUTION.mdAdded by AutoGineer895 B
- GENERATION.md136 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md3.6 KiB
- references/advanced-environments.md4.9 KiB
- references/advanced-projects.md7.4 KiB
- references/advanced-type-testing.md4.6 KiB
- references/advanced-vi.md5.8 KiB
- references/core-cli.md4.9 KiB
- references/core-config.md7.7 KiB
- references/core-describe.md3.5 KiB
- references/core-expect.md8.8 KiB
- references/core-hooks.md4.8 KiB
- references/core-test-api.md5.5 KiB
- references/features-benchmarking.md3.9 KiB
- references/features-concurrency.md4.7 KiB
- references/features-context.md5.3 KiB
- references/features-coverage.md5.0 KiB
- references/features-filtering.md4.8 KiB
- references/features-mocking.md9.8 KiB
- references/features-reporters.md4.0 KiB
- references/features-snapshots.md5.2 KiB
- references/features-test-tags.md3.6 KiB
references/core-expect.md
name: expect-api description: Assertions with matchers, asymmetric matchers, and custom matchers
Expect API
Vitest uses Chai assertions with Jest-compatible API.
Basic Assertions
import { expect, test } from 'vitest'
test('assertions', () => {
// Equality
expect(1 + 1).toBe(2) // Strict equality (===)
expect({ a: 1 }).toEqual({ a: 1 }) // Deep equality
// Truthiness
expect(true).toBeTruthy()
expect(false).toBeFalsy()
expect(null).toBeNull()
expect(undefined).toBeUndefined()
expect('value').toBeDefined()
// Numbers
expect(10).toBeGreaterThan(5)
expect(10).toBeGreaterThanOrEqual(10)
expect(5).toBeLessThan(10)
expect(0.1 + 0.2).toBeCloseTo(0.3, 5)
// Strings
expect('hello world').toMatch(/world/)
expect('hello').toContain('ell')
// Arrays
expect([1, 2, 3]).toContain(2)
expect([{ a: 1 }]).toContainEqual({ a: 1 })
expect([1, 2, 3]).toHaveLength(3)
// Objects
expect({ a: 1, b: 2 }).toHaveProperty('a')
expect({ a: 1, b: 2 }).toHaveProperty('a', 1)
expect({ a: { b: 1 } }).toHaveProperty('a.b', 1)
expect({ a: 1 }).toMatchObject({ a: 1 })
// Types
expect('string').toBeTypeOf('string')
expect(new Date()).toBeInstanceOf(Date)
})Negation
expect(1).not.toBe(2)
expect({ a: 1 }).not.toEqual({ a: 2 })Error Assertions
// Sync errors - wrap in function
expect(() => throwError()).toThrow()
expect(() => throwError()).toThrow('message') // string = substring of the message
expect(() => throwError()).toThrow(/pattern/)
expect(() => throwError()).toThrow(CustomError)
// v5: toThrow('') matches ANY message (empty string is a substring of all).
// To assert an empty message, match the pattern: .toThrow(/^$/)
// Async errors - use rejects
await expect(asyncThrow()).rejects.toThrow('error')Promise Assertions
// Resolves
await expect(Promise.resolve(1)).resolves.toBe(1)
await expect(fetchData()).resolves.toEqual({ data: true })
// Rejects
await expect(Promise.reject('error')).rejects.toBe('error')
await expect(failingFetch()).rejects.toThrow()v5: unawaited async assertions (
resolves,rejects,toMatchFileSnapshot) now fail the test — v4 only printed a warning and auto-awaited at the end. Alwaysawaitthem.
Spy/Mock Assertions
const fn = vi.fn()
fn('arg1', 'arg2')
fn('arg3')
expect(fn).toHaveBeenCalled()
expect(fn).toHaveBeenCalledTimes(2)
expect(fn).toHaveBeenCalledWith('arg1', 'arg2')
expect(fn).toHaveBeenLastCalledWith('arg3')
expect(fn).toHaveBeenNthCalledWith(1, 'arg1', 'arg2')
expect(fn).toHaveReturned()
expect(fn).toHaveReturnedWith(value)
// v4 additions
expect(fn).toHaveBeenCalledExactlyOnceWith('arg1', 'arg2')
expect(fnA).toHaveBeenCalledBefore(fnB)
expect(fnA).toHaveBeenCalledAfter(fnB)Chai-Style Spy Assertions (4.1+)
Sinon-chai-compatible aliases, useful when migrating from Sinon:
expect(spy).to.have.been.called
expect(spy).to.have.been.calledOnce
expect(spy).to.have.been.calledWith('arg1', 'arg2')
expect(spy).to.have.been.calledOnceWith('arg')Conditional Mock Exhaustion (v5)
Assert every vi.when behavior was consumed:
const w = vi.when(spy).calledWith(1).thenReturnOnce('a')
spy(1)
expect(w).toHaveBeenExhausted()Asymmetric Matchers
Use inside toEqual, toHaveBeenCalledWith, etc:
expect({ id: 1, name: 'test' }).toEqual({
id: expect.any(Number),
name: expect.any(String),
})
expect({ a: 1, b: 2, c: 3 }).toEqual(
expect.objectContaining({ a: 1 })
)
expect([1, 2, 3, 4]).toEqual(
expect.arrayContaining([1, 3])
)
expect('hello world').toEqual(
expect.stringContaining('world')
)
expect('hello world').toEqual(
expect.stringMatching(/world$/)
)
expect({ value: null }).toEqual({
value: expect.anything() // Matches anything except null/undefined
})
// Negate with expect.not
expect([1, 2]).toEqual(
expect.not.arrayContaining([3])
)
// toBeOneOf - value matches any option (great for optional props)
expect(user).toEqual({
name: expect.any(String),
middleName: expect.toBeOneOf([expect.any(String), undefined]),
})
// schemaMatching (4.0+) - matches any Standard Schema (Zod, Valibot, ArkType)
import { z } from 'zod'
expect(payload).toEqual({
email: expect.schemaMatching(z.string().email()),
})
expect(repo.save).toHaveBeenCalledWith(expect.schemaMatching(UserSchema))Soft Assertions
Prefer expect.soft for non-critical assertions — it marks the test failed but continues so all failures are reported together:
expect.soft(response.status).toBe(200) // non-critical, keeps going
expect.soft(response.headers.get('x-id')).toBeTruthy()
expect(response.body).toBeDefined() // critical: hard expect stops on failureType-Narrowing Assertions (4.0+)
expect.assert throws at runtime and narrows the TypeScript type (unlike toBeTruthy/toBeDefined, which return void):
const user = cache.get('alice') // { id, name } | undefined
expect.assert(user) // throws if undefined, narrows below
expect(user.name).toBe('Alice') // no `!`, no `as`
// Narrows typeof / instanceof too
expect.assert(typeof input === 'string')
input.toUpperCase()
// Chai assert helpers via the same namespace
expect.assert.isDefined(maybeUser)
expect.assert.instanceOf(error, MyError)expect.unreachable
Type is (message?: string) => never, so a plain if guard narrows discriminated unions without assert helpers:
const result = v.safeParse(UserSchema, input) // { success: true, output } | { success: false, ... }
if (!result.success)
expect.unreachable('should parse')
expect(result.output.age).toBe(25) // narrowed to the success branchAlso use it to mark branches that must not run, e.g. after an await that should throw, or a default case in an exhaustive switch.
Poll Assertions
Retry until passes (with fake timers on, timers are auto-advanced by interval after each failed attempt):
await expect.poll(() => fetchStatus()).toBe('ready')
await expect.poll(
() => document.querySelector('.element'),
{ interval: 100, timeout: 5000 }
).toBeTruthy()v5:
expect.pollnow rejects when it times out (v4 could still pass on a late attempt). The callback receives anAbortSignalthat aborts on timeout so you can cancel in-flight work:
await expect.poll(async ({ signal }) => {
const res = await fetch('/api/status', { signal })
return res.status
}, { timeout: 1000 }).toBe(200)Assertion Count
test('async assertions', async () => {
expect.assertions(2) // Exactly 2 assertions must run
await doAsync((data) => {
expect(data).toBeDefined()
expect(data.id).toBe(1)
})
})
test('at least one', () => {
expect.hasAssertions() // At least 1 assertion must run
})Extending Matchers
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling
return {
pass,
message: () =>
`expected ${received} to be within range ${floor} - ${ceiling}`,
}
},
})
test('custom matcher', () => {
expect(100).toBeWithinRange(90, 110)
})Inside a matcher, this.equals(a, b, customTesters) doesn't compare Map/Set contents; to match toEqual, pass [...this.customTesters, this.utils.iterableEquality] as the third argument.
TypeScript Declarations (v5)
The Matchers interface now takes the return type first (R) and the received type second (T). R is void synchronously, Promise<void> through .resolves/.rejects/expect.poll/expect.element:
import 'vitest'
declare module 'vitest' {
interface Matchers<R, T> {
toBeFoo: () => R
toEqualTyped: (expected: T) => R // T mirrors the received value's type
}
}Referencing assertion types directly also needs the return type first: Assertion<void, string> (sync) / Assertion<Promise<void>, string> (async). v5 no longer reads matchers from the global jest.Matchers interface — augment vitest.Matchers separately.
Snapshot Assertions
expect(data).toMatchSnapshot()
expect(data).toMatchInlineSnapshot(`{ "id": 1 }`)
await expect(result).toMatchFileSnapshot('./expected.json')
expect(() => throw new Error('fail')).toThrowErrorMatchingSnapshot()Key Points
Use
toBefor primitives,toEqualfor objects/arraystoStrictEqualchecks undefined properties and array sparsenessAlways
awaitasync assertions (resolves,rejects,poll)Use context's
expectin concurrent tests for correct trackingtoThrowrequires wrapping sync code in a functionUse
expect.softfor non-critical assertions; reserve hardexpectfor must-pass conditionsUse
expect.assert(nottoBeTruthy) when you also need TypeScript narrowing
<!-- Source references: - https://vitest.dev/api/expect.html - https://vitest.dev/guide/recipes/type-narrowing - https://vitest.dev/guide/recipes/schema-matching -->
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Anthony Fu
- Publisher
- Anthony Fu (Community)
- Source
- antfu/skills · skills/vitest · commit f63e9ec
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Anthony Fu.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download vitest.zip