Claude-skills bun-test-mocking
Use for mock functions in Bun tests, spyOn, mock.module, implementations, and test doubles.
install
source · Clone the upstream repo
git clone https://github.com/secondsky/claude-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/secondsky/claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/bun/skills/bun-test-mocking" ~/.claude/skills/secondsky-claude-skills-bun-test-mocking && rm -rf "$T"
manifest:
plugins/bun/skills/bun-test-mocking/SKILL.mdsource content
Bun Test Mocking
Bun provides Jest-compatible mocking with
mock(), spyOn(), and module mocking.
Mock Functions
import { test, expect, mock } from "bun:test"; // Create mock function const fn = mock(() => "original"); test("mock function", () => { fn("arg1", "arg2"); expect(fn).toHaveBeenCalled(); expect(fn).toHaveBeenCalledTimes(1); expect(fn).toHaveBeenCalledWith("arg1", "arg2"); });
jest.fn() Compatibility
import { test, expect, jest } from "bun:test"; const fn = jest.fn(() => "value"); test("jest.fn works", () => { const result = fn(); expect(result).toBe("value"); expect(fn).toHaveBeenCalled(); });
Mock Return Values
const fn = mock(); // Return value once fn.mockReturnValueOnce("first"); fn.mockReturnValueOnce("second"); // Permanent return value fn.mockReturnValue("default"); // Promise returns fn.mockResolvedValue("resolved"); fn.mockResolvedValueOnce("once"); fn.mockRejectedValue(new Error("fail")); fn.mockRejectedValueOnce(new Error("once"));
Mock Implementations
const fn = mock(); // Set implementation fn.mockImplementation((x) => x * 2); // One-time implementation fn.mockImplementationOnce((x) => x * 10); // Chain implementations fn .mockImplementationOnce(() => "first") .mockImplementationOnce(() => "second") .mockImplementation(() => "default");
Spy on Methods
import { test, expect, spyOn } from "bun:test"; const obj = { method: () => "original", }; test("spy on method", () => { const spy = spyOn(obj, "method"); obj.method(); expect(spy).toHaveBeenCalled(); expect(obj.method()).toBe("original"); // Still works // Override implementation spy.mockImplementation(() => "mocked"); expect(obj.method()).toBe("mocked"); // Restore spy.mockRestore(); expect(obj.method()).toBe("original"); });
Mock Modules
import { test, expect, mock } from "bun:test"; // Mock entire module mock.module("./utils", () => ({ add: mock(() => 999), subtract: mock(() => 0), })); // Now imports use mocked version import { add } from "./utils"; test("mocked module", () => { expect(add(1, 2)).toBe(999); });
Mock Node Modules
mock.module("axios", () => ({ default: { get: mock(() => Promise.resolve({ data: "mocked" })), post: mock(() => Promise.resolve({ data: "created" })), }, }));
Mock with Factory
mock.module("./config", () => { return { API_URL: "http://test.local", DEBUG: true, }; });
Mock Assertions
const fn = mock(); fn("a", "b"); fn("c", "d"); // Call count expect(fn).toHaveBeenCalled(); expect(fn).toHaveBeenCalledTimes(2); // Call arguments expect(fn).toHaveBeenCalledWith("a", "b"); expect(fn).toHaveBeenLastCalledWith("c", "d"); expect(fn).toHaveBeenNthCalledWith(1, "a", "b"); // Return values fn.mockReturnValue("result"); fn(); expect(fn).toHaveReturned(); expect(fn).toHaveReturnedWith("result"); expect(fn).toHaveReturnedTimes(1);
Mock Properties
const fn = mock(() => "value"); fn("arg1"); fn("arg2"); // Access call info fn.mock.calls; // [["arg1"], ["arg2"]] fn.mock.results; // [{ type: "return", value: "value" }, ...] fn.mock.lastCall; // ["arg2"] // Clear history fn.mockClear(); // Clear calls, keep implementation fn.mockReset(); // Clear calls + implementation fn.mockRestore(); // Restore original (for spies)
Common Patterns
Mock Fetch
import { test, expect, spyOn } from "bun:test"; test("mock fetch", async () => { const spy = spyOn(global, "fetch").mockResolvedValue( new Response(JSON.stringify({ data: "mocked" })) ); const response = await fetch("/api/data"); const json = await response.json(); expect(json.data).toBe("mocked"); expect(spy).toHaveBeenCalledWith("/api/data"); spy.mockRestore(); });
Mock Console
test("mock console", () => { const spy = spyOn(console, "log"); console.log("test message"); expect(spy).toHaveBeenCalledWith("test message"); spy.mockRestore(); });
Mock Class Methods
class UserService { async getUser(id: string) { // Real implementation } } test("mock class method", () => { const service = new UserService(); const spy = spyOn(service, "getUser").mockResolvedValue({ id: "1", name: "Test User", }); const user = await service.getUser("1"); expect(user.name).toBe("Test User"); expect(spy).toHaveBeenCalledWith("1"); });
Common Errors
| Error | Cause | Fix |
|---|---|---|
| Property doesn't exist | Check property name |
| Trying to mock non-function | Use correct mock approach |
| Double mocking | Use mockRestore first |
| Wrong module path | Check path in mock.module |
When to Load References
Load
references/mock-api.md when:
- Complete mock/spy API reference
- Advanced mocking patterns
Load
references/module-mocking.md when:
- Complex module mocking
- Hoisting behavior details