test(runner): add direct tests for the capability live-process wait helper

The waitForCapabilityLiveProcess helper had no direct test. Add tests
for a first-attempt success, a retry after a thrown error, a deadline
failure that carries the last observed error as its cause, and a
deadline failure when the callback never settles. The tests use fake
timers, so they run in milliseconds instead of the real 10,000 ms
deadline.

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Priya RamanandPaperclip committed 2026-09-04 03:06:40 +00:00
1 parent 71ab54c0dd
commit ead297e61b
1 file changed
+94
@@ -0,0 +1,94 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import {
CAPABILITY_LIVE_PROCESS_WAIT_DEADLINE_MS,
waitForCapabilityLiveProcess,
} from "../../test/wait-for-live-process.js";
afterEach(() => {
vi.useRealTimers();
});
describe("waitForCapabilityLiveProcess", () => {
it("returns the callback's value when the first attempt succeeds", async () => {
const result = await waitForCapabilityLiveProcess(
"first-attempt-succeeds",
() => "ok",
);
expect(result).toBe("ok");
});
it("retries a callback that throws, and returns the value when a later attempt succeeds", async () => {
vi.useFakeTimers();
let attempts = 0;
const promise = waitForCapabilityLiveProcess(
"retries-then-succeeds",
() => {
attempts += 1;
if (attempts === 1) throw new Error("first attempt failed");
return "recovered";
},
);
await vi.advanceTimersByTimeAsync(100);
await expect(promise).resolves.toBe("recovered");
expect(attempts).toBe(2);
});
it("fails at the deadline when every attempt throws, naming the label and the elapsed time and carrying the last observed error as its cause", async () => {
vi.useFakeTimers();
const lastError = new Error("connection refused");
const promise = waitForCapabilityLiveProcess("always-fails", () => {
throw lastError;
});
const caughtError = promise.catch((error: unknown) => error);
await vi.advanceTimersByTimeAsync(
CAPABILITY_LIVE_PROCESS_WAIT_DEADLINE_MS + 200,
);
const error = (await caughtError) as Error;
expect(error).toBeInstanceOf(Error);
expect(error.message).toContain("always-fails");
expect(error.message).toContain(
`did not settle within ${CAPABILITY_LIVE_PROCESS_WAIT_DEADLINE_MS}ms`,
);
expect(error.message).toMatch(/observed \d+ms/);
expect(error.message).toContain("connection refused");
expect(error.cause).toBe(lastError);
});
it("fails at the deadline, instead of running past it, when the callback never settles, and raises no unhandled rejection", async () => {
vi.useFakeTimers();
const unhandledRejections: unknown[] = [];
const onUnhandledRejection = (reason: unknown) => {
unhandledRejections.push(reason);
};
process.on("unhandledRejection", onUnhandledRejection);
try {
const promise = waitForCapabilityLiveProcess(
"never-settles",
() => new Promise<never>(() => {}),
);
const caughtError = promise.catch((error: unknown) => error);
await vi.advanceTimersByTimeAsync(
CAPABILITY_LIVE_PROCESS_WAIT_DEADLINE_MS + 200,
);
const error = (await caughtError) as Error;
expect(error).toBeInstanceOf(Error);
expect(error.message).toContain("never-settles");
expect(error.message).toContain(
`did not settle within ${CAPABILITY_LIVE_PROCESS_WAIT_DEADLINE_MS}ms`,
);
} finally {
process.off("unhandledRejection", onUnhandledRejection);
}
expect(unhandledRejections).toEqual([]);
});
});