mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-15 15:46:00 -05:00
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
import { fetchWithTimeout } from "./fetch";
|
|
import { logger } from "./logger";
|
|
|
|
const fetchMock = vi.fn(
|
|
(_input: RequestInfo | URL, init?: RequestInit) =>
|
|
new Promise<Response>((resolve, reject) => {
|
|
init?.signal?.addEventListener("abort", () =>
|
|
reject(init.signal?.reason),
|
|
);
|
|
setTimeout(() => resolve(new Response("ok")), 1000);
|
|
}),
|
|
);
|
|
|
|
describe("fetchWithTimeout", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
vi.spyOn(logger, "error").mockImplementation(() => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
vi.unstubAllGlobals();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
test("aborts with a TimeoutError once the timeout elapses", async () => {
|
|
const promise = fetchWithTimeout("https://example.com", undefined, 100);
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
await expect(promise).rejects.toMatchObject({ name: "TimeoutError" });
|
|
expect(logger.error).toHaveBeenCalledWith("Fetch timed out");
|
|
});
|
|
|
|
test("still times out when the caller passes their own signal", async () => {
|
|
const promise = fetchWithTimeout(
|
|
"https://example.com",
|
|
{ signal: new AbortController().signal },
|
|
100,
|
|
);
|
|
await vi.advanceTimersByTimeAsync(100);
|
|
|
|
await expect(promise).rejects.toMatchObject({ name: "TimeoutError" });
|
|
});
|
|
|
|
test("caller abort rejects without logging a timeout", async () => {
|
|
const controller = new AbortController();
|
|
const promise = fetchWithTimeout(
|
|
"https://example.com",
|
|
{ signal: controller.signal },
|
|
100,
|
|
);
|
|
controller.abort();
|
|
|
|
await expect(promise).rejects.toMatchObject({ name: "AbortError" });
|
|
await vi.advanceTimersByTimeAsync(200);
|
|
expect(logger.error).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("failed fetch does not log a timeout later", async () => {
|
|
fetchMock.mockRejectedValueOnce(new TypeError("fetch failed"));
|
|
const promise = fetchWithTimeout("https://example.com", undefined, 100);
|
|
|
|
await expect(promise).rejects.toThrow("fetch failed");
|
|
await vi.advanceTimersByTimeAsync(200);
|
|
expect(logger.error).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("resolves with the response when it arrives in time", async () => {
|
|
const promise = fetchWithTimeout("https://example.com", undefined, 5000);
|
|
await vi.advanceTimersByTimeAsync(1000);
|
|
|
|
await expect(promise).resolves.toBeInstanceOf(Response);
|
|
expect(logger.error).not.toHaveBeenCalled();
|
|
});
|
|
});
|