---
outline: deep
---
# Test
- **Alias:** `it`
```ts
function test(
name: string | Function,
body?: () => unknown,
timeout?: number
): void
function test(
name: string | Function,
options: TestOptions,
body?: () => unknown,
): void
```
`test` or `it` defines 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, or a set of [additional options](#test-options). The default timeout is 5 seconds, and can be configured globally with [`testTimeout`](/config/testtimeout).
```ts
import { expect, test } from 'vitest'
test('should work as expected', () => {
expect(Math.sqrt(4)).toBe(2)
})
```
::: warning
If the first argument is a function, its `name` property will be used as the name of the test. The function itself will not be called.
If test body is not provided, the test is marked as `todo`.
:::
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](/guide/migration#done-callback).
:::
## Test Options
You can define boolean options by chaining properties on a function:
```ts
import { test } from 'vitest'
test.skip('skipped test', () => {
// some logic that fails right now
})
test.concurrent.skip('skipped concurrent test', () => {
// some logic that fails right now
})
```
But you can also provide an object as a second argument instead:
```ts
import { test } from 'vitest'
test('skipped test', { skip: true }, () => {
// some logic that fails right now
})
test('skipped concurrent test', { skip: true, concurrent: true }, () => {
// some logic that fails right now
})
```
They both work in exactly the same way. To use either one is purely a stylistic choice.
### timeout
- **Type:** `number`
- **Default:** `5_000` (configured by [`testTimeout`](/config/testtimeout))
Test timeout in milliseconds.
::: warning
Note that if you are providing timeout as the last argument, you cannot use options anymore:
```ts
import { test } from 'vitest'
// ✅ this works
test.skip('heavy test', () => {
// ...
}, 10_000)
// ❌ this doesn't work
test('heavy test', { skip: true }, () => {
// ...
}, 10_000)
```
However, you can provide a timeout inside the object:
```ts
import { test } from 'vitest'
// ✅ this works
test('heavy test', { skip: true, timeout: 10_000 }, () => {
// ...
})
```
:::
### retry
- **Default:** `0` (configured by [`retry`](/config/retry))
- **Type:**
```ts
type Retry = number | {
/**
* The number of times to retry the test if it fails.
* @default 0
*/
count?: number
/**
* Delay in milliseconds between retry attempts.
* @default 0
*/
delay?: number
/**
* Condition to determine if a test should be retried based on the error.
* - If a RegExp, it is tested against the error message
* - If a function, called with the TestError object; return true to retry
*
* NOTE: Functions can only be used in test files, not in vitest.config.ts,
* because the configuration is serialized when passed to worker threads.
*
* @default undefined (retry on all errors)
*/
condition?: RegExp | ((error: TestError) => boolean)
}
```
Retry configuration for the test. If a number, specifies how many times to retry. If an object, allows fine-grained retry control.
Note that the object configuration is available only since Vitest 4.1.
### repeats
- **Type:** `number`
- **Default:** `0`
How many times the test will run again. If set to `0` (the default), the test will run only one time.
This can be useful for debugging flaky tests.
### tags 4.1.0 {#tags}
- **Type:** `string[]`
- **Default:** `[]`
Custom user [tags](/guide/test-tags). If the tag is not specified in the [configuration](/config/tags), the test will fail before it starts, unless [`strictTags`](/config/stricttags) is disabled manually.
```ts
import { it } from 'vitest'
it('user returns data from db', { tags: ['db', 'flaky'] }, () => {
// ...
})
```
### meta 4.1.0 {#meta}
- **Type:** `TaskMeta`
Attaches custom [metadata](/api/advanced/metadata) available in reporters.
::: warning
Vitest merges top-level properties inherited from suites or tags. However, it does not perform a deep merge of nested objects.
```ts
import { describe, test } from 'vitest'
describe(
'nested meta',
{
meta: {
nested: { object: true, array: false },
},
},
() => {
test(
'overrides part of meta',
{
meta: {
nested: { object: false }
},
},
({ task }) => {
// task.meta === { nested: { object: false } }
// notice array got lost because "nested" object was overridden
}
)
}
)
```
Prefer using non-nested meta, if possible.
:::
### concurrent
- **Type:** `boolean`
- **Default:** `false` (configured by [`sequence.concurrent`](/config/sequence#sequence-concurrent))
- **Alias:** [`test.concurrent`](#test-concurrent)
Whether this test run concurrently with other concurrent tests in the suite.
### sequential
- **Type:** `boolean`
- **Default:** `true`
- **Alias:** [`test.sequential`](#test-sequential)
::: warning DEPRECATED
Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency.
:::
Whether tests run sequentially. When both `concurrent` and `sequential` are specified, `concurrent` takes precedence.
### skip
- **Type:** `boolean`
- **Default:** `false`
- **Alias:** [`test.skip`](#test-skip)
Whether the test should be skipped.
### only
- **Type:** `boolean`
- **Default:** `false`
- **Alias:** [`test.only`](#test-only)
Should this test be the only one running in a suite.
### todo
- **Type:** `boolean`
- **Default:** `false`
- **Alias:** [`test.todo`](#test-todo)
Whether the test should be skipped and marked as a todo.
### fails
- **Type:** `boolean`
- **Default:** `false`
- **Alias:** [`test.fails`](#test-fails)
Whether the test is expected to fail. If it does, the test will pass, otherwise it will fail.
## test.extend
- **Alias:** `it.extend`
Use `test.extend` to extend the test context with custom fixtures. This will return a new `test` and it's also extendable, so you can compose more fixtures or override existing ones by extending it as you need. See [Extend Test Context](/guide/test-context#extend-test-context) for more information.
```ts
import { test as baseTest, expect } from 'vitest'
export const test = baseTest
// Simple value - type is inferred as { port: number; host: string }
.extend('config', { port: 3000, host: 'localhost' })
// Function fixture - type is inferred from return value
.extend('server', async ({ config }) => {
// TypeScript knows config is { port: number; host: string }
return `http://${config.host}:${config.port}`
})
test('server uses correct port', ({ config, server }) => {
// TypeScript knows the types:
// - config is { port: number; host: string }
// - server is string
expect(server).toBe('http://localhost:3000')
expect(config.port).toBe(3000)
})
```
## test.override 4.1.0 {#test-override}
Use `test.override` to override fixture values for all tests within the current suite and its nested suites. This must be called at the top level of a `describe` block. See [Overriding Fixture Values](/guide/test-context.html#overriding-fixture-values) for more information.
```ts
import { test as baseTest, describe, expect } from 'vitest'
const test = baseTest
.extend('dependency', 'default')
.extend('dependant', ({ dependency }) => dependency)
describe('use scoped values', () => {
test.override({ dependency: 'new' })
test('uses scoped value', ({ dependant }) => {
// `dependant` uses the new overridden value that is scoped
// to all tests in this suite
expect(dependant).toEqual({ dependency: 'new' })
})
})
```
## test.scoped 3.1.0 {#test-scoped}
- **Alias:** `it.scoped`
::: danger DEPRECATED
`test.scoped` is deprecated in favor of [`test.override`](#test-override) and will be removed in a future major version.
:::
Alias of [`test.override`](#test-override)
## test.skip
- **Alias:** `it.skip`
If you want to skip running certain tests, but you don't want to delete the code due to any reason, you can use `test.skip` to avoid running them.
```ts
import { assert, test } from 'vitest'
test.skip('skipped test', () => {
// Test skipped, no error
assert.equal(Math.sqrt(4), 3)
})
```
You can also skip test by calling `skip` on its [context](/guide/test-context) dynamically:
```ts
import { assert, test } from 'vitest'
test('skipped test', (context) => {
context.skip()
// Test skipped, no error
assert.equal(Math.sqrt(4), 3)
})
```
If the condition is unknown, you can provide it to the `skip` method as the first arguments:
```ts
import { assert, test } from 'vitest'
test('skipped test', (context) => {
context.skip(Math.random() < 0.5, 'optional message')
// Test skipped, no error
assert.equal(Math.sqrt(4), 3)
})
```
## test.skipIf
- **Alias:** `it.skipIf`
In 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 use `test.skipIf` to skip the test whenever the condition is truthy.
```ts
import { assert, test } from 'vitest'
const isDev = process.env.NODE_ENV === 'development'
test.skipIf(isDev)('prod only test', () => {
// this test only runs in production
})
```
## test.runIf
- **Alias:** `it.runIf`
Opposite of [test.skipIf](#test-skipif).
```ts
import { assert, test } from 'vitest'
const isDev = process.env.NODE_ENV === 'development'
test.runIf(isDev)('dev only test', () => {
// this test only runs in development
})
```
## test.only
- **Alias:** `it.only`
Use `test.only` to only run certain tests in a given suite. This is useful when debugging.
```ts
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 `only` tests in a certain file, ignoring all other tests from the whole test suite, which pollute the output.
In order to do that, run `vitest` with specific file containing the tests in question:
```shell
vitest interesting.test.ts
```
::: warning
Vitest detects when tests are running in CI and will throw an error if any test has `only` flag. You can configure this behaviour via [`allowOnly`](/config/allowonly) option.
:::
## test.concurrent
- **Alias:** `it.concurrent`
`test.concurrent` marks 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).
```ts
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`, and `test.todo` works with concurrent tests. All the following combinations are valid:
```ts
test.concurrent(/* ... */)
test.skip.concurrent(/* ... */) // or test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */) // or test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */) // or test.concurrent.todo(/* ... */)
```
When running concurrent tests, Snapshots and Assertions must use `expect` from the local [Test Context](/guide/test-context.md) to ensure the right test is detected.
```ts
test.concurrent('test 1', async ({ expect }) => {
expect(foo).toMatchSnapshot()
})
test.concurrent('test 2', async ({ expect }) => {
expect(foo).toMatchSnapshot()
})
```
Note that if tests are synchronous, Vitest will still run them sequentially.
## test.sequential {#test-sequential}
- **Alias:** `it.sequential`
::: warning DEPRECATED
Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency.
:::
`test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option.
```ts
import { describe, test } from 'vitest'
// with config option { sequence: { concurrent: true } }
test('concurrent test 1', async () => { /* ... */ })
test('concurrent test 2', async () => { /* ... */ })
test.sequential('sequential test 1', async () => { /* ... */ })
test.sequential('sequential test 2', async () => { /* ... */ })
// within concurrent suite
describe.concurrent('suite', () => {
test('concurrent test 1', async () => { /* ... */ })
test('concurrent test 2', async () => { /* ... */ })
test.sequential('sequential test 1', async () => { /* ... */ })
test.sequential('sequential test 2', async () => { /* ... */ })
})
```
## test.todo
- **Alias:** `it.todo`
Use `test.todo` to 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.
```ts
// An entry will be shown in the report for this test
test.todo('unimplemented test', () => {
// failing implementation...
})
```
::: tip
Vitest will automatically mark test as `todo` if test has no body.
:::
## test.fails
- **Alias:** `it.fails`
Use `test.fails` to indicate that an assertion will fail explicitly.
```ts
import { expect, test } from 'vitest'
test.fails('repro #1234', () => {
expect(add(1, 2)).toBe(4)
})
```
This flag is useful to track difference in behaviour of your library over time. For example, you can define a failing test without fixing the issue yet due to time constraints. Tests marked with `fails` are tracked in the test summary since Vitest 4.1.
## test.each
- **Alias:** `it.each`
::: tip
While `test.each` is provided for Jest compatibility,
Vitest also has [`test.for`](#test-for) with an additional feature to integrate [`TestContext`](/guide/test-context).
:::
Use `test.each` when you need to run the same test with different variables.
You can inject parameters with [printf formatting](https://nodejs.org/api/util.html#util_util_format_format_args) 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
- `%#`: 0-based index of the test case
- `%$`: 1-based index of the test case
- `%%`: single percent sign ('%')
```ts
import { expect, test } from 'vitest'
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) -> 3
```
You can also access object properties and array elements with `$` prefix:
```ts
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) -> 3
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add($0, $1) -> $2', (a, b, expected) => {
expect(a + b).toBe(expected)
})
// this will return
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3
```
You can also access Object attributes with `.`, if you are using objects as arguments:
```ts
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) -> 3b
```
* First row should be column names, separated by `|`;
* One or more subsequent rows of data supplied as template literal expressions using `${value}` syntax.
```ts
import { expect, test } from 'vitest'
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)
})
```
::: tip
Vitest processes `$values` with Chai `format` method. If the value is too truncated, you can increase [chaiConfig.truncateThreshold](/config/chaiconfig#chaiconfig-truncatethreshold) in your config file.
:::
## test.for
- **Alias:** `it.for`
Alternative to `test.each` to provide [`TestContext`](/guide/test-context).
The difference from `test.each` lies in how arrays are provided in the arguments.
Non-array arguments to `test.for` (including template string usage) work exactly the same as for `test.each`.
```ts
// `each` spreads arrays
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => { // [!code --]
expect(a + b).toBe(expected)
})
// `for` doesn't spread arrays (notice the square brackets around the arguments)
test.for([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => { // [!code ++]
expect(a + b).toBe(expected)
})
```
The 2nd argument is [`TestContext`](/guide/test-context) and can be used for concurrent snapshots, for example:
```ts
test.concurrent.for([
[1, 1],
[1, 2],
[2, 1],
])('add(%i, %i)', ([a, b], { expect }) => {
expect(a + b).toMatchSnapshot()
})
```
## test.describe 4.1.0 {#test-describe}
Scoped `describe`. See [describe](/api/describe) for more information.
## test.suite 4.1.0 {#test-suite}
Alias for `suite`. See [describe](/api/describe) for more information.
## test.beforeEach
Scoped `beforeEach` hook that inherits types from [`test.extend`](#test-extend). See [beforeEach](/api/hooks#beforeeach) for more information.
## test.afterEach
Scoped `afterEach` hook that inherits types from [`test.extend`](#test-extend). See [afterEach](/api/hooks#aftereach) for more information.
## test.beforeAll
Scoped `beforeAll` hook that inherits types from [`test.extend`](#test-extend). See [beforeAll](/api/hooks#beforeall) for more information.
## test.afterAll
Scoped `afterAll` hook that inherits types from [`test.extend`](#test-extend). See [afterAll](/api/hooks#afterall) for more information.
## test.aroundEach 4.1.0 {#test-aroundeach}
Scoped `aroundEach` hook that inherits types from [`test.extend`](#test-extend). See [aroundEach](/api/hooks#aroundeach) for more information.
## test.aroundAll 4.1.0 {#test-aroundall}
Scoped `aroundAll` hook that inherits types from [`test.extend`](#test-extend). See [aroundAll](/api/hooks#aroundall) for more information.
## bench {#bench}
- **Type:** `(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void`
::: danger
Benchmarking is experimental and does not follow SemVer.
:::
`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 the [`tinybench`](https://github.com/tinylibs/tinybench) library under the hood, inheriting all its options that can be used as a third argument.
```ts
import { bench } from 'vitest'
bench('normal sorting', () => {
const x = [1, 5, 4, 2, 3]
x.sort((a, b) => {
return a - b
})
}, { time: 1000 })
```
```ts
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
/**
* Throw if a task fails (events will not work if true)
*/
throws?: boolean
/**
* 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
}
```
After the test case is run, the output structure information is as follows:
```
name hz min max mean p75 p99 p995 p999 rme samples
· normal sorting 6,526,368.12 0.0001 0.3638 0.0002 0.0002 0.0002 0.0002 0.0004 ±1.41% 652638
```
```ts
export interface TaskResult {
/*
* the last error that was thrown while running the task
*/
error?: unknown
/**
* The amount of time in milliseconds to run the benchmark task (cycle).
*/
totalTime: number
/**
* the minimum value in the samples
*/
min: number
/**
* the maximum value in the samples
*/
max: number
/**
* the number of operations per second
*/
hz: number
/**
* how long each operation takes (ms)
*/
period: number
/**
* task samples of each task iteration time (ms)
*/
samples: number[]
/**
* samples mean/average (estimate of the population mean)
*/
mean: number
/**
* samples variance (estimate of the population variance)
*/
variance: number
/**
* samples standard deviation (estimate of the population standard deviation)
*/
sd: number
/**
* standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean)
*/
sem: number
/**
* degrees of freedom
*/
df: number
/**
* critical value of the samples
*/
critical: number
/**
* margin of error
*/
moe: number
/**
* relative margin of error
*/
rme: number
/**
* median absolute deviation
*/
mad: number
/**
* p50/median percentile
*/
p50: number
/**
* p75 percentile
*/
p75: number
/**
* p99 percentile
*/
p99: number
/**
* p995 percentile
*/
p995: number
/**
* p999 percentile
*/
p999: number
}
```
### bench.skip
- **Type:** `(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void`
You can use `bench.skip` syntax to skip running certain benchmarks.
```ts
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 | Function, fn: BenchFunction, options?: BenchOptions) => void`
Use `bench.only` to only run certain benchmarks in a given suite. This is useful when debugging.
```ts
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 | Function) => void`
Use `bench.todo` to stub benchmarks to be implemented later.
```ts
import { bench } from 'vitest'
bench.todo('unimplemented test')
```