--- outline: deep --- # Test API Reference The following types are used in the type signatures below ```ts type Awaitable = T | PromiseLike type TestFunction = () => Awaitable interface TestOptions { /** * Will fail the test if it takes too long to execute */ timeout?: number /** * Will retry the test specific number of times if it fails * * @default 0 */ retry?: number /** * Will repeat the same test several times even if it fails each time * If you have "retry" option and it fails, it will use every retry in each cycle * Useful for debugging random failings * * @default 0 */ repeats?: number } ``` Vitest 1.3.0 deprecates the use of options as the last parameter. You will see a deprecation message until 2.0.0 when this syntax will be removed. If you need to pass down options, use `test` function's second argument: ```ts import { test } from 'vitest' test('flaky test', () => {}, { retry: 3 }) // [!code --] test('flaky test', { retry: 3 }, () => {}) // [!code ++] ``` 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). ::: Most options support both dot-syntax and object-syntax allowing you to use whatever style you prefer. :::code-group ```ts [dot-syntax] twoslash import { test } from 'vitest' test.skip('skipped test', () => { // some logic that fails right now }) ``` ```ts [object-syntax] twoslash import { test } from 'vitest' test('skipped test', { skip: true }, () => { // some logic that fails right now }) ``` ::: ## test - **Alias:** `it` `test` 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. The default is 5 seconds, and can be configured globally with [testTimeout](/config/#testtimeout) ```ts twoslash import { expect, test } from 'vitest' test('should work as expected', () => { expect(Math.sqrt(4)).toBe(2) }) ``` ### test.extend {#test-extended} - **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.html#test-extend) for more information. ```ts import { expect, test } from 'vitest' const todos = [] const archive = [] const myTest = test.extend({ todos: async ({ task }, use) => { todos.push(1, 2, 3) await use(todos) todos.length = 0 }, archive }) myTest('add item', ({ todos }) => { expect(todos.length).toBe(3) todos.push(4) expect(todos.length).toBe(4) }) ``` ### 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 twoslash 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 twoslash import { assert, test } from 'vitest' test('skipped test', (context) => { context.skip() // 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 twoslash 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](/guide/testing-types). ::: ### test.runIf - **Alias:** `it.runIf` Opposite of [test.skipIf](#test-skipif). ```ts twoslash 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](/guide/testing-types). ::: ### test.only - **Alias:** `it.only` Use `test.only` to 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](/config/#testtimeout). ```ts twoslash 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. ``` # vitest interesting.test.ts ``` ### 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 twoslash 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() }) ``` ::: warning You cannot use this syntax, when using Vitest as [type checker](/guide/testing-types). ::: ### test.sequential - **Alias:** `it.sequential` `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 twoslash import { describe, test } from 'vitest' // ---cut--- // 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') ``` ### test.fails - **Alias:** `it.fails` Use `test.fails` to indicate that an assertion will fail explicitly. ```ts twoslash import { expect, test } from 'vitest' function myAsyncFunc() { return 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](/guide/testing-types). ::: ### 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 - `%#`: index of the test case - `%%`: single percent sign ('%') ```ts twoslash import { expect, test } from 'vitest' // ---cut--- 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 with `$` prefix, if you are using objects as arguments: ```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 ``` 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 ``` 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. ```ts twoslash import { expect, test } from 'vitest' // ---cut--- 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-truncatethreshold) in your config file. ::: ::: warning You cannot use this syntax, when using Vitest as [type checker](/guide/testing-types). ::: ### test.for - **Alias:** `it.for` Alternative of `test.each` to provide [`TestContext`](/guide/test-context). The difference from `test.each` is how array case is provided in the arguments. Other non array case (including template string usage) works exactly same. ```ts // `each` spreads array case 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 array case test.for([ [1, 1, 2], [1, 2, 3], [2, 1, 3], ])('add(%i, %i) -> %i', ([a, b, expected]) => { // [!code ++] expect(a + b).toBe(expected) }) ``` 2nd argument is [`TestContext`](/guide/test-context) and it can be used for concurrent snapshot, for example, ```ts test.concurrent.for([ [1, 1], [1, 2], [2, 1], ])('add(%i, %i)', ([a, b], { expect }) => { expect(a + b).matchSnapshot() }) ``` ## bench - **Type:** `(name: string | Function, 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`](https://github.com/tinylibs/tinybench) library under the hood, inheriting all its options that can be used as a third argument. ```ts twoslash 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 /** * 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 | Function, fn: BenchFunction, options?: BenchOptions) => void` You can use `bench.skip` syntax to skip running certain benchmarks. ```ts twoslash 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 twoslash 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 twoslash 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. ```ts twoslash // 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) }) }) ``` ```ts twoslash // 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: ```ts twoslash import { describe, expect, test } from 'vitest' function numberToCurrency(value: number | string) { 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 - **Alias:** `suite.skip` Use `describe.skip` in a suite to avoid running a particular describe block. ```ts twoslash import { assert, describe, test } from 'vitest' describe.skip('skipped suite', () => { test('sqrt', () => { // Suite skipped, no error assert.equal(Math.sqrt(4), 3) }) }) ``` ### describe.skipIf - **Alias:** `suite.skipIf` In some cases, you might run suites multiple times with different environments, and some of the suites might be environment-specific. Instead of wrapping the suite with `if`, you can use `describe.skipIf` to skip the suite whenever the condition is truthy. ```ts twoslash import { describe, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' describe.skipIf(isDev)('prod only test suite', () => { // this test suite only runs in production }) ``` ::: warning You cannot use this syntax when using Vitest as [type checker](/guide/testing-types). ::: ### describe.runIf - **Alias:** `suite.runIf` Opposite of [describe.skipIf](#describe-skipif). ```ts twoslash import { assert, describe, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' describe.runIf(isDev)('dev only test suite', () => { // this test suite only runs in development }) ``` ::: warning You cannot use this syntax, when using Vitest as [type checker](/guide/testing-types). ::: ### describe.only - **Type:** `(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void` Use `describe.only` to only run certain suites ```ts twoslash import { assert, describe, test } from 'vitest' // ---cut--- // 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 `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. ``` # vitest interesting.test.ts ``` ### describe.concurrent - **Alias:** `suite.concurrent` `describe.concurrent` runs all inner suites and tests in parallel ```ts twoslash import { describe, test } from 'vitest' // ---cut--- // All suites and tests within this suite will be run in parallel describe.concurrent('suite', () => { test('concurrent test 1', async () => { /* ... */ }) describe('concurrent suite 2', async () => { test('concurrent test inner 1', async () => { /* ... */ }) test('concurrent test inner 2', async () => { /* ... */ }) }) test.concurrent('concurrent test 3', async () => { /* ... */ }) }) ``` `.skip`, `.only`, and `.todo` works with concurrent suites. All the following combinations are valid: ```ts describe.concurrent(/* ... */) describe.skip.concurrent(/* ... */) // or describe.concurrent.skip(/* ... */) describe.only.concurrent(/* ... */) // or describe.concurrent.only(/* ... */) describe.todo.concurrent(/* ... */) // or describe.concurrent.todo(/* ... */) ``` When running concurrent tests, Snapshots and Assertions must use `expect` from the local [Test Context](/guide/test-context) to ensure the right test is detected. ```ts describe.concurrent('suite', () => { 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](/guide/testing-types). ::: ### describe.sequential - **Alias:** `suite.sequential` `describe.sequential` in a suite marks every 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 twoslash import { describe, test } from 'vitest' // ---cut--- describe.concurrent('suite', () => { test('concurrent test 1', async () => { /* ... */ }) test('concurrent test 2', async () => { /* ... */ }) describe.sequential('', () => { test('sequential test 1', async () => { /* ... */ }) test('sequential test 2', async () => { /* ... */ }) }) }) ``` ### describe.shuffle - **Alias:** `suite.shuffle` Vitest provides a way to run all tests in random order via CLI flag [`--sequence.shuffle`](/guide/cli) or config option [`sequence.shuffle`](/config/#sequence-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. ```ts twoslash import { describe, test } from 'vitest' // ---cut--- 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](/guide/testing-types). ::: ### describe.todo - **Alias:** `suite.todo` Use `describe.todo` to 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. ```ts // An entry will be shown in the report for this suite describe.todo('unimplemented suite') ``` ### describe.each - **Alias:** `suite.each` Use `describe.each` if you have more than one test that depends on the same data. ```ts twoslash import { describe, expect, test } from 'vitest' // ---cut--- 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. ```ts twoslash import { describe, expect, test } from 'vitest' // ---cut--- 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) }) }) ``` ::: warning You cannot use this syntax, when using Vitest as [type checker](/guide/testing-types). ::: ## 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, 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. ```ts 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 `beforeEach` ensures that user is added for each test. `beforeEach` also accepts an optional cleanup function (equivalent to `afterEach`). ```ts 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, 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. ```ts import { afterEach } from 'vitest' afterEach(async () => { await clearTestingData() // clear testing data after each test run }) ``` Here, the `afterEach` ensures that testing data is cleared after each test runs. ::: tip Vitest 1.3.0 added [`onTestFinished`](#ontestfinished) hook. You can call it during the test execution to cleanup any state after the test has finished running. ::: ### beforeAll - **Type:** `beforeAll(fn: () => Awaitable, 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. ```ts import { beforeAll } from 'vitest' beforeAll(async () => { await startMocking() // called once before all tests run }) ``` Here the `beforeAll` ensures that the mock data is set up before tests run. `beforeAll` also accepts an optional cleanup function (equivalent to `afterAll`). ```ts 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, 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. ```ts import { afterAll } from 'vitest' afterAll(async () => { await stopMocking() // this method is called after all tests run }) ``` Here the `afterAll` ensures that `stopMocking` method is called after all tests run. ## Test Hooks Vitest provides a few hooks that you can call _during_ the test execution to cleanup the state when the test has finished runnning. ::: warning These hooks will throw an error if they are called outside of the test body. ::: ### onTestFinished {#ontestfinished} This hook is always called after the test has finished running. It is called after `afterEach` hooks since they can influence the test result. It receives a `TaskResult` object with the current test result. ```ts {1,5} import { onTestFinished, test } from 'vitest' test('performs a query', () => { const db = connectDb() onTestFinished(() => db.close()) db.query('SELECT * FROM users') }) ``` ::: warning If you are running tests concurrently, you should always use `onTestFinished` hook from the test context since Vitest doesn't track concurrent tests in global hooks: ```ts {3,5} import { test } from 'vitest' test.concurrent('performs a query', ({ onTestFinished }) => { const db = connectDb() onTestFinished(() => db.close()) db.query('SELECT * FROM users') }) ``` ::: This hook is particularly useful when creating reusable logic: ```ts // this can be in a separate file function getTestDb() { const db = connectMockedDb() onTestFinished(() => db.close()) return db } test('performs a user query', async () => { const db = getTestDb() expect( await db.query('SELECT * from users').perform() ).toEqual([]) }) test('performs an organization query', async () => { const db = getTestDb() expect( await db.query('SELECT * from organizations').perform() ).toEqual([]) }) ``` ::: tip This hook is always called in reverse order and is not affected by [`sequence.hooks`](/config/#sequence-hooks) option. ::: ### onTestFailed This hook is called only after the test has failed. It is called after `afterEach` hooks since they can influence the test result. It receives a `TaskResult` object with the current test result. This hook is useful for debugging. ```ts {1,5-7} import { onTestFailed, test } from 'vitest' test('performs a query', () => { const db = connectDb() onTestFailed((e) => { console.log(e.result.errors) }) db.query('SELECT * FROM users') }) ``` ::: warning If you are running tests concurrently, you should always use `onTestFailed` hook from the test context since Vitest doesn't track concurrent tests in global hooks: ```ts {3,5-7} import { test } from 'vitest' test.concurrent('performs a query', ({ onTestFailed }) => { const db = connectDb() onTestFailed((result) => { console.log(result.errors) }) db.query('SELECT * FROM users') }) ``` :::