Skip to main content
Bun’s test runner supports lifecycle hooks for loading fixtures, managing shared resources, and configuring the test environment.

Per-test setup and teardown

Use beforeEach and afterEach for setup and cleanup that should happen around every test:

Per-scope setup and teardown

Use beforeAll and afterAll for setup and cleanup that should happen once for a group of tests. The scope is determined by where the hook is defined.

Scoped to a describe block

Scoped to a test file

Hooks defined at the top level of a file apply to all tests in that file:

Global setup and teardown

To run hooks before any test file executes, define them in a preload file:
setup.ts
Register the preload file in bunfig.toml:
bunfig.toml
Or pass it on the command line:

Async hooks

All hooks support async functions. Bun awaits each hook before proceeding.

onTestFinished

Use onTestFinished to register a callback that runs after a specific test completes, after all afterEach hooks:
onTestFinished is not supported inside concurrent tests. Use test.serial for tests that need per-test cleanup via this hook.

Execution order

When hooks are nested inside describe blocks, they run in this order:
Output:

Parameterized tests

test.each

Run the same test function with multiple inputs:
Pass objects to use named fields in the title:

describe.each

Create a parameterized suite — every test inside runs once per data set:

Error handling

If a hook throws, all tests in its scope are skipped:

Best practices

Use beforeAll/afterAll for expensive shared resources (servers, database connections) and beforeEach/afterEach for per-test state (mock data, DOM resets).
Failing to clean up can cause test pollution and flakiness:
Move complex setup logic into helper functions to keep hooks readable and testable: