2.4 KiB
hmr-tester
(no submodules)
Purpose
withHMR round-trips a single Vite HMR edit through an injectable HmrServerLike adapter and asserts that the expected events fire in order. It is designed for tests that exercise HMR-driven UI logic without spinning up a real Vite dev server — the adapter can wrap an in-memory event bus, a Playwright page, or a real ws connection depending on the testing strategy.
Features
- Injectable server adapter (
send+onEvent). - Ordered event matching — events fire in the order specified in
expectEvents. - Configurable
timeoutMswithTestViteError(TEST_VITE.HMR_TIMEOUT)on expiry. - Injectable
Clockfor deterministic duration accounting. - OTel
test_vite_hmr_round_trip_mshistogram recorded on every resolution.
Usage: Basic
import { withHMR } from "@suaveplan/test-vite/hmr-tester";
const events = await withHMR({
server: viteServerAdapter,
edit: { file: "src/widget.ts", content: "..." },
expectEvents: ["vite:beforeUpdate", "vite:afterUpdate"],
timeoutMs: 5000,
});
Usage: Advanced
Drive a synthetic server in tests:
import { withHMR } from "@suaveplan/test-vite/hmr-tester";
let listener: ((event: string) => void) | undefined;
const server = {
send: () => setTimeout(() => listener?.("vite:afterUpdate"), 1),
onEvent: (cb: (event: string) => void) => {
listener = cb;
return () => { listener = undefined; };
},
};
await withHMR({
server,
edit: { file: "a.ts", content: "1" },
expectEvents: ["vite:afterUpdate"],
timeoutMs: 100,
clock: () => Date.now(),
});
API Reference
withHMR(opts: WithHmrOptions): Promise<readonly string[]>.WithHmrOptions—{ server, edit: { file, content }, expectEvents, timeoutMs?, clock? }.- Throws
TestViteErrorwithTEST_VITE.INVALID_OPTIONSorTEST_VITE.HMR_TIMEOUT.
Implementation Notes
withHMR matches expected events in order — non-matching events are captured but do not advance the cursor. Once the final expected event fires the promise resolves with the complete capture array, including any non-matching events that arrived along the way. The timer is cleared and the onEvent disposer invoked before resolution so the caller does not have to wire teardown. Test consumers can swap the clock to record deterministic durations and exercise edge cases without real wall-clock delays.