home / skills / secondsky / claude-skills / bun-test-basics

bun-test-basics skill

/plugins/bun/skills/bun-test-basics

This skill helps you write and run Bun test suites with Jest-compatible syntax, including describe/it, patterns, and modifiers.

npx playbooks add skill secondsky/claude-skills --skill bun-test-basics

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

Files (1)
SKILL.md
4.1 KB
---
name: Bun Test Basics
description: Use for bun:test syntax, assertions, describe/it, test.skip/only/each, and basic patterns.
version: 1.0.0
---

# Bun Test Basics

Bun ships with a fast, built-in, Jest-compatible test runner. Tests run with the Bun runtime and support TypeScript/JSX natively.

## Quick Start

```bash
# Run all tests
bun test

# Run specific file
bun test ./test/math.test.ts

# Run tests matching pattern
bun test --test-name-pattern "addition"
```

## Writing Tests

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

test("2 + 2", () => {
  expect(2 + 2).toBe(4);
});

describe("math", () => {
  test("addition", () => {
    expect(1 + 1).toBe(2);
  });

  test("subtraction", () => {
    expect(5 - 3).toBe(2);
  });
});
```

## Test File Patterns

Bun discovers test files matching:
- `*.test.{js|jsx|ts|tsx}`
- `*_test.{js|jsx|ts|tsx}`
- `*.spec.{js|jsx|ts|tsx}`
- `*_spec.{js|jsx|ts|tsx}`

## Test Modifiers

```typescript
// Skip a test
test.skip("not ready", () => {
  // won't run
});

// Only run this test
test.only("focus on this", () => {
  // other tests won't run
});

// Placeholder for future test
test.todo("implement later");

// Expected to fail
test.failing("known bug", () => {
  throw new Error("This is expected");
});
```

## Parameterized Tests

```typescript
test.each([
  [1, 1, 2],
  [2, 2, 4],
  [3, 3, 6],
])("add(%i, %i) = %i", (a, b, expected) => {
  expect(a + b).toBe(expected);
});

// With objects
test.each([
  { a: 1, b: 2, expected: 3 },
  { a: 5, b: 5, expected: 10 },
])("add($a, $b) = $expected", ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});
```

## Concurrent Tests

```typescript
// Run tests in parallel
test.concurrent("async test 1", async () => {
  await fetch("/api/1");
});

test.concurrent("async test 2", async () => {
  await fetch("/api/2");
});

// Force sequential when using --concurrent
test.serial("must run alone", () => {
  // runs sequentially
});
```

## Common Matchers

```typescript
// Equality
expect(value).toBe(4);           // Strict equality
expect(obj).toEqual({ a: 1 });   // Deep equality
expect(value).toStrictEqual(4);  // Strict + type

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

// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3);
expect(value).toBeLessThan(5);
expect(value).toBeCloseTo(0.3, 5);  // Floating point

// Strings
expect(str).toMatch(/pattern/);
expect(str).toContain("substring");
expect(str).toStartWith("Hello");
expect(str).toEndWith("world");

// Arrays
expect(arr).toContain(item);
expect(arr).toContainEqual({ a: 1 });
expect(arr).toHaveLength(3);

// Objects
expect(obj).toHaveProperty("key");
expect(obj).toHaveProperty("key", value);
expect(obj).toMatchObject({ a: 1 });

// Exceptions
expect(() => fn()).toThrow();
expect(() => fn()).toThrow("message");
expect(() => fn()).toThrow(CustomError);

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

// Negation
expect(value).not.toBe(5);
```

## CLI Options

```bash
# Timeout per test (default 5000ms)
bun test --timeout 20

# Bail after N failures
bun test --bail
bun test --bail=10

# Watch mode
bun test --watch

# Random order
bun test --randomize
bun test --seed 12345

# Concurrent execution
bun test --concurrent
bun test --concurrent --max-concurrency 4

# Filter by name
bun test -t "pattern"
```

## Output Reporters

```bash
# Dots (compact)
bun test --dots

# JUnit XML (CI/CD)
bun test --reporter=junit --reporter-outfile=./results.xml
```

## Common Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `Test timeout` | Test exceeds 5s | Use `--timeout` or optimize |
| `No tests found` | Wrong file pattern | Check file naming |
| `expect is not defined` | Missing import | Import from `bun:test` |
| `Assertion failed` | Test failure | Check expected vs actual |

## When to Load References

Load `references/matchers.md` when:
- Need complete matcher reference
- Custom matcher patterns

Load `references/cli-options.md` when:
- Full CLI flag reference
- Advanced execution options

Overview

This skill teaches Bun's built-in test runner patterns and syntax for fast, Jest-compatible testing in TypeScript/JSX. It covers core test primitives, file discovery patterns, modifiers like skip/only/todo, parameterized and concurrent tests, common matchers, and useful CLI options. Use it to get tests running quickly and to standardize test patterns for projects using Bun.

How this skill works

The skill inspects and explains Bun test primitives (test, describe, expect) and file naming conventions that Bun auto-discovers. It walks through test modifiers (skip/only/todo/failing), parameterized tests with test.each, concurrent/serial execution, and common assertion matchers. It also summarizes CLI flags for running, filtering, and reporting test runs.

When to use it

  • When you need a quick guide to write Bun-compatible tests in TypeScript or JSX.
  • When configuring test file naming so Bun discovers tests automatically.
  • When implementing parameterized or concurrent test cases.
  • When you need to tune test runs with CLI flags (timeout, bail, concurrency).
  • When you need common matcher examples for assertions and async testing.

Best practices

  • Import test helpers from bun:test at the top of each file to avoid runtime errors.
  • Keep test files named with *.test.*, *.spec.*, or *_test.* so Bun auto-discovers them.
  • Prefer parameterized tests (test.each) to cover multiple inputs with one test body.
  • Use test.skip/test.only sparingly; remove before merging to avoid hidden tests.
  • Limit global test timeout or set per-run timeout with --timeout to catch slow tests early.
  • Use reporters (dots or junit) in CI for concise output or artifact generation.

Example use cases

  • Unit testing math utilities with describe blocks and multiple it-style tests.
  • Running a focused test file: bun test ./test/math.test.ts.
  • Data-driven tests for functions using test.each with arrays or objects.
  • Testing async endpoints concurrently with test.concurrent to speed up suites.
  • Generating JUnit XML in CI with --reporter=junit --reporter-outfile=./results.xml.

FAQ

How do I run only tests matching a name?

Use bun test --test-name-pattern "pattern" or the short flag -t "pattern" to filter by test name.

What file names will Bun discover as tests?

Bun finds files matching patterns like *.test.{js,ts,jsx,tsx}, *_test.*, *.spec.*, and *_spec.*.

How do I handle flaky or expected-failing tests?

Use test.failing for expected failures and test.skip to skip flaky cases until fixed; avoid long-term skips.