5.0 KiB
Runner — vitest / bun-test conditional re-exports
(no submodules)
- vitest — The `runner/vitest` module re-exports vite…-
vitest — The
runner/vitestmodule re-exports vitest'sdescribe,it,test,expect,beforeAll,beforeEach, `afterAll… -
vitest — The
runner/vitestmodule re-exports vite… -
vitest — The
runner/vitestmodule re-exports vitest'sdescribe,it,test,expect,beforeAll,beforeEach, `afterAll… -
vitest — The
runner/vitestmodule re-exports vite… -
vitest — The
runner/vitestmodule re-exports vitest'sdescribe,it,test,expect,beforeAll,beforeEach, `afterAll… -
vitest — The
runner/vitestmodule re-exports vite… -
vitest — The
runner/vitestmodule re-exports vitest'sdescribe,it,test,expect,beforeAll,beforeEach, `afterAll… -
vitest — The
runner/vitestmodule re-exports vitest'sdescribe,it,test,expect,beforeAll,beforeEach, `afterAll…
Purpose
The runner barrel re-exports the test primitives (describe, it, test, expect, beforeAll, beforeEach, afterAll, afterEach, vi) plus a runner-neutral mock surface (fn, spy, stub, mock, fakeClock, restoreMocks, restoreTimers). Two backends are supported: vitest (the default) and bun's built-in bun:test. Which backend resolves at import time is driven by package.json conditional exports — under the bun condition Node resolves ./dist/runner/bun-test.js; under vitest or default it resolves ./dist/index.js which barrels in vitest.ts.
The mock helpers exist so test code can stay runner-agnostic. A package that uses fn() / spy() / stub() instead of importing vi directly will run unchanged when its consumers swap test runners — no test-source rewrites required. This is the pattern the original 2026-04-08-testing-libraries change established and we preserve it here.
Features
- Re-exports of
vitestprimitives under the default / vitest conditions bun:testre-exports under the bun condition with API-shaped equivalents (viis aliased to bun'sjestnamespace)- Runner-neutral mock helpers:
fn,spy,stub,mock(modulePath),fakeClock,restoreMocks,restoreTimers mock(modulePath, factory?)returns a{ restore() }handle for symmetry across runnersfakeClock()exists for legacy compatibility — new code should prefer the deterministicFakeClockclass from@suaveplan/testing/clock/fake-clock
Usage
Basic example — runner-neutral test
import {
describe,
it,
expect,
fn,
spy,
} from "@suaveplan/testing";
describe("user service", () => {
it("calls the dependency exactly once", { timeout: 5000 }, () => {
const dep = { fetch: () => "real" };
const handle = spy(dep, "fetch");
const callback = fn();
callback("hello");
expect(callback).toHaveBeenCalledWith("hello");
expect(handle).toHaveBeenCalledTimes(0);
});
});
Advanced example — module mocking with restore
import { mock, restoreMocks } from "@suaveplan/testing";
const handle = mock("./network.js", () => ({
fetchUser: () => ({ id: 42 }),
}));
// run tests against the mocked module ...
handle.restore();
restoreMocks();
Switching to bun-test
In a consumer's package.json, set the bun condition (or run via bun test). Resolution picks @suaveplan/testing/dist/runner/bun-test.js automatically; no test-source changes are needed.
API Reference
Test primitives
describe, it, test, expect, beforeAll, beforeEach, afterAll, afterEach, vi — re-exported from the active runner.
Mock helpers
fn<TArgs, TReturn>(implementation?): Mockspy<T, K>(obj: T, method: K): SpyHandlestub<T, K>(obj: T, method: K, implementation?): SpyHandlemock(modulePath: string, factory?: () => unknown): { restore() }fakeClock(): { advance(ms), restore() }restoreMocks(): voidrestoreTimers(): void
Implementation Notes
vion the bun path is aliased tojest. Bun-test's mock surface lives underjestfor API compatibility; the alias keeps consumer code identical across runners.fakeClockis legacy. Prefer the deterministicFakeClockclass from the clock module — it's runner-independent, supportsClockinjection across the package, and gives yousnapshot()/restore()for fine control.mock()on bun has a no-oprestore()becausebun:testdoes not exposeunmock. CallrestoreMocks()(which delegates tojest.restoreAllMocks()) to reset state.- The conditional-exports routing is load-bearing — see
package.json#exports.".".bunand.vitest. Removing either branch breaks the dual-runner contract documented in the spec. - Type safety on cross-runner mocks is approximate. The wrappers use
as nevercasts internally because the spy/stub generics differ between the two libraries; consumer code sees a stable shape.