> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Hooks

Hooks allow you to run setup and teardown logic before or after your tests or test suites.

## beforeAll

- **Type:** `(fn: (ctx: SuiteContext) => void | Promise<void>, timeout?: number) => void`

Runs once before all tests in the current suite.

Rstest does not run this hook when the current suite has no tests to run. For example, this happens when all tests are skipped, excluded by test name filtering, or not selected by `test.only`.

```ts
import { beforeAll } from '@rstest/core';

beforeAll(async (ctx) => {
  // Setup logic before all tests
  // ctx.filepath gives the current test file path
  ctx.meta.startedAt = Date.now();
});
```

`beforeAll` also supports returning a function that runs after all tests for cleanup (equivalent to `afterAll`):

```ts
import { beforeAll } from '@rstest/core';

beforeAll(async () => {
  const cleanUp = await doSomething();

  // Cleanup logic after all tests
  return async () => {
    await cleanUp();
  };
});
```

## afterAll

- **Type:** `(fn: (ctx: SuiteContext) => void | Promise<void>, timeout?: number) => void`

Runs once after all tests in the current suite.

Rstest does not run this hook when the current suite has no tests to run. For example, this happens when all tests are skipped, excluded by test name filtering, or not selected by `test.only`.

```ts
import { afterAll } from '@rstest/core';

afterAll(async (ctx) => {
  // Cleanup logic after all tests
  ctx.meta.finished = true;
});
```


[Added in v0.11.1](https://github.com/web-infra-dev/rstest/releases/tag/v0.11.1)

`ctx.meta` is the mutable metadata object for the current suite. If the suite was declared with `describe(name, { meta }, fn)`, `ctx.meta` starts with that metadata after suite inheritance has been applied. File-level hooks write metadata to `TestFileResult.meta`; hooks inside a `describe` block write metadata to that suite result passed to custom reporters.

## beforeEach

- **Type:** `<ExtraContext = object>(fn: (ctx: TestContext & ExtraContext) => void | ((ctx: TestContext & ExtraContext) => void | Promise<void>) | Promise<void | ((ctx: TestContext & ExtraContext) => void | Promise<void>)>, timeout?: number) => void`

See [`TestContext`](/api/runtime-api/test-api/test.md#testcontext) for the `ctx` fields (the same applies to the per-test hooks below).

Runs before each test in the current suite.

```ts
import { beforeEach } from '@rstest/core';

beforeEach(async () => {
  // Setup logic before each test
});
```

`beforeEach` also supports returning a function that runs after each test for cleanup (equivalent to `afterEach`):

```ts
import { beforeEach } from '@rstest/core';

beforeEach(async () => {
  const cleanUp = await doSomething();

  // Cleanup logic after each test
  return async () => {
    await cleanUp();
  };
});
```


[Added in v0.11.4](https://github.com/web-infra-dev/rstest/releases/tag/v0.11.4)

The `beforeEach` and `afterEach` callbacks, as well as a cleanup returned by `beforeEach`, can use fixtures created with `test.extend`. Pass the fixture type as `ExtraContext`; Rstest initializes each fixture before the callback that first requests it. See [Using fixtures in hooks](/api/runtime-api/test-api/test.md#using-fixtures-in-hooks).

List fixture dependencies through direct object destructuring in the hook parameter. Rstest does not infer dependencies from the hook body. Object rest properties and default values are not supported in fixture-aware callbacks.

## afterEach

- **Type:** `<ExtraContext = object>(fn: (ctx: TestContext & ExtraContext) => void | Promise<void>, timeout?: number) => void`

Runs after each test in the current suite.

```ts
import { afterEach } from '@rstest/core';

afterEach(async () => {
  // Cleanup logic after each test
});
```

## onTestFinished

- **Type:** `(fn: (ctx: TestContext) => void | Promise<void>, timeout?: number) => void`

Called after the test has finished running **whatever the test result is**. This can be used to perform cleanup actions. This hook will be called after `afterEach`.

```ts
import { onTestFinished, test } from '@rstest/core';

test('test server', () => {
  const server = startServer();
  // Register a cleanup function to close the server after the test
  onTestFinished(() => server.close());

  server.listen(3000, () => {
    console.log('Server is running on port 3000');
  });
});
```

It should be noted that when you use the `onTestFinished` hook in concurrent tests, you should get the hook from the test context. This is because Rstest cannot accurately track the specific test to which the global `onTestFinished` hook belongs in concurrent tests.

```ts
describe.concurrent('concurrent suite', () => {
  test('test 1', async ({ onTestFinished }) => {
    /* ... */
  });
  test('test 2', async ({ onTestFinished }) => {
    /* ... */
  });
});
```

## onTestFailed

- **Type:** `(fn: (ctx: TestContext) => void | Promise<void>, timeout?: number) => void`

Called after the test has failed.

```ts
import { onTestFailed, test } from '@rstest/core';

test('test server', () => {
  const server = startServer();

  onTestFailed(({ task }) => {
    console.log(task.result?.errors);
  });

  server.listen(3000, () => {
    console.log('Server is running on port 3000');
  });
});
```

It should be noted that when you use the `onTestFailed` hook in concurrent tests, you should get the hook from the test context. This is because Rstest cannot accurately track the specific test to which the global `onTestFailed` hook belongs in concurrent tests.
