bun-test-patterns
Bun test runner - Jest-compatible testing with mocks, snapshots, coverage, and DOM testing patterns When user writes tests with Bun, uses bun:test, creates mocks, runs test coverage, or mentions describe/it/expect patterns
What this skill does
# Bun Test Patterns Agent
## What's New in Bun Test (2024-2025)
- **Vitest compatibility**: `vi` alias for easier migration
- **Module mocking**: `mock.module()` for ESM/CJS mocking
- **Type testing**: `expectTypeOf` for TypeScript type assertions
- **Custom matchers**: `expect.extend()` for custom assertions
- **Improved coverage**: Built-in code coverage reporting
- **Watch mode**: Automatic test re-runs on file changes
## Running Tests
### Basic Commands
```bash
# Run all tests
bun test
# Run specific file
bun test math.test.ts
# Run tests matching pattern
bun test --test-name-pattern "add"
bun test -t "add"
# Run with watch mode
bun test --watch
# Run with coverage
bun test --coverage
# Run with timeout
bun test --timeout 10000
# Run specific files by path pattern
bun test src/utils
```
### File Discovery
Bun automatically finds test files matching:
- `*.test.{js|jsx|ts|tsx}`
- `*_test.{js|jsx|ts|tsx}`
- `*.spec.{js|jsx|ts|tsx}`
- `*_spec.{js|jsx|ts|tsx}`
### Configuration (bunfig.toml)
```toml
[test]
# Enable coverage by default
coverage = true
# Set coverage threshold
coverageThreshold = { line = 80, function = 80 }
# Preload scripts
preload = ["./test/setup.ts"]
# Test timeout in ms
timeout = 5000
# Smol mode for reduced memory
smol = true
```
## Writing Tests
### Basic Structure
```typescript
import { describe, test, it, expect, beforeAll, afterEach } from "bun:test";
describe("Calculator", () => {
describe("add()", () => {
it("adds two positive numbers", () => {
expect(add(2, 3)).toBe(5);
});
it("handles negative numbers", () => {
expect(add(-1, 1)).toBe(0);
});
});
});
```
### Test Modifiers
```typescript
// Skip a test
test.skip("not ready yet", () => {
// ...
});
// Run only this test
test.only("focus on this", () => {
// ...
});
// Mark as todo
test.todo("implement later");
// Conditional skip
test.if(process.env.CI)("only in CI", () => {
// ...
});
// Skip if condition
test.skipIf(!process.env.DB_URL)("needs database", () => {
// ...
});
```
### Async Tests
```typescript
// Async/await
test("fetches user", async () => {
const user = await fetchUser(1);
expect(user.name).toBe("Alice");
});
// Promise
test("resolves correctly", () => {
return fetchUser(1).then((user) => {
expect(user.name).toBe("Alice");
});
});
// Callback (done)
test("callback style", (done) => {
setTimeout(() => {
expect(true).toBe(true);
done();
}, 100);
});
```
### Timeout
```typescript
// Per-test timeout
test("slow operation", async () => {
const result = await slowOperation();
expect(result).toBeDefined();
}, 10000); // 10 second timeout
```
## Expect Matchers
### Equality
```typescript
expect(value).toBe(expected); // === comparison
expect(value).toEqual(expected); // deep equality
expect(value).toStrictEqual(expected); // strict deep equality
expect(value).not.toBe(other); // negation
```
### Truthiness
```typescript
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();
expect(value).toBeNaN();
```
### Numbers
```typescript
expect(num).toBeGreaterThan(5);
expect(num).toBeGreaterThanOrEqual(5);
expect(num).toBeLessThan(10);
expect(num).toBeLessThanOrEqual(10);
expect(num).toBeCloseTo(0.3, 5); // floating point
expect(num).toBePositive();
expect(num).toBeNegative();
expect(num).toBeInteger();
expect(num).toBeFinite();
```
### Strings
```typescript
expect(str).toMatch(/pattern/);
expect(str).toContain("substring");
expect(str).toStartWith("prefix");
expect(str).toEndWith("suffix");
expect(str).toHaveLength(10);
```
### Arrays and Iterables
```typescript
expect(arr).toContain(item);
expect(arr).toContainEqual({ id: 1 });
expect(arr).toHaveLength(3);
expect(arr).toBeArray();
expect(arr).toBeArrayOfSize(3);
expect(arr).toInclude(item);
expect(arr).toIncludeAllMembers([1, 2]);
expect(arr).toIncludeAnyMembers([1, 5]);
expect(arr).toSatisfyAll((x) => x > 0);
```
### Objects
```typescript
expect(obj).toHaveProperty("key");
expect(obj).toHaveProperty("nested.key", value);
expect(obj).toMatchObject({ subset: true });
expect(obj).toContainKey("key");
expect(obj).toContainKeys(["a", "b"]);
expect(obj).toContainAllKeys(["a", "b"]);
expect(obj).toContainValue(42);
```
### Functions and Errors
```typescript
expect(() => fn()).toThrow();
expect(() => fn()).toThrow("message");
expect(() => fn()).toThrow(Error);
expect(() => fn()).toThrowError(/pattern/);
// Async errors
await expect(asyncFn()).rejects.toThrow();
await expect(asyncFn()).resolves.toBe(value);
```
### Assertions Count
```typescript
test("multiple assertions", () => {
expect.assertions(3); // Must have exactly 3 assertions
expect(a).toBe(1);
expect(b).toBe(2);
expect(c).toBe(3);
});
test("at least one", async () => {
expect.hasAssertions(); // Must have at least one assertion
const data = await fetchData();
expect(data).toBeDefined();
});
```
## Lifecycle Hooks
### Basic Hooks
```typescript
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
// Run once before all tests in file/describe block
beforeAll(() => {
console.log("Setting up");
});
// Run once after all tests
afterAll(() => {
console.log("Tearing down");
});
// Run before each test
beforeEach(() => {
console.log("Before each test");
});
// Run after each test
afterEach(() => {
console.log("After each test");
});
```
### Async Hooks
```typescript
beforeAll(async () => {
await database.connect();
});
afterAll(async () => {
await database.disconnect();
});
```
### Scoped Hooks
```typescript
describe("outer", () => {
beforeAll(() => console.log("outer beforeAll"));
beforeEach(() => console.log("outer beforeEach"));
describe("inner", () => {
beforeAll(() => console.log("inner beforeAll"));
beforeEach(() => console.log("inner beforeEach"));
test("example", () => {
// Runs: outer beforeAll, inner beforeAll,
// outer beforeEach, inner beforeEach, test
});
});
});
```
### Preload Scripts
```typescript
// test/setup.ts - loaded before all tests
import { beforeEach, afterEach, mock } from "bun:test";
// Global setup
beforeEach(() => {
// Reset mocks before each test
mock.restore();
});
afterEach(() => {
// Cleanup after each test
});
```
```toml
# bunfig.toml
[test]
preload = ["./test/setup.ts"]
```
## Mocking
### Mock Functions
```typescript
import { mock, expect, test } from "bun:test";
test("mock function", () => {
// Create mock
const mockFn = mock(() => 42);
// Call it
const result = mockFn("arg1", "arg2");
// Assert
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");
expect(result).toBe(42);
// Access call history
expect(mockFn.mock.calls).toEqual([["arg1", "arg2"]]);
expect(mockFn.mock.results).toEqual([{ type: "return", value: 42 }]);
});
```
### Mock Implementations
```typescript
const mockFn = mock();
// Set return value
mockFn.mockReturnValue(42);
expect(mockFn()).toBe(42);
// Return once then default
mockFn.mockReturnValueOnce(1).mockReturnValueOnce(2).mockReturnValue(0);
expect(mockFn()).toBe(1);
expect(mockFn()).toBe(2);
expect(mockFn()).toBe(0);
// Custom implementation
mockFn.mockImplementation((x) => x * 2);
expect(mockFn(5)).toBe(10);
// Async mocks
mockFn.mockResolvedValue({ data: "test" });
await expect(mockFn()).resolves.toEqual({ data: "test" });
mockFn.mockRejectedValue(new Error("fail"));
await expect(mockFn()).rejects.toThrow("fail");
```
### Spies
```typescript
import { spyOn, expect, test } from "bun:test";
const calculator = {
add(a: number, b: number) {
return a + b;
},
};
test("spy on method", () => {
const spy = spyOn(calculator, "add");
const result = calculator.add(2, 3);
expect(spy).toHaveBeenCalledWith(2, 3);
expect(spy).toHaveBeenCalledTimes(1);
expect(result).toBe(5); // OrigRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.