* docs: update API mocking documentation * Apply suggestions from code review Co-authored-by: Anjorin Damilare <damilareanjorin1@gmail.com> * chore: more docs * chore: cleanup Co-authored-by: Anjorin Damilare <damilareanjorin1@gmail.com>
93 KiB
| outline |
|---|
| deep |
API Reference
The following types are used in the type signatures below
type Awaitable<T> = T | PromiseLike<T>
type TestFunction = () => Awaitable<void>
interface TestOptions {
timeout?: number
retry?: number
}
When a test function returns a promise, the runner will wait until it is resolved to collect async expectations. If the promise is rejected, the test will fail.
::: tip
In Jest, TestFunction can also be of type (done: DoneCallback) => void. If this form is used, the test will not be concluded until done is called. You can achieve the same using an async function, see the Migration guide Done Callback section.
:::
test
-
Type:
(name: string, fn: TestFunction, timeout?: number | TestOptions) => void -
Alias:
ittestdefines a set of related expectations. It receives the test name and a function that holds the expectations to test.Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds, and can be configured globally with testTimeout
import { expect, test } from 'vitest' test('should work as expected', () => { expect(Math.sqrt(4)).toBe(2) })
test.skip
-
Type:
(name: string, fn: TestFunction, timeout?: number | TestOptions) => void -
Alias:
it.skipIf you want to skip running certain tests, but you don't want to delete the code due to any reason, you can use
test.skipto avoid running them.import { assert, test } from 'vitest' test.skip('skipped test', () => { // Test skipped, no error assert.equal(Math.sqrt(4), 3) })
test.skipIf
-
Type:
(condition: any) => Test -
Alias:
it.skipIfIn some cases you might run tests multiple times with different environments, and some of the tests might be environment-specific. Instead of wrapping the test code with
if, you can usetest.skipIfto skip the test whenever the condition is truthy.import { assert, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' test.skipIf(isDev)('prod only test', () => { // this test only runs in production })
::: warning You cannot use this syntax, when using Vitest as type checker. :::
test.runIf
-
Type:
(condition: any) => Test -
Alias:
it.runIfOpposite of test.skipIf.
import { assert, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' test.runIf(isDev)('dev only test', () => { // this test only runs in development })
::: warning You cannot use this syntax, when using Vitest as type checker. :::
test.only
-
Type:
(name: string, fn: TestFunction, timeout?: number) => void -
Alias:
it.onlyUse
test.onlyto only run certain tests in a given suite. This is useful when debugging.Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds, and can be configured globally with testTimeout.
import { assert, test } from 'vitest' test.only('test', () => { // Only this test (and others marked with only) are run assert.equal(Math.sqrt(4), 2) })Sometimes it is very useful to run
onlytests in a certain file, ignoring all other tests from the whole test suite, which pollute the output.In order to do that run
vitestwith specific file containing the tests in question.# vitest interesting.test.ts
test.concurrent
-
Type:
(name: string, fn: TestFunction, timeout?: number) => void -
Alias:
it.concurrenttest.concurrentmarks consecutive tests to be run in parallel. It receives the test name, an async function with the tests to collect, and an optional timeout (in milliseconds).import { describe, test } from 'vitest' // The two tests marked with concurrent will be run in parallel describe('suite', () => { test('serial test', async () => { /* ... */ }) test.concurrent('concurrent test 1', async () => { /* ... */ }) test.concurrent('concurrent test 2', async () => { /* ... */ }) })test.skip,test.only, andtest.todoworks with concurrent tests. All the following combinations are valid:test.concurrent(/* ... */) test.skip.concurrent(/* ... */) // or test.concurrent.skip(/* ... */) test.only.concurrent(/* ... */) // or test.concurrent.only(/* ... */) test.todo.concurrent(/* ... */) // or test.concurrent.todo(/* ... */)When using Snapshots with async concurrent tests, due to the limitation of JavaScript, you need to use the
expectfrom the Test Context to ensure the right test is being detected.test.concurrent('test 1', async ({ expect }) => { expect(foo).toMatchSnapshot() }) test.concurrent('test 2', async ({ expect }) => { expect(foo).toMatchSnapshot() })
::: warning You cannot use this syntax, when using Vitest as type checker. :::
test.todo
-
Type:
(name: string) => void -
Alias:
it.todoUse
test.todoto stub tests to be implemented later. An entry will be shown in the report for the tests so you know how many tests you still need to implement.// An entry will be shown in the report for this test test.todo('unimplemented test')
test.fails
-
Type:
(name: string, fn: TestFunction, timeout?: number) => void -
Alias:
it.failsUse
test.failsto indicate that an assertion will fail explicitly.import { expect, test } from 'vitest' const myAsyncFunc = () => new Promise(resolve => resolve(1)) test.fails('fail test', async () => { await expect(myAsyncFunc()).rejects.toBe(1) })
::: warning You cannot use this syntax, when using Vitest as type checker. :::
test.each
-
Type:
(cases: ReadonlyArray<T>, ...args: any[]) => void -
Alias:
it.eachUse
test.eachwhen you need to run the same test with different variables. You can inject parameters with printf formatting in the test name in the order of the test function parameters.%s: string%d: number%i: integer%f: floating point value%j: json%o: object%#: index of the test case%%: single percent sign ('%')
test.each([ [1, 1, 2], [1, 2, 3], [2, 1, 3], ])('add(%i, %i) -> %i', (a, b, expected) => { expect(a + b).toBe(expected) }) // this will return // ✓ add(1, 1) -> 2 // ✓ add(1, 2) -> 3 // ✓ add(2, 1) -> 3You can also access object properties with
$prefix, if you are using objects as arguments:test.each([ { a: 1, b: 1, expected: 2 }, { a: 1, b: 2, expected: 3 }, { a: 2, b: 1, expected: 3 }, ])('add($a, $b) -> $expected', ({ a, b, expected }) => { expect(a + b).toBe(expected) }) // this will return // ✓ add(1, 1) -> 2 // ✓ add(1, 2) -> 3 // ✓ add(2, 1) -> 3You can also access Object attributes with
., if you are using objects as arguments:test.each` a | b | expected ${{ val: 1 }} | ${'b'} | ${'1b'} ${{ val: 2 }} | ${'b'} | ${'2b'} ${{ val: 3 }} | ${'b'} | ${'3b'} `('add($a.val, $b) -> $expected', ({ a, b, expected }) => { expect(a.val + b).toBe(expected) }) // this will return // ✓ add(1, b) -> 1b // ✓ add(2, b) -> 2b // ✓ add(3, b) -> 3bStarting from Vitest 0.25.3, you can also use template string table.
- First row should be column names, separated by
|; - One or more subsequent rows of data supplied as template literal expressions using
${value}syntax.
test.each` a | b | expected ${1} | ${1} | ${2} ${'a'} | ${'b'} | ${'ab'} ${[]} | ${'b'} | ${'b'} ${{}} | ${'b'} | ${'[object Object]b'} ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} `('returns $expected when $a is added $b', ({ a, b, expected }) => { expect(a + b).toBe(expected) })If you want to have access to
TestContext, usedescribe.eachwith a single test.
::: warning You cannot use this syntax, when using Vitest as type checker. :::
bench
- Type:
(name: string, fn: BenchFunction, options?: BenchOptions) => void
bench defines a benchmark. In Vitest terms benchmark is a function that defines a series of operations. Vitest runs this function multiple times to display different performance results.
Vitest uses tinybench library under the hood, inheriting all its options that can be used as a third argument.
import { bench } from 'vitest'
bench('normal sorting', () => {
const x = [1, 5, 4, 2, 3]
x.sort((a, b) => {
return a - b
})
}, { time: 1000 })
export interface Options {
/**
* time needed for running a benchmark task (milliseconds)
* @default 500
*/
time?: number
/**
* number of times that a task should run if even the time option is finished
* @default 10
*/
iterations?: number
/**
* function to get the current timestamp in milliseconds
*/
now?: () => number
/**
* An AbortSignal for aborting the benchmark
*/
signal?: AbortSignal
/**
* warmup time (milliseconds)
* @default 100ms
*/
warmupTime?: number
/**
* warmup iterations
* @default 5
*/
warmupIterations?: number
/**
* setup function to run before each benchmark task (cycle)
*/
setup?: Hook
/**
* teardown function to run after each benchmark task (cycle)
*/
teardown?: Hook
}
bench.skip
- Type:
(name: string, fn: BenchFunction, options?: BenchOptions) => void
You can use bench.skip syntax to skip running certain benchmarks.
import { bench } from 'vitest'
bench.skip('normal sorting', () => {
const x = [1, 5, 4, 2, 3]
x.sort((a, b) => {
return a - b
})
})
bench.only
- Type:
(name: string, fn: BenchFunction, options?: BenchOptions) => void
Use bench.only to only run certain benchmarks in a given suite. This is useful when debugging.
import { bench } from 'vitest'
bench.only('normal sorting', () => {
const x = [1, 5, 4, 2, 3]
x.sort((a, b) => {
return a - b
})
})
bench.todo
- Type:
(name: string) => void
Use bench.todo to stub benchmarks to be implemented later.
import { bench } from 'vitest'
bench.todo('unimplemented test')
describe
When you use test or bench in the top level of file, they are collected as part of the implicit suite for it. Using describe you can define a new suite in the current context, as a set of related tests or benchmarks and other nested suites. A suite lets you organize your tests and benchmarks so reports are more clear.
// basic.spec.ts
// organizing tests
import { describe, expect, test } from 'vitest'
const person = {
isActive: true,
age: 32,
}
describe('person', () => {
test('person is defined', () => {
expect(person).toBeDefined()
})
test('is active', () => {
expect(person.isActive).toBeTruthy()
})
test('age limit', () => {
expect(person.age).toBeLessThanOrEqual(32)
})
})
// basic.bench.ts
// organizing benchmarks
import { bench, describe } from 'vitest'
describe('sort', () => {
bench('normal', () => {
const x = [1, 5, 4, 2, 3]
x.sort((a, b) => {
return a - b
})
})
bench('reverse', () => {
const x = [1, 5, 4, 2, 3]
x.reverse().sort((a, b) => {
return a - b
})
})
})
You can also nest describe blocks if you have a hierarchy of tests or benchmarks:
import { describe, expect, test } from 'vitest'
const numberToCurrency = (value) => {
if (typeof value !== 'number')
throw new Error('Value must be a number')
return value.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
describe('numberToCurrency', () => {
describe('given an invalid number', () => {
test('composed of non-numbers to throw error', () => {
expect(() => numberToCurrency('abc')).toThrowError()
})
})
describe('given a valid number', () => {
test('returns the correct currency format', () => {
expect(numberToCurrency(10000)).toBe('10,000.00')
})
})
})
describe.skip
-
Type:
(name: string, fn: TestFunction, options?: number | TestOptions) => voidUse
describe.skipin a suite to avoid running a particular describe block.import { assert, describe, test } from 'vitest' describe.skip('skipped suite', () => { test('sqrt', () => { // Suite skipped, no error assert.equal(Math.sqrt(4), 3) }) })
describe.only
-
Type:
(name: string, fn: TestFunction, options?: number | TestOptions) => voidUse
describe.onlyto only run certain suites// Only this suite (and others marked with only) are run describe.only('suite', () => { test('sqrt', () => { assert.equal(Math.sqrt(4), 3) }) }) describe('other suite', () => { // ... will be skipped })Sometimes it is very useful to run
onlytests in a certain file, ignoring all other tests from the whole test suite, which pollute the output.In order to do that run
vitestwith specific file containing the tests in question.# vitest interesting.test.ts
describe.concurrent
-
Type:
(name: string, fn: TestFunction, options?: number | TestOptions) => voiddescribe.concurrentin a suite marks every tests as concurrent// All tests within this suite will be run in parallel describe.concurrent('suite', () => { test('concurrent test 1', async () => { /* ... */ }) test('concurrent test 2', async () => { /* ... */ }) test.concurrent('concurrent test 3', async () => { /* ... */ }) }).skip,.only, and.todoworks with concurrent suites. All the following combinations are valid:describe.concurrent(/* ... */) describe.skip.concurrent(/* ... */) // or describe.concurrent.skip(/* ... */) describe.only.concurrent(/* ... */) // or describe.concurrent.only(/* ... */) describe.todo.concurrent(/* ... */) // or describe.concurrent.todo(/* ... */)
::: warning You cannot use this syntax, when using Vitest as type checker. :::
describe.shuffle
-
Type:
(name: string, fn: TestFunction, options?: number | TestOptions) => voidVitest provides a way to run all tests in random order via CLI flag
--sequence.shuffleor config optionsequence.shuffle, but if you want to have only part of your test suite to run tests in random order, you can mark it with this flag.describe.shuffle('suite', () => { test('random test 1', async () => { /* ... */ }) test('random test 2', async () => { /* ... */ }) test('random test 3', async () => { /* ... */ }) }) // order depends on sequence.seed option in config (Date.now() by default)
.skip, .only, and .todo works with random suites.
::: warning You cannot use this syntax, when using Vitest as type checker. :::
describe.todo
-
Type:
(name: string) => voidUse
describe.todoto stub suites to be implemented later. An entry will be shown in the report for the tests so you know how many tests you still need to implement.// An entry will be shown in the report for this suite describe.todo('unimplemented suite')
describe.each
-
Type:
(cases: ReadonlyArray<T>, ...args: any[]): (name: string, fn: (...args: T[]) => void, options?: number | TestOptions) => voidUse
describe.eachif you have more than one test that depends on the same data.describe.each([ { a: 1, b: 1, expected: 2 }, { a: 1, b: 2, expected: 3 }, { a: 2, b: 1, expected: 3 }, ])('describe object add($a, $b)', ({ a, b, expected }) => { test(`returns ${expected}`, () => { expect(a + b).toBe(expected) }) test(`returned value not be greater than ${expected}`, () => { expect(a + b).not.toBeGreaterThan(expected) }) test(`returned value not be less than ${expected}`, () => { expect(a + b).not.toBeLessThan(expected) }) })Starting from Vitest 0.25.3, you can also use template string table.
- First row should be column names, separated by
|; - One or more subsequent rows of data supplied as template literal expressions using
${value}syntax.
describe.each` a | b | expected ${1} | ${1} | ${2} ${'a'} | ${'b'} | ${'ab'} ${[]} | ${'b'} | ${'b'} ${{}} | ${'b'} | ${'[object Object]b'} ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} `('describe template string add($a, $b)', ({ a, b, expected }) => { test(`returns ${expected}`, () => { expect(a + b).toBe(expected) }) }) - First row should be column names, separated by
::: warning You cannot use this syntax, when using Vitest as type checker. :::
expect
-
Type:
ExpectStatic & (actual: any) => Assertionsexpectis used to create assertions. In this contextassertionsare functions that can be called to assert a statement. Vitest provideschaiassertions by default and alsoJestcompatible assertions build on top ofchai.For example, this code asserts that an
inputvalue is equal to2. If it's not, 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
testfunction, so in the console you will see Nodejs error instead of Vitest output. To learn more abouttest, please read next chapter.Also,
expectcan be used statically to access matchers functions, described later, and more.
::: warning
expect has no effect on testing types, if expression doesn't have a type error. If you want to use Vitest as type checker, use expectTypeOf or assertType.
:::
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, 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 API
toBe
-
Type:
(value: any) => Awaitable<void>toBecan be used to assert if primitives are equal or that objects share the same reference. It is equivalent of callingexpect(Object.is(3, 3)).toBe(true). If the objects are not the same, but you want check if their structures are identical, you can usetoEqual.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
toBewith floating-point numbers. Since JavaScript rounds them,0.1 + 0.2is not strictly0.3. To reliably assert floating-point numbers, usetoBeCloseToassertion.
toBeCloseTo
-
Type:
(value: number, numDigits?: number) => Awaitable<void>Use
toBeCloseToto compare floating-point numbers. The optionalnumDigitsargument limits the number of digits to check after the decimal point. 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>toBeDefinedasserts that the value is not equal toundefined. Useful use case would be to check if function returned anything.import { expect, test } from 'vitest' const getApples = () => 3 test('function returned something', () => { expect(getApples()).toBeDefined() })
toBeUndefined
-
Type:
() => Awaitable<void>Opposite of
toBeDefined,toBeUndefinedasserts that the value is equal toundefined. Useful use case would be to check if function hasn't returned anything.import { expect, test } from 'vitest' function getApplesFromStock(stock) { if (stock === 'Bill') return 13 } test('mary doesn\'t have a stock', () => { expect(getApplesFromStock('Mary')).toBeUndefined() })
toBeTruthy
-
Type:
() => Awaitable<void>toBeTruthyasserts 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 totrue.For example having this code you don't care for the return value of
stocks.getInfo- it maybe complex object, a string or anything else. The code will still work.import { Stocks } from './stocks' const stocks = new Stocks() stocks.sync('Bill') if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill')So if you want to test that
stocks.getInfowill be truthy, you could write:import { expect, test } from 'vitest' import { Stocks } from './stocks' 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,0,'',null,undefined, andNaN.
toBeFalsy
-
Type:
() => Awaitable<void>toBeFalsyasserts that the value is false, when converted to boolean. Useful if you don't care for the value, but just want to know it can be converted tofalse.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' const stocks = new Stocks() stocks.sync('Bill') if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill')So if you want to test that
stocks.stockFailedwill be falsy, you could write:import { expect, test } from 'vitest' import { Stocks } from './stocks' 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,0,'',null,undefined, andNaN.
toBeNull
-
Type:
() => Awaitable<void>toBeNullsimply asserts if something isnull. Alias for.toBe(null).import { expect, test } from 'vitest' function apples() { return null } test('we don\'t have apples', () => { expect(apples()).toBeNull() })
toBeNaN
-
Type:
() => Awaitable<void>toBeNaNsimply asserts if something isNaN. Alias for.toBe(NaN).import { expect, test } from 'vitest' let i = 0 function getApplesCount() { i++ return i > 1 ? NaN : i } test('getApplesCount has some unusual side effects...', () => { expect(getApplesCount()).not.toBeNaN() expect(getApplesCount()).toBeNaN() })
toBeTypeOf
-
Type:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>toBeTypeOfasserts 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') })
toBeInstanceOf
-
Type:
(c: any) => Awaitable<void>toBeInstanceOfasserts if an actual value is instance of received class.import { expect, test } from 'vitest' import { Stocks } from './stocks' const stocks = new Stocks() test('stocks are instance of Stocks', () => { expect(stocks).toBeInstanceOf(Stocks) })
toBeGreaterThan
-
Type:
(n: number | bigint) => Awaitable<void>toBeGreaterThanasserts if actual value is greater than received one. Equal values will fail the test.import { expect, test } from 'vitest' import { getApples } from './stock' test('have more then 10 apples', () => { expect(getApples()).toBeGreaterThan(10) })
toBeGreaterThanOrEqual
-
Type:
(n: number | bigint) => Awaitable<void>toBeGreaterThanOrEqualasserts if actual value is greater than received one or equal to it.import { expect, test } from 'vitest' import { getApples } from './stock' test('have 11 apples or more', () => { expect(getApples()).toBeGreaterThanOrEqual(11) })
toBeLessThan
-
Type:
(n: number | bigint) => Awaitable<void>toBeLessThanasserts if actual value is less than received one. Equal values will fail the test.import { expect, test } from 'vitest' import { getApples } from './stock' test('have less then 20 apples', () => { expect(getApples()).toBeLessThan(20) })
toBeLessThanOrEqual
-
Type:
(n: number | bigint) => Awaitable<void>toBeLessThanOrEqualasserts if actual value is less than received one or equal to it.import { expect, test } from 'vitest' import { getApples } from './stock' test('have 11 apples or less', () => { expect(getApples()).toBeLessThanOrEqual(11) })
toEqual
-
Type:
(received: any) => Awaitable<void>toEqualasserts 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 betweentoEqualandtoBein 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 A deep equality will not be performed for
Errorobjects. To test if something was thrown, usetoThrowErrorassertion. :::
toStrictEqual
-
Type:
(received: any) => Awaitable<void>toStrictEqualasserts if actual value is equal to 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' }) }) - Keys with
toContain
-
Type:
(received: string) => Awaitable<void>toContainasserts if actual value is in an array.toContaincan also check whether a string is a substring of another string.import { expect, test } from 'vitest' import { getAllFruits } from './stock' test('the fruit list contains orange', () => { expect(getAllFruits()).toContain('orange') })
toContainEqual
-
Type:
(received: any) => Awaitable<void>toContainEqualasserts if an item with a specific structure and values is contained in an array. It works liketoEqualinside for each element.import { expect, test } from 'vitest' import { getFruitStock } from './stock' test('apple available', () => { expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 }) })
toHaveLength
-
Type:
(received: number) => Awaitable<void>toHaveLengthasserts if an object has a.lengthproperty 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>toHavePropertyasserts if a property at provided referencekeyexists for an object.You can provide an optional value argument also known as deep equality, like the
toEqualmatcher 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 // Wrap your key in an array to avoid the key from being parsed as a deep reference expect(invoice).toHaveProperty(['P.O'], '12345') })
toMatch
-
Type:
(received: string | regexp) => Awaitable<void>toMatchasserts 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>toMatchObjectasserts 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 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 }, ]) })
toThrowError
-
Type:
(received: any) => Awaitable<void>toThrowErrorasserts if a function throws an error when it is called.For example, if we want to test that
getFruitStock('pineapples')throws, we could write:You can provide an optional argument to test that a specific error is thrown:
- regular expression: error message matches the pattern
- string: error message includes the substring
:::tip You must wrap the code in a function, otherwise the error will not be caught, and the assertion will fail. :::
import { expect, test } from 'vitest' function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError('Pineapples is not good for people with diabetes') // Do some other stuff } test('throws on pineapples', () => { // Test that the error message says "diabetes" somewhere: these are equivalent expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/) expect(() => getFruitStock('pineapples')).toThrowError('diabetes') // Test the exact error message expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples is not good for people with diabetes$/, ) })
toMatchSnapshot
-
Type:
<T>(shape?: Partial<T> | string, message?: string) => voidThis ensures that a value matches the most recent snapshot.
You can provide an optional
hintstring 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.snapfile.:::tip When snapshot mismatch and causing the test failing, if the mismatch is expected, you can press
ukey to update the snapshot for once. Or you can pass-uor--updateCLI 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, message?: string) => voidThis 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
.snapfile).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>, } ` ) })
toThrowErrorMatchingSnapshot
-
Type:
(message?: string) => voidThe same as
toMatchSnapshot, but expects the same value astoThrowError.If the function throws an
Error, the snapshot will be the error message. Otherwise, snapshot will be the value thrown by the function.
toThrowErrorMatchingInlineSnapshot
-
Type:
(snapshot?: string, message?: string) => voidThe same as
toMatchInlineSnapshot, but expects the same value astoThrowError.If the function throws an
Error, the snapshot will be the error message. Otherwise, snapshot will be the value thrown by the function.
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)
})
toHaveBeenLastCalledWith
- Type:
(...args: any[]) => Awaitable<void>
This assertion checks if a function was called with certain parameters at it's 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'
const 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 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 value with certain parameters on it's last invoking. 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.
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' })
})
toSatisfy
- Type:
(predicate: (value: any) => boolean) => Awaitable<void>
This assertion checks if a value satisfies a certain predicate.
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0
it('pass with 0', () => {
expect(1).toSatisfy(isOdd)
})
it('pass with negotiation', () => {
expect(2).not.toSatisfy(isOdd)
})
})
resolves
-
Type:
Promisify<Assertions>resolvesis 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
Assertionsobject, but all matchers now returnPromise, so you would need toawaitit. Also works withchaiassertions.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, then you will have a false-positive test that will pass every time. To make sure that assertions are actually called, you may use
expect.assertions(number). :::
rejects
-
Type:
Promisify<Assertions>rejectsis intended to remove boilerplate when asserting asynchronous code. Use it to unwrap reason why promise was rejected, and assert its value with usual assertions. If promise successfully resolves, the assertion will fail.It returns the same
Assertionsobject, but all matchers are now returnPromise, so you would need toawaitit. Also works withchaiassertions.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, then you will have a false-positive test that will pass every time. To make sure that assertions are actually happened, you may use
expect.assertions(number). :::
expect.assertions
-
Type:
(count: number) => voidAfter the test has passed or failed verifies that certain number of assertions was called during a test. 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) })
expect.hasAssertions
-
Type:
() => voidAfter the test has passed or failed verifies that at least one assertion was called during a test. 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' 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.anything
-
Type:
() => anyThis asymmetric matcher, when used with equality check, will always return
true. Useful, if you just want to be sure that the property exist.import { expect, test } from 'vitest' test('object has "apples" key', () => { expect({ apples: 22 }).toEqual({ apples: expect.anything() }) })
expect.any
-
Type:
(constructor: unknown) => anyThis asymmetric matcher, when used with equality check, will return
trueonly if value is an instance of specified constructor. Useful, if you have a value that is generated each time, and you only want to know that it exist with a proper type.import { expect, test } from 'vitest' import { generateId } from './generators' test('"id" is a number', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }) })
expect.arrayContaining
-
Type:
<T>(expected: T[]) => anyWhen used with equality check, this asymmetric matcher will return
trueif 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.notwith this matcher to negate the expected value. :::
expect.objectContaining
-
Type:
(expected: any) => anyWhen used with equality check, this asymmetric matcher will return
trueif 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.notwith this matcher to negate the expected value. :::
expect.stringContaining
-
Type:
(expected: any) => anyWhen used with equality check, this asymmetric matcher will return
trueif value is a string and contains specified substring.import { expect, test } from 'vitest' test('variety has "Emp" in its name', () => { const variety = { name: 'Empire', count: 1, } expect(basket).toEqual({ name: expect.stringContaining('Emp'), count: 1, }) }):::tip You can use
expect.notwith this matcher to negate the expected value. :::
expect.stringMatching
-
Type:
(expected: any) => anyWhen used with equality check, this asymmetric matcher will return
trueif value is a string and contains specified substring or the string matches regular expression.import { expect, test } from 'vitest' test('variety ends with "re"', () => { const variety = { name: 'Empire', count: 1, } expect(basket).toEqual({ name: expect.stringMatching(/re$/), count: 1, }) }):::tip You can use
expect.notwith this matcher to negate the expected value. :::
expect.addSnapshotSerializer
-
Type:
(plugin: PrettyFormatPlugin) => voidThis method adds custom serializers that are called when creating a snapshot. This is 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) => voidYou 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, expected) => { if (received !== 'foo') { return { message: () => `expected ${received} to be foo`, pass: false, } } }, }) expect('foo').toBeFoo() expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() }) })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 default Matchers interface with the code bellow:
interface CustomMatchers<R = unknown> { toBeFoo(): R } declare global { namespace Vi { interface Assertion extends CustomMatchers {} interface AsymmetricMatchersContaining extends CustomMatchers {} } }Note: augmenting jest.Matchers interface will also work.
:::tip If you want to know more, checkout guide on extending matchers. :::
expectTypeOf
- 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 types are fully equal to each other. This matcher will not fail, if two objects have different values, but the same type, but will fail, if 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
This matcher checks if expect type extends provided type. It is different from toEqual and is more similar to expect's toMatch. 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>()
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 }
const getResponsiveProp = <T>(_props: T): ResponsiveProp<T> => ({})
interface CSSProperties { margin?: string; padding?: string }
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<unknown[]>() // 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 }
const getResponsiveProp = <T>(_props: T): ResponsiveProp<T> => ({})
interface CSSProperties { margin?: string; padding?: string }
const cssProperties: CSSProperties = { margin: '1px', padding: '2px' }
expectTypeOf(getResponsiveProp(cssProperties))
.exclude<unknown[]>()
.exclude<{ xs?: unknown }>() // or just .exclude<unknown[] | { xs?: unknown }>()
.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<Parameters>
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'
const foo = (a: number, b: string) => [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'
const asyncFunc = async () => 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'
const isString = (v: any): v is string => 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'
const 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 functon.
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<boolean>().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<undefined>().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<1 | undefined>().toBeNullable()
expectTypeOf<1 | null>().toBeNullable()
expectTypeOf<1 | undefined | null>().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 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()
assertType
- Type:
<T>(value: T): void
You can use this function as an alternative for expectTypeOf to easily assert that argument type is equal to provided generic.
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))
Setup and Teardown
These functions allow you to hook into the life cycle of tests to avoid repeating setup and teardown code. They apply to the current context: the file if they are used at the top-level or the current suite if they are inside a describe block. These hooks are not called, when you are running Vitest as a type checker.
beforeEach
-
Type:
beforeEach(fn: () => Awaitable<void>, timeout?: number)Register a callback to be called before each of the tests in the current context runs. If the function returns a promise, Vitest waits until the promise resolve before running the test.
Optionally, you can pass a timeout (in milliseconds) defining how long to wait before terminating. The default is 5 seconds.
import { beforeEach } from 'vitest' beforeEach(async () => { // Clear mocks and add some testing data after before each test run await stopMocking() await addUser({ name: 'John' }) })Here, the
beforeEachensures that user is added for each test.Since Vitest v0.10.0,
beforeEachalso accepts an optional cleanup function (equivalent toafterEach).import { beforeEach } from 'vitest' beforeEach(async () => { // called once before each test run await prepareSomething() // clean up function, called once after each test run return async () => { await resetSomething() } })
afterEach
-
Type:
afterEach(fn: () => Awaitable<void>, timeout?: number)Register a callback to be called after each one of the tests in the current context completes. If the function returns a promise, Vitest waits until the promise resolve before continuing.
Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds.
import { afterEach } from 'vitest' afterEach(async () => { await clearTestingData() // clear testing data after each test run })Here, the
afterEachensures that testing data is cleared after each test runs.
beforeAll
-
Type:
beforeAll(fn: () => Awaitable<void>, timeout?: number)Register a callback to be called once before starting to run all tests in the current context. If the function returns a promise, Vitest waits until the promise resolve before running tests.
Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds.
import { beforeAll } from 'vitest' beforeAll(async () => { await startMocking() // called once before all tests run })Here the
beforeAllensures that the mock data is set up before tests run.Since Vitest v0.10.0,
beforeAllalso accepts an optional cleanup function (equivalent toafterAll).import { beforeAll } from 'vitest' beforeAll(async () => { // called once before all tests run await startMocking() // clean up function, called once after all tests run return async () => { await stopMocking() } })
afterAll
-
Type:
afterAll(fn: () => Awaitable<void>, timeout?: number)Register a callback to be called once after all tests have run in the current context. If the function returns a promise, Vitest waits until the promise resolve before continuing.
Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds.
import { afterAll } from 'vitest' afterAll(async () => { await stopMocking() // this method is called after all tests run })Here the
afterAllensures thatstopMockingmethod is called after all tests run.
Vi
Vitest provides utility functions to help you out through it's vi helper. You can import { vi } from 'vitest' or access it globally (when globals configuration is enabled).
vi.advanceTimersByTime
-
Type:
(ms: number) => VitestWorks just like
runAllTimers, but will end after passed milliseconds. For example this will log1, 2, 3and will not throw:let i = 0 setInterval(() => console.log(++i), 50) vi.advanceTimersByTime(150)
vi.advanceTimersToNextTimer
-
Type:
() => 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 3
vi.getTimerCount
-
Type:
() => numberGet the number of waiting timers.
vi.clearAllMocks
Will call .mockClear() on all spies. This will clear mock history, but not reset its implementation to the default one.
vi.clearAllTimers
Removes all timers that are scheduled to run. These timers will never run in the future.
vi.dynamicImportSettled
Wait for all imports to load. Useful, if you have a synchronous call that starts importing a module, that you cannot wait otherwise.
vi.fn
-
Type:
(fn?: Function) => CallableMockInstanceCreates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, 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)
vi.getMockedSystemTime
-
Type:
() => Date | nullReturns mocked current date that was set using
setSystemTime. If date is not mocked, will returnnull.
vi.getRealSystemTime
-
Type:
() => numberWhen using
vi.useFakeTimers,Date.nowcalls are mocked. If you need to get real time in milliseconds, you can call this function.
vi.mock
-
Type:
(path: string, factory?: () => unknown) => voidSubstitutes all imported modules from provided
pathwith another module. You can use configured Vite aliases inside a path. The call tovi.mockis hoisted, so it doesn't matter where you call it. It will always be executed before all imports.::: warning
vi.mockworks only for modules that were imported with theimportkeyword. It doesn't work withrequire.Vitest statically analyzes your files to hoist
vi.mock. It means that you cannot usevithat was not imported directly fromvitestpackage (for example, from some utility file). To fix this, always usevi.mockwithviimported fromvitest, or enableglobalsconfig option. :::If
factoryis defined, all imports will return its result. Vitest calls factory only once and caches result for all subsequent imports untilvi.unmockorvi.doUnmockis called.Unlike in
jest, the factory can be asynchronous, so you can usevi.importActualor a helper, received as the first argument, inside to get the original module.vi.mock('./path/to/module.js', async (importOriginal) => { const mod = await importOriginal() return { ...mod, // replace some exports namedExport: vi.fn(), } })::: warning
vi.mockis hoisted (in other words, moved) to top of the file. It means that whenever you write it (be it insidebeforeEachortest), 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. :::::: warning If you are mocking a module with default export, you will need to provide a
defaultkey within the returned factory function object. This is an ES modules-specific caveat, thereforejestdocumentation may differ asjestuses 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 isprocess.cwd()).For example, you have this file structure:
- __mocks__ - axios.js - src __mocks__ - increment.js - increment.js - tests - increment.test.jsIf you call
vi.mockin a test file without a factory provided, it will find a file in the__mocks__folder to use as a module:// increment.test.js 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. :::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
-
Type:
(path: string, factory?: () => unknown) => voidThe same as
vi.mock, but it's not hoisted at the top of the file, so you can reference variables in the global file scope. The next import of the module will be mocked. This will not mock modules that were imported before this was called.
// ./increment.js
export const increment = number => 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(() => {
// simple doMock doesn't clear the previous cache, so we need to clear it manually here
vi.doUnmock('./increment.js')
// you can access variables inside a factory
vi.doMock('./increment.js', () => ({ increment: () => mockedIncrement++ }))
})
test('importing the next module imports mocked one', () => {
// 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 import returns mocked module
expect(mockedIncrement(1)).toBe(101)
expect(mockedIncrement(1)).toBe(102)
expect(mockedIncrement(1)).toBe(103)
})
vi.mocked
-
Type:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T> -
Type:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>Type helper for TypeScript. In reality just returns the object that was passed.
When
partialistrueit will expect aPartial<T>as a return value.import example from './example' vi.mock('./example') test('1+1 equals 2', async () => { vi.mocked(example.calc).mockRestore() const res = example.calc(1, '+', 1) expect(res).toBe(2) })
vi.importActual
-
Type:
<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', async () => { const axios = await vi.importActual('./example') return { ...axios, get: vi.fn() } })
vi.importMock
-
Type:
<T>(path: string) => Promise<MaybeMockedDeep<T>>Imports a module with all of its properties (including nested properties) mocked. Follows the same rules that
vi.mockfollows. For the rules applied, see algorithm.
vi.resetAllMocks
Will call .mockReset() on all spies. This will clear mock history and reset its implementation to an empty function (will return undefined).
vi.resetConfig
-
Type:
RuntimeConfigIf
vi.setConfigwas called before, this will reset config to the original state.
vi.resetModules
-
Type:
() => VitestResets modules registry by clearing cache of all modules. Might be useful to isolate modules where local state conflicts between tests.
import { vi } from 'vitest' beforeAll(() => { vi.resetModules() }) test('change state', async () => { const mod = await import('./some/path') mod.changeLocalState('new value') expect(mod.getlocalState()).toBe('new value') }) test('module has old state', async () => { const mod = await import('./some/path') expect(mod.getlocalState()).toBe('old value') })
::: warning
Does not reset mocks registry. To clear mocks registry, use vi.unmock or vi.doUnmock.
:::
vi.restoreAllMocks
Will call .mockRestore() on all spies. This will clear mock history and reset its implementation to the original one.
vi.restoreCurrentDate
-
Type:
() => voidRestores
Dateback to its native implementation.
vi.stubEnv
-
Type:
(name: string, value: string) => Vitest -
Version: Since Vitest 0.26.0
Changes the value of environmental variable on
process.envandimport.meta.env. You can restore its value by callingvi.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'
// 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'
:::
:::warning
Vitest transforms all import.meta.env calls into process.env, so they can be easily changed at runtime. Node.js only supports string values as env parameters, while Vite supports several built-in envs as boolean (namely, SSR, DEV, PROD). To mimic Vite, set "truthy" values as env: '' instead of false, and '1' instead of true.
But beware that you cannot rely on import.meta.env.DEV === false in this case. Use !import.meta.env.DEV. This also affects simple assigning, not just vi.stubEnv method.
:::
vi.unstubAllEnvs
-
Type:
() => Vitest -
Version: Since Vitest 0.26.0
Restores all
import.meta.envandprocess.envvalues that were changed withvi.stubEnv. When it's called for the first time, Vitest remembers the original value and will store it, untilunstubAllEnvsis 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
-
Type:
(name: stirng | number | symbol, value: uknown) => VitestChanges the value of global variable. You can restore its original value by calling
vi.unstubAllGlobals.
import { vi } from 'vitest'
// `innerWidth` is "0" before callling 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
-
Type:
() => Vitest -
Version: Since Vitest 0.26.0
Restores all global values on
globalThis/global(andwindow/top/self/parent, if you are usingjsdomorhappy-domenvironment) that were changed withvi.stubGlobal. When it's called for the first time, Vitest remembers the original value and will store it, untilunstubAllGlobalsis 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 === undefined
vi.runAllTicks
-
Type:
() => VitestCalls every microtask that was queued by
proccess.nextTick. This will also run all microtasks scheduled by themselves.
vi.runAllTimers
-
Type:
() => VitestThis method will invoke every initiated timer until the timers queue is empty. It means that every timer called during
runAllTimerswill be fired. If you have an infinite interval, it will throw after 10 000 tries. For example this will log1, 2, 3:let i = 0 setTimeout(() => console.log(++i)) const interval = setInterval(() => { console.log(++i) if (i === 3) clearInterval(interval) }, 50) vi.runAllTimers()
vi.runOnlyPendingTimers
-
Type:
() => 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. For example this will only log1:let i = 0 setInterval(() => console.log(++i), 50) vi.runOnlyPendingTimers()
vi.setSystemTime
-
Type:
(date: string | number | Date) => voidSets current date to the one that was passed. All
Datecalls will return this date.Useful if you need to test anything that depends on the current date - for example luxon calls inside your code.
const date = new Date(1998, 11, 19) vi.useFakeTimers() vi.setSystemTime(date) expect(Date.now()).toBe(date.valueOf()) vi.useRealTimers()
vi.setConfig
-
Type:
RuntimeConfigUpdates config for the current test file. You can only affect values that are used, when executing tests.
vi.spyOn
-
Type:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstanceCreates a spy on a method or getter/setter of an object.
let apples = 0 const obj = { getApples: () => 13, } const spy = vi.spyOn(obj, 'getApples').mockImplementation(() => apples) apples = 1 expect(obj.getApples()).toBe(1) expect(spy).toHaveBeenCalled() expect(spy).toHaveReturnedWith(1)
vi.stubGlobal
-
Type:
(key: keyof globalThis & Window, value: any) => VitestPuts a value on global variable. If you are using
jsdomorhappy-dom, also puts the value onwindowobject.Read more in "Mocking Globals" section.
vi.unmock
-
Type:
(path: string) => 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 (moved) to the top of the file, so it will only unmock modules that were defined in
setupFiles, for example.
vi.doUnmock
-
Type:
(path: string) => 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.
// ./increment.js
export const increment = number => 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) === 31
vi.useFakeTimers
-
Type:
() => VitestTo enable mocking timers, you need to call this method. It will wrap all further calls to timers (such as
setTimeout,setInterval,clearTimeout,clearInterval,nextTick,setImmediate,clearImmediate, andDate), untilvi.useRealTimers()is called.The implementation is based internally on
@sinonjs/fake-timers.
vi.useRealTimers
-
Type:
() => VitestWhen timers are run out, you may call this method to return mocked timers to its original implementations. All timers that were run before will not be restored.
MockInstance Methods
getMockName
-
Type:
() => stringUse it to return the name given to mock with method
.mockName(name).
mockClear
-
Type:
() => MockInstanceClears all information about every call. After calling it,
spy.mock.calls,spy.mock.resultswill return empty arrays. It is useful if you need to clean up spy between different assertions.If you want this method to be called before each test automatically, you can enable
clearMockssetting in config.
mockName
-
Type:
(name: string) => MockInstanceSets internal mock name. Useful to see what mock has failed the assertion.
mockImplementation
-
Type:
(fn: Function) => MockInstanceAccepts a function that will be used as an implementation of the mock.
For example:
const mockFn = vi.fn().mockImplementation(apples => 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 // true
mockImplementationOnce
-
Type:
(fn: Function) => MockInstanceAccepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results.
const myMockFn = vi .fn() .mockImplementationOnce(() => true) .mockImplementationOnce(() => false) myMockFn() // true myMockFn() // falseWhen the mocked function runs out of implementations, it will invoke the default implementation that was 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())
mockRejectedValue
-
Type:
(value: any) => MockInstanceAccepts an error that will be rejected, when async function will be called.
test('async test', async () => { const asyncMock = vi.fn().mockRejectedValue(new Error('Async error')) await asyncMock() // throws "Async error" })
mockRejectedValueOnce
-
Type:
(value: any) => MockInstanceAccepts a value that will be rejected for one call to the mock function. If chained, every consecutive call will reject passed value.
test('async test', async () => { const asyncMock = vi .fn() .mockResolvedValueOnce('first call') .mockRejectedValueOnce(new Error('Async error')) await asyncMock() // first call await asyncMock() // throws "Async error" })
mockReset
-
Type:
() => MockInstanceDoes what
mockCleardoes and makes inner implementation as an empty function (returningundefined, when invoked). This is useful when you want to completely reset a mock back to its initial state.If you want this method to be called before each test automatically, you can enable
mockResetsetting in config.
mockRestore
-
Type:
() => MockInstanceDoes what
mockResetdoes and restores inner implementation to the original function.Note that restoring mock from
vi.fn()will set implementation to an empty function that returnsundefined. Restoring avi.fn(impl)will restore implementation toimpl.If you want this method to be called before each test automatically, you can enable
restoreMockssetting in config.
mockResolvedValue
-
Type:
(value: any) => MockInstanceAccepts a value that will be resolved, when async function will be called.
test('async test', async () => { const asyncMock = vi.fn().mockResolvedValue(43) await asyncMock() // 43 })
mockResolvedValueOnce
-
Type:
(value: any) => MockInstanceAccepts a value that will be resolved for one call to the mock function. If chained, every consecutive call will resolve passed value.
test('async test', async () => { 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() // default })
mockReturnThis
-
Type:
() => MockInstanceSets inner implementation to return
thiscontext.
mockReturnValue
-
Type:
(value: any) => MockInstanceAccepts a value that will be returned whenever the mock function is called.
const mock = vi.fn() mock.mockReturnValue(42) mock() // 42 mock.mockReturnValue(43) mock() // 43
mockReturnValueOnce
-
Type:
(value: any) => MockInstanceAccepts a value that will be returned for one call to the mock function. If chained, every consecutive call will return passed value. When there are no more
mockReturnValueOncevalues to use, calls a function specified bymockImplementationor othermockReturn*methods.const myMockFn = vi .fn() .mockReturnValue('default') .mockReturnValueOnce('first call') .mockReturnValueOnce('second call') // 'first call', 'second call', 'default', 'default' console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn())
MockInstance Properties
mock.calls
This is an array containing all arguments for each call. One item of the array is arguments of that call.
If a function was invoked twice with the following arguments fn(arg1, arg2), fn(arg3, arg4) in that order, then mock.calls will be:
[
['arg1', 'arg2'],
['arg3', 'arg4'],
]
mock.lastCall
This contains the arguments of the last call. If spy wasn't called, will return undefined.
mock.results
This is an array containing all values, that were returned from 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.
The value property contains returned value or thrown error.
If function returned result, then threw an error, then mock.results will be:
[
{
type: 'return',
value: 'result',
},
{
type: 'throw',
value: Error,
},
]
mock.instances
This is an array containing all instances that were instantiated when mock was called with a new keyword. Note, this is an actual context (this) of the function, not a return value.
For example, if mock was instantiated with new MyClass(), then mock.instances will be an array of one value:
import { expect, vi } from 'vitest'
const MyClass = vi.fn()
const a = new MyClass()
expect(MyClass.mock.instances[0]).toBe(a)
If you return a value from constructor, it will not be in instances array, but instead on results:
import { expect, vi } from 'vitest'
const Spy = vi.fn(() => ({ method: vi.fn() }))
const a = new Spy()
expect(Spy.mock.instances[0]).not.toBe(a)
expect(Spy.mock.results[0]).toBe(a)