File: README.md
Vitest
Features
- Vite's config, transformers, resolvers, and plugins. Use the same setup from your app!
- Jest Snapshot
- Chai built-in for assertions, with Jest expect compatible APIs
- Smart & instant watch mode, like HMR for tests!
- Native code coverage via
v8oristanbul. - Jest-compatible mocking, stubbing, and spies.
- JSDOM and happy-dom for DOM and browser API mocking
- Browser Mode for running component tests in the browser
- Components testing (Vue, React, Svelte, Lit, Marko)
- Benchmarking support with Tinybench
- Projects support
- expect-type for type-level testing
- ESM first, top level await
- Out-of-box TypeScript / JSX support
- Filtering, timeouts, concurrent for suite and tests
- Sharding support
- Reporting Uncaught Errors
- Run your tests in the browser natively
Vitest requires Vite >=v6.4.0 and Node >=v22.12.0
import { assert, describe, expect, it } from 'vitest'
describe('suite name', () => {
it('foo', () => {
expect(1 + 1).toEqual(2)
expect(true).to.be.true
})
it('bar', () => {
assert.equal(Math.sqrt(4), 2)
})
it('snapshot', () => {
expect({ foo: 'bar' }).toMatchSnapshot()
})
})$ npx vitestSponsors
Credits
Thanks to:
- The Jest team and community for creating a delightful testing API
- @lukeed for the work on uvu where we are inspired a lot from.
- @pi0 for the idea and implementation of using Vite to transform and bundle the server code.
- The Vite team for brainstorming the initial idea.
- @patak-dev for the awesome package name!
Contribution
See Contributing Guide.
License
MIT License © 2021-Present VoidZero Inc. and Vitest contributors
File: docs/api/assert.md
assert
Vitest reexports the assert method from chai for verifying invariants.
::: warning In-Source Testing {#in-source-testing}
When using assertion functions such as assert from import.meta.vitest in in-source tests, TypeScript reports error TS2775 because they must be called via an explicitly annotated name. Annotate the variable with Chai.Assert or call it directly:
::: code-group
if (import.meta.vitest) {
const { test, assert } = import.meta.vitest // [!code --]
const { test } = import.meta.vitest // [!code ++]
const assert: Chai.Assert = import.meta.vitest.assert // [!code ++]
test('assert', () => {
assert('foo' !== 'bar', 'foo should not be equal to bar')
})
}if (import.meta.vitest) {
const { test, assert } = import.meta.vitest // [!code --]
const { test } = import.meta.vitest // [!code ++]
test('assert', () => {
assert('foo' !== 'bar', 'foo should not be equal to bar') // [!code --]
import.meta.vitest!.assert('foo' !== 'bar', 'foo should not be equal to bar') // [!code ++]
})
}:::
assert
- Type:
(expression: any, message?: string) => asserts expression
Assert that the given expression is truthy, otherwise the assertion fails.
import { assert, test } from 'vitest'
test('assert', () => {
assert('foo' !== 'bar', 'foo should not be equal to bar')
})fail
- Type:
(message?: string) => never<T>(actual: T, expected: T, message?: string, operator?: string) => never
Force an assertion failure.
import { assert, test } from 'vitest'
test('assert.fail', () => {
assert.fail('error message on failure')
assert.fail('foo', 'bar', 'foo is not bar', '===')
})isOk
- Type:
<T>(value: T, message?: string) => asserts value - Alias:
ok
Assert that the given value is truthy.
import { assert, test } from 'vitest'
test('assert.isOk', () => {
assert.isOk('foo', 'every truthy is ok')
assert.isOk(false, 'this will fail since false is not truthy')
})isNotOk
- Type:
<T>(value: T, message?: string) => void - Alias:
notOk
Assert that the given value is falsy.
import { assert, test } from 'vitest'
test('assert.isNotOk', () => {
assert.isNotOk('foo', 'this will fail, every truthy is not ok')
assert.isNotOk(false, 'this will pass since false is falsy')
})equal
- Type:
<T>(actual: T, expected: T, message?: string) => void
Asserts non-strict equality (==) of actual and expected.
import { assert, test } from 'vitest'
test('assert.equal', () => {
assert.equal(Math.sqrt(4), '2')
})notEqual
- Type:
<T>(actual: T, expected: T, message?: string) => void
Asserts non-strict inequality (!=) of actual and expected.
import { assert, test } from 'vitest'
test('assert.equal', () => {
assert.notEqual(Math.sqrt(4), 3)
})strictEqual
- Type:
<T>(actual: T, expected: T, message?: string) => void
Asserts strict equality (===) of actual and expected.
import { assert, test } from 'vitest'
test('assert.strictEqual', () => {
assert.strictEqual(Math.sqrt(4), 2)
})deepEqual
- Type:
<T>(actual: T, expected: T, message?: string) => void
Asserts that actual is deeply equal to expected.
import { assert, test } from 'vitest'
test('assert.deepEqual', () => {
assert.deepEqual({ color: 'green' }, { color: 'green' })
})notDeepEqual
- Type:
<T>(actual: T, expected: T, message?: string) => void
Assert that actual is not deeply equal to expected.
import { assert, test } from 'vitest'
test('assert.notDeepEqual', () => {
assert.notDeepEqual({ color: 'green' }, { color: 'red' })
})isAbove
- Type:
(valueToCheck: number, valueToBeAbove: number, message?: string) => void
Assert that valueToCheck is strictly greater than (>) valueToBeAbove.
import { assert, test } from 'vitest'
test('assert.isAbove', () => {
assert.isAbove(5, 2, '5 is strictly greater than 2')
})isAtLeast
- Type:
(valueToCheck: number, valueToBeAtLeast: number, message?: string) => void
Assert that valueToCheck is greater than or equal to (>=) valueToBeAtLeast.
import { assert, test } from 'vitest'
test('assert.isAtLeast', () => {
assert.isAtLeast(5, 2, '5 is greater or equal to 2')
assert.isAtLeast(3, 3, '3 is greater or equal to 3')
})isBelow
- Type:
(valueToCheck: number, valueToBeBelow: number, message?: string) => void
Asserts valueToCheck is strictly less than (<) valueToBeBelow.
import { assert, test } from 'vitest'
test('assert.isBelow', () => {
assert.isBelow(3, 6, '3 is strictly less than 6')
})isAtMost
- Type:
(valueToCheck: number, valueToBeAtMost: number, message?: string) => void
Asserts valueToCheck is less than or equal to (<=) valueToBeAtMost.
import { assert, test } from 'vitest'
test('assert.isAtMost', () => {
assert.isAtMost(3, 6, '3 is less than or equal to 6')
assert.isAtMost(4, 4, '4 is less than or equal to 4')
})isTrue
- Type:
<T>(value: T, message?: string) => asserts value is true
Asserts that value is true.
import { assert, test } from 'vitest'
const testPassed = true
test('assert.isTrue', () => {
assert.isTrue(testPassed)
})isNotTrue
- Type:
<T>(value: T, message?: string) => asserts value is Exclude<T, true>
Asserts that value is not true.
import { assert, test } from 'vitest'
const testPassed = 'ok'
test('assert.isNotTrue', () => {
assert.isNotTrue(testPassed)
})isFalse
- Type:
<T>(value: T, message?: string) => asserts value is false
Asserts that value is false.
import { assert, test } from 'vitest'
const testPassed = false
test('assert.isFalse', () => {
assert.isFalse(testPassed)
})isNotFalse
- Type:
<T>(value: T, message?: string) => asserts value is Exclude<T, false>
Asserts that value is not false.
import { assert, test } from 'vitest'
const testPassed = 'no'
test('assert.isNotFalse', () => {
assert.isNotFalse(testPassed)
})isNull
- Type:
<T>(value: T, message?: string) => asserts value is null
Asserts that value is null.
import { assert, test } from 'vitest'
const error = null
test('assert.isNull', () => {
assert.isNull(error, 'error is null')
})isNotNull
- Type:
<T>(value: T, message?: string) => asserts value is Exclude<T, null>
Asserts that value is not null.
import { assert, test } from 'vitest'
const error = { message: 'error was occurred' }
test('assert.isNotNull', () => {
assert.isNotNull(error, 'error is not null but object')
})isNaN
- Type:
<T>(value: T, message?: string) => void
Asserts that value is NaN.
import { assert, test } from 'vitest'
const calculation = 1 * 'vitest'
test('assert.isNaN', () => {
assert.isNaN(calculation, '1 * "vitest" is NaN')
})isNotNaN
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not NaN.
import { assert, test } from 'vitest'
const calculation = 1 * 2
test('assert.isNotNaN', () => {
assert.isNotNaN(calculation, '1 * 2 is Not NaN but 2')
})exists
- Type:
<T>(value: T, message?: string) => asserts value is NonNullable<T>
Asserts that value is neither null nor undefined.
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.exists', () => {
assert.exists(name, 'foo is neither null nor undefined')
})notExists
- Type:
<T>(value: T, message?: string) => asserts value is null | undefined
Asserts that value is either null nor undefined.
import { assert, test } from 'vitest'
const foo = null
const bar = undefined
test('assert.notExists', () => {
assert.notExists(foo, 'foo is null so not exist')
assert.notExists(bar, 'bar is undefined so not exist')
})isUndefined
- Type:
<T>(value: T, message?: string) => asserts value is undefined
Asserts that value is undefined.
import { assert, test } from 'vitest'
const name = undefined
test('assert.isUndefined', () => {
assert.isUndefined(name, 'name is undefined')
})isDefined
- Type:
<T>(value: T, message?: string) => asserts value is Exclude<T, undefined>
Asserts that value is not undefined.
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.isDefined', () => {
assert.isDefined(name, 'name is not undefined')
})isFunction
- Type:
<T>(value: T, message?: string) => void - Alias:
isCallable
Asserts thatvalueis a function.
import { assert, test } from 'vitest'
function name() { return 'foo' };
test('assert.isFunction', () => {
assert.isFunction(name, 'name is function')
})isNotFunction
- Type:
<T>(value: T, message?: string) => void - Alias:
isNotCallable
Asserts that value is not a function.
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.isNotFunction', () => {
assert.isNotFunction(name, 'name is not function but string')
})isObject
- Type:
<T>(value: T, message?: string) => void
Asserts that value is an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects.
import { assert, test } from 'vitest'
const someThing = { color: 'red', shape: 'circle' }
test('assert.isObject', () => {
assert.isObject(someThing, 'someThing is object')
})isNotObject
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects.
import { assert, test } from 'vitest'
const someThing = 'redCircle'
test('assert.isNotObject', () => {
assert.isNotObject(someThing, 'someThing is not object but string')
})isArray
- Type:
<T>(value: T, message?: string) => void
Asserts that value is an array.
import { assert, test } from 'vitest'
const color = ['red', 'green', 'yellow']
test('assert.isArray', () => {
assert.isArray(color, 'color is array')
})isNotArray
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not an array.
import { assert, test } from 'vitest'
const color = 'red'
test('assert.isNotArray', () => {
assert.isNotArray(color, 'color is not array but string')
})isString
- Type:
<T>(value: T, message?: string) => void
Asserts that value is a string.
import { assert, test } from 'vitest'
const color = 'red'
test('assert.isString', () => {
assert.isString(color, 'color is string')
})isNotString
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not a string.
import { assert, test } from 'vitest'
const color = ['red', 'green', 'yellow']
test('assert.isNotString', () => {
assert.isNotString(color, 'color is not string but array')
})isNumber
- Type:
<T>(value: T, message?: string) => void
Asserts that value is a number.
import { assert, test } from 'vitest'
const colors = 3
test('assert.isNumber', () => {
assert.isNumber(colors, 'colors is number')
})isNotNumber
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not a number.
import { assert, test } from 'vitest'
const colors = '3 colors'
test('assert.isNotNumber', () => {
assert.isNotNumber(colors, 'colors is not number but strings')
})isFinite
- Type:
<T>(value: T, message?: string) => void
Asserts that value is a finite number (not NaN, Infinity).
import { assert, test } from 'vitest'
const colors = 3
test('assert.isFinite', () => {
assert.isFinite(colors, 'colors is number not NaN or Infinity')
})isBoolean
- Type:
<T>(value: T, message?: string) => void
Asserts that value is a boolean.
import { assert, test } from 'vitest'
const isReady = true
test('assert.isBoolean', () => {
assert.isBoolean(isReady, 'isReady is a boolean')
})isNotBoolean
- Type:
<T>(value: T, message?: string) => void
Asserts that value is not a boolean.
import { assert, test } from 'vitest'
const isReady = 'sure'
test('assert.isBoolean', () => {
assert.isBoolean(isReady, 'isReady is not a boolean but string')
})typeOf
- Type:
<T>(value: T, name: string, message?: string) => void
Asserts that value’s type is name, as determined by Object.prototype.toString.
import { assert, test } from 'vitest'
test('assert.typeOf', () => {
assert.typeOf({ color: 'red' }, 'object', 'we have an object')
assert.typeOf(['red', 'green'], 'array', 'we have an array')
assert.typeOf('red', 'string', 'we have a string')
assert.typeOf(/red/, 'regexp', 'we have a regular expression')
assert.typeOf(null, 'null', 'we have a null')
assert.typeOf(undefined, 'undefined', 'we have an undefined')
})notTypeOf
- Type:
<T>(value: T, name: string, message?: string) => void
Asserts that value’s type is not name, as determined by Object.prototype.toString.
import { assert, test } from 'vitest'
test('assert.notTypeOf', () => {
assert.notTypeOf('red', 'number', '"red" is not a number')
})instanceOf
- Type:
<T>(value: T, constructor: Function, message?: string) => asserts value is T
Asserts that value is an instance of constructor.
import { assert, test } from 'vitest'
function Person(name) { this.name = name }
const foo = new Person('foo')
class Tea {
constructor(name) {
this.name = name
}
}
const coffee = new Tea('coffee')
test('assert.instanceOf', () => {
assert.instanceOf(foo, Person, 'foo is an instance of Person')
assert.instanceOf(coffee, Tea, 'coffee is an instance of Tea')
})notInstanceOf
- Type:
<T>(value: T, constructor: Function, message?: string) => asserts value is Exclude<T, U>
Asserts that value is not an instance of constructor.
import { assert, test } from 'vitest'
function Person(name) { this.name = name }
const foo = new Person('foo')
class Tea {
constructor(name) {
this.name = name
}
}
const coffee = new Tea('coffee')
test('assert.instanceOf', () => {
assert.instanceOf(foo, Tea, 'foo is not an instance of Tea')
})include
- Type:
(haystack: string, needle: string, message?: string) => void<T>(haystack: readonly T[] | ReadonlySet<T> | ReadonlyMap<any, T>, needle: T, message?: string) => void<T extends object>(haystack: WeakSet<T>, needle: T, message?: string) => void<T>(haystack: T, needle: Partial<T>, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a value in an array, a substring in a string, or a subset of properties in an object.
import { assert, test } from 'vitest'
test('assert.include', () => {
assert.include([1, 2, 3], 2, 'array contains value')
assert.include('foobar', 'foo', 'string contains substring')
assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property')
})notInclude
- Type:
(haystack: string, needle: string, message?: string) => void<T>(haystack: readonly T[] | ReadonlySet<T> | ReadonlyMap<any, T>, needle: T, message?: string) => void<T extends object>(haystack: WeakSet<T>, needle: T, message?: string) => void<T>(haystack: T, needle: Partial<T>, message?: string) => void
Asserts that haystack does not include needle. It can be used to assert the absence of a value in an array, a substring in a string, or a subset of properties in an object.
import { assert, test } from 'vitest'
test('assert.notInclude', () => {
assert.notInclude([1, 2, 3], 4, 'array doesn\'t contain 4')
assert.notInclude('foobar', 'baz', 'foobar doesn\'t contain baz')
assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn\'t contain property')
})deepInclude
- Type:
(haystack: string, needle: string, message?: string) => void<T>(haystack: readonly T[] | ReadonlySet<T> | ReadonlyMap<any, T>, needle: T, message?: string) => void<T>(haystack: T, needle: T extends WeakSet<any> ? never : Partial<T>, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a value in an array or a subset of properties in an object. Deep equality is used.
import { assert, test } from 'vitest'
const obj1 = { a: 1 }
const obj2 = { b: 2 }
test('assert.deepInclude', () => {
assert.deepInclude([obj1, obj2], { a: 1 })
assert.deepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 1 } })
})notDeepInclude
- Type:
(haystack: string, needle: string, message?: string) => void<T>(haystack: readonly T[] | ReadonlySet<T> | ReadonlyMap<any, T>, needle: T, message?: string) => void<T>(haystack: T, needle: T extends WeakSet<any> ? never : Partial<T>, message?: string) => void
Asserts that haystack does not include needle. It can be used to assert the absence of a value in an array or a subset of properties in an object. Deep equality is used.
import { assert, test } from 'vitest'
const obj1 = { a: 1 }
const obj2 = { b: 2 }
test('assert.notDeepInclude', () => {
assert.notDeepInclude([obj1, obj2], { a: 10 })
assert.notDeepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 10 } })
})nestedInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
import { assert, test } from 'vitest'
test('assert.nestedInclude', () => {
assert.nestedInclude({ '.a': { b: 'x' } }, { '\\.a.[b]': 'x' })
assert.nestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'x' })
})notNestedInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack does not include needle. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
import { assert, test } from 'vitest'
test('assert.nestedInclude', () => {
assert.notNestedInclude({ '.a': { b: 'x' } }, { '\\.a.b': 'y' })
assert.notNestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'y' })
})deepNestedInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
import { assert, test } from 'vitest'
test('assert.deepNestedInclude', () => {
assert.deepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { x: 1 } })
assert.deepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { x: 1 } })
})notDeepNestedInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack not includes needle. Can be used to assert the absence of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
import { assert, test } from 'vitest'
test('assert.notDeepNestedInclude', () => {
assert.notDeepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { y: 1 } })
assert.notDeepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { y: 2 } })
})ownInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties.
import { assert, test } from 'vitest'
test('assert.ownInclude', () => {
assert.ownInclude({ a: 1 }, { a: 1 })
})notOwnInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties.
import { assert, test } from 'vitest'
const obj1 = {
b: 2
}
const obj2 = object.create(obj1)
obj2.a = 1
test('assert.notOwnInclude', () => {
assert.notOwnInclude(obj2, { b: 2 })
})deepOwnInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack includes needle. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties and checking for deep equality.
import { assert, test } from 'vitest'
test('assert.deepOwnInclude', () => {
assert.deepOwnInclude({ a: { b: 2 } }, { a: { b: 2 } })
})notDeepOwnInclude
- Type:
(haystack: any, needle: any, message?: string) => void
Asserts that haystack not includes needle. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties and checking for deep equality.
import { assert, test } from 'vitest'
test('assert.notDeepOwnInclude', () => {
assert.notDeepOwnInclude({ a: { b: 2 } }, { a: { c: 3 } })
})match
- Type:
(value: string, regexp: RegExp, message?: string) => void
Asserts that value matches the regular expression regexp.
import { assert, test } from 'vitest'
test('assert.match', () => {
assert.match('foobar', /^foo/, 'regexp matches')
})notMatch
- Type:
(value: string, regexp: RegExp, message?: string) => void
Asserts that value does not matches the regular expression regexp.
import { assert, test } from 'vitest'
test('assert.notMatch', () => {
assert.notMatch('foobar', /^foo/, 'regexp does not match')
})property
- Type:
<T>(object: T, property: string, message?: string) => void
Asserts that object has a direct or inherited property named by property
import { assert, test } from 'vitest'
test('assert.property', () => {
assert.property({ tea: { green: 'matcha' } }, 'tea')
assert.property({ tea: { green: 'matcha' } }, 'toString')
})notProperty
- Type:
<T>(object: T, property: string, message?: string) => void
Asserts that object does not have a direct or inherited property named by property
import { assert, test } from 'vitest'
test('assert.notProperty', () => {
assert.notProperty({ tea: { green: 'matcha' } }, 'coffee')
})propertyVal
- Type:
<T, V>(object: T, property: string, value: V, message?: string) => void
Asserts that object has a direct or inherited property named by property with a value given by value. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.notPropertyVal', () => {
assert.propertyVal({ tea: 'is good' }, 'tea', 'is good')
})notPropertyVal
- Type:
<T, V>(object: T, property: string, value: V, message?: string) => void
Asserts that object does not have a direct or inherited property named by property with a value given by value. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.notPropertyVal', () => {
assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad')
assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good')
})deepPropertyVal
- Type:
<T, V>(object: T, property: string, value: V, message?: string) => void
Asserts that object has a direct or inherited property named by property with a value given by value. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' })
})notDeepPropertyVal
- Type:
<T, V>(object: T, property: string, value: V, message?: string) => void
Asserts that object does not have a direct or inherited property named by property with a value given by value. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' })
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' })
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' })
})nestedProperty
- Type:
<T>(object: T, property: string, message?: string) => void
Asserts that object has a direct or inherited property named by property, which can be a string using dot- and bracket-notation for nested reference.
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.nestedProperty({ tea: { green: 'matcha' } }, 'tea.green')
})notNestedProperty
- Type:
<T>(object: T, property: string, message?: string) => void
Asserts that object does not have a direct or inherited property named by property, which can be a string using dot- and bracket-notation for nested reference.
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.notNestedProperty({ tea: { green: 'matcha' } }, 'tea.oolong')
})nestedPropertyVal
- Type:
<T>(object: T, property: string, value: any, message?: string) => void
Asserts that object has a property named by property with value given by value. property can use dot- and bracket-notation for nested reference. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.nestedPropertyVal', () => {
assert.nestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'matcha')
})notNestedPropertyVal
- Type:
<T>(object: T, property: string, value: any, message?: string) => void
Asserts that object does not have a property named by property with value given by value. property can use dot- and bracket-notation for nested reference. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})deepNestedPropertyVal
- Type:
<T>(object: T, property: string, value: any, message?: string) => void
Asserts that object has a property named by property with a value given by value. property can use dot- and bracket-notation for nested reference. Uses a deep equality check (===).
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})notDeepNestedPropertyVal
- Type:
<T>(object: T, property: string, value: any, message?: string) => void
Asserts that object does not have a property named by property with value given by value. property can use dot- and bracket-notation for nested reference. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.notDeepNestedPropertyVal', () => {
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' })
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' })
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' })
})lengthOf
- Type:
<T extends { readonly length?: number | undefined } | { readonly size?: number | undefined }>(object: T, length: number, message?: string) => void
Asserts that object has a length or size with the expected value.
import { assert, test } from 'vitest'
test('assert.lengthOf', () => {
assert.lengthOf([1, 2, 3], 3, 'array has length of 3')
assert.lengthOf('foobar', 6, 'string has length of 6')
assert.lengthOf(new Set([1, 2, 3]), 3, 'set has size of 3')
assert.lengthOf(new Map([['a', 1], ['b', 2], ['c', 3]]), 3, 'map has size of 3')
})hasAnyKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has at least one of the keys provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'iDontExist', 'baz'])
assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, iDontExist: 99, baz: 1337 })
assert.hasAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.hasAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ foo: 'bar' }, 'anotherKey'])
})hasAllKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has all and only all of the keys provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.hasAllKeys', () => {
assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
assert.hasAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.hasAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})containsAllKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has all of the keys provided but may have more keys not listed. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.containsAllKeys', () => {
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, baz: 1337 })
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }])
assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }]))
assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})doesNotHaveAnyKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has none of the keys provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyKeys', () => {
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example'])
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example'])
assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ one: 'two' }, 'example']))
})doesNotHaveAllKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object does not have at least one of the keys provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example'])
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example'])
assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ one: 'two' }, 'example'])
})hasAnyDeepKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has at least one of the keys provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' })
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), [{ one: 'one' }, { two: 'two' }])
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' })
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { three: 'three' }])
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})hasAllDeepKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has all and only all of the keys provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne']]), { one: 'one' })
assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.hasAllDeepKeys(new Set([{ one: 'one' }]), { one: 'one' })
assert.hasAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})containsAllDeepKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object contains all of the keys provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.containsAllDeepKeys', () => {
assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' })
assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' })
assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})doesNotHaveAnyDeepKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object has none of the keys provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyDeepKeys', () => {
assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' })
assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { fifty: 'fifty' }])
assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' })
assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ twenty: 'twenty' }, { fifty: 'fifty' }])
})doesNotHaveAllDeepKeys
- Type:
<T>(object: T, keys: Array<Object | string> | { [key: string]: any }, message?: string) => void
Asserts that object does not have at least one of the keys provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
import { assert, test } from 'vitest'
test('assert.doesNotHaveAllDeepKeys', () => {
assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' })
assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { one: 'one' }])
assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' })
assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { fifty: 'fifty' }])
})throws
- Type:
(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void
- Alias:
throwThrow
If errorLike is an Error constructor, asserts that fn will throw an error that is an instance of errorLike. If errorLike is an Error instance, asserts that the error thrown is the same instance as errorLike. If errMsgMatcher is provided, it also asserts that the error thrown will have a message matching errMsgMatcher.
import { assert, test } from 'vitest'
test('assert.throws', () => {
assert.throws(fn, 'Error thrown must have this msg')
assert.throws(fn, /Error thrown must have a msg that matches this/)
assert.throws(fn, ReferenceError)
assert.throws(fn, errorInstance)
assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg')
assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg')
assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/)
assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/)
})doesNotThrow
- Type:
(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void - Type:
(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void
If errorLike is an Error constructor, asserts that fn will not throw an error that is an instance of errorLike. If errorLike is an Error instance, asserts that the error thrown is not the same instance as errorLike. If errMsgMatcher is provided, it also asserts that the error thrown will not have a message matching errMsgMatcher.
import { assert, test } from 'vitest'
test('assert.doesNotThrow', () => {
assert.doesNotThrow(fn, 'Any Error thrown must not have this message')
assert.doesNotThrow(fn, /Any Error thrown must not match this/)
assert.doesNotThrow(fn, Error)
assert.doesNotThrow(fn, errorInstance)
assert.doesNotThrow(fn, Error, 'Error must not have this message')
assert.doesNotThrow(fn, errorInstance, 'Error must not have this message')
assert.doesNotThrow(fn, Error, /Error must not match this/)
assert.doesNotThrow(fn, errorInstance, /Error must not match this/)
})operator
- Type:
(val1: OperatorComparable, operator: Operator, val2: OperatorComparable, message?: string) => void
Compare val1 and val2 using operator.
import { assert, test } from 'vitest'
test('assert.operator', () => {
assert.operator(1, '<', 2, 'everything is ok')
})closeTo
- Type:
(actual: number, expected: number, delta: number, message?: string) => void - Alias:
approximately
Asserts that the actual is equal expected, to within a +/- delta range.
import { assert, test } from 'vitest'
test('assert.closeTo', () => {
assert.closeTo(1.5, 1, 0.5, 'numbers are close')
})sameMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 have the same members in any order. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.sameMembers', () => {
assert.sameMembers([1, 2, 3], [2, 1, 3], 'same members')
})notSameMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 don't have the same members in any order. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.sameMembers', () => {
assert.notSameMembers([1, 2, 3], [5, 1, 3], 'not same members')
})sameDeepMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 have the same members in any order. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})notSameDeepMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 don’t have the same members in any order. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})sameOrderedMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 have the same members in the same order. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.sameOrderedMembers', () => {
assert.sameOrderedMembers([1, 2, 3], [1, 2, 3], 'same ordered members')
})notSameOrderedMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 have the same members in the same order. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.notSameOrderedMembers', () => {
assert.notSameOrderedMembers([1, 2, 3], [2, 1, 3], 'not same ordered members')
})sameDeepOrderedMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 have the same members in the same order. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.sameDeepOrderedMembers', () => {
assert.sameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { c: 3 }], 'same deep ordered members')
})notSameDeepOrderedMembers
- Type:
<T>(set1: T[], set2: T[], message?: string) => void
Asserts that set1 and set2 don’t have the same members in the same order. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.notSameDeepOrderedMembers', () => {
assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { z: 5 }], 'not same deep ordered members')
assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'not same deep ordered members')
})includeMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset is included in superset in any order. Uses a strict equality check (===). Duplicates are ignored.
import { assert, test } from 'vitest'
test('assert.includeMembers', () => {
assert.includeMembers([1, 2, 3], [2, 1, 2], 'include members')
})notIncludeMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset isn't included in superset in any order. Uses a strict equality check (===). Duplicates are ignored.
import { assert, test } from 'vitest'
test('assert.notIncludeMembers', () => {
assert.notIncludeMembers([1, 2, 3], [5, 1], 'not include members')
})includeDeepMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset is included in superset in any order. Uses a deep equality check. Duplicates are ignored.
import { assert, test } from 'vitest'
test('assert.includeDeepMembers', () => {
assert.includeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { b: 2 }], 'include deep members')
})notIncludeDeepMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset isn’t included in superset in any order. Uses a deep equality check. Duplicates are ignored.
import { assert, test } from 'vitest'
test('assert.notIncludeDeepMembers', () => {
assert.notIncludeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { f: 5 }], 'not include deep members')
})includeOrderedMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset is included in superset in the same order beginning with the first element in superset. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.includeOrderedMembers', () => {
assert.includeOrderedMembers([1, 2, 3], [1, 2], 'include ordered members')
})notIncludeOrderedMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset isn't included in superset in the same order beginning with the first element in superset. Uses a strict equality check (===).
import { assert, test } from 'vitest'
test('assert.notIncludeOrderedMembers', () => {
assert.notIncludeOrderedMembers([1, 2, 3], [2, 1], 'not include ordered members')
assert.notIncludeOrderedMembers([1, 2, 3], [2, 3], 'not include ordered members')
})includeDeepOrderedMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset is included in superset in the same order beginning with the first element in superset. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
assert.includeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }], 'include deep ordered members')
})notIncludeDeepOrderedMembers
- Type:
<T>(superset: T[], subset: T[], message?: string) => void
Asserts that subset isn’t included in superset in the same order beginning with the first element in superset. Uses a deep equality check.
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { f: 5 }], 'not include deep ordered members')
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }], 'not include deep ordered members')
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { c: 3 }], 'not include deep ordered members')
})oneOf
- Type:
<T>(inList: T, list: T[], message?: string) => void
Asserts that non-object, non-array value inList appears in the flat array list.
import { assert, test } from 'vitest'
test('assert.oneOf', () => {
assert.oneOf(1, [2, 1], 'Not found in list')
})changes
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier changes the object of a property.
import { assert, test } from 'vitest'
test('assert.changes', () => {
const obj = { val: 10 }
function fn() { obj.val = 22 };
assert.changes(fn, obj, 'val')
})changesBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier changes the object of a property by a change.
import { assert, test } from 'vitest'
test('assert.changesBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 2 };
assert.changesBy(fn, obj, 'val', 2)
})doesNotChange
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier does not changes the object of a property.
import { assert, test } from 'vitest'
test('assert.doesNotChange', () => {
const obj = { val: 10 }
function fn() { obj.val += 2 };
assert.doesNotChange(fn, obj, 'val', 2)
})changesButNotBy
- Type:
<T>(modifier: Function, object: T, property: string, change:number, message?: string) => void
Asserts that a modifier does not change the object of a property or of a modifier return value by a change.
import { assert, test } from 'vitest'
test('assert.changesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 10 };
assert.changesButNotBy(fn, obj, 'val', 5)
})increases
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier increases a numeric object's property.
import { assert, test } from 'vitest'
test('assert.increases', () => {
const obj = { val: 10 }
function fn() { obj.val = 13 };
assert.increases(fn, obj, 'val')
})increasesBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier increases a numeric object's property or a modifier return value by an change.
import { assert, test } from 'vitest'
test('assert.increasesBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 10 };
assert.increasesBy(fn, obj, 'val', 10)
})doesNotIncrease
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier does not increases a numeric object's property.
import { assert, test } from 'vitest'
test('assert.doesNotIncrease', () => {
const obj = { val: 10 }
function fn() { obj.val = 8 }
assert.doesNotIncrease(fn, obj, 'val')
})increasesButNotBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier does not increases a numeric object's property or a modifier return value by an change.
import { assert, test } from 'vitest'
test('assert.increasesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 15 };
assert.increasesButNotBy(fn, obj, 'val', 10)
})decreases
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier decreases a numeric object's property.
import { assert, test } from 'vitest'
test('assert.decreases', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.decreases(fn, obj, 'val')
})decreasesBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier decreases a numeric object's property or a modifier return value by a change.
import { assert, test } from 'vitest'
test('assert.decreasesBy', () => {
const obj = { val: 10 }
function fn() { obj.val -= 5 };
assert.decreasesBy(fn, obj, 'val', 5)
})doesNotDecrease
- Type:
<T>(modifier: Function, object: T, property: string, message?: string) => void
Asserts that a modifier dose not decrease a numeric object's property.
import { assert, test } from 'vitest'
test('assert.doesNotDecrease', () => {
const obj = { val: 10 }
function fn() { obj.val = 15 }
assert.doesNotDecrease(fn, obj, 'val')
})doesNotDecreaseBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier does not decrease a numeric object's property or a modifier return value by a change.
import { assert, test } from 'vitest'
test('assert.doesNotDecreaseBy', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.doesNotDecreaseBy(fn, obj, 'val', 1)
})decreasesButNotBy
- Type:
<T>(modifier: Function, object: T, property: string, change: number, message?: string) => void
Asserts that a modifier does not decrease a numeric object's property or a modifier return value by a change.
import { assert, test } from 'vitest'
test('assert.decreasesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.decreasesButNotBy(fn, obj, 'val', 1)
})ifError
- Type:
<T>(object: T, message?: string) => void
Asserts if object is not a false value, and throws if it is a true value. This is added to allow for chai to be a drop-in replacement for Node’s assert class.
import { assert, test } from 'vitest'
test('assert.ifError', () => {
const err = new Error('I am a custom error')
assert.ifError(err) // Rethrows err!
})isExtensible
- Type:
<T>(object: T, message?: string) => void - Alias:
extensible
Asserts that object is extensible (can have new properties added to it).
import { assert, test } from 'vitest'
test('assert.isExtensible', () => {
assert.isExtensible({})
})isNotExtensible
- Type:
<T>(object: T, message?: string) => void - Alias:
notExtensible
Asserts that object is not extensible (can not have new properties added to it).
import { assert, test } from 'vitest'
test('assert.isNotExtensible', () => {
const nonExtensibleObject = Object.preventExtensions({})
const sealedObject = Object.seal({})
const frozenObject = Object.freeze({})
assert.isNotExtensible(nonExtensibleObject)
assert.isNotExtensible(sealedObject)
assert.isNotExtensible(frozenObject)
})isSealed
- Type:
<T>(object: T, message?: string) => void - Alias:
sealed
Asserts that object is sealed (cannot have new properties added to it and its existing properties cannot be removed).
import { assert, test } from 'vitest'
test('assert.isSealed', () => {
const sealedObject = Object.seal({})
const frozenObject = Object.seal({})
assert.isSealed(sealedObject)
assert.isSealed(frozenObject)
})isNotSealed
- Type:
<T>(object: T, message?: string) => void - Alias:
notSealed
Asserts that object is not sealed (can have new properties added to it and its existing properties can be removed).
import { assert, test } from 'vitest'
test('assert.isNotSealed', () => {
assert.isNotSealed({})
})isFrozen
- Type:
<T>(object: T, message?: string) => void - Alias:
frozen
Asserts that object is frozen (cannot have new properties added to it and its existing properties cannot be modified).
import { assert, test } from 'vitest'
test('assert.isFrozen', () => {
const frozenObject = Object.freeze({})
assert.frozen(frozenObject)
})isNotFrozen
- Type:
<T>(object: T, message?: string) => void - Alias:
notFrozen
Asserts that object is not frozen (can have new properties added to it and its existing properties can be modified).
import { assert, test } from 'vitest'
test('assert.isNotFrozen', () => {
assert.isNotFrozen({})
})isEmpty
- Type:
<T>(target: T, message?: string) => void - Alias:
empty
Asserts that the target does not contain any values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys.
import { assert, test } from 'vitest'
test('assert.isEmpty', () => {
assert.isEmpty([])
assert.isEmpty('')
assert.isEmpty(new Map())
assert.isEmpty({})
})isNotEmpty
- Type:
<T>(object: T, message?: string) => void - Alias:
notEmpty
Asserts that the target contains values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys.
import { assert, test } from 'vitest'
test('assert.isNotEmpty', () => {
assert.isNotEmpty([1, 2])
assert.isNotEmpty('34')
assert.isNotEmpty(new Set([5, 6]))
assert.isNotEmpty({ key: 7 })
})File: docs/api/assert-type.md
assertType
::: warning
During runtime this function doesn't do anything. To enable typechecking, don't forget to pass down --typecheck flag.
:::
- Type:
<T>(value: T): void
You can use this function as an alternative for expectTypeOf to easily assert that the argument type is equal to the generic provided.
import { assertType } from 'vitest'
function concat(a: string, b: string): string
function concat(a: number, b: number): number
function concat(a: string | number, b: string | number): string | number
assertType<string>(concat('a', 'b'))
assertType<number>(concat(1, 2))
// @ts-expect-error wrong types
assertType(concat('a', 2))File: docs/api/expect.md
expect
The following types are used in the type signatures below
type Awaitable<T> = T | PromiseLike<T>expect is used to create assertions. In this context assertions are functions that can be called to assert a statement. Vitest provides chai assertions by default and also Jest compatible assertions built on top of chai. Since Vitest 4.1, for spy/mock testing, Vitest also provides Chai-style assertions (e.g., expect(spy).to.have.been.called()) alongside Jest-style assertions (e.g., expect(spy).toHaveBeenCalled()). Unlike Jest, Vitest supports a message as the second argument - if the assertion fails, the error message will be equal to it.
export interface ExpectStatic
extends Chai.ExpectStatic,
Matchers<any>,
AsymmetricMatchersContaining {
<T>(actual: T, message?: string): Assertion<void, T>
extend: (expects: MatchersObject) => void
anything: () => any
any: (constructor: unknown) => any
getState: () => MatcherState
setState: (state: Partial<MatcherState>) => void
not: AsymmetricMatchersContaining
}For example, this code asserts that an input value is equal to 2. If it's not, the assertion will throw an error, and the test will fail.
import { expect } from 'vitest'
const input = Math.sqrt(4)
expect(input).to.equal(2) // chai API
expect(input).toBe(2) // jest APITechnically this example doesn't use test function, so in the console you will see Node.js error instead of Vitest output. To learn more about test, please read Test API Reference.
Also, expect can be used statically to access matcher functions, described later, and more.
::: warningexpect has no effect on testing types, if the expression doesn't have a type error. If you want to use Vitest as type checker, use expectTypeOf or assertType.
:::
assert
- Type:
Chai.AssertStatic
Vitest reexports chai's assert API as expect.assert for convenience. You can see the supported methods on the Assert API page.
This is especially useful if you need to narrow down the type, since expect.to* methods do not support that:
interface Cat {
__type: 'Cat'
mew(): void
}
interface Dog {
__type: 'Dog'
bark(): void
}
type Animal = Cat | Dog
const animal: Animal = { __type: 'Dog', bark: () => {} }
expect.assert(animal.__type === 'Dog')
// does not show a type error!
expect(animal.bark()).toBeUndefined()::: tip
Note that expect.assert also supports other type-narrowing methods (like assert.isDefined, assert.exists and so on).
:::
soft
- Type:
ExpectStatic & (actual: any) => Assertions
expect.soft functions similarly to expect, but instead of terminating the test execution upon a failed assertion, it continues running and marks the failure as a test failure. All errors encountered during the test will be displayed until the test is completed.
import { expect, test } from 'vitest'
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3) // mark the test as fail and continue
expect.soft(1 + 2).toBe(4) // mark the test as fail and continue
})
// reporter will report both errors at the end of the runIt can also be used with expect. if expect assertion fails, the test will be terminated and all errors will be displayed.
import { expect, test } from 'vitest'
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3) // mark the test as fail and continue
expect(1 + 2).toBe(4) // failed and terminate the test, all previous errors will be output
expect.soft(1 + 3).toBe(5) // do not run
})::: warningexpect.soft can only be used inside the test function.
:::
poll
interface ExpectPoll extends ExpectStatic {
(actual: (options: { signal: AbortSignal }) => T, options?: { interval?: number; timeout?: number; message?: string }): Promise<Assertions<Awaited<T>>>
}expect.poll reruns the assertion until it is succeeded. You can configure how often Vitest retries and how long it waits by setting interval and timeout options. The timeout applies to the whole polling operation, including pending callback and async matcher execution.
The callback receives an AbortSignal that is aborted when the poll timeout is reached.
If an error is thrown inside the expect.poll callback, Vitest will retry again until the timeout runs out.
import { expect, test } from 'vitest'
test('element exists', async () => {
asyncInjectElement()
await expect.poll(() => document.querySelector('.element')).toBeTruthy()
})::: warningexpect.poll makes every assertion asynchronous, so you need to await it. Since Vitest 3, if you forget to await it, the test will fail with a warning to do so.
expect.poll doesn't work with several matchers:
- Snapshot matchers are not supported because they will always succeed. If your condition is flaky, consider using
vi.waitForinstead to resolve it first:
import { expect, vi } from 'vitest'
const flakyValue = await vi.waitFor(() => getFlakyValue())
expect(flakyValue).toMatchSnapshot().resolvesand.rejectsare not supported.expect.pollalready awaits the condition if it's asynchronous.toThrowand its aliases are not supported because theexpect.pollcondition is always resolved before the matcher gets the value
:::
not
Using not will negate the assertion. For example, this code asserts that an input value is not equal to 2. If it's equal, the assertion will throw an error, and the test will fail.
import { expect, test } from 'vitest'
const input = Math.sqrt(16)
expect(input).not.to.equal(2) // chai API
expect(input).not.toBe(2) // jest APItoBe
- Type:
(value: any) => Awaitable<void>
toBe can be used to assert if primitives are equal or that objects share the same reference. It is equivalent of calling expect(Object.is(3, 3)).toBe(true). If the objects are not the same, but you want to check if their structures are identical, you can use toEqual.
For example, the code below checks if the trader has 13 apples.
import { expect, test } from 'vitest'
const stock = {
type: 'apples',
count: 13,
}
test('stock has 13 apples', () => {
expect(stock.type).toBe('apples')
expect(stock.count).toBe(13)
})
test('stocks are the same', () => {
const refStock = stock // same reference
expect(stock).toBe(refStock)
})Try not to use toBe with floating-point numbers. Since JavaScript rounds them, 0.1 + 0.2 is not strictly 0.3. To reliably assert floating-point numbers, use toBeCloseTo assertion.
toBeCloseTo
- Type:
(value: number, numDigits?: number) => Awaitable<void>
Use toBeCloseTo to compare floating-point numbers. The optional numDigits argument limits the number of digits to check after the decimal point. The default for numDigits is 2. For example:
import { expect, test } from 'vitest'
test.fails('decimals are not equal in javascript', () => {
expect(0.2 + 0.1).toBe(0.3) // 0.2 + 0.1 is 0.30000000000000004
})
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 is 0.30000 | "000000000004" removed
expect(0.2 + 0.1).toBeCloseTo(0.3, 5)
// nothing from 0.30000000000000004 is removed
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50)
})toBeDefined
- Type:
() => Awaitable<void>
toBeDefined asserts that the value is not equal to undefined. Useful use case would be to check if function returned anything.
import { expect, test } from 'vitest'
function getApples() {
return 3
}
test('function returned something', () => {
expect(getApples()).toBeDefined()
})toBeUndefined
- Type:
() => Awaitable<void>
Opposite of toBeDefined, toBeUndefined asserts that the value is equal to undefined. Useful use case would be to check if function hasn't returned anything.
import { expect, test } from 'vitest'
function getApplesFromStock(stock: string) {
if (stock === 'Bill') {
return 13
}
}
test('mary doesn\'t have a stock', () => {
expect(getApplesFromStock('Mary')).toBeUndefined()
})toBeTruthy
- Type:
() => Awaitable<void>
toBeTruthy asserts that the value is true when converted to boolean. Useful if you don't care for the value, but just want to know it can be converted to true.
For example, having this code you don't care for the return value of stocks.getInfo - it maybe a complex object, a string, or anything else. The code will still work.
import { Stocks } from './stocks.js'
const stocks = new Stocks()
stocks.sync('Bill')
if (stocks.getInfo('Bill')) {
stocks.sell('apples', 'Bill')
}So if you want to test that stocks.getInfo will be truthy, you could write:
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('if we know Bill stock, sell apples to him', () => {
stocks.sync('Bill')
expect(stocks.getInfo('Bill')).toBeTruthy()
})Everything in JavaScript is truthy, except false, null, undefined, NaN, 0, -0, 0n, "" and document.all.
toBeFalsy
- Type:
() => Awaitable<void>
toBeFalsy asserts that the value is false when converted to boolean. Useful if you don't care for the value, but just want to know if it can be converted to false.
For example, having this code you don't care for the return value of stocks.stockFailed - it may return any falsy value, but the code will still work.
import { Stocks } from './stocks.js'
const stocks = new Stocks()
stocks.sync('Bill')
if (!stocks.stockFailed('Bill')) {
stocks.sell('apples', 'Bill')
}So if you want to test that stocks.stockFailed will be falsy, you could write:
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('if Bill stock hasn\'t failed, sell apples to him', () => {
stocks.syncStocks('Bill')
expect(stocks.stockFailed('Bill')).toBeFalsy()
})Everything in JavaScript is truthy, except false, null, undefined, NaN, 0, -0, 0n, "" and document.all.
toBeNull
- Type:
() => Awaitable<void>
toBeNull simply asserts if something is null. Alias for .toBe(null).
import { expect, test } from 'vitest'
function apples() {
return null
}
test('we don\'t have apples', () => {
expect(apples()).toBeNull()
})toBeNullable
- Type:
() => Awaitable<void>
toBeNullable simply asserts if something is nullable (null or undefined).
import { expect, test } from 'vitest'
function apples() {
return null
}
function bananas() {
return undefined
}
test('we don\'t have apples', () => {
expect(apples()).toBeNullable()
})
test('we don\'t have bananas', () => {
expect(bananas()).toBeNullable()
})toBeNaN
- Type:
() => Awaitable<void>
toBeNaN simply asserts if something is NaN. Alias for .toBe(NaN).
import { expect, test } from 'vitest'
let i = 0
function getApplesCount() {
i++
return i > 1 ? Number.NaN : i
}
test('getApplesCount has some unusual side effects...', () => {
expect(getApplesCount()).not.toBeNaN()
expect(getApplesCount()).toBeNaN()
})toBeOneOf
- Type:
(sample: Array<any> | Set<any>) => any
toBeOneOf asserts if a value matches any of the values in the provided array or set.
::: warning EXPERIMENTAL
Providing a Set is an experimental feature and may change in a future release.
:::
import { expect, test } from 'vitest'
test('fruit is one of the allowed values', () => {
expect(fruit).toBeOneOf(['apple', 'banana', 'orange'])
})The asymmetric matcher is particularly useful when testing optional properties that could be either null or undefined:
test('optional properties can be null or undefined', () => {
const user = {
firstName: 'John',
middleName: undefined,
lastName: 'Doe'
}
expect(user).toEqual({
firstName: expect.any(String),
middleName: expect.toBeOneOf([expect.any(String), undefined]),
lastName: expect.any(String),
})
}):::tip
You can use expect.not with this matcher to ensure a value does NOT match any of the provided options.
:::
toBeTypeOf
- Type:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf asserts if an actual value is of type of received type.
import { expect, test } from 'vitest'
const actual = 'stock'
test('stock is type of string', () => {
expect(actual).toBeTypeOf('string')
}):::warningtoBeTypeOf uses the native typeof operator under the hood with all its quirks, most notably that the value null has type object.
test('toBeTypeOf cannot check for null or array', () => {
expect(null).toBeTypeOf('object')
expect([]).toBeTypeOf('object')
}):::
toBeInstanceOf
- Type:
(c: any) => Awaitable<void>
toBeInstanceOf asserts if an actual value is instance of received class.
import { expect, test } from 'vitest'
import { Stocks } from './stocks.js'
const stocks = new Stocks()
test('stocks are instance of Stocks', () => {
expect(stocks).toBeInstanceOf(Stocks)
})toBeGreaterThan
- Type:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan asserts if actual value is greater than received one. Equal values will fail the test.
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have more then 10 apples', () => {
expect(getApples()).toBeGreaterThan(10)
})toBeGreaterThanOrEqual
- Type:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual asserts if actual value is greater than received one or equal to it.
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have 11 apples or more', () => {
expect(getApples()).toBeGreaterThanOrEqual(11)
})toBeLessThan
- Type:
(n: number | bigint) => Awaitable<void>
toBeLessThan asserts if actual value is less than received one. Equal values will fail the test.
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have less then 20 apples', () => {
expect(getApples()).toBeLessThan(20)
})toBeLessThanOrEqual
- Type:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual asserts if actual value is less than received one or equal to it.
import { expect, test } from 'vitest'
import { getApples } from './stocks.js'
test('have 11 apples or less', () => {
expect(getApples()).toBeLessThanOrEqual(11)
})toEqual
- Type:
(received: any) => Awaitable<void>
toEqual asserts if actual value is equal to received one or has the same structure, if it is an object (compares them recursively). You can see the difference between toEqual and toBe in this example:
import { expect, test } from 'vitest'
const stockBill = {
type: 'apples',
count: 13,
}
const stockMary = {
type: 'apples',
count: 13,
}
test('stocks have the same properties', () => {
expect(stockBill).toEqual(stockMary)
})
test('stocks are not the same', () => {
expect(stockBill).not.toBe(stockMary)
}):::warning
For Error objects, non-enumerable properties such as name, message, cause and AggregateError.errors are also compared. For Error.cause, the comparison is done asymmetrically:
// success
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi'))
// fail
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' }))To test if something was thrown, use toThrow assertion.
:::
toStrictEqual
- Type:
(received: any) => Awaitable<void>
toStrictEqual asserts if the actual value is equal to the received one or has the same structure if it is an object (compares them recursively), and of the same type.
Differences from .toEqual:
- Keys with
undefinedproperties are checked. e.g.{a: undefined, b: 2}does not match{b: 2}when using.toStrictEqual. - Array sparseness is checked. e.g.
[, 1]does not match[undefined, 1]when using.toStrictEqual. - Object types are checked to be equal. e.g. A class instance with fields
aandbwill not equal a literal object with fieldsaandb.
import { expect, test } from 'vitest'
class Stock {
constructor(type) {
this.type = type
}
}
test('structurally the same, but semantically different', () => {
expect(new Stock('apples')).toEqual({ type: 'apples' })
expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' })
})toContain
- Type:
(received: string) => Awaitable<void>
toContain asserts if the actual value is in an array. toContain can also check whether a string is a substring of another string. If you are running tests in a browser-like environment, this assertion can also check if class is contained in a classList, or an element is inside another one.
import { expect, test } from 'vitest'
import { getAllFruits } from './stocks.js'
test('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange')
})
test('pineapple contains apple', () => {
expect('pineapple').toContain('apple')
})
test('the element contains a class and is contained', () => {
const element = document.querySelector('#el')
// element has a class
expect(element.classList).toContain('flex')
// element is inside another one
expect(document.querySelector('#wrapper')).toContain(element)
})toContainEqual
- Type:
(received: any) => Awaitable<void>
toContainEqual asserts if an item with a specific structure and values is contained in an array.
It works like toEqual inside for each element.
import { expect, test } from 'vitest'
import { getFruitStock } from './stocks.js'
test('apple available', () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 })
})toHaveLength
- Type:
(received: number) => Awaitable<void>
toHaveLength asserts if an object has a .length property and it is set to a certain numeric value.
import { expect, test } from 'vitest'
test('toHaveLength', () => {
expect('abc').toHaveLength(3)
expect([1, 2, 3]).toHaveLength(3)
expect('').not.toHaveLength(3) // doesn't have .length of 3
expect({ length: 3 }).toHaveLength(3)
})toHaveProperty
- Type:
(key: any, received?: any) => Awaitable<void>
toHaveProperty asserts if a property at provided reference key exists for an object.
You can provide an optional value argument also known as deep equality, like the toEqual matcher to compare the received property value.
import { expect, test } from 'vitest'
const invoice = {
'isActive': true,
'P.O': '12345',
'customer': {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
'total_amount': 5000,
'items': [
{
type: 'apples',
quantity: 10,
},
{
type: 'oranges',
quantity: 5,
},
],
}
test('John Doe Invoice', () => {
expect(invoice).toHaveProperty('isActive') // assert that the key exists
expect(invoice).toHaveProperty('total_amount', 5000) // assert that the key exists and the value is equal
expect(invoice).not.toHaveProperty('account') // assert that this key does not exist
// Deep referencing using dot notation
expect(invoice).toHaveProperty('customer.first_name')
expect(invoice).toHaveProperty('customer.last_name', 'Doe')
expect(invoice).not.toHaveProperty('customer.location', 'India')
// Deep referencing using an array containing the key
expect(invoice).toHaveProperty('items[0].type', 'apples')
expect(invoice).toHaveProperty('items.0.type', 'apples') // dot notation also works
// Deep referencing using an array containing the keyPath
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples')
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples') // string notation also works
// Wrap your key in an array to avoid the key from being parsed as a deep reference
expect(invoice).toHaveProperty(['P.O'], '12345')
// Deep equality of object property
expect(invoice).toHaveProperty('items[0]', { type: 'apples', quantity: 10 })
})toMatch
- Type:
(received: string | regexp) => Awaitable<void>
toMatch asserts if a string matches a regular expression or a string.
import { expect, test } from 'vitest'
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/)
expect('applefruits').toMatch('fruit') // toMatch also accepts a string
})toMatchObject
- Type:
(received: object | array) => Awaitable<void>
toMatchObject asserts if an object matches a subset of the properties of an object.
You can also pass an array of objects. This is useful if you want to check that two arrays match in their number and order of elements, as opposed to arrayContaining, which allows for extra elements in the received array.
import { expect, test } from 'vitest'
const johnInvoice = {
isActive: true,
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
total_amount: 5000,
items: [
{
type: 'apples',
quantity: 10,
},
{
type: 'oranges',
quantity: 5,
},
],
}
const johnDetails = {
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
}
test('invoice has john personal details', () => {
expect(johnInvoice).toMatchObject(johnDetails)
})
test('the number of elements must match exactly', () => {
// Assert that an array of object matches
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
])
})toThrow
Type:
(expected?: any) => Awaitable<void>Alias:
toThrowError
toThrow asserts if a function throws an error when it is called.
You can provide an optional argument to test that a specific error is thrown:
RegExp: error message matches the patternstring: error message includes the substring- any other value: compare with thrown value using deep equality (similar to
toEqual)
:::tip
You must wrap the code in a function, otherwise the error will not be caught, and test will fail.
This does not apply for async calls as rejects correctly unwraps the promise:
test('expect rejects toThrow', async ({ expect }) => {
const promise = Promise.reject(new Error('Test'))
await expect(promise).rejects.toThrow()
}):::
For example, if we want to test that getFruitStock('pineapples') throws, we could write:
import { expect, test } from 'vitest'
function getFruitStock(type: string) {
if (type === 'pineapples') {
throw new Error('Pineapples are not in stock')
}
// Do some other stuff
}
test('throws on pineapples', () => {
// Test that the error message says "stock" somewhere: these are equivalent
expect(() => getFruitStock('pineapples')).toThrow(/stock/)
expect(() => getFruitStock('pineapples')).toThrow('stock')
// Test the exact error message
expect(() => getFruitStock('pineapples')).toThrow(
/^Pineapples are not in stock$/,
)
expect(() => getFruitStock('pineapples')).toThrow(
new Error('Pineapples are not in stock'),
)
expect(() => getFruitStock('pineapples')).toThrow(expect.objectContaining({
message: 'Pineapples are not in stock',
}))
}):::tip
To test async functions, use in combination with rejects.
function getAsyncFruitStock() {
return Promise.reject(new Error('empty'))
}
test('throws on pineapples', async () => {
await expect(() => getAsyncFruitStock()).rejects.toThrow('empty')
}):::
:::tip
You can also test non-Error values that are thrown:
test('throws non-Error values', () => {
expect(() => { throw 42 }).toThrow(42)
expect(() => { throw { message: 'error' } }).toThrow({ message: 'error' })
}):::
:::warning Unhandled Rejections with Fake Timers
When using fake timers, an async function that rejects during a vi.advanceTimersByTimeAsync call will trigger an unhandled rejection — even if you later assert it with .rejects.toThrow(). This happens because the error is thrown before the expect chain has a chance to catch it.
async function foo() {
await new Promise(resolve => setTimeout(resolve, 100))
throw new Error('boom')
}
test('rejects', async () => {
const result = foo()
await vi.advanceTimersByTimeAsync(100)
// The assertion passes, but the error was already "unhandled" during advanceTimersByTimeAsync
await expect(result).rejects.toThrow()
})To avoid this, prefer vi.setTimerTickMode('nextTimerAsync') so that timers tick automatically as promises settle, without needing a manual advance:
beforeEach(() => {
vi.useFakeTimers()
vi.setTimerTickMode('nextTimerAsync')
})
test('rejects', async () => {
// No advanceTimersByTimeAsync needed — the error is caught by rejects.toThrow()
await expect(foo()).rejects.toThrow('boom')
})Alternatively, set up the .rejects.toThrow() assertion before advancing timers so the rejection is handled immediately:
test('rejects', async () => {
const result = foo()
const assertion = expect(result).rejects.toThrow('boom')
await vi.advanceTimersByTimeAsync(100)
await assertion
}):::
toMatchSnapshot
- Type:
<T>(shape?: Partial<T> | string, hint?: string) => void
This ensures that a value matches the most recent snapshot.
You can provide an optional hint string argument that is appended to the test name. Although Vitest always appends a number at the end of a snapshot name, short descriptive hints might be more useful than numbers to differentiate multiple snapshots in a single it or test block. Vitest sorts snapshots by name in the corresponding .snap file.
:::tip
When a snapshot mismatches and causes the test to fail, if the mismatch is expected, you can press u key to update the snapshot once. Or you can pass -u or --update CLI options to make Vitest always update the tests.
:::
import { expect, test } from 'vitest'
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) }
expect(data).toMatchSnapshot()
})You can also provide a shape of an object, if you are testing just a shape of an object, and don't need it to be 100% compatible:
import { expect, test } from 'vitest'
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) }
expect(data).toMatchSnapshot({ foo: expect.any(Set) })
})toMatchInlineSnapshot
- Type:
<T>(shape?: Partial<T> | string, snapshot?: string, hint?: string) => void
This ensures that a value matches the most recent snapshot.
Vitest adds and updates the inlineSnapshot string argument to the matcher in the test file (instead of an external .snap file).
import { expect, test } from 'vitest'
test('matches inline snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) }
// Vitest will update following content when updating the snapshot
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`)
})You can also provide a shape of an object, if you are testing just a shape of an object, and don't need it to be 100% compatible:
import { expect, test } from 'vitest'
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) }
expect(data).toMatchInlineSnapshot(
{ foo: expect.any(Set) },
`
{
"foo": Any<Set>,
}
`
)
})toMatchFileSnapshot {#tomatchfilesnapshot}
- Type:
<T>(filepath: string, hint?: string) => Promise<void>
Compare or update the snapshot with the content of a file explicitly specified (instead of the .snap file).
import { expect, it } from 'vitest'
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }))
await expect(result).toMatchFileSnapshot('./test/basic.output.html')
})Note that since file system operation is async, you need to use await with toMatchFileSnapshot(). If await is not used, Vitest treats it like expect.soft, meaning the code after the statement will continue to run even if the snapshot mismatches. After the test finishes, Vitest will check the snapshot and fail if there is a mismatch.
toThrowErrorMatchingSnapshot
- Type:
(hint?: string) => void
The same as toMatchSnapshot, but expects the same value as toThrow.
toThrowErrorMatchingInlineSnapshot
- Type:
(snapshot?: string, hint?: string) => void
The same as toMatchInlineSnapshot, but expects the same value as toThrow.
toMatchAriaSnapshot 4.1.4 {#tomatcharisnapshot}
- Type:
() => void
Captures the accessibility tree of a DOM element and generate a snapshot file or compares it against a stored snapshot. See the ARIA Snapshots guide for more details.
import { expect, test } from 'vitest'
test('navigation accessibility', () => {
document.body.innerHTML = `
<nav aria-label="Actions">
Save
Cancel
</nav>
`
expect(document.querySelector('nav')).toMatchAriaSnapshot()
})toMatchAriaInlineSnapshot 4.1.4 {#tomatchariainlinesnapshot}
- Type:
(snapshot?: string) => void
Same as toMatchAriaSnapshot, but stores the snapshot inline in the test file. See the ARIA Snapshots guide for more details.
import { expect, test } from 'vitest'
test('user profile', () => {
expect(document.body).toMatchAriaInlineSnapshot(`
- heading "Dashboard" [level=1]
- button /User \\d+/: Profile
`)
})toHaveBeenCalled
- Type:
() => Awaitable<void>
This assertion is useful for testing that a function has been called. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy')
expect(buySpy).not.toHaveBeenCalled()
market.buy('apples', 10)
expect(buySpy).toHaveBeenCalled()
})toHaveBeenCalledTimes
- Type:
(amount: number) => Awaitable<void>
This assertion checks if a function was called a certain amount of times. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('spy function called two times', () => {
const buySpy = vi.spyOn(market, 'buy')
market.buy('apples', 10)
market.buy('apples', 20)
expect(buySpy).toHaveBeenCalledTimes(2)
})toHaveBeenCalledWith
- Type:
(...args: any[]) => Awaitable<void>
This assertion checks if a function was called at least once with certain parameters. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy')
market.buy('apples', 10)
market.buy('apples', 20)
expect(buySpy).toHaveBeenCalledWith('apples', 10)
expect(buySpy).toHaveBeenCalledWith('apples', 20)
})toHaveBeenCalledBefore
- Type:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
This assertion checks if a Mock was called before another Mock.
test('calls mock1 before mock2', () => {
const mock1 = vi.fn()
const mock2 = vi.fn()
mock1()
mock2()
mock1()
expect(mock1).toHaveBeenCalledBefore(mock2)
})toHaveBeenCalledAfter
- Type:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
This assertion checks if a Mock was called after another Mock.
test('calls mock1 after mock2', () => {
const mock1 = vi.fn()
const mock2 = vi.fn()
mock2()
mock1()
mock2()
expect(mock1).toHaveBeenCalledAfter(mock2)
})toHaveBeenCalledExactlyOnceWith
- Type:
(...args: any[]) => Awaitable<void>
This assertion checks if a function was called exactly once and with certain parameters. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy')
market.buy('apples', 10)
expect(buySpy).toHaveBeenCalledExactlyOnceWith('apples', 10)
})toHaveBeenLastCalledWith
- Type:
(...args: any[]) => Awaitable<void>
This assertion checks if a function was called with certain parameters at its last invocation. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy')
market.buy('apples', 10)
market.buy('apples', 20)
expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10)
expect(buySpy).toHaveBeenLastCalledWith('apples', 20)
})toHaveBeenNthCalledWith
- Type:
(time: number, ...args: any[]) => Awaitable<void>
This assertion checks if a function was called with certain parameters at the certain time. The count starts at 1. So, to check the second entry, you would write .toHaveBeenNthCalledWith(2, ...).
Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
const market = {
buy(subject: string, amount: number) {
// ...
},
}
test('first call of spy function called with right params', () => {
const buySpy = vi.spyOn(market, 'buy')
market.buy('apples', 10)
market.buy('apples', 20)
expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10)
})toHaveReturned
- Type:
() => Awaitable<void>
This assertion checks if a function has successfully returned a value at least once (i.e., did not throw an error). Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
function getApplesPrice(amount: number) {
const PRICE = 10
return amount * PRICE
}
test('spy function returned a value', () => {
const getPriceSpy = vi.fn(getApplesPrice)
const price = getPriceSpy(10)
expect(price).toBe(100)
expect(getPriceSpy).toHaveReturned()
})toHaveReturnedTimes
- Type:
(amount: number) => Awaitable<void>
This assertion checks if a function has successfully returned a value an exact amount of times (i.e., did not throw an error). Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
test('spy function returns a value two times', () => {
const sell = vi.fn((product: string) => ({ product }))
sell('apples')
sell('bananas')
expect(sell).toHaveReturnedTimes(2)
})toHaveReturnedWith
- Type:
(returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully returned a value with certain parameters at least once. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
test('spy function returns a product', () => {
const sell = vi.fn((product: string) => ({ product }))
sell('apples')
expect(sell).toHaveReturnedWith({ product: 'apples' })
})toHaveLastReturnedWith
- Type:
(returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully returned a certain value when it was last invoked. Requires a spy function to be passed to expect.
import { expect, test, vi } from 'vitest'
test('spy function returns bananas on a last call', () => {
const sell = vi.fn((product: string) => ({ product }))
sell('apples')
sell('bananas')
expect(sell).toHaveLastReturnedWith({ product: 'bananas' })
})toHaveNthReturnedWith
- Type:
(time: number, returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully returned a value with certain parameters on a certain call. Requires a spy function to be passed to expect.
The count starts at 1. So, to check the second entry, you would write .toHaveNthReturnedWith(2, ...).
import { expect, test, vi } from 'vitest'
test('spy function returns bananas on second call', () => {
const sell = vi.fn((product: string) => ({ product }))
sell('apples')
sell('bananas')
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' })
})toHaveResolved
- Type:
() => Awaitable<void>
This assertion checks if a function has successfully resolved a value at least once (i.e., did not reject). Requires a spy function to be passed to expect.
If the function returned a promise, but it was not resolved yet, this will fail.
import { expect, test, vi } from 'vitest'
import db from './db/apples.js'
async function getApplesPrice(amount: number) {
return amount * await db.get('price')
}
test('spy function resolved a value', async () => {
const getPriceSpy = vi.fn(getApplesPrice)
const price = await getPriceSpy(10)
expect(price).toBe(100)
expect(getPriceSpy).toHaveResolved()
})toHaveResolvedTimes
- Type:
(amount: number) => Awaitable<void>
This assertion checks if a function has successfully resolved a value an exact amount of times (i.e., did not reject). Requires a spy function to be passed to expect.
This will only count resolved promises. If the function returned a promise, but it was not resolved yet, it will not be counted.
import { expect, test, vi } from 'vitest'
test('spy function resolved a value two times', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))
await sell('apples')
await sell('bananas')
expect(sell).toHaveResolvedTimes(2)
})toHaveResolvedWith
- Type:
(returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully resolved a certain value at least once. Requires a spy function to be passed to expect.
If the function returned a promise, but it was not resolved yet, this will fail.
import { expect, test, vi } from 'vitest'
test('spy function resolved a product', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))
await sell('apples')
expect(sell).toHaveResolvedWith({ product: 'apples' })
})toHaveLastResolvedWith
- Type:
(returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully resolved a certain value when it was last invoked. Requires a spy function to be passed to expect.
If the function returned a promise, but it was not resolved yet, this will fail.
import { expect, test, vi } from 'vitest'
test('spy function resolves bananas on a last call', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))
await sell('apples')
await sell('bananas')
expect(sell).toHaveLastResolvedWith({ product: 'bananas' })
})toHaveNthResolvedWith
- Type:
(time: number, returnValue: any) => Awaitable<void>
You can call this assertion to check if a function has successfully resolved a certain value on a specific invocation. Requires a spy function to be passed to expect.
If the function returned a promise, but it was not resolved yet, this will fail.
The count starts at 1. So, to check the second entry, you would write .toHaveNthResolvedWith(2, ...).
import { expect, test, vi } from 'vitest'
test('spy function returns bananas on second call', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))
await sell('apples')
await sell('bananas')
expect(sell).toHaveNthResolvedWith(2, { product: 'bananas' })
})toHaveBeenExhausted 5.0.0 {#tohavebeenexhausted}
- Type:
() => void
This assertion checks that every behavior registered on a vi.when chain has been consumed. A behavior is considered exhausted when it has been called the number of times specified by its times option, or at least once for behaviors that apply indefinitely.
Requires a When chain returned by vi.when to be passed to expect.
import { expect, test, vi } from 'vitest'
test('all behaviors were consumed', () => {
const spy = vi.fn()
const w = vi.when(spy)
.calledWith(1)
.thenReturnOnce('once')
.calledWith(2)
.thenReturn('always')
expect(w).not.toHaveBeenExhausted()
spy(1) // consumes the `thenReturnOnce` behavior
spy(2) // satisfies the `thenReturn` behavior (called at least once)
expect(w).toHaveBeenExhausted()
})::: warning
A When chain with no registered behaviors is never considered exhausted. toHaveBeenExhausted only passes when at least one calledWith with an associated action (then*) has been registered and every registered behavior has been fully consumed.
:::
called 4.1.0 {#called}
- Type:
Assertion(property, not a method)
Chai-style assertion that checks if a spy was called at least once. This is equivalent to toHaveBeenCalled().
::: tip
This is a property assertion following sinon-chai conventions. Access it without parentheses: expect(spy).to.have.been.called
:::
import { expect, test, vi } from 'vitest'
test('spy was called', () => {
const spy = vi.fn()
spy()
expect(spy).to.have.been.called
expect(spy).to.not.have.been.called // negation
})callCount 4.1.0 {#callcount}
- Type:
(count: number) => void
Chai-style assertion that checks if a spy was called a specific number of times. This is equivalent to toHaveBeenCalledTimes(count).
import { expect, test, vi } from 'vitest'
test('spy call count', () => {
const spy = vi.fn()
spy()
spy()
spy()
expect(spy).to.have.callCount(3)
})calledWith 4.1.0 {#calledwith}
- Type:
(...args: any[]) => void
Chai-style assertion that checks if a spy was called with specific arguments at least once. This is equivalent to toHaveBeenCalledWith(...args).
import { expect, test, vi } from 'vitest'
test('spy called with arguments', () => {
const spy = vi.fn()
spy('apple', 10)
spy('banana', 20)
expect(spy).to.have.been.calledWith('apple', 10)
expect(spy).to.have.been.calledWith('banana', 20)
})calledOnce 4.1.0 {#calledonce}
- Type:
Assertion(property, not a method)
Chai-style assertion that checks if a spy was called exactly once. This is equivalent to toHaveBeenCalledOnce().
::: tip
This is a property assertion following sinon-chai conventions. Access it without parentheses: expect(spy).to.have.been.calledOnce
:::
import { expect, test, vi } from 'vitest'
test('spy called once', () => {
const spy = vi.fn()
spy()
expect(spy).to.have.been.calledOnce
})calledOnceWith 4.1.0 {#calledoncewith}
- Type:
(...args: any[]) => void
Chai-style assertion that checks if a spy was called exactly once with specific arguments. This is equivalent to toHaveBeenCalledExactlyOnceWith(...args).
import { expect, test, vi } from 'vitest'
test('spy called once with arguments', () => {
const spy = vi.fn()
spy('apple', 10)
expect(spy).to.have.been.calledOnceWith('apple', 10)
})calledTwice 4.1.0 {#calledtwice}
- Type:
Assertion(property, not a method)
Chai-style assertion that checks if a spy was called exactly twice. This is equivalent to toHaveBeenCalledTimes(2).
::: tip
This is a property assertion following sinon-chai conventions. Access it without parentheses: expect(spy).to.have.been.calledTwice
:::
import { expect, test, vi } from 'vitest'
test('spy called twice', () => {
const spy = vi.fn()
spy()
spy()
expect(spy).to.have.been.calledTwice
})calledThrice 4.1.0 {#calledthrice}
- Type:
Assertion(property, not a method)
Chai-style assertion that checks if a spy was called exactly three times. This is equivalent to toHaveBeenCalledTimes(3).
::: tip
This is a property assertion following sinon-chai conventions. Access it without parentheses: expect(spy).to.have.been.calledThrice
:::
import { expect, test, vi } from 'vitest'
test('spy called thrice', () => {
const spy = vi.fn()
spy()
spy()
spy()
expect(spy).to.have.been.calledThrice
})lastCalledWith
- Type:
(...args: any[]) => void
Chai-style assertion that checks if the last call to a spy was made with specific arguments. This is equivalent to toHaveBeenLastCalledWith(...args).
import { expect, test, vi } from 'vitest'
test('spy last called with', () => {
const spy = vi.fn()
spy('apple', 10)
spy('banana', 20)
expect(spy).to.have.been.lastCalledWith('banana', 20)
})nthCalledWith
- Type:
(n: number, ...args: any[]) => void
Chai-style assertion that checks if the nth call to a spy was made with specific arguments. This is equivalent to toHaveBeenNthCalledWith(n, ...args).
import { expect, test, vi } from 'vitest'
test('spy nth called with', () => {
const spy = vi.fn()
spy('apple', 10)
spy('banana', 20)
spy('cherry', 30)
expect(spy).to.have.been.nthCalledWith(2, 'banana', 20)
})returned 4.1.0 {#returned}
- Type:
(value: any) => void
Chai-style assertion that checks if a spy returned a specific value at least once. This is equivalent to toHaveReturnedWith(value).
import { expect, test, vi } from 'vitest'
test('spy returned', () => {
const spy = vi.fn(() => 'value')
spy()
expect(spy).to.have.returned('value')
})returnedWith 4.1.0 {#returnedwith}
- Type:
(value: any) => void
Chai-style assertion that checks if a spy returned a specific value at least once. This is equivalent to toHaveReturnedWith(value).
import { expect, test, vi } from 'vitest'
test('spy returned with value', () => {
const spy = vi.fn()
.mockReturnValueOnce('apple')
.mockReturnValueOnce('banana')
spy()
spy()
expect(spy).to.have.returnedWith('apple')
expect(spy).to.have.returnedWith('banana')
})returnedTimes 4.1.0 {#returnedtimes}
- Type:
(count: number) => void
Chai-style assertion that checks if a spy returned successfully a specific number of times. This is equivalent to toHaveReturnedTimes(count).
import { expect, test, vi } from 'vitest'
test('spy returned times', () => {
const spy = vi.fn(() => 'result')
spy()
spy()
spy()
expect(spy).to.have.returnedTimes(3)
})lastReturnedWith
- Type:
(value: any) => void
Chai-style assertion that checks if the last return value of a spy matches the expected value. This is equivalent to toHaveLastReturnedWith(value).
import { expect, test, vi } from 'vitest'
test('spy last returned with', () => {
const spy = vi.fn()
.mockReturnValueOnce('apple')
.mockReturnValueOnce('banana')
spy()
spy()
expect(spy).to.have.lastReturnedWith('banana')
})nthReturnedWith
- Type:
(n: number, value: any) => void
Chai-style assertion that checks if the nth return value of a spy matches the expected value. This is equivalent to toHaveNthReturnedWith(n, value).
import { expect, test, vi } from 'vitest'
test('spy nth returned with', () => {
const spy = vi.fn()
.mockReturnValueOnce('apple')
.mockReturnValueOnce('banana')
.mockReturnValueOnce('cherry')
spy()
spy()
spy()
expect(spy).to.have.nthReturnedWith(2, 'banana')
})calledBefore 4.1.0 {#calledbefore}
- Type:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => void
Chai-style assertion that checks if a spy was called before another spy. This is equivalent to toHaveBeenCalledBefore(mock, failIfNoFirstInvocation).
import { expect, test, vi } from 'vitest'
test('spy called before another', () => {
const spy1 = vi.fn()
const spy2 = vi.fn()
spy1()
spy2()
expect(spy1).to.have.been.calledBefore(spy2)
})calledAfter 4.1.0 {#calledafter}
- Type:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => void
Chai-style assertion that checks if a spy was called after another spy. This is equivalent to toHaveBeenCalledAfter(mock, failIfNoFirstInvocation).
import { expect, test, vi } from 'vitest'
test('spy called after another', () => {
const spy1 = vi.fn()
const spy2 = vi.fn()
spy1()
spy2()
expect(spy2).to.have.been.calledAfter(spy1)
})::: tip Migration Guide
For a complete guide on migrating from Mocha+Chai+Sinon to Vitest, see the Migration Guide.
:::
toSatisfy
- Type:
(predicate: (value: any) => boolean) => Awaitable<void>
This assertion checks if a value satisfies a certain predicate.
import { describe, expect, it } from 'vitest'
const isOdd = (value: number) => value % 2 !== 0
describe('toSatisfy()', () => {
it('pass with 0', () => {
expect(1).toSatisfy(isOdd)
})
it('pass with negation', () => {
expect(2).not.toSatisfy(isOdd)
})
})resolves
- Type:
Promisify<Assertions>
resolves is intended to remove boilerplate when asserting asynchronous code. Use it to unwrap value from the pending promise and assert its value with usual assertions. If the promise rejects, the assertion will fail.
It returns the same Assertions object, but all matchers now return Promise, so you would need to await it. Also works with chai assertions.
For example, if you have a function, that makes an API call and returns some data, you may use this code to assert its return value:
import { expect, test } from 'vitest'
async function buyApples() {
return fetch('/buy/apples').then(r => r.json())
}
test('buyApples returns new stock id', async () => {
// toEqual returns a promise now, so you HAVE to await it
await expect(buyApples()).resolves.toEqual({ id: 1 }) // jest API
await expect(buyApples()).resolves.to.equal({ id: 1 }) // chai API
}):::warning
If the assertion is not awaited, the test will be marked as "failed" at the end of the test.
:::
rejects
- Type:
Promisify<Assertions>
rejects is intended to remove boilerplate when asserting asynchronous code. Use it to unwrap reason why the promise was rejected, and assert its value with usual assertions. If the promise successfully resolves, the assertion will fail.
It returns the same Assertions object, but all matchers now return Promise, so you would need to await it. Also works with chai assertions.
For example, if you have a function that fails when you call it, you may use this code to assert the reason:
import { expect, test } from 'vitest'
async function buyApples(id) {
if (!id) {
throw new Error('no id')
}
}
test('buyApples throws an error when no id provided', async () => {
// toThrow returns a promise now, so you HAVE to await it
await expect(buyApples()).rejects.toThrow('no id')
}):::warning
If the assertion is not awaited, the test will be marked as "failed" at the end of the test.
:::
expect.assertions
- Type:
(count: number) => void
After the test has passed or failed verify that a certain number of assertions was called during a test. A useful case would be to check if an asynchronous code was called.
For example, if we have a function that asynchronously calls two matchers, we can assert that they were actually called.
import { expect, test } from 'vitest'
async function doAsync(...cbs) {
await Promise.all(
cbs.map((cb, index) => cb({ index })),
)
}
test('all assertions are called', async () => {
expect.assertions(2)
function callback1(data) {
expect(data).toBeTruthy()
}
function callback2(data) {
expect(data).toBeTruthy()
}
await doAsync(callback1, callback2)
})::: warning
When using assertions with async concurrent tests, expect from the local Test Context must be used to ensure the right test is detected.
:::
expect.hasAssertions
- Type:
() => void
After the test has passed or failed verify that at least one assertion was called during a test. A useful case would be to check if an asynchronous code was called.
For example, if you have a code that calls a callback, we can make an assertion inside a callback, but the test will always pass if we don't check if an assertion was called.
import { expect, test } from 'vitest'
import { db } from './db.js'
const cbs = []
function onSelect(cb) {
cbs.push(cb)
}
// after selecting from db, we call all callbacks
function select(id) {
return db.select({ id }).then((data) => {
return Promise.all(
cbs.map(cb => cb(data)),
)
})
}
test('callback was called', async () => {
expect.hasAssertions()
onSelect((data) => {
// should be called on select
expect(data).toBeTruthy()
})
// if not awaited, test will fail
// if you don't have expect.hasAssertions(), test will pass
await select(3)
})expect.unreachable
- Type:
(message?: string) => never
This method is used to assert that a line should never be reached.
For example, if we want to test that build() throws due to receiving directories having no src folder, and also handle each error separately, we could do this:
import { expect, test } from 'vitest'
async function build(dir) {
if (dir.includes('no-src')) {
throw new Error(`${dir}/src does not exist`)
}
}
const errorDirs = [
'no-src-folder',
// ...
]
test.each(errorDirs)('build fails with "%s"', async (dir) => {
try {
await build(dir)
expect.unreachable('Should not pass build')
}
catch (err: any) {
expect(err).toBeInstanceOf(Error)
expect(err.stack).toContain('build')
switch (dir) {
case 'no-src-folder':
expect(err.message).toBe(`${dir}/src does not exist`)
break
default:
// to exhaust all error tests
expect.unreachable('All error test must be handled')
break
}
}
})expect.fail
- Type:
(message?: string) => never
Explicitly forces a test failure with an optional custom message.
For example, you can use it inside a try/catch block to ensure an error was thrown:
import { expect, test } from 'vitest'
test('fails when error is not thrown', async () => {
try {
await performAction()
expect.fail('Expected performAction to throw an error')
}
catch (error) {
expect(error).toBeInstanceOf(CustomError)
}
})expect.anything
- Type:
() => any
This asymmetric matcher matches anything except null or undefined. Useful if you just want to be sure that a property exists with any value that's not either null or undefined.
import { expect, test } from 'vitest'
test('object has "apples" key', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() })
})expect.any
- Type:
(constructor: unknown) => any
This asymmetric matcher, when used with an equality check, will return true only if the value is an instance of a specified constructor. Useful, if you have a value that is generated each time, and you only want to know that it exists with a proper type.
import { expect, test } from 'vitest'
import { generateId } from './generators.js'
test('"id" is a number', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) })
})expect.closeTo {#expect-closeto}
- Type:
(expected: any, precision?: number) => any
expect.closeTo is useful when comparing floating point numbers in object properties or array item. If you need to compare a number, please use .toBeCloseTo instead.
The optional precision argument limits the number of digits to check after the decimal point. For the default value 2, the test criterion is Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).
For example, this test passes with a precision of 5 digits:
test('compare float in object properties', () => {
expect({
title: '0.1 + 0.2',
sum: 0.1 + 0.2,
}).toEqual({
title: '0.1 + 0.2',
sum: expect.closeTo(0.3, 5),
})
})expect.arrayContaining
- Type:
<T>(expected: T[]) => any
When used with an equality check, this asymmetric matcher will return true if the value is an array and contains specified items.
import { expect, test } from 'vitest'
test('basket includes fuji', () => {
const basket = {
varieties: [
'Empire',
'Fuji',
'Gala',
],
count: 3
}
expect(basket).toEqual({
count: 3,
varieties: expect.arrayContaining(['Fuji'])
})
}):::tip
You can use expect.not with this matcher to negate the expected value.
:::
expect.objectContaining
- Type:
(expected: any) => any
When used with an equality check, this asymmetric matcher will return true if the value has a similar shape.
import { expect, test } from 'vitest'
test('basket has empire apples', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
}
],
}
expect(basket).toEqual({
varieties: [
expect.objectContaining({ name: 'Empire' }),
]
})
}):::tip
You can use expect.not with this matcher to negate the expected value.
:::
expect.stringContaining
- Type:
(expected: any) => any
When used with an equality check, this asymmetric matcher will return true if the value is a string and contains a specified substring.
import { expect, test } from 'vitest'
test('variety has "Emp" in its name', () => {
const variety = {
name: 'Empire',
count: 1,
}
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
})
}):::tip
You can use expect.not with this matcher to negate the expected value.
:::
expect.stringMatching
- Type:
(expected: any) => any
When used with an equality check, this asymmetric matcher will return true if the value is a string and contains a specified substring or if the string matches a regular expression.
import { expect, test } from 'vitest'
test('variety ends with "re"', () => {
const variety = {
name: 'Empire',
count: 1,
}
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
})
}):::tip
You can use expect.not with this matcher to negate the expected value.
:::
expect.schemaMatching
- Type:
(expected: StandardSchemaV1) => any
When used with an equality check, this asymmetric matcher will return true if the value matches the provided schema. The schema must implement the Standard Schema v1 specification.
import { expect, test } from 'vitest'
import { z } from 'zod'
import * as v from 'valibot'
import { type } from 'arktype'
test('email validation', () => {
const user = { email: '[email protected]' }
// using Zod
expect(user).toEqual({
email: expect.schemaMatching(z.string().email()),
})
// using Valibot
expect(user).toEqual({
email: expect.schemaMatching(v.pipe(v.string(), v.email()))
})
// using ArkType
expect(user).toEqual({
email: expect.schemaMatching(type('string.email')),
})
}):::tip
You can use expect.not with this matcher to negate the expected value.
:::
expect.addSnapshotSerializer
- Type:
(plugin: PrettyFormatPlugin) => void
This method adds custom serializers that are called when creating a snapshot. This is an advanced feature - if you want to know more, please read a guide on custom serializers.
If you are adding custom serializers, you should call this method inside setupFiles. This will affect every snapshot.
:::tip
If you previously used Vue CLI with Jest, you might want to install jest-serializer-vue. Otherwise, your snapshots will be wrapped in a string, which cases " to be escaped.
:::
expect.extend
- Type:
(matchers: MatchersObject) => void
You can extend default matchers with your own. This function is used to extend the matchers object with custom matchers.
When you define matchers that way, you also create asymmetric matchers that can be used like expect.stringContaining.
import { expect, test } from 'vitest'
test('custom matchers', () => {
expect.extend({
toBeFoo(received) {
const { isNot } = this
return {
message: () => `expected ${received} is${isNot ? ' not' : ''} foo`,
pass: received === 'foo',
}
},
})
expect('foo').toBeFoo()
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() })
})::: tip
If you want your matchers to appear in every test, you should call this method inside setupFiles.
:::
This function is compatible with Jest's expect.extend, so any library that uses it to create custom matchers will work with Vitest.
If you are using TypeScript, you can extend the default Matchers interface in an ambient declaration file (e.g: vitest.d.ts) with the code below:
import 'vitest'
declare module 'vitest' {
interface Matchers<R, T> {
toBeFoo: () => R
}
}R is the assertion return type, and T is the type of the received value.
::: warning
Don't forget to include the ambient declaration file in your tsconfig.json.
:::
:::tip
If you want to know more, checkout guide on extending matchers.
:::
expect.addEqualityTesters {#expect-addequalitytesters}
- Type:
(tester: Array<Tester>) => void
You can use this method to define custom testers, which are methods used by matchers, to test if two objects are equal. It is compatible with Jest's expect.addEqualityTesters.
import { expect, test } from 'vitest'
class AnagramComparator {
public word: string
constructor(word: string) {
this.word = word
}
equals(other: AnagramComparator): boolean {
const cleanStr1 = this.word.replace(/ /g, '').toLowerCase()
const cleanStr2 = other.word.replace(/ /g, '').toLowerCase()
const sortedStr1 = cleanStr1.split('').sort().join('')
const sortedStr2 = cleanStr2.split('').sort().join('')
return sortedStr1 === sortedStr2
}
}
function isAnagramComparator(a: unknown): a is AnagramComparator {
return a instanceof AnagramComparator
}
function areAnagramsEqual(a: unknown, b: unknown): boolean | undefined {
const isAAnagramComparator = isAnagramComparator(a)
const isBAnagramComparator = isAnagramComparator(b)
if (isAAnagramComparator && isBAnagramComparator) {
return a.equals(b)
}
else if (isAAnagramComparator === isBAnagramComparator) {
return undefined
}
else {
return false
}
}
expect.addEqualityTesters([areAnagramsEqual])
test('custom equality tester', () => {
expect(new AnagramComparator('listen')).toEqual(new AnagramComparator('silent'))
})File: docs/api/expect-typeof.md
expectTypeOf
::: warning
During runtime this function doesn't do anything. To enable typechecking, don't forget to pass down --typecheck flag.
:::
- Type:
<T>(a: unknown) => ExpectTypeOf
not
- Type:
ExpectTypeOf
You can negate all assertions, using .not property.
toEqualTypeOf
- Type:
<T>(expected: T) => void
This matcher will check if the types are fully equal to each other. This matcher will not fail if two objects have different values, but the same type. It will fail however if an object is missing a property.
import { expectTypeOf } from 'vitest'
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>()
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 })
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 })
expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>()toMatchTypeOf
- Type:
<T>(expected: T) => void
::: warning DEPRECATED
This matcher has been deprecated since expect-type v1.2.0. Use toExtend instead.
:::
This matcher checks if expect type extends provided type. It is different from toEqual and is more similar to expect's toMatchObject(). With this matcher, you can check if an object “matches” a type.
import { expectTypeOf } from 'vitest'
expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 1 })
expectTypeOf<number>().toMatchTypeOf<string | number>()
expectTypeOf<string | number>().not.toMatchTypeOf<number>()toExtend
- Type:
<T>(expected: T) => void
This matcher checks if expect type extends provided type. It is different from toEqual and is more similar to expect's toMatchObject(). With this matcher, you can check if an object "matches" a type.
import { expectTypeOf } from 'vitest'
expectTypeOf({ a: 1, b: 1 }).toExtend({ a: 1 })
expectTypeOf<number>().toExtend<string | number>()
expectTypeOf<string | number>().not.toExtend<number>()toMatchObjectType
- Type:
() => void
This matcher performs a strict check on object types, ensuring that the expected type matches the provided object type. It's stricter than toExtend and is the recommended choice when working with object types as it's more likely to catch issues like readonly properties.
import { expectTypeOf } from 'vitest'
expectTypeOf({ a: 1, b: 2 }).toMatchObjectType<{ a: number }>() // preferred
expectTypeOf({ a: 1, b: 2 }).toExtend<{ a: number }>() // works but less strict
// Supports nested object checking
const user = {
name: 'John',
address: { city: 'New York', zip: '10001' }
}
expectTypeOf(user).toMatchObjectType<{ name: string; address: { city: string } }>()::: warning
This matcher only works with plain object types. It will fail for union types and other complex types. For those cases, use toExtend instead.
:::
extract
- Type:
ExpectTypeOf<ExtractedUnion>
You can use .extract to narrow down types for further testing.
import { expectTypeOf } from 'vitest'
type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T }
interface CSSProperties { margin?: string; padding?: string }
function getResponsiveProp<T>(_props: T): ResponsiveProp<T> {
return {}
}
const cssProperties: CSSProperties = { margin: '1px', padding: '2px' }
expectTypeOf(getResponsiveProp(cssProperties))
.extract<{ xs?: any }>() // extracts the last type from a union
.toEqualTypeOf<{ xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties }>()
expectTypeOf(getResponsiveProp(cssProperties))
.extract() // extracts an array from a union
.toEqualTypeOf<CSSProperties[]>()::: warning
If no type is found in the union, .extract will return never.
:::
exclude
- Type:
ExpectTypeOf<NonExcludedUnion>
You can use .exclude to remove types from a union for further testing.
import { expectTypeOf } from 'vitest'
type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T }
interface CSSProperties { margin?: string; padding?: string }
function getResponsiveProp<T>(_props: T): ResponsiveProp<T> {
return {}
}
const cssProperties: CSSProperties = { margin: '1px', padding: '2px' }
expectTypeOf(getResponsiveProp(cssProperties))
.exclude()
.exclude<{ xs?: unknown }>() // or just .exclude()
.toEqualTypeOf<CSSProperties>()::: warning
If no type is found in the union, .exclude will return never.
:::
returns
- Type:
ExpectTypeOf<ReturnValue>
You can use .returns to extract return value of a function type.
import { expectTypeOf } from 'vitest'
expectTypeOf(() => {}).returns.toBeVoid()
expectTypeOf((a: number) => [a, a]).returns.toEqualTypeOf([1, 2])::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
parameters
- Type:
ExpectTypeOf
You can extract function arguments with .parameters to perform assertions on its value. Parameters are returned as an array.
import { expectTypeOf } from 'vitest'
type NoParam = () => void
type HasParam = (s: string) => void
expectTypeOf<NoParam>().parameters.toEqualTypeOf<[]>()
expectTypeOf<HasParam>().parameters.toEqualTypeOf<[string]>()::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
::: tip
You can also use .toBeCallableWith matcher as a more expressive assertion.
:::
parameter
- Type:
(nth: number) => ExpectTypeOf
You can extract a certain function argument with .parameter(number) call to perform other assertions on it.
import { expectTypeOf } from 'vitest'
function foo(a: number, b: string) {
return [a, b]
}
expectTypeOf(foo).parameter(0).toBeNumber()
expectTypeOf(foo).parameter(1).toBeString()::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
constructorParameters
- Type:
ExpectTypeOf<ConstructorParameters>
You can extract constructor parameters as an array of values and perform assertions on them with this method.
import { expectTypeOf } from 'vitest'
expectTypeOf(Date).constructorParameters.toEqualTypeOf<[] | [string | number | Date]>()::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
::: tip
You can also use .toBeConstructibleWith matcher as a more expressive assertion.
:::
instance
- Type:
ExpectTypeOf<ConstructableInstance>
This property gives access to matchers that can be performed on an instance of the provided class.
import { expectTypeOf } from 'vitest'
expectTypeOf(Date).instance.toHaveProperty('toISOString')::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
items
- Type:
ExpectTypeOf<T>
You can get array item type with .items to perform further assertions.
import { expectTypeOf } from 'vitest'
expectTypeOf([1, 2, 3]).items.toEqualTypeOf<number>()
expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf<string>()resolves
- Type:
ExpectTypeOf<ResolvedPromise>
This matcher extracts resolved value of a Promise, so you can perform other assertions on it.
import { expectTypeOf } from 'vitest'
async function asyncFunc() {
return 123
}
expectTypeOf(asyncFunc).returns.resolves.toBeNumber()
expectTypeOf(Promise.resolve('string')).resolves.toBeString()::: warning
If used on a non-promise type, it will return never, so you won't be able to chain it with other matchers.
:::
guards
- Type:
ExpectTypeOf<Guard>
This matcher extracts guard value (e.g., v is number), so you can perform assertions on it.
import { expectTypeOf } from 'vitest'
function isString(v: any): v is string {
return typeof v === 'string'
}
expectTypeOf(isString).guards.toBeString()::: warning
Returns never, if the value is not a guard function, so you won't be able to chain it with other matchers.
:::
asserts
- Type:
ExpectTypeOf<Assert>
This matcher extracts assert value (e.g., assert v is number), so you can perform assertions on it.
import { expectTypeOf } from 'vitest'
function assertNumber(v: any): asserts v is number {
if (typeof v !== 'number') {
throw new TypeError('Nope !')
}
}
expectTypeOf(assertNumber).asserts.toBeNumber()::: warning
Returns never, if the value is not an assert function, so you won't be able to chain it with other matchers.
:::
toBeAny
- Type:
() => void
With this matcher you can check, if provided type is any type. If the type is too specific, the test will fail.
import { expectTypeOf } from 'vitest'
expectTypeOf<any>().toBeAny()
expectTypeOf({} as any).toBeAny()
expectTypeOf('string').not.toBeAny()toBeUnknown
- Type:
() => void
This matcher checks, if provided type is unknown type.
import { expectTypeOf } from 'vitest'
expectTypeOf().toBeUnknown()
expectTypeOf({} as unknown).toBeUnknown()
expectTypeOf('string').not.toBeUnknown()toBeNever
- Type:
() => void
This matcher checks, if provided type is a never type.
import { expectTypeOf } from 'vitest'
expectTypeOf<never>().toBeNever()
expectTypeOf((): never => {}).returns.toBeNever()toBeFunction
- Type:
() => void
This matcher checks, if provided type is a function.
import { expectTypeOf } from 'vitest'
expectTypeOf(42).not.toBeFunction()
expectTypeOf((): never => {}).toBeFunction()toBeObject
- Type:
() => void
This matcher checks, if provided type is an object.
import { expectTypeOf } from 'vitest'
expectTypeOf(42).not.toBeObject()
expectTypeOf({}).toBeObject()toBeArray
- Type:
() => void
This matcher checks, if provided type is Array<T>.
import { expectTypeOf } from 'vitest'
expectTypeOf(42).not.toBeArray()
expectTypeOf([]).toBeArray()
expectTypeOf([1, 2]).toBeArray()
expectTypeOf([{}, 42]).toBeArray()toBeString
- Type:
() => void
This matcher checks, if provided type is a string.
import { expectTypeOf } from 'vitest'
expectTypeOf(42).not.toBeString()
expectTypeOf('').toBeString()
expectTypeOf('a').toBeString()toBeBoolean
- Type:
() => void
This matcher checks, if provided type is boolean.
import { expectTypeOf } from 'vitest'
expectTypeOf(42).not.toBeBoolean()
expectTypeOf(true).toBeBoolean()
expectTypeOf().toBeBoolean()toBeVoid
- Type:
() => void
This matcher checks, if provided type is void.
import { expectTypeOf } from 'vitest'
expectTypeOf(() => {}).returns.toBeVoid()
expectTypeOf<void>().toBeVoid()toBeSymbol
- Type:
() => void
This matcher checks, if provided type is a symbol.
import { expectTypeOf } from 'vitest'
expectTypeOf(Symbol(1)).toBeSymbol()
expectTypeOf<symbol>().toBeSymbol()toBeNull
- Type:
() => void
This matcher checks, if provided type is null.
import { expectTypeOf } from 'vitest'
expectTypeOf(null).toBeNull()
expectTypeOf<null>().toBeNull()
expectTypeOf(undefined).not.toBeNull()toBeUndefined
- Type:
() => void
This matcher checks, if provided type is undefined.
import { expectTypeOf } from 'vitest'
expectTypeOf(undefined).toBeUndefined()
expectTypeOf().toBeUndefined()
expectTypeOf(null).not.toBeUndefined()toBeNullable
- Type:
() => void
This matcher checks, if you can use null or undefined with provided type.
import { expectTypeOf } from 'vitest'
expectTypeOf().toBeNullable()
expectTypeOf<null | 1>().toBeNullable()
expectTypeOf().toBeNullable()toBeCallableWith
- Type:
() => void
This matcher ensures you can call provided function with a set of parameters.
import { expectTypeOf } from 'vitest'
type NoParam = () => void
type HasParam = (s: string) => void
expectTypeOf<NoParam>().toBeCallableWith()
expectTypeOf<HasParam>().toBeCallableWith('some string')::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
toBeConstructibleWith
- Type:
() => void
This matcher ensures you can create a new instance with a set of constructor parameters.
import { expectTypeOf } from 'vitest'
expectTypeOf(Date).toBeConstructibleWith(new Date())
expectTypeOf(Date).toBeConstructibleWith('01-01-2000')::: warning
If used on a non-function type, it will return never, so you won't be able to chain it with other matchers.
:::
toHaveProperty
- Type:
<K extends keyof T>(property: K) => ExpectTypeOf<T[K>
This matcher checks if a property exists on the provided object. If it exists, it also returns the same set of matchers for the type of this property, so you can chain assertions one after another.
import { expectTypeOf } from 'vitest'
const obj = { a: 1, b: '' }
expectTypeOf(obj).toHaveProperty('a')
expectTypeOf(obj).not.toHaveProperty('c')
expectTypeOf(obj).toHaveProperty('a').toBeNumber()
expectTypeOf(obj).toHaveProperty('b').toBeString()
expectTypeOf(obj).toHaveProperty('a').not.toBeString()branded
- Type:
ExpectTypeOf
You can use .branded to allow type assertions to succeed for types that are semantically equivalent but differ in representation.
import { expectTypeOf } from 'vitest'
// Without .branded, this fails even though the types are effectively the same
expectTypeOf<{ a: { b: 1 } & { c: 1 } }>().toEqualTypeOf<{ a: { b: 1; c: 1 } }>()
// With .branded, the assertion succeeds
expectTypeOf<{ a: { b: 1 } & { c: 1 } }>().branded.toEqualTypeOf<{ a: { b: 1; c: 1 } }>()::: warning
This helper comes at a performance cost and can cause the TypeScript compiler to 'give up' if used with excessively deep types. Use it sparingly and only when necessary.
:::
File: docs/api/mock.md
Mocks
You can create a mock function or a class to track its execution with the vi.fn method. If you want to track a property on an already created object, you can use the vi.spyOn method:
import { vi } from 'vitest'
const fn = vi.fn()
fn('hello world')
fn.mock.calls[0] === ['hello world']
const market = {
getApples: () => 100
}
const getApplesSpy = vi.spyOn(market, 'getApples')
market.getApples()
getApplesSpy.mock.calls.length === 1You should use mock assertions (e.g., toHaveBeenCalled) on expect to assert mock results. This API reference describes available properties and methods to manipulate mock behavior.
::: warning IMPORTANT
Vitest spies inherit implementation's length property when initialized, but it doesn't override it if the implementation was changed later:
::: code-group
const fn = vi.fn((arg1) => {})
fn.length // == 1
fn.mockImplementation(() => {})
fn.length // == 1const example = {
fn(arg1, arg2) {
// ...
}
}
const fn = vi.spyOn(example, 'fn')
fn.length // == 2
fn.mockImplementation(() => {})
fn.length // == 2:::
::: tip
The custom function implementation in the types below is marked with a generic <T>.
:::
::: warning Class Support {#class-support}
Shorthand methods like mockReturnValue, mockReturnValueOnce, mockResolvedValue and others cannot be used on a mocked class. Class constructors have unintuitive behaviour regarding the return value:
const CorrectDogClass = vi.fn(class {
constructor(public name: string) {}
})
const IncorrectDogClass = vi.fn(class {
constructor(public name: string) {
return { name }
}
})
const Marti = new CorrectDogClass('Marti')
const Newt = new IncorrectDogClass('Newt')
Marti instanceof CorrectDogClass // ✅ true
Newt instanceof IncorrectDogClass // ❌ false!Even though the shapes are the same, the return value from the constructor is assigned to Newt, which is a plain object, not an instance of a mock. Vitest guards you against this behaviour in shorthand methods (but not in mockImplementation!) and throws an error instead.
If you need to mock constructed instance of a class, consider using the class syntax with mockImplementation instead:
mock.mockReturnValue({ hello: () => 'world' }) // [!code --]
mock.mockImplementation(class { hello = () => 'world' }) // [!code ++]If you need to test the behaviour where this is a valid use case, you can use mockImplementation with a constructor:
mock.mockImplementation(class {
constructor(name: string) {
return { name }
}
}):::
getMockImplementation
function getMockImplementation(): T | undefinedReturns the current mock implementation if there is one.
If the mock was created with vi.fn, it will use the provided method as the mock implementation.
If the mock was created with vi.spyOn, it will return undefined unless a custom implementation is provided.
getMockName
function getMockName(): stringUse it to return the name assigned to the mock with the .mockName(name) method. By default, vi.fn() mocks will return 'vi.fn()', while spies created with vi.spyOn will keep the original name.
mockClear
function mockClear(): Mock<T>Clears all information about every call. After calling it, all properties on .mock will return to their initial state. This method does not reset implementations. It is useful for cleaning up mocks between different assertions.
const person = {
greet: (name: string) => `Hello ${name}`,
}
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked')
expect(person.greet('Alice')).toBe('mocked')
expect(spy.mock.calls).toEqual([['Alice']])
// clear call history but keep mock implementation
spy.mockClear()
expect(spy.mock.calls).toEqual([])
expect(person.greet('Bob')).toBe('mocked')
expect(spy.mock.calls).toEqual([['Bob']])To automatically call this method before each test, enable the clearMocks setting in the configuration.
mockName
function mockName(name: string): Mock<T>Sets the internal mock name. This is useful for identifying the mock when an assertion fails.
mockImplementation
function mockImplementation(fn: T): Mock<T>Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1)
// or: vi.fn(apples => apples + 1);
const NelliesBucket = mockFn(0)
const BobsBucket = mockFn(1)
NelliesBucket === 1 // true
BobsBucket === 2 // true
mockFn.mock.calls[0][0] === 0 // true
mockFn.mock.calls[1][0] === 1 // trueIf the implementation is a class, the mock's prototype is re-pointed to the implementation's prototype, so constructed instances see its prototype methods and pass instanceof checks against it. See Mocking Classes for details.
mockImplementationOnce
function mockImplementationOnce(fn: T): Mock<T>Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function. This method can be chained to produce different results for multiple function calls.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1st call
.mockImplementationOnce(() => false) // 2nd call
myMockFn() // 1st call: true
myMockFn() // 2nd call: falseWhen the mocked function runs out of implementations, it will invoke the default implementation set with vi.fn(() => defaultValue) or .mockImplementation(() => defaultValue) if they were called:
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call')
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn())withImplementation
function withImplementation(
fn: T,
cb: () => void
): Mock<T>
function withImplementation(
fn: T,
cb: () => Promise<void>
): Promise<Mock<T>>Overrides the original mock implementation temporarily while the callback is being executed.
const myMockFn = vi.fn(() => 'original')
myMockFn.withImplementation(() => 'temp', () => {
myMockFn() // 'temp'
})
myMockFn() // 'original'Can be used with an asynchronous callback. The method has to be awaited to use the original implementation afterward.
test('async callback', () => {
const myMockFn = vi.fn(() => 'original')
// We await this call since the callback is async
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn() // 'temp'
},
)
myMockFn() // 'original'
})Note that this method takes precedence over the mockImplementationOnce.
mockRejectedValue
function mockRejectedValue(value: unknown): Mock<T>Accepts an error that will be rejected when an async function is called.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
await asyncMock() // throws Error<'Async error'>mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): Mock<T>Accepts a value that will be rejected during the next function call. If chained, each consecutive call will reject the specified value.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'))
await asyncMock() // 'first call'
await asyncMock() // throws Error<'Async error'>mockReset
function mockReset(): Mock<T>Does what mockClear does and resets the mock implementation. This also resets all "once" implementations.
Note that resetting a mock from vi.fn() will set the implementation to an empty function that returns undefined.
Resetting a mock from vi.fn(impl) will reset the implementation to impl.
The mock's prototype chain follows along: it reverts to the original class for vi.fn(impl) and vi.spyOn(), and to a plain object for vi.fn(), so instances constructed after the reset no longer pass instanceof checks against a previously set class implementation.
This is useful when you want to reset a mock to its original state.
const person = {
greet: (name: string) => `Hello ${name}`,
}
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked')
expect(person.greet('Alice')).toBe('mocked')
expect(spy.mock.calls).toEqual([['Alice']])
// clear call history and reset implementation, but method is still spied
spy.mockReset()
expect(spy.mock.calls).toEqual([])
expect(person.greet).toBe(spy)
expect(person.greet('Bob')).toBe('Hello Bob')
expect(spy.mock.calls).toEqual([['Bob']])To automatically call this method before each test, enable the mockReset setting in the configuration.
mockRestore
function mockRestore(): Mock<T>Does what mockReset does and restores the original descriptors of spied-on objects, if the mock was created with vi.spyOn.
mockRestore on a vi.fn() mock is identical to mockReset.
const person = {
greet: (name: string) => `Hello ${name}`,
}
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked')
expect(person.greet('Alice')).toBe('mocked')
expect(spy.mock.calls).toEqual([['Alice']])
// clear call history and restore spied object method
spy.mockRestore()
expect(spy.mock.calls).toEqual([])
expect(person.greet).not.toBe(spy)
expect(person.greet('Bob')).toBe('Hello Bob')
expect(spy.mock.calls).toEqual([])To automatically call this method before each test, enable the restoreMocks setting in the configuration.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): Mock<T>Accepts a value that will be resolved when the async function is called. TypeScript will only accept values that match the return type of the original function.
const asyncMock = vi.fn().mockResolvedValue(42)
await asyncMock() // 42mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): Mock<T>Accepts a value that will be resolved during the next function call. TypeScript will only accept values that match the return type of the original function. If chained, each consecutive call will resolve the specified value.
const asyncMock = vi
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call')
await asyncMock() // first call
await asyncMock() // second call
await asyncMock() // default
await asyncMock() // defaultmockReturnThis
function mockReturnThis(): Mock<T>Use this if you need to return the this context from the method without invoking the actual implementation. This is a shorthand for:
spy.mockImplementation(function () {
return this
})mockReturnValue
function mockReturnValue(value: ReturnType<T>): Mock<T>Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
const mock = vi.fn()
mock.mockReturnValue(42)
mock() // 42
mock.mockReturnValue(43)
mock() // 43mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): Mock<T>Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
When the mocked function runs out of implementations, it will invoke the default implementation set with vi.fn(() => defaultValue) or .mockImplementation(() => defaultValue) if they were called:
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call')
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn())mockThrow 4.1.0 {#mockthrow}
function mockThrow(value: unknown): Mock<T>Accepts a value that will be thrown whenever the mock function is called.
const myMockFn = vi.fn()
myMockFn.mockThrow(new Error('error message'))
myMockFn() // throws Error<'error message'>mockThrowOnce 4.1.0 {#mockthrowonce}
function mockThrowOnce(value: unknown): Mock<T>Accepts a value that will be thrown during the next function call. If chained, every consecutive call will throw the specified value.
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockThrowOnce(new Error('first call error'))
.mockThrowOnce('second call error')
expect(() => myMockFn()).toThrow('first call error')
expect(() => myMockFn()).toThrow('second call error')
expect(myMockFn()).toEqual('default')mock.calls
const calls: Parameters<T>[]This is an array containing all arguments for each call. One item of the array is the arguments of that call.
const fn = vi.fn()
fn('arg1', 'arg2')
fn('arg3')
fn.mock.calls === [
['arg1', 'arg2'], // first call
['arg3'], // second call
]:::warning Objects are Stored by Reference
Note that Vitest always stores objects by reference in all properties of the mock state. This means that if the properties were changed by your code, then some assertions like .toHaveBeenCalledWith will not pass:
const argument = {
value: 0,
}
const fn = vi.fn()
fn(argument) // { value: 0 }
argument.value = 10
expect(fn).toHaveBeenCalledWith({ value: 0 }) // [!code --]
// The equality check is done against the original argument,
// but its property was changed between the call and assertion
expect(fn).toHaveBeenCalledWith({ value: 10 }) // [!code ++]In this case you can clone the argument yourself:
const calledArguments = []
const fn = vi.fn((arg) => {
calledArguments.push(structuredClone(arg))
})
expect(calledArguments[0]).toEqual({ value: 0 }):::
mock.lastCall
const lastCall: Parameters<T> | undefinedThis contains the arguments of the last call. If the mock wasn't called, it will return undefined.
mock.results
interface MockResultReturn<T> {
type: 'return'
/**
* The value that was returned from the function.
* If the function returned a Promise, then this will be a resolved value.
*/
value: T
}
interface MockResultIncomplete {
type: 'incomplete'
value: undefined
}
interface MockResultThrow {
type: 'throw'
/**
* An error that was thrown during function execution.
*/
value: any
}
type MockResult<T>
= | MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete
const results: MockResult<ReturnType<T>>[]This is an array containing all values that were returned from the function. One item of the array is an object with properties type and value. Available types are:
'return'- function returned without throwing.'throw'- function threw a value.'incomplete'- the function did not finish running yet.
The value property contains the returned value or thrown error. If the function returned a Promise, then result will always be 'return' even if the promise was rejected.
const fn = vi.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => { throw new Error('thrown error') })
const result = fn() // returned 'result'
try {
fn() // threw Error
}
catch {}
fn.mock.results === [
// first result
{
type: 'return',
value: 'result',
},
// last result
{
type: 'throw',
value: Error,
},
]mock.settledResults
interface MockSettledResultIncomplete {
type: 'incomplete'
value: undefined
}
interface MockSettledResultFulfilled<T> {
type: 'fulfilled'
value: T
}
interface MockSettledResultRejected {
type: 'rejected'
value: any
}
export type MockSettledResult<T>
= | MockSettledResultFulfilled<T>
| MockSettledResultRejected
| MockSettledResultIncomplete
const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[]An array containing all values that were resolved or rejected by the function.
If the function returned non-promise values, the value will be kept as is, but the type will still says fulfilled or rejected.
Until the value is resolved or rejected, the settledResult type will be incomplete.
const fn = vi.fn().mockResolvedValueOnce('result')
const result = fn()
fn.mock.settledResults === [
{
type: 'incomplete',
value: undefined,
},
]
await result
fn.mock.settledResults === [
{
type: 'fulfilled',
value: 'result',
},
]mock.invocationCallOrder
const invocationCallOrder: number[]This property returns the order of the mock function's execution. It is an array of numbers that are shared between all defined mocks.
const fn1 = vi.fn()
const fn2 = vi.fn()
fn1()
fn2()
fn1()
fn1.mock.invocationCallOrder === [1, 3]
fn2.mock.invocationCallOrder === [2]mock.contexts
const contexts: ThisParameterType<T>[]This property is an array of this values used during each call to the mock function.
const fn = vi.fn()
const context = {}
fn.apply(context)
fn.call(context)
fn.mock.contexts[0] === context
fn.mock.contexts[1] === contextmock.instances
const instances: ReturnType<T>[]This property is an array containing all instances that were created when the mock was called with the new keyword. Note that this is the actual context (this) of the function, not a return value.
::: warning
If the mock was instantiated with new MyClass(), then mock.instances will be an array with one value:
const MyClass = vi.fn()
const a = new MyClass()
MyClass.mock.instances[0] === aIf you return a value from the constructor, it will not be in the instances array, but instead inside results:
const Spy = vi.fn(function () {
return { method: vi.fn() }
})
const a = new Spy()
Spy.mock.instances[0] !== a
Spy.mock.results[0] === a:::
File: docs/api/vi.md
outline: deep
Vi
Vitest provides utility functions to help you out through its vi helper. You can access it globally (when globals configuration is enabled), or import it from vitest directly:
import { vi } from 'vitest'Mock Modules
This section describes the API that you can use when mocking a module. Beware that Vitest doesn't support mocking modules imported using require().
vi.mock
interface MockOptions {
spy?: boolean
}
interface MockFactory<T> {
(importOriginal: () => T): unknown
}
function mock(
path: string,
factory?: MockOptions | MockFactory
): void
function mock<T>(
module: Promise<T>,
factory?: MockOptions | MockFactory<T>
): voidSubstitutes all imported modules from provided path with another module. You can use configured Vite aliases inside a path. The call to vi.mock is hoisted, so it doesn't matter where you call it. It will always be executed before all imports. If you need to reference some variables outside of its scope, you can define them inside vi.hoisted and reference them inside vi.mock.
It is recommended to use vi.mock or vi.hoisted only inside test files. If Vite's module runner is disabled, they will not be hoisted. This is a performance optimisation to avoid ready unnecessary files.
::: warningvi.mock works only for modules that were imported with the import keyword. It doesn't work with require.
In order to hoist vi.mock, Vitest statically analyzes your files. It indicates that vi that was not directly imported from the vitest package (for example, from some utility file) cannot be used. Use vi.mock with vi imported from vitest, or enable globals config option.
Vitest will not mock modules that were imported inside a setup file because they are cached by the time a test file is running. You can call vi.resetModules() inside vi.hoisted to clear all module caches before running a test file.
:::
If the factory function is defined, all imports will return its result. Vitest calls factory only once and caches results for all subsequent imports until vi.unmock or vi.doUnmock is called.
Unlike in jest, the factory can be asynchronous. You can use vi.importActual or a helper with the factory passed in as the first argument, and get the original module inside.
You can also provide an object with a spy property instead of a factory function. If spy is true, then Vitest will automock the module as usual, but it won't override the implementation of exports. This is useful if you just want to assert that the exported method was called correctly by another method.
import { calculator } from './src/calculator.ts'
vi.mock('./src/calculator.ts', { spy: true })
// calls the original implementation,
// but allows asserting the behaviour later
const result = calculator(1, 2)
expect(result).toBe(3)
expect(calculator).toHaveBeenCalledWith(1, 2)
expect(calculator).toHaveReturnedWith(3)Vitest also supports a module promise instead of a string in the vi.mock and vi.doMock methods for better IDE support. When the file is moved, the path will be updated, and importOriginal inherits the type automatically. Using this signature will also enforce factory return type to be compatible with the original module (keeping exports optional).
// @filename: ./path/to/module.js
export declare function total(...numbers: number[]): number
// @filename: test.js
import { vi } from 'vitest'
// ---cut---
vi.mock(import('./path/to/module.js'), async (importOriginal) => {
const mod = await importOriginal() // type is inferred
// ^?
return {
...mod,
// replace some exports
total: vi.fn(),
}
})Under the hood, Vitest still operates on a string and not a module object.
If you are using TypeScript with paths aliases configured in tsconfig.json however, the compiler won't be able to correctly resolve import types.
In order to make it work, make sure to replace all aliased imports, with their corresponding relative paths.
Eg. use import('./path/to/module.js') instead of import('@/module').
::: warningvi.mock is hoisted (in other words, moved) to top of the file. It means that whenever you write it (be it inside beforeEach or test), it will actually be called before that.
This also means that you cannot use any variables inside the factory that are defined outside the factory.
If you need to use variables inside the factory, try vi.doMock. It works the same way but isn't hoisted. Beware that it only mocks subsequent imports.
You can also reference variables defined by vi.hoisted method if it was declared before vi.mock:
import { namedExport } from './path/to/module.js'
const mocks = vi.hoisted(() => {
return {
namedExport: vi.fn(),
}
})
vi.mock('./path/to/module.js', () => {
return {
namedExport: mocks.namedExport,
}
})
vi.mocked(namedExport).mockReturnValue(100)
expect(namedExport()).toBe(100)
expect(namedExport).toBe(mocks.namedExport):::
::: warning
If you are mocking a module with default export, you will need to provide a default key within the returned factory function object. This is an ES module-specific caveat; therefore, jest documentation may differ as jest uses CommonJS modules. For example,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// etc...
}
}):::
If there is a __mocks__ folder alongside a file that you are mocking, and the factory is not provided, Vitest will try to find a file with the same name in the __mocks__ subfolder and use it as an actual module. If you are mocking a dependency, Vitest will try to find a __mocks__ folder in the root of the project (default is process.cwd()). You can tell Vitest where the dependencies are located through the deps.moduleDirectories config option.
For example, you have this file structure:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.jsIf you call vi.mock in a test file without a factory or options provided, it will find a file in the __mocks__ folder to use as a module:
import { vi } from 'vitest'
// axios is a default export from `__mocks__/axios.js`
import axios from 'axios'
// increment is a named export from `src/__mocks__/increment.js`
import { increment } from '../increment.js'
vi.mock('axios')
vi.mock('../increment.js')
axios.get(`/apples/${increment(1)}`)::: warning
Beware that if you don't call vi.mock, modules are not mocked automatically. To replicate Jest's automocking behaviour, you can call vi.mock for each required module inside setupFiles.
:::
If there is no __mocks__ folder or a factory provided, Vitest will import the original module and auto-mock all its exports. For the rules applied, see algorithm.
vi.doMock
function doMock(
path: string,
factory?: MockOptions | MockFactory
): Disposable
function doMock<T>(
module: Promise<T>,
factory?: MockOptions | MockFactory<T>
): DisposableThe same as vi.mock, but it's not hoisted to the top of the file, so you can reference variables in the global file scope. The next dynamic import of the module will be mocked.
::: warning
This will not mock modules that were imported before this was called. Don't forget that all static imports in ESM are always hoisted, so putting this before static import will not force it to be called before the import:
vi.doMock('./increment.js') // this will be called _after_ the import statement
import { increment } from './increment.js':::
export function increment(number) {
return number + 1
}import { beforeEach, test } from 'vitest'
import { increment } from './increment.js'
// the module is not mocked, because vi.doMock is not called yet
increment(1) === 2
let mockedIncrement = 100
beforeEach(() => {
// you can access variables inside a factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }))
})
test('importing the next module imports mocked one', async () => {
// original import WAS NOT MOCKED, because vi.doMock is evaluated AFTER imports
expect(increment(1)).toBe(2)
const { increment: mockedIncrement } = await import('./increment.js')
// new dynamic import returns mocked module
expect(mockedIncrement(1)).toBe(101)
expect(mockedIncrement(1)).toBe(102)
expect(mockedIncrement(1)).toBe(103)
})::: tip
In environments that support Explicit Resource Management, you can use using on the value returned from vi.doMock() to automatically call vi.doUnmock() on the mocked module when the containing block is exited. This is especially useful when mocking a dynamically imported module for a single test case.
it('uses a mocked version of my-module', () => {
using _mockDisposable = vi.doMock('my-module')
const myModule = await import('my-module') // mocked
// my-module is restored here
})
it('uses the normal version of my-module again', () => {
const myModule = await import('my-module') // not mocked
}):::
vi.mocked
function mocked<T>(
object: T,
deep?: boolean
): MaybeMockedDeep<T>
function mocked<T>(
object: T,
options?: { partial?: boolean; deep?: boolean }
): MaybePartiallyMockedDeep<T>Type helper for TypeScript. Just returns the object that was passed.
When partial is true it will expect a Partial<T> as a return value. By default, this will only make TypeScript believe that the first level values are mocked. You can pass down { deep: true } as a second argument to tell TypeScript that the whole object is mocked, if it actually is. You can pass down { partial: true, deep: true } to make nested objects also partial recursively.
export function add(x: number, y: number): number {
return x + y
}
export function fetchSomething(): Promise<Response> {
return fetch('https://vitest.dev/')
}
export function getUser(): { name: string; address: { city: string; zip: string } } {
return { name: 'John', address: { city: 'New York', zip: '10001' } }
}import * as example from './example'
vi.mock('./example')
test('1 + 1 equals 10', async () => {
vi.mocked(example.add).mockReturnValue(10)
expect(example.add(1, 1)).toBe(10)
})
test('mock return value with only partially correct typing', async () => {
vi.mocked(example.fetchSomething).mockResolvedValue(new Response('hello'))
vi.mocked(example.fetchSomething, { partial: true }).mockResolvedValue({ ok: false })
// vi.mocked(example.someFn).mockResolvedValue({ ok: false }) // this is a type error
})
test('mock return value with deep partial typing', async () => {
vi.mocked(example.getUser, { partial: true, deep: true }).mockReturnValue({
address: { city: 'Los Angeles' },
})
expect(example.getUser().address.city).toBe('Los Angeles')
})vi.importActual
function importActual<T>(path: string): Promise<T>Imports module, bypassing all checks if it should be mocked. Can be useful if you want to mock module partially.
vi.mock('./example.js', async () => {
const originalModule = await vi.importActual('./example.js')
return { ...originalModule, get: vi.fn() }
})vi.importMock
function importMock<T>(path: string): Promise<MaybeMockedDeep<T>>Imports a module with all of its properties (including nested properties) mocked. Follows the same rules that vi.mock does. For the rules applied, see algorithm.
vi.unmock
function unmock(path: string | Promise<Module>): voidRemoves module from the mocked registry. All calls to import will return the original module even if it was mocked before. This call is hoisted to the top of the file, so it will only unmock modules that were defined in setupFiles, for example.
vi.doUnmock
function doUnmock(path: string | Promise<Module>): voidThe same as vi.unmock, but is not hoisted to the top of the file. The next import of the module will import the original module instead of the mock. This will not unmock previously imported modules.
export function increment(number) {
return number + 1
}import { increment } from './increment.js'
// increment is already mocked, because vi.mock is hoisted
increment(1) === 100
// this is hoisted, and factory is called before the import on line 1
vi.mock('./increment.js', () => ({ increment: () => 100 }))
// all calls are mocked, and `increment` always returns 100
increment(1) === 100
increment(30) === 100
// this is not hoisted, so other import will return unmocked module
vi.doUnmock('./increment.js')
// this STILL returns 100, because `vi.doUnmock` doesn't reevaluate a module
increment(1) === 100
increment(30) === 100
// the next import is unmocked, now `increment` is the original function that returns count + 1
const { increment: unmockedIncrement } = await import('./increment.js')
unmockedIncrement(1) === 2
unmockedIncrement(30) === 31vi.resetModules
function resetModules(): VitestResets modules registry by clearing the cache of all modules. This allows modules to be reevaluated when reimported. Top-level imports cannot be re-evaluated. Might be useful to isolate modules where local state conflicts between tests.
import { vi } from 'vitest'
import { data } from './data.js' // Will not get reevaluated beforeEach test
beforeEach(() => {
vi.resetModules()
})
test('change state', async () => {
const mod = await import('./some/path.js') // Will get reevaluated
mod.changeLocalState('new value')
expect(mod.getLocalState()).toBe('new value')
})
test('module has old state', async () => {
const mod = await import('./some/path.js') // Will get reevaluated
expect(mod.getLocalState()).toBe('old value')
})::: warning
Does not reset mocks registry. To clear mocks registry, use vi.unmock or vi.doUnmock.
:::
vi.dynamicImportSettled
function dynamicImportSettled(): Promise<void>Wait for all imports to load. Useful, if you have a synchronous call that starts importing a module that you cannot wait otherwise.
import { expect, test } from 'vitest'
// cannot track import because Promise is not returned
function renderComponent() {
import('./component.js').then(({ render }) => {
render()
})
}
test('operations are resolved', async () => {
renderComponent()
await vi.dynamicImportSettled()
expect(document.querySelector('.component')).not.toBeNull()
})::: tip
If during a dynamic import another dynamic import is initiated, this method will wait until all of them are resolved.
This method will also wait for the next setTimeout tick after the import is resolved so all synchronous operations should be completed by the time it's resolved.
:::
Mocking Functions and Objects
This section describes how to work with method mocks and replace environmental and global variables.
vi.fn
function fn(fn?: Procedure | Constructable): MockCreates a spy on a function, but can also be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Additionally, you can manipulate its behavior with methods.
If no function is given, mock will return undefined when invoked.
const getApples = vi.fn(() => 0)
getApples()
expect(getApples).toHaveBeenCalled()
expect(getApples).toHaveReturnedWith(0)
getApples.mockReturnValueOnce(5)
const res = getApples()
expect(res).toBe(5)
expect(getApples).toHaveNthReturnedWith(2, 5)You can also pass down a class to vi.fn:
const Cart = vi.fn(class {
get() {
return 0
}
})
const cart = new Cart()
expect(Cart).toHaveBeenCalled()
expect(cart.get()).toBe(0)Instances keep the prototype chain of the implementation class, so its prototype methods are available on instances, and instanceof checks against the implementation class pass. See Mocking Classes for details.
vi.mockObject 3.2.0
function mockObject<T>(value: T, options?: MockOptions): MaybeMockedDeep<T>Deeply mocks properties and methods of a given object in the same way as vi.mock() mocks module exports. See automocking for the detail.
const original = {
simple: () => 'value',
nested: {
method: () => 'real'
},
prop: 'foo',
}
const mocked = vi.mockObject(original)
expect(mocked.simple()).toBe(undefined)
expect(mocked.nested.method()).toBe(undefined)
expect(mocked.prop).toBe('foo')
mocked.simple.mockReturnValue('mocked')
mocked.nested.method.mockReturnValue('mocked nested')
expect(mocked.simple()).toBe('mocked')
expect(mocked.nested.method()).toBe('mocked nested')Just like vi.mock(), you can pass { spy: true } as a second argument to keep function implementations:
const spied = vi.mockObject(original, { spy: true })
expect(spied.simple()).toBe('value')
expect(spied.simple).toHaveBeenCalled()
expect(spied.simple.mock.results[0]).toEqual({ type: 'return', value: 'value' })vi.isMockFunction
function isMockFunction(fn: unknown): asserts fn is MockChecks that a given parameter is a mock function. If you are using TypeScript, it will also narrow down its type.
vi.clearAllMocks
function clearAllMocks(): VitestCalls .mockClear() on all spies.
This will clear mock history without affecting mock implementations.
vi.resetAllMocks
function resetAllMocks(): VitestCalls .mockReset() on all spies.
This will clear mock history and reset each mock's implementation.
vi.restoreAllMocks
function restoreAllMocks(): VitestThis restores all original implementations on spies created with vi.spyOn.
After the mock was restored, you can spy on it again.
::: warning
This method also does not affect mocks created during automocking.
Note that unlike mock.mockRestore, vi.restoreAllMocks will not clear mock history or reset the mock implementation
:::
vi.spyOn
function spyOn<T, K extends keyof T>(
object: T,
key: K,
accessor?: 'get' | 'set'
): Mock<T[K]>Creates a spy on a method or getter/setter of an object similar to vi.fn(). It returns a mock function.
let apples = 0
const cart = {
getApples: () => 42,
}
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples)
apples = 1
expect(cart.getApples()).toBe(1)
expect(spy).toHaveBeenCalled()
expect(spy).toHaveReturnedWith(1)If the spying method is a class definition, the mock implementations have to use the function or the class keyword:
const cart = {
Apples: class Apples {
getApples() {
return 42
}
}
}
const spy = vi.spyOn(cart, 'Apples')
.mockImplementation(() => ({ getApples: () => 0 })) // [!code --]
// with a function keyword
.mockImplementation(function () {
this.getApples = () => 0
})
// with a custom class
.mockImplementation(class MockApples {
getApples() {
return 0
}
})If you provide an arrow function, you will get <anonymous> is not a constructor error when the mock is called.
With a class implementation, instances keep the prototype chain of that class: prototype methods like getApples are available on instances, and instanceof checks against the implementation class pass. See Mocking Classes for details.
::: tip
In environments that support Explicit Resource Management, you can use using instead of const to automatically call mockRestore on any mocked function when the containing block is exited. This is especially useful for spied methods:
it('calls console.log', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('message')
expect(spy).toHaveBeenCalled()
})
// console.log is restored here:::
::: tip
You can call vi.restoreAllMocks inside afterEach (or enable test.restoreMocks) to restore all methods to their original implementations after every test. This will restore the original object descriptor, so you won't be able to change method's implementation anymore, unless you spy again:
const cart = {
getApples: () => 42,
}
const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10)
console.log(cart.getApples()) // 10
vi.restoreAllMocks()
console.log(cart.getApples()) // 42
spy.mockReturnValue(10)
console.log(cart.getApples()) // still 42!:::
::: tip
It is not possible to spy on exported methods in Browser Mode. Instead, you can spy on every exported method by calling vi.mock("./file-path.js", { spy: true }). This will mock every export but keep its implementation intact, allowing you to assert if the method was called correctly.
import { calculator } from './src/calculator.ts'
vi.mock('./src/calculator.ts', { spy: true })
calculator(1, 2)
expect(calculator).toHaveBeenCalledWith(1, 2)
expect(calculator).toHaveReturned(3)And while it is possible to spy on exports in jsdom or other Node.js environments, this might change in the future.
:::
vi.stubEnv {#vi-stubenv}
function stubEnv<T extends string>(
name: T,
value: T extends 'PROD' | 'DEV' | 'SSR' ? boolean : string | undefined
): VitestChanges the value of environmental variable on process.env and import.meta.env. You can restore its value by calling vi.unstubAllEnvs.
import { vi } from 'vitest'
// `process.env.NODE_ENV` and `import.meta.env.NODE_ENV`
// are "development" before calling "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production')
process.env.NODE_ENV === 'production'
import.meta.env.NODE_ENV === 'production'
vi.stubEnv('NODE_ENV', undefined)
process.env.NODE_ENV === undefined
import.meta.env.NODE_ENV === undefined
// doesn't change other envs
import.meta.env.MODE === 'development':::tip
You can also change the value by simply assigning it, but you won't be able to use vi.unstubAllEnvs to restore previous value:
import.meta.env.MODE = 'test':::
vi.unstubAllEnvs {#vi-unstuballenvs}
function unstubAllEnvs(): VitestRestores all import.meta.env and process.env values that were changed with vi.stubEnv. When it's called for the first time, Vitest remembers the original value and will store it, until unstubAllEnvs is called again.
import { vi } from 'vitest'
// `process.env.NODE_ENV` and `import.meta.env.NODE_ENV`
// are "development" before calling stubEnv
vi.stubEnv('NODE_ENV', 'production')
process.env.NODE_ENV === 'production'
import.meta.env.NODE_ENV === 'production'
vi.stubEnv('NODE_ENV', 'staging')
process.env.NODE_ENV === 'staging'
import.meta.env.NODE_ENV === 'staging'
vi.unstubAllEnvs()
// restores to the value that were stored before the first "stubEnv" call
process.env.NODE_ENV === 'development'
import.meta.env.NODE_ENV === 'development'vi.stubGlobal
function stubGlobal(
name: string | number | symbol,
value: unknown
): VitestChanges the value of global variable. You can restore its original value by calling vi.unstubAllGlobals.
import { vi } from 'vitest'
// `innerWidth` is "0" before calling stubGlobal
vi.stubGlobal('innerWidth', 100)
innerWidth === 100
globalThis.innerWidth === 100
// if you are using jsdom or happy-dom
window.innerWidth === 100:::tip
You can also change the value by simply assigning it to globalThis or window (if you are using jsdom or happy-dom environment), but you won't be able to use vi.unstubAllGlobals to restore original value:
globalThis.innerWidth = 100
// if you are using jsdom or happy-dom
window.innerWidth = 100:::
vi.unstubAllGlobals {#vi-unstuballglobals}
function unstubAllGlobals(): VitestRestores all global values on globalThis/global (and window/top/self/parent, if you are using jsdom or happy-dom environment) that were changed with vi.stubGlobal. When it's called for the first time, Vitest remembers the original value and will store it, until unstubAllGlobals is called again.
import { vi } from 'vitest'
const Mock = vi.fn()
// IntersectionObserver is "undefined" before calling "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock)
IntersectionObserver === Mock
global.IntersectionObserver === Mock
globalThis.IntersectionObserver === Mock
// if you are using jsdom or happy-dom
window.IntersectionObserver === Mock
vi.unstubAllGlobals()
globalThis.IntersectionObserver === undefined
'IntersectionObserver' in globalThis === false
// throws ReferenceError, because it's not defined
IntersectionObserver === undefinedvi.when 5.0.0 {#vi-when}
interface WhenOptions {
onUnmatched?: 'throw' | 'passthrough' | ((...args: unknown[]) => unknown)
}
interface BehaviorOptions {
times?: number
}
function when(spy: Mock, options?: WhenOptions): WhenDefines per-argument behaviors on a spy, replacing its implementation for the duration of the when chain.
Call .calledWith(...args) on the returned object to specify which call arguments to match, then chain one or more then* methods to declare what the spy should return, throw, or resolve when invoked with those arguments. Arguments are matched with deep equality and support asymmetric matchers such as expect.any().
const spy = vi.fn()
vi.when(spy)
.calledWith(1)
.thenReturn('one')
.calledWith(2)
.thenReturn('two')
expect(spy(1)).toBe('one')
expect(spy(2)).toBe('two')Available then* methods:
| Method | Description |
|---|---|
thenReturn(value, options?) |
Returns value. |
thenReturnOnce(value) |
Returns value once, then falls back. |
thenThrow(error, options?) |
Throws error. |
thenThrowOnce(error) |
Throws error once, then falls back. |
thenResolve(value, options?) |
Returns a resolved Promise with value. |
thenResolveOnce(value) |
Resolves once, then falls back. |
thenReject(error, options?) |
Returns a rejected Promise with error. |
thenRejectOnce(error) |
Rejects once, then falls back. |
The optional times option limits how many times a behavior applies before being exhausted. Behaviors registered for the same arguments are consumed last-in-first-out: the most recently registered behavior is tried first, and once exhausted, earlier ones act as fallbacks.
const spy = vi.fn<(key: string) => string>()
vi.when(spy)
.calledWith('theme')
.thenReturn('light') // fallback, applies indefinitely
.thenReturn('dark', { times: 2 }) // applied first for the next 2 calls
expect(spy('theme')).toBe('dark')
expect(spy('theme')).toBe('dark')
expect(spy('theme')).toBe('light') // falls backWhen called with arguments that match no registered behavior, the spy falls through to its original implementation by default. Use the onUnmatched option to change this:
'passthrough'(default): delegates to the spy's original implementation'throw': throws an error listing the unmatched arguments- a function: called with the unmatched arguments; its return value is used
const spy = vi.fn<(id: number) => string>()
vi.when(spy, { onUnmatched: 'throw' })
.calledWith(1)
.thenReturn('Alice')
expect(spy(1)).toBe('Alice')
expect(() => spy(99)).toThrow() // no behavior defined for 99The When object returned by vi.when supports the toHaveBeenExhausted assertion, which passes once every registered behavior has been consumed.
const spy = vi.fn()
const w = vi.when(spy)
.calledWith(1)
.thenReturnOnce('once')
.calledWith(2)
.thenReturn('always')
expect(w).not.toHaveBeenExhausted()
spy(1) // consumes the `thenReturnOnce` behavior
spy(2) // satisfies `thenReturn` (called at least once)
expect(w).toHaveBeenExhausted()::: tip
In environments that support Explicit Resource Management, you can use using instead of const to automatically restore the spy's original implementation when the containing block exits:
const spy = vi.fn(() => 'original')
{
using w = vi.when(spy)
.calledWith('hello')
.thenReturn('mocked')
expect(spy('hello')).toBe('mocked')
} // ← spy's original implementation is restored here
expect(spy('hello')).toBe('original'):::
vi.isWhenChain 5.0.0 {#vi-iswhenchain}
function isWhenChain(input: object): input is WhenReturns true if the given value is a When chain created by vi.when. If you are using TypeScript, it will also narrow down its type.
const spy = vi.fn()
const w = vi.when(spy).calledWith(1).thenReturn(0)
expect(vi.isWhenChain(w)).toBe(true)
expect(vi.isWhenChain(spy)).toBe(false)Fake Timers
This sections describes how to work with fake timers.
vi.advanceTimersByTime
function advanceTimersByTime(ms: number): VitestThis method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first.
let i = 0
setInterval(() => console.log(++i), 50)
vi.advanceTimersByTime(150)
// log: 1
// log: 2
// log: 3vi.advanceTimersByTimeAsync
function advanceTimersByTimeAsync(ms: number): Promise<Vitest>This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first. This will include asynchronously set timers.
let i = 0
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50)
await vi.advanceTimersByTimeAsync(150)
// log: 1
// log: 2
// log: 3vi.advanceTimersToNextTimer
function advanceTimersToNextTimer(): VitestWill call next available timer. Useful to make assertions between each timer call. You can chain call it to manage timers by yourself.
let i = 0
setInterval(() => console.log(++i), 50)
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer() // log: 3vi.advanceTimersToNextTimerAsync
function advanceTimersToNextTimerAsync(): Promise<Vitest>Will call next available timer and wait until it's resolved if it was set asynchronously. Useful to make assertions between each timer call.
let i = 0
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50)
await vi.advanceTimersToNextTimerAsync() // log: 1
expect(console.log).toHaveBeenCalledWith(1)
await vi.advanceTimersToNextTimerAsync() // log: 2
await vi.advanceTimersToNextTimerAsync() // log: 3vi.advanceTimersToNextFrame {#vi-advancetimerstonextframe}
function advanceTimersToNextFrame(): VitestSimilar to vi.advanceTimersByTime, but will advance timers by the milliseconds needed to execute callbacks currently scheduled with requestAnimationFrame.
let frameRendered = false
requestAnimationFrame(() => {
frameRendered = true
})
vi.advanceTimersToNextFrame()
expect(frameRendered).toBe(true)vi.getTimerCount
function getTimerCount(): numberGet the number of waiting timers.
vi.clearAllTimers
function clearAllTimers(): voidRemoves all timers that are scheduled to run. These timers will never run in the future.
vi.getMockedSystemTime
function getMockedSystemTime(): Date | nullReturns mocked current date. If date is not mocked the method will return null.
vi.getRealSystemTime
function getRealSystemTime(): numberWhen using vi.useFakeTimers, Date.now calls are mocked. If you need to get real time in milliseconds, you can call this function.
vi.runAllTicks
function runAllTicks(): VitestCalls every microtask that was queued by process.nextTick. This will also run all microtasks scheduled by themselves.
vi.runAllTimers
function runAllTimers(): VitestThis method will invoke every initiated timer until the timer queue is empty. It means that every timer called during runAllTimers will be fired. If you have an infinite interval, it will throw after 10 000 tries (can be configured with fakeTimers.loopLimit).
let i = 0
setTimeout(() => console.log(++i))
const interval = setInterval(() => {
console.log(++i)
if (i === 3) {
clearInterval(interval)
}
}, 50)
vi.runAllTimers()
// log: 1
// log: 2
// log: 3vi.runAllTimersAsync
function runAllTimersAsync(): Promise<Vitest>This method will asynchronously invoke every initiated timer until the timer queue is empty. It means that every timer called during runAllTimersAsync will be fired even asynchronous timers. If you have an infinite interval,
it will throw after 10 000 tries (can be configured with fakeTimers.loopLimit).
setTimeout(async () => {
console.log(await Promise.resolve('result'))
}, 100)
await vi.runAllTimersAsync()
// log: resultvi.runOnlyPendingTimers
function runOnlyPendingTimers(): VitestThis method will call every timer that was initiated after vi.useFakeTimers call. It will not fire any timer that was initiated during its call.
let i = 0
setInterval(() => console.log(++i), 50)
vi.runOnlyPendingTimers()
// log: 1vi.runOnlyPendingTimersAsync
function runOnlyPendingTimersAsync(): Promise<Vitest>This method will asynchronously call every timer that was initiated after vi.useFakeTimers call, even asynchronous ones. It will not fire any timer that was initiated during its call.
setTimeout(() => {
console.log(1)
}, 100)
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2)
setInterval(() => {
console.log(3)
}, 40)
})
}, 10)
await vi.runOnlyPendingTimersAsync()
// log: 2
// log: 3
// log: 3
// log: 1vi.setSystemTime
function setSystemTime(date: string | number | Date): VitestIf fake timers are enabled, this method simulates a user changing the system clock (will affect date related API like hrtime, performance.now or new Date()) - however, it will not fire any timers. If fake timers are not enabled, this method will only mock Date.* and Temporal.Now.* calls.
Useful if you need to test anything that depends on the current date - for example Luxon calls inside your code.
Accepts the same string and number arguments as the Date.
const date = new Date(1998, 11, 19)
vi.useFakeTimers()
vi.setSystemTime(date)
expect(Date.now()).toBe(date.valueOf())
vi.useRealTimers()vi.useFakeTimers
function useFakeTimers(config?: FakeTimersConfig): VitestTo enable mocking timers, you need to call this method. It will wrap all further calls to timers (such as setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate, and Date) until vi.useRealTimers() is called.
Mocking nextTick is not supported when running Vitest inside node:child_process by using --pool=forks. NodeJS uses process.nextTick internally in node:child_process and hangs when it is mocked. Mocking nextTick is supported when running Vitest with --pool=threads.
The implementation is based internally on @sinonjs/fake-timers.
::: tipvi.useFakeTimers() does not automatically mock process.nextTick and queueMicrotask.
But you can enable it by specifying the option in toFake argument: vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] }).
:::
You can use toFake to specify which timers to mock, or toNotFake to specify which timers to keep native. Note that toFake and toNotFake cannot be specified together.
// only mock setTimeout and clearTimeout
vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] })
// mock all timers except setInterval
vi.useFakeTimers({ toNotFake: ['setInterval'] })vi.setTimerTickMode 4.1.0 {#vi-settimertickmode}
- Type:
(mode: 'manual' | 'nextTimerAsync') => Vitest | (mode: 'interval', interval?: number) => Vitest
Controls how fake timers are advanced.
manual: The default behavior. Timers will only advance when you call one ofvi.advanceTimers...()methods.nextTimerAsync: Timers will be advanced automatically to the next available timer after each macrotask.interval: Timers are advanced automatically by a specified interval.
When mode is 'interval', you can also provide an interval in milliseconds.
Example:
import { vi } from 'vitest'
vi.useFakeTimers()
// Manual mode (default)
vi.setTimerTickMode('manual')
let i = 0
setInterval(() => console.log(++i), 50)
vi.advanceTimersByTime(150) // logs 1, 2, 3
// nextTimerAsync mode
vi.setTimerTickMode('nextTimerAsync')
// Timers will advance automatically after each macrotask
await new Promise(resolve => setTimeout(resolve, 150)) // logs 4, 5, 6
// interval mode (default when 'fakeTimers.shouldAdvanceTime' is `true`)
vi.setTimerTickMode('interval', 50)
// Timers will advance automatically every 50ms
await new Promise(resolve => setTimeout(resolve, 150)) // logs 7, 8, 9vi.isFakeTimers {#vi-isfaketimers}
function isFakeTimers(): booleanReturns true if fake timers are enabled.
vi.useRealTimers
function useRealTimers(): VitestWhen timers have run out, you may call this method to return mocked timers to its original implementations. All timers that were scheduled before will be discarded.
Miscellaneous
A set of useful helper functions that Vitest provides.
vi.waitFor {#vi-waitfor}
function waitFor<T>(
callback: WaitForCallback<T>,
options?: number | WaitForOptions
): Promise<T>Wait for the callback to execute successfully. If the callback throws an error or returns a rejected promise it will continue to wait until it succeeds or times out.
If options is set to a number, the effect is equivalent to setting { timeout: options }.
This is very useful when you need to wait for some asynchronous action to complete, for example, when you start a server and need to wait for it to start.
import { expect, test, vi } from 'vitest'
import { createServer } from './server.js'
test('Server started successfully', async () => {
const server = createServer()
await vi.waitFor(
() => {
if (!server.isReady) {
throw new Error('Server not started')
}
console.log('Server started')
},
{
timeout: 500, // default is 1000
interval: 20, // default is 50
}
)
expect(server.isReady).toBe(true)
})It also works for asynchronous callbacks
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest'
import { getDOMElementAsync, populateDOMAsync } from './dom.js'
test('Element exists in a DOM', async () => {
// start populating DOM
populateDOMAsync()
const element = await vi.waitFor(async () => {
// try to get the element until it exists
const element = await getDOMElementAsync() as HTMLElement | null
expect(element).toBeTruthy()
expect(element.dataset.initialized).toBeTruthy()
return element
}, {
timeout: 500, // default is 1000
interval: 20, // default is 50
})
expect(element).toBeInstanceOf(HTMLElement)
})If vi.useFakeTimers is used, vi.waitFor automatically calls vi.advanceTimersByTime(interval) in every check callback.
vi.waitUntil {#vi-waituntil}
function waitUntil<T>(
callback: WaitUntilCallback<T>,
options?: number | WaitUntilOptions
): Promise<T>This is similar to vi.waitFor, but if the callback throws any errors, execution is immediately interrupted and an error message is received. If the callback returns falsy value, the next check will continue until truthy value is returned. This is useful when you need to wait for something to exist before taking the next step.
Look at the example below. We can use vi.waitUntil to wait for the element to appear on the page, and then we can do something with the element.
import { expect, test, vi } from 'vitest'
test('Element render correctly', async () => {
const element = await vi.waitUntil(
() => document.querySelector('.element'),
{
timeout: 500, // default is 1000
interval: 20, // default is 50
}
)
// do something with the element
expect(element.querySelector('.element-child')).toBeTruthy()
})vi.hoisted {#vi-hoisted}
function hoisted<T>(factory: () => T): TAll static import statements in ES modules are hoisted to the top of the file, so any code that is defined before the imports will actually be executed after imports are evaluated.
However, it can be useful to invoke some side effects like mocking dates before importing a module.
To bypass this limitation, you can rewrite static imports into dynamic ones like this:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')When running vitest, you can do this automatically by using vi.hoisted method. Under the hood, Vitest will convert static imports into dynamic ones with preserved live-bindings.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())::: warning IMPORTS ARE NOT AVAILABLE
Running code before the imports means that you cannot access imported variables because they are not defined yet:
import { value } from './some/module.js'
vi.hoisted(() => { value }) // throws an error // [!code warning]This code will produce an error:
Cannot access '__vi_import_0__' before initializationIf you need to access a variable from another module inside of vi.hoisted, use dynamic import:
await vi.hoisted(async () => {
const { value } = await import('./some/module.js')
})However, it is discourage to import anything inside of vi.hoisted because imports are already hoisted - if you need to execute something before the tests are running, just execute it in the imported module itself.
:::
This method returns the value that was returned from the factory. You can use that value in your vi.mock factories if you need easy access to locally defined variables:
import { expect, vi } from 'vitest'
import { originalMethod } from './path/to/module.js'
const { mockedMethod } = vi.hoisted(() => {
return { mockedMethod: vi.fn() }
})
vi.mock('./path/to/module.js', () => {
return { originalMethod: mockedMethod }
})
mockedMethod.mockReturnValue(100)
expect(originalMethod()).toBe(100)Note that this method can also be called asynchronously even if your environment doesn't support top-level await:
const json = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts')
return response.json()
})vi.setConfig
function setConfig(config: RuntimeOptions): voidUpdates config for the current test file. This method supports only config options that will affect the current test file:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supports the whole object
},
maxConcurrency: 10,
sequence: {
hooks: 'stack'
// supports only "sequence.hooks"
}
})vi.resetConfig
function resetConfig(): voidIf vi.setConfig was called before, this will reset config to the original state.
vi.defineHelper 4.1.0 {#vi-definehelper}
function defineHelper<F extends (...args: any) => any>(fn: F): FWraps a function to create an assertion helper. When an assertion fails inside the helper, the error stack trace will point to where the helper was called, not inside the helper itself. This makes it easier to identify the source of test failures when using custom assertion functions.
Works with both synchronous and asynchronous functions, and supports expect.soft().
import { expect, vi } from 'vitest'
const assertPair = vi.defineHelper((a, b) => {
expect(a).toEqual(b)
})
test('example', () => {
assertPair('left', 'right') // Error points to this line
})Example output:
FAIL example.test.ts > example
AssertionError: expected 'left' to deeply equal 'right'
Expected: "right"
Received: "left"
❯ example.test.ts:8:3
7| test('example', () => {
8| assertPair('left', 'right')
| ^
9| })