test(server): bind request fixtures to explicit loopback

Wait for the asynchronous loopback bind before dispatching Supertest requests. Avoid wildcard ephemeral ports overlapping existing localhost listeners on macOS.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Dotta 2026-09-10 10:08:02 -05:00
parent cc4f0069d2
commit 7ea9c1b611
1 changed files with 56 additions and 17 deletions

View File

@ -12,11 +12,17 @@ type SupertestServer = NetServer & {
type SupertestTestInstance = {
_server?: SupertestServer;
url: string;
__paperclipListening?: Promise<void>;
assert(error: Error, response: undefined, callback?: SupertestCallback): void;
};
type SupertestCallback = (error: Error | null, response?: unknown) => void;
type SupertestTestConstructor = {
prototype: {
serverAddress(this: SupertestTestInstance, app: SupertestServer, path: string): string;
end(this: SupertestTestInstance, callback?: SupertestCallback): SupertestTestInstance;
__paperclipLoopbackPatched?: boolean;
};
};
@ -39,25 +45,58 @@ if (!process.env.PAPERCLIP_MANAGED_RUNTIME_HTTPS) {
}
if (!SupertestTest.prototype.__paperclipLoopbackPatched) {
const pendingListeners = new WeakMap<SupertestServer, Promise<void>>();
const originalEnd = SupertestTest.prototype.end;
SupertestTest.prototype.serverAddress = function serverAddress(app, path) {
const addr = app.address();
if (!addr) {
this._server = app.listen(0) as SupertestServer;
}
const listeningAddress = app.address() as AddressInfo | string | null;
if (!listeningAddress || typeof listeningAddress === "string") {
throw new Error("Expected Supertest server to listen on a TCP port");
}
const host = listeningAddress.address === "::"
? "[::1]"
: listeningAddress.address === "0.0.0.0"
? "127.0.0.1"
: listeningAddress.address;
const protocol = app instanceof TlsServer ? "https" : "http";
return `${protocol}://${host}:${listeningAddress.port}${path}`;
const addressUrl = () => {
const address = app.address() as AddressInfo | string | null;
if (!address || typeof address === "string") {
throw new Error("Expected Supertest server to listen on a TCP port");
}
const host = address.address === "0.0.0.0" ? "127.0.0.1" : address.address;
return `${protocol}://${host.includes(":") ? `[${host === "::" ? "::1" : host}]` : host}:${address.port}${path}`;
};
if (app.address()) return addressUrl();
// A wildcard ephemeral listener can overlap an existing loopback listener
// on macOS. Bind the address we actually request, and await the asynchronous
// bind before Superagent resolves the URL or sends any request bytes.
let listening = pendingListeners.get(app);
if (!listening) {
listening = new Promise<void>((resolve, reject) => {
const onError = (error: Error) => {
app.off("listening", onListening);
pendingListeners.delete(app);
reject(error);
};
const onListening = () => {
app.off("error", onError);
pendingListeners.delete(app);
resolve();
};
app.once("error", onError);
app.once("listening", onListening);
app.listen(0, "127.0.0.1");
});
pendingListeners.set(app, listening);
}
this._server = app;
this.__paperclipListening = listening.then(() => { this.url = addressUrl(); });
// A request may be configured before the caller attaches its callback.
void this.__paperclipListening.catch(() => {});
return `${protocol}://127.0.0.1:0${path}`;
};
SupertestTest.prototype.end = function end(callback) {
if (!this.__paperclipListening) return originalEnd.call(this, callback);
void this.__paperclipListening.then(
() => { originalEnd.call(this, callback); },
(error: Error) => { this.assert(error, undefined, callback); },
);
return this;
};
SupertestTest.prototype.__paperclipLoopbackPatched = true;