Marketplace

Bun Jest Migration

Use when migrating from Jest to Bun's test runner, import compatibility, mocks, and config.

$ 安裝

git clone https://github.com/secondsky/claude-skills /tmp/claude-skills && cp -r /tmp/claude-skills/plugins/bun/skills/bun-jest-migration ~/.claude/skills/claude-skills

// tip: Run this command in your terminal to install the skill


name: Bun Jest Migration description: Use when migrating from Jest to Bun's test runner, import compatibility, mocks, and config. version: 1.0.0

Bun Jest Migration

Bun's test runner is Jest-compatible. Most Jest tests run without changes.

Quick Migration

# 1. Remove Jest dependencies
bun remove jest ts-jest @types/jest babel-jest

# 2. Update test script
# package.json: "test": "bun test"

# 3. Run tests
bun test

Import Changes

// Before (Jest)
import { describe, it, expect, jest } from '@jest/globals';

// After (Bun) - No import needed, or explicit:
import { describe, test, expect, mock, spyOn } from "bun:test";

API Compatibility

Fully Compatible

JestBunNotes
describe()describe()Identical
it() / test()test()Use test()
expect()expect()Same matchers
beforeAll/EachbeforeAll/EachIdentical
afterAll/EachafterAll/EachIdentical
jest.fn()mock()Use mock()
jest.spyOn()spyOn()Identical

Requires Changes

JestBun Equivalent
jest.mock('module')mock.module('module', () => {...})
jest.useFakeTimers()import { setSystemTime } from "bun:test"
jest.setTimeout()Third argument to test()
jest.clearAllMocks()Call .mockClear() on each mock

Mock Migration

Mock Functions

// Jest
const fn = jest.fn().mockReturnValue('value');

// Bun
const fn = mock(() => 'value');
// Or for compatibility:
import { jest } from "bun:test";
const fn = jest.fn(() => 'value');

Module Mocking

// Jest (top-level hoisting)
jest.mock('./utils', () => ({
  helper: jest.fn(() => 'mocked')
}));

// Bun (inline, no hoisting)
import { mock } from "bun:test";
mock.module('./utils', () => ({
  helper: mock(() => 'mocked')
}));

Spy Migration

// Jest
jest.spyOn(console, 'log').mockImplementation(() => {});

// Bun (identical)
spyOn(console, 'log').mockImplementation(() => {});

Timer Migration

// Jest
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01'));
jest.advanceTimersByTime(1000);

// Bun - supports Jest-compatible timer APIs
import { setSystemTime } from "bun:test";
import { jest } from "bun:test";

jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01'));
jest.advanceTimersByTime(1000);  // Now supported

Snapshot Testing

// Jest
expect(component).toMatchSnapshot();
expect(data).toMatchInlineSnapshot(`"expected"`);

// Bun (identical)
expect(component).toMatchSnapshot();
expect(data).toMatchInlineSnapshot(`"expected"`);

Update snapshots:

bun test --update-snapshots

Configuration Migration

jest.config.js → bunfig.toml

// jest.config.js (before)
module.exports = {
  testMatch: ['**/*.test.ts'],
  testTimeout: 10000,
  setupFilesAfterEnv: ['./jest.setup.ts'],
  collectCoverage: true,
  coverageThreshold: { global: { lines: 80 } }
};
# bunfig.toml (after)
[test]
root = "./"
preload = ["./jest.setup.ts"]
timeout = 10000
coverage = true
coverageThreshold = 0.8

Common Migration Issues

Issue: jest.mock Not Working

// Jest mock hoisting doesn't exist in Bun
// Move mock.module before imports or use dynamic imports

// Solution 1: Use mock.module at top
mock.module('./api', () => ({ fetch: mock() }));
import { fetch } from './api';

// Solution 2: Dynamic import
const mockFetch = mock();
mock.module('./api', () => ({ fetch: mockFetch }));
const { fetch } = await import('./api');

Issue: Timer Functions Missing

// Bun timer support is limited
// Use setSystemTime for date mocking
import { setSystemTime } from "bun:test";

beforeEach(() => {
  setSystemTime(new Date('2024-01-01'));
});

afterEach(() => {
  setSystemTime(); // Reset to real time
});

Issue: Custom Matchers

// Jest
expect.extend({ toBeWithinRange(received, floor, ceiling) {...} });

// Bun (same API)
import { expect } from "bun:test";
expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling;
    return {
      pass,
      message: () => `expected ${received} to be within ${floor}-${ceiling}`
    };
  }
});

Step-by-Step Migration

  1. Remove Jest packages

    bun remove jest ts-jest @types/jest babel-jest jest-environment-jsdom
    
  2. Update package.json

    {
      "scripts": {
        "test": "bun test",
        "test:watch": "bun test --watch",
        "test:coverage": "bun test --coverage"
      }
    }
    
  3. Convert jest.config.js to bunfig.toml

  4. Update imports in test files

    • Find/replace @jest/globalsbun:test
    • Find/replace jest.fn()mock()
    • Find/replace jest.mock()mock.module()
  5. Run and fix

    bun test 2>&1 | head -50  # Check first errors
    

Common Errors

ErrorCauseFix
Cannot find module '@jest/globals'Old importUse bun:test
jest is not definedGlobal jestImport from bun:test
mock.module is not a functionWrong importimport { mock } from "bun:test"
Snapshot mismatchDifferent serializationUpdate with --update-snapshots

When to Load References

Load references/compatibility-matrix.md when:

  • Full Jest API compatibility details
  • Unsupported features list
  • Workarounds for missing features