Agent Skills: Bun Jest Migration

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

UncategorizedID: secondsky/claude-skills/bun-jest-migration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/secondsky/claude-skills/tree/HEAD/plugins/bun/skills/bun-jest-migration

Skill Files

Browse the full folder contents for bun-jest-migration.

Download Skill

Loading file tree…

plugins/bun/skills/bun-jest-migration/SKILL.md

Skill Metadata

Name
bun-jest-migration
Description
Use when migrating from Jest to Bun's test runner, import compatibility, mocks, and config.

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

| Jest | Bun | Notes | |------|-----|-------| | describe() | describe() | Identical | | it() / test() | test() | Use test() | | expect() | expect() | Same matchers | | beforeAll/Each | beforeAll/Each | Identical | | afterAll/Each | afterAll/Each | Identical | | jest.fn() | mock() | Use mock() | | jest.spyOn() | spyOn() | Identical |

Requires Changes

| Jest | Bun 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

| Error | Cause | Fix | |-------|-------|-----| | Cannot find module '@jest/globals' | Old import | Use bun:test | | jest is not defined | Global jest | Import from bun:test | | mock.module is not a function | Wrong import | import { mock } from "bun:test" | | Snapshot mismatch | Different serialization | Update 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