/** * A throwaway HTTP server on a random loopback port. * * The suite points a real {@link Client} at a real socket: no test touches the * network, and no test stubs `fetch`. The code path exercised is the one that * runs in production, request construction and error body reading included. * * It doubles as the test that `baseUrl` works — if it did not, none of this * would run. * * @module */ /** What the fake server should answer for one request. */ export interface Reply { status: number; body: string; headers?: Record; } /** Per-test programmable routes, plus a request counter. */ export class Router { private readonly routes = new Map(); /** Every path requested so far, in order. */ readonly calls: string[] = []; /** Answers any path with no registered route. */ fallback?: (path: string) => Reply; /** * Register the answer for a path. * * An array makes each request consume the next entry, which is how retrying * is tested. The last entry repeats once the array runs out. */ respond(path: string, reply: Reply | Reply[]): void { this.routes.set(path, reply); } /** Record the call and return the answer registered for `path`. */ next(path: string): Reply { this.calls.push(path); const reply = this.routes.get(path); if (reply === undefined) { if (this.fallback !== undefined) { return this.fallback(path); } return { status: 404, body: JSON.stringify({ erro: "cep_nao_encontrado" }), }; } if (Array.isArray(reply)) { return (reply.length > 1 ? reply.shift() : reply[0]) as Reply; } return reply; } /** How many requests so far began with `prefix`. */ count(prefix: string): number { return this.calls.filter((call) => call.startsWith(prefix)).length; } } /** A running fake API, with its router. */ export interface FakeServer { url: string; routes: Router; stop: () => void; } /** Start a fake API on `127.0.0.1` and a port the kernel picks. */ export function startServer(): FakeServer { const routes = new Router(); const server = Bun.serve({ hostname: "127.0.0.1", port: 0, fetch(request) { const url = new URL(request.url); const reply = routes.next(`${url.pathname}${url.search}`); return new Response(reply.body, { status: reply.status, headers: { "Content-Type": "application/json; charset=utf-8", ...reply.headers, }, }); }, }); return { url: `http://127.0.0.1:${server.port}`, routes, stop: () => { server.stop(true); }, }; }