bun-test

import { describe, expect, it, mock, spyOn, beforeEach, afterEach, afterAll } from "bun:test";

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "bun-test" with this command: npx skills add ainergiz/xfeed/ainergiz-xfeed-bun-test

Bun Test Guide

Quick Start

import { describe, expect, it, mock, spyOn, beforeEach, afterEach, afterAll } from "bun:test";

describe("MyModule", () => { it("does something", () => { expect(1 + 1).toBe(2); }); });

Run tests:

bun test # Run all tests bun test --watch # Watch mode bun test --coverage # With coverage report bun test src/api # Specific directory bun test --test-name-pattern "pattern" # Filter by name

Mocking Patterns

Mock Functions

const mockFn = mock(() => "mocked value"); mockFn(); expect(mockFn).toHaveBeenCalled(); expect(mockFn).toHaveBeenCalledTimes(1);

// Reset between tests mockFn.mockReset(); mockFn.mockImplementation(() => "new value");

Spy on Object Methods

import { myModule } from "./my-module";

let methodSpy: Mock<typeof myModule.method>;

beforeAll(() => { methodSpy = spyOn(myModule, "method").mockImplementation(() => "mocked"); });

afterAll(() => { methodSpy.mockRestore(); // IMPORTANT: Always restore spies });

Mock fetch (globalThis.fetch)

Bun's fetch has extra properties (like preconnect ) that mocks don't have. Use // @ts-nocheck at file top for test files with fetch mocking:

// @ts-nocheck - Test file with fetch mocking import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test";

const originalFetch = globalThis.fetch;

// Helper for mock responses function mockResponse(body: unknown, options: { status?: number; ok?: boolean } = {}) { const status = options.status ?? 200; const ok = options.ok ?? (status >= 200 && status < 300); return { ok, status, text: () => Promise.resolve(typeof body === "string" ? body : JSON.stringify(body)), json: () => Promise.resolve(body), } as Response; }

describe("API", () => { afterEach(() => { globalThis.fetch = originalFetch; // Always restore });

it("fetches data", async () => { globalThis.fetch = mock(() => Promise.resolve(mockResponse({ data: "test" })));

const result = await myApi.getData();
expect(result).toEqual({ data: "test" });

});

it("handles errors", async () => { globalThis.fetch = mock(() => Promise.reject(new Error("Network error")));

await expect(myApi.getData()).rejects.toThrow("Network error");

}); });

Mock Modules (External Dependencies)

Use mock.module() BEFORE importing the module under test:

// @ts-nocheck - Test file with module mocking import { describe, expect, it, mock } from "bun:test";

// Create mutable mock implementation let mockImpl = () => Promise.resolve({ data: "default" });

// Mock the module BEFORE importing mock.module("external-package", () => ({ someFunction: () => mockImpl(), }));

// NOW import the module that uses external-package const { myFunction } = await import("./my-module");

// Helper to change mock behavior per test function setMockReturn(value: unknown) { mockImpl = () => Promise.resolve(value); }

describe("MyModule", () => { it("uses external package", async () => { setMockReturn({ data: "test" }); const result = await myFunction(); expect(result.data).toBe("test"); }); });

Test Isolation

State Sharing Warning

Tests within a file share module-level state. Use setup/teardown hooks carefully:

// Store original values at module level const originalEnv = process.env.NODE_ENV; const originalFetch = globalThis.fetch;

afterAll(() => { // Restore everything globalThis.fetch = originalFetch; if (originalEnv !== undefined) { process.env.NODE_ENV = originalEnv; } else { delete process.env.NODE_ENV; } });

Temp Directory Isolation

Use mkdtemp() per test, not a shared temp directory:

import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path";

let testDir: string;

beforeEach(async () => { // Unique temp dir per test - avoids race conditions testDir = await mkdtemp(path.join(tmpdir(), "my-test-")); });

afterEach(async () => { if (testDir) { await rm(testDir, { recursive: true, force: true }).catch(() => {}); } });

Coverage

bun test --coverage # Generate text report bun test --coverage-reporter lcov # For CI/tooling integration

Coverage Quirks

  • Closing braces after return may show uncovered even when executed

  • Function declarations may not count if only body runs

  • 100% may be impossible - aim for 99%+ on meaningful code

Improving Coverage

  • Test all branches (if/else, switch cases)

  • Test error paths and edge cases

  • Test with different input types

  • Don't obsess over unreachable code (closing braces, etc.)

Common Patterns

Async Tests

it("handles async", async () => { const result = await asyncFunction(); expect(result).toBe("expected"); });

it("expects rejection", async () => { await expect(asyncFunction()).rejects.toThrow("error message"); });

Parameterized Tests

const testCases = [ { input: 1, expected: 2 }, { input: 2, expected: 4 }, ];

for (const { input, expected } of testCases) { it(doubles ${input} to ${expected}, () => { expect(double(input)).toBe(expected); }); }

Testing Timeouts

it("handles timeout", async () => { // Use small delays for tests const result = await functionWithDelay(1); // 1ms instead of 1000ms expect(result).toBeDefined(); });

Checklist for New Test Files

  • Add // @ts-nocheck if mocking fetch or complex types

  • Store original values (fetch, env vars) before modifying

  • Restore everything in afterEach or afterAll

  • Use mkdtemp() for temp directories (not shared paths)

  • Call mockRestore() on spies in afterAll

  • Use descriptive test names that explain the scenario

Debugging Tests

bun test --bail # Stop on first failure bun test --timeout 30000 # Increase timeout (ms) bun test --test-name-pattern "specific test" # Run one test

Add console.log for debugging (remove before committing):

it("debugging", () => { console.log("Value:", someValue); expect(someValue).toBeDefined(); });

Additional Resources

For xfeed-specific patterns (XClient, RuntimeQueryIdStore, cookie mocking, GraphQL responses), see PATTERNS.md.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

new-issue

No summary provided by upstream source.

Repository SourceNeeds Review
General

opentui

No summary provided by upstream source.

Repository SourceNeeds Review
General

bun-test

No summary provided by upstream source.

Repository SourceNeeds Review
General

notebooklm-superskill

No summary provided by upstream source.

Repository SourceNeeds Review