Files
diegosouzapw--omniroute/tests/unit/fetch-timeout.test.ts
T
2026-07-13 13:39:12 +08:00

114 lines
3.4 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const originalFetch = globalThis.fetch;
const originalTimeoutEnv = process.env.FETCH_TIMEOUT_MS;
async function loadFetchTimeoutModule(tag) {
return import(`../../src/shared/utils/fetchTimeout.ts?case=${tag}-${Date.now()}`);
}
test.afterEach(() => {
globalThis.fetch = originalFetch;
if (originalTimeoutEnv === undefined) {
delete process.env.FETCH_TIMEOUT_MS;
} else {
process.env.FETCH_TIMEOUT_MS = originalTimeoutEnv;
}
});
test("fetchWithTimeout forwards options and exposes the configured timeout", async () => {
process.env.FETCH_TIMEOUT_MS = "3210";
const mod = await loadFetchTimeoutModule("configured-timeout");
let seenUrl = null;
let seenOptions = null;
const expectedResponse = { ok: true, status: 204 };
globalThis.fetch = async (url, options) => {
seenUrl = url;
seenOptions = options;
return expectedResponse;
};
const response = await mod.fetchWithTimeout("https://example.test/ping", {
method: "POST",
headers: { "x-test": "1" },
});
assert.equal(mod.getConfiguredTimeout(), 3210);
assert.equal(response, expectedResponse);
assert.equal(seenUrl, "https://example.test/ping");
assert.equal(seenOptions.method, "POST");
assert.equal(seenOptions.headers["x-test"], "1");
assert.equal(seenOptions.signal instanceof AbortSignal, true);
});
test("fetchWithTimeout converts both pre-aborted and externally aborted requests into FetchTimeoutError", async () => {
const mod = await loadFetchTimeoutModule("abort");
const preAborted = new AbortController();
preAborted.abort();
globalThis.fetch = async (_url, options) => {
assert.equal(options.signal.aborted, true);
const error = new Error("aborted");
error.name = "AbortError";
throw error;
};
await assert.rejects(
mod.fetchWithTimeout("https://example.test/pre-aborted", {
signal: preAborted.signal,
timeoutMs: 9,
}),
(error) => {
assert.equal(error instanceof mod.FetchTimeoutError, true);
assert.equal((error as any).timeoutMs, 9);
(assert as any).equal((error as any).url, "https://example.test/pre-aborted");
(assert as any).match((error as any).message, /timed out after 9ms/);
return true;
}
);
const external = new AbortController();
let fetchSawSignal = false;
globalThis.fetch = async (_url, options) => {
fetchSawSignal = true;
setTimeout(() => external.abort(), 0);
await new Promise((resolve) => setTimeout(resolve, 5));
const error = new Error("aborted later");
error.name = "AbortError";
throw error;
};
await assert.rejects(
mod.fetchWithTimeout("https://example.test/external-abort", {
signal: external.signal,
timeoutMs: 15,
}),
(error) => {
assert.equal(fetchSawSignal, true);
assert.equal(error instanceof mod.FetchTimeoutError, true);
assert.equal((error as any).timeoutMs, 15);
assert.equal((error as any).url, "https://example.test/external-abort");
return true;
}
);
});
test("fetchWithTimeout rethrows non-timeout failures unchanged", async () => {
const mod = await loadFetchTimeoutModule("generic-error");
const failure = new Error("network down");
globalThis.fetch = async () => {
throw failure;
};
await assert.rejects(
mod.fetchWithTimeout("https://example.test/fail", { timeoutMs: 5 }),
(error) => error === failure
);
});