Skip to main content
Bun’s test runner has specific runtime behavior that affects how tests are executed, how state is managed, and how resources are handled.

Test isolation

File-level isolation

Each test file runs in its own module scope:
Tests in different files don’t share global state.

Test-level isolation

Tests within the same file share the module scope:
Use beforeEach to reset state:

Execution model

Sequential execution

By default, tests in a file run sequentially:

Concurrent execution

Mark tests as concurrent:

File-level concurrency

Run multiple test files in parallel:
Or configure in bunfig.toml:

Global state

Process environment

Environment variables are shared across all tests:
Reset in beforeEach:

Global objects

Changes to global objects persist:

Module caching

Modules are cached per test file:
To clear cache, use dynamic import:

Resource management

Automatic cleanup with using

Bun supports JavaScript’s using keyword:

Manual cleanup

Use afterEach or afterAll for cleanup:

Error handling

Unhandled promise rejections

Bun catches unhandled rejections and fails the test:

Uncaught exceptions

Uncaught exceptions fail the test:

Async test completion

Async tests must complete:

Memory management

Garbage collection

Bun runs garbage collection between test files:

Memory leaks

Avoid keeping references in global scope:

Performance characteristics

Test startup time

First test in a file includes:
  • Module loading
  • Dependency resolution
  • Global setup

Optimization tips

  1. Minimize global imports:
  2. Use lazy imports for heavy dependencies:
  3. Share expensive setup with beforeAll:

Timeout behavior

Default timeout

Tests timeout after 5 seconds by default:

Custom timeout

Set per-test timeout:

Infinite operations

Ensure tests complete:

Exit behavior

Normal exit

Bun exits with code 0 if all tests pass:

Failure exit

Bun exits with code 1 if any test fails:

Hanging processes

Bun waits for async operations to complete:
Clean up resources: