home / skills / daleseo / bun-skills / bun-test

bun-test skill

/skills/bun-test

This skill helps you configure Bun's built-in test runner with Jest-compatible APIs, enabling faster, scalable unit, integration, and snapshot testing.

npx playbooks add skill daleseo/bun-skills --skill bun-test

Review the files below or copy the command above to add this skill to your agents.

Files (4)
SKILL.md
8.9 KB
---
name: bun-test
description: Configure Bun's built-in test runner with Jest-compatible APIs. Use when setting up testing infrastructure, writing unit/integration/snapshot tests, migrating from Jest, or configuring test coverage. 3-10x faster than Jest.
compatibility: Requires Bun 1.0+
allowed-tools: ["Bash", "Write", "Read"]
metadata:
  author: dale
  category: bun-runtime
  tags: [bun, testing, jest, unit-tests, tdd]
---

# Bun Test Configuration

Set up Bun's built-in test runner with Jest-compatible APIs and significantly faster execution (3-10x faster than Jest).

## Quick Reference

For detailed patterns, see:
- **Jest Migration**: [jest-migration.md](references/jest-migration.md) - Complete Jest to Bun migration guide
- **Mocking**: [mocking.md](references/mocking.md) - Mock functions, spies, module mocking
- **Examples**: [examples.md](references/examples.md) - Test patterns for APIs, databases, async code

## Core Workflow

### 1. Check Prerequisites

```bash
# Verify Bun installation
bun --version

# Check if project exists
ls -la package.json
```

### 2. Determine Testing Needs

Ask the user what type of testing they need:

- **Unit Testing**: Test individual functions and modules
- **Integration Testing**: Test component interactions
- **API Testing**: Test HTTP endpoints
- **Snapshot Testing**: Test output consistency

### 3. Create Test Directory Structure

```bash
# Create test directories
mkdir -p tests/{unit,integration,fixtures}
```

Recommended structure:
```
project/
├── src/
│   ├── utils.ts
│   └── components/
├── tests/
│   ├── unit/              # Unit tests
│   ├── integration/       # Integration tests
│   ├── fixtures/          # Test data
│   └── setup.ts          # Global setup
├── package.json
└── bunfig.toml           # Test configuration
```

### 4. Configure Bun Test

Create `bunfig.toml` in project root:

```toml
[test]
# Preload files before running tests
preload = ["./tests/setup.ts"]

# Code coverage
coverage = true
coverageDir = "coverage"
coverageThreshold = 80

# Timeouts (in milliseconds)
timeout = 5000

# Bail after first failure
bail = false
```

### 5. Create Test Setup File

Create `tests/setup.ts`:

```typescript
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";

// Global test setup
beforeAll(() => {
  console.log("🧪 Starting test suite");
  process.env.NODE_ENV = "test";
});

afterAll(() => {
  console.log("✅ Test suite complete");
});

// Reset mocks before each test
beforeEach(() => {
  // Clear mock state
});

afterEach(() => {
  // Cleanup after each test
});

// Global test utilities
globalThis.testHelpers = {
  wait: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)),
};
```

### 6. Write First Test

Create `tests/unit/example.test.ts`:

```typescript
import { describe, it, expect, test } from "bun:test";

// Simple test
test("addition works", () => {
  expect(1 + 1).toBe(2);
});

// Describe blocks for organization
describe("Array utilities", () => {
  it("should filter even numbers", () => {
    const numbers = [1, 2, 3, 4, 5, 6];
    const evens = numbers.filter(n => n % 2 === 0);

    expect(evens).toEqual([2, 4, 6]);
    expect(evens).toHaveLength(3);
  });
});

// Async tests
describe("Async operations", () => {
  it("should handle promises", async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
});
```

For more test examples (API testing, database testing, etc.), see [examples.md](references/examples.md).

### 7. Add Mocking (If Needed)

```typescript
import { describe, it, expect, mock, spyOn } from "bun:test";

describe("Mock functions", () => {
  it("should create mock functions", () => {
    const mockFn = mock((x: number) => x * 2);

    const result = mockFn(5);

    expect(result).toBe(10);
    expect(mockFn).toHaveBeenCalledTimes(1);
    expect(mockFn).toHaveBeenCalledWith(5);
  });

  it("should spy on methods", () => {
    const obj = {
      method: (x: number) => x * 2,
    };

    const spy = spyOn(obj, "method");

    obj.method(5);

    expect(spy).toHaveBeenCalledWith(5);
    expect(spy).toHaveReturnedWith(10);
  });
});
```

For advanced mocking patterns, see [mocking.md](references/mocking.md).

### 8. Update package.json

Add test scripts:

```json
{
  "scripts": {
    "test": "bun test",
    "test:watch": "bun test --watch",
    "test:coverage": "bun test --coverage",
    "test:ui": "bun test --coverage --reporter=html"
  }
}
```

### 9. Run Tests

```bash
# Run all tests
bun test

# Run specific file
bun test tests/unit/utils.test.ts

# Watch mode
bun test --watch

# With coverage
bun test --coverage

# Filter by name
bun test --test-name-pattern="should handle"
```

## Jest Migration

If migrating from Jest, see [jest-migration.md](references/jest-migration.md) for:
- Import updates (`@jest/globals` → `bun:test`)
- Mock syntax changes (`jest.fn()` → `mock()`)
- Configuration migration
- Compatibility notes

**Key changes:**
```typescript
// Before (Jest)
import { describe, it, expect } from '@jest/globals';
const mockFn = jest.fn();

// After (Bun)
import { describe, it, expect, mock } from 'bun:test';
const mockFn = mock();
```

## Common Test Patterns

### Testing Functions

```typescript
import { test, expect } from "bun:test";

function add(a: number, b: number): number {
  return a + b;
}

test("add function", () => {
  expect(add(2, 3)).toBe(5);
  expect(add(-1, 1)).toBe(0);
});
```

### Testing Errors

```typescript
test("should throw errors", () => {
  const throwError = () => {
    throw new Error("Something went wrong");
  };

  expect(throwError).toThrow("Something went wrong");
  expect(throwError).toThrow(Error);
});

test("should reject promises", async () => {
  const asyncReject = async () => {
    throw new Error("Async error");
  };

  await expect(asyncReject()).rejects.toThrow("Async error");
});
```

### Snapshot Testing

```typescript
test("should match snapshot", () => {
  const data = {
    id: 1,
    name: "Test User",
    email: "[email protected]",
  };

  expect(data).toMatchSnapshot();
});

test("should match inline snapshot", () => {
  const config = { theme: "dark", language: "en" };

  expect(config).toMatchInlineSnapshot(`
    {
      "theme": "dark",
      "language": "en"
    }
  `);
});
```

## Matchers Reference

Common matchers available:

```typescript
// Equality
expect(value).toBe(expected);           // ===
expect(value).toEqual(expected);        // Deep equality

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeDefined();
expect(value).toBeUndefined();

// Numbers
expect(number).toBeGreaterThan(3);
expect(number).toBeLessThan(5);

// Strings
expect(string).toMatch(/pattern/);
expect(string).toContain("substring");

// Arrays
expect(array).toContain(item);
expect(array).toHaveLength(3);

// Objects
expect(object).toHaveProperty("key");
expect(object).toMatchObject({ subset });

// Promises
await expect(promise).resolves.toBe(value);
await expect(promise).rejects.toThrow();

// Mock functions
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(3);
expect(mockFn).toHaveBeenCalledWith(arg1, arg2);
```

## Test Organization

### Setup and Teardown

```typescript
import { beforeAll, afterAll, beforeEach, afterEach, describe, it } from "bun:test";

describe("User service", () => {
  let db: Database;

  beforeAll(async () => {
    // Setup before all tests
    db = await connectToDatabase();
  });

  afterAll(async () => {
    // Cleanup after all tests
    await db.close();
  });

  beforeEach(async () => {
    // Reset before each test
    await db.clear();
  });

  it("should create user", async () => {
    const user = await db.users.create({ name: "Test" });
    expect(user.id).toBeDefined();
  });
});
```

## Coverage Configuration

View coverage report:

```bash
# Generate coverage
bun test --coverage

# View HTML report
bun test --coverage --reporter=html
open coverage/index.html
```

Set coverage thresholds in `bunfig.toml`:

```toml
[test]
coverage = true
coverageThreshold = 80  # Fail if coverage < 80%
```

## Debugging Tests

```bash
# Run with debugger
bun test --inspect

# Verbose output
bun test --verbose

# Show all test results
bun test --reporter=tap
```

## Performance

Bun test is significantly faster than Jest:

- **Jest**: ~15 seconds for 100 tests
- **Bun**: ~2 seconds for 100 tests

**3-10x faster execution!**

## Completion Checklist

- ✅ Test directory structure created
- ✅ bunfig.toml configured
- ✅ Test setup file created
- ✅ Example tests written
- ✅ Package.json scripts updated
- ✅ Tests run successfully
- ✅ Coverage configured (if needed)

## Next Steps

After basic setup:

1. **Write tests**: Add tests for critical business logic
2. **CI/CD**: Configure tests to run in your pipeline
3. **Coverage**: Set up coverage reporting
4. **Pre-commit**: Add pre-commit hooks to run tests
5. **Documentation**: Document testing patterns for the team

For detailed implementations, see the reference files linked above.

Overview

This skill configures Bun's built-in test runner with Jest-compatible APIs to speed up testing and simplify migration from Jest. It provides sensible defaults, example tests, mocking utilities, coverage settings, and package scripts so teams can get running quickly. Expect 3–10x faster test execution compared to Jest.

How this skill works

It creates a recommended test directory layout, a global setup file, and a bunfig.toml test configuration that enables preload files, timeouts, coverage and thresholds. It shows Jest-to-Bun API swaps (import from 'bun:test', mock() in place of jest.fn()), example unit/integration/snapshot tests, and script entries to run, watch, and generate coverage. The skill also includes common patterns for setup/teardown, mocking, and debugging.

When to use it

  • Setting up a new project test runner with Bun
  • Migrating an existing Jest test suite to Bun
  • Writing unit, integration, API, or snapshot tests
  • Enabling fast local test feedback and CI runs
  • Configuring coverage thresholds and HTML reports

Best practices

  • Organize tests into tests/unit, tests/integration, and tests/fixtures for clarity
  • Create tests/setup.ts and preload it via bunfig.toml for global setup/teardown and utilities
  • Keep coverageThreshold in bunfig.toml and run test:coverage in CI to enforce quality
  • Use Bun's mock() and spyOn helpers for deterministic tests and to mirror Jest patterns during migration
  • Add package.json scripts for test, test:watch, test:coverage and include bun test flags in CI pipelines

Example use cases

  • Add basic unit tests for utility functions and run them with bun test
  • Migrate Jest tests: replace @jest/globals imports with 'bun:test' and jest.fn() with mock()
  • Write integration tests that connect to a test database and use beforeAll/afterAll to manage lifecycle
  • Create snapshot tests for serializable outputs and store snapshots alongside tests
  • Enable coverage reporting and fail CI when coverage falls below bunfig.toml thresholds

FAQ

Do I need to rewrite all Jest tests to use Bun APIs?

No — common patterns map directly (e.g., @jest/globals → 'bun:test', jest.fn() → mock()). Small import and mock updates usually suffice.

How do I enable coverage and enforce a minimum threshold?

Set coverage = true and coverageThreshold in bunfig.toml, then run bun test --coverage; CI can fail when coverage is below the threshold.