Mirrors journal PR #5. `fetchSegment()` and `computeSegmentGpx()` in lib/brouter.ts called `fetch()` with no AbortSignal — a hung or slow BRouter would stall the request handler indefinitely. New `lib/http.server.ts::fetchWithTimeout()` (same as the journal's helper) wraps fetch with `AbortSignal.timeout(30_000)`, composable with a caller-supplied signal via `AbortSignal.any()`. Tests: lib/http.server.test.ts (2 cases — timeout abort, happy path).
28 lines
1 KiB
TypeScript
28 lines
1 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { fetchWithTimeout } from "./http.server.ts";
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
afterEach(() => {
|
|
globalThis.fetch = originalFetch;
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("fetchWithTimeout (planner)", () => {
|
|
it("aborts when the upstream exceeds the timeout", async () => {
|
|
globalThis.fetch = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
|
|
return new Promise((_resolve, reject) => {
|
|
init?.signal?.addEventListener("abort", () => {
|
|
reject(new DOMException("aborted", "AbortError"));
|
|
});
|
|
});
|
|
}) as typeof fetch;
|
|
await expect(fetchWithTimeout("https://example.test", {}, 25)).rejects.toThrow();
|
|
});
|
|
|
|
it("returns the response when the call resolves in time", async () => {
|
|
globalThis.fetch = vi.fn(async () => new Response("ok", { status: 200 })) as typeof fetch;
|
|
const resp = await fetchWithTimeout("https://example.test", {}, 1000);
|
|
expect(resp.status).toBe(200);
|
|
});
|
|
});
|