import { probePortFree, waitForPortBindable } from "./ports.js";
/** Build a minimal fake net.Server that emits a given error code on listen(). */ function makeErrServer(code: string): net.Server { const err = Object.assign(new Error(`bind error: ${code}`), {
code,
}) as NodeJS.ErrnoException;
const fake = new EventEmitter() as unknown as net.Server;
(fake as unknown as { close: (cb?: () => void) => net.Server }).close = (cb?: () => void) => {
cb?.(); return fake;
};
(fake as unknown as { unref: () => net.Server }).unref = () => fake;
(fake as unknown as { listen: (...args: unknown[]) => net.Server }).listen = (
..._args: unknown[]
) => {
setImmediate(() => fake.emit("error", err)); return fake;
}; return fake;
}
it("rejects immediately for other non-retryable errors", async () => {
mockCreateServer.mockReturnValue(makeErrServer("EINVAL"));
await expect(probePortFree(9999, "0.0.0.0")).rejects.toMatchObject({ code: "EINVAL" });
});
it("resolves true when the port is free", async () => { // Mock a successful bind: the "listening" event fires immediately without // acquiring a real socket, making this deterministic and avoiding TOCTOU races. // (A real-socket approach would bind to :0, release, then reprobe — the OS can // reassign the ephemeral port in between, causing a flaky EADDRINUSE failure.) const fakeServer = new EventEmitter() as unknown as net.Server;
(fakeServer as unknown as { close: (cb?: () => void) => net.Server }).close = (
cb?: () => void,
) => {
cb?.(); return fakeServer;
};
(fakeServer as unknown as { unref: () => net.Server }).unref = () => fakeServer;
(fakeServer as unknown as { listen: (...args: unknown[]) => net.Server }).listen = (
..._args: unknown[]
) => { // Simulate a successful bind by firing the "listening" callback. const callback = _args.find((a) => typeof a === "function") as (() => void) | undefined;
setImmediate(() => callback?.()); return fakeServer;
};
mockCreateServer.mockReturnValue(fakeServer);
const result = await probePortFree(9999, "127.0.0.1");
expect(result).toBe(true);
});
});
describe("waitForPortBindable", () => {
it("probes the provided host when waiting for bindability", async () => { const listenCalls: Array<{ port: number; host: string }> = []; const fakeServer = new EventEmitter() as unknown as net.Server;
(fakeServer as unknown as { close: (cb?: () => void) => net.Server }).close = (
cb?: () => void,
) => {
cb?.(); return fakeServer;
};
(fakeServer as unknown as { unref: () => net.Server }).unref = () => fakeServer;
(fakeServer as unknown as { listen: (...args: unknown[]) => net.Server }).listen = (
...args: unknown[]
) => { const [port, host] = args as [number, string];
listenCalls.push({ port, host }); const callback = args.find((a) => typeof a === "function") as (() => void) | undefined;
setImmediate(() => callback?.()); return fakeServer;
};
mockCreateServer.mockReturnValue(fakeServer);
it("propagates EACCES rejection immediately without retrying", async () => { // Every call to createServer will emit EACCES — so if waitForPortBindable retried, // mockCreateServer would be called many times. We assert it's called exactly once.
mockCreateServer.mockClear();
mockCreateServer.mockReturnValue(makeErrServer("EACCES"));
await expect(
waitForPortBindable(80, { timeoutMs: 5000, intervalMs: 50 }),
).rejects.toMatchObject({ code: "EACCES" }); // Only one probe should have been attempted — no spinning through the retry loop.
expect(mockCreateServer).toHaveBeenCalledTimes(1);
});
});
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.