Skip to main content
Mocking replaces a dependency with a controlled implementation. Bun supports function mocks, spies, and module mocks.

Basic Function Mocks

Create mocks with the mock function.
test.ts

Jest Compatibility

You can also use jest.fn(), as in Jest. It behaves identically.
test.ts

Mock Function Properties

mock() returns a new function decorated with additional properties.
test.ts

Available Properties and Methods

Mock functions implement the following properties and methods:

Practical Examples

Basic Mock Usage

test.ts

Dynamic Mock Implementations

test.ts

Async Mocks

test.ts

Spies with spyOn()

Use spyOn() to track calls to a function without replacing it with a mock. Spies can be passed to .toHaveBeenCalled() and .toHaveBeenCalledTimes().
test.ts

Advanced Spy Usage

test.ts

Module Mocks with mock.module()

Use mock.module(path: string, callback: () => Object) to override the behavior of a module.
test.ts
Like the rest of Bun, module mocks support both import and require.

Overriding Already Imported Modules

Calling mock.module() overrides the module even if it has already been imported.
test.ts

Hoisting & Preloading

To make sure a module is mocked before it’s imported, use --preload to load your mocks before your tests run.
my-preload.ts
terminal
To avoid typing --preload every time you run tests, add it to your bunfig.toml:
bunfig.toml

Module Mock Best Practices

When to Use Preload

Mocking a module that’s already been imported updates the module cache, so anything that imports it gets the mocked version. The original module has already been evaluated, though, so its side effects have already happened. To prevent the original module from being evaluated at all, use --preload to load your mocks before your tests run.

Practical Module Mock Examples

api-client.test.ts

Mocking External Dependencies

database.test.ts

Global Mock Functions

Clear All Mocks

mock.clearAllMocks() resets the .mock.calls, .mock.instances, .mock.contexts, and .mock.results properties of every mock. Unlike mock.restore(), it does not restore the original implementation:
test.ts

Restore All Mocks

mock.restore() restores every mock at once, instead of calling mockFn.mockRestore() on each one. It does not reset modules overridden with mock.module().
test.ts
Call mock.restore() in an afterEach block, or in your test preload script, instead of repeating cleanup in every test.

Vitest Compatibility

For added compatibility with tests written for Vitest, Bun provides the vi object as an alias for parts of the Jest mocking API:
test.ts
You can port tests from Vitest without rewriting your mocks.

Implementation Details

Cache Interaction

Module mocks interact with both ESM and CommonJS module caches.

Lazy Evaluation

The mock factory callback is only evaluated when the module is imported or required.

Path Resolution

Bun resolves the module specifier the same way it resolves an import, supporting:
  • Relative paths ('./module')
  • Absolute paths ('/path/to/module')
  • Package names ('lodash')

Import Timing Effects

  • When mocking before first import: No side effects from the original module occur
  • When mocking after import: The original module’s side effects have already happened
For this reason, use --preload for mocks that need to prevent side effects.

Live Bindings

Mocked ESM modules maintain live bindings, so changing the mock updates all existing imports.

Advanced Patterns

Factory Functions

test.ts

Conditional Mocking

test.ts

Mock Cleanup Patterns

test.ts

Best Practices

Keep Mocks Simple

test.ts

Use Type-Safe Mocks

Test Mock Behavior

test.ts

Notes

Auto-mocking

Bun does not support the __mocks__ directory or auto-mocking. If this is blocking you from switching to Bun, file an issue.

ESM vs CommonJS

Module mocks have different implementations for ESM and CommonJS modules. For ES modules, Bun patches JavaScriptCore so it can override export values at runtime and update live bindings recursively.