---
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/jest#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.
Set `concurrent` to `false` to opt out of concurrency inherited from [`describe.concurrent`](/api/describe#describe-concurrent) or [`sequence.concurrent`](/config/sequence#sequence-concurrent):
```ts
test('runs sequentially', { concurrent: false }, async () => {
// ...
})
```
### 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.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 formats interpolated title values with its display formatter. If the value is too truncated, you can increase [taskTitleValueFormatTruncate](/config/tasktitlevalueformattruncate) 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}
::: warning Updated in Vitest 5
The benchmarking API has been rewritten. `bench` is no longer a top-level import from `vitest`, and the `bench.skip` / `bench.only` / `bench.todo` helpers have been removed. `bench` is now a [test-context fixture](/guide/test-context#bench) accessed from inside a `test()`.
See the [Benchmarking guide](/guide/benchmarking) for the new API.
:::