test: add fetch mock helper and reaction coverage

This commit is contained in:
Sebastian
2026-02-17 09:01:30 -05:00
parent 0e023e300e
commit cc359d338e
28 changed files with 193 additions and 106 deletions

View File

@@ -1,4 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import { withFetchPreconnect } from "../test-utils/fetch-mock.js";
import { resolveFetch, wrapFetchWithAbortSignal } from "./fetch.js";
function createForeignSignalHarness() {
@@ -29,10 +30,12 @@ function createForeignSignalHarness() {
describe("wrapFetchWithAbortSignal", () => {
it("adds duplex for requests with a body", async () => {
let seenInit: RequestInit | undefined;
const fetchImpl = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
seenInit = init;
return {} as Response;
});
const fetchImpl = withFetchPreconnect(
vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
seenInit = init;
return {} as Response;
}),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
@@ -43,10 +46,12 @@ describe("wrapFetchWithAbortSignal", () => {
it("converts foreign abort signals to native controllers", async () => {
let seenSignal: AbortSignal | undefined;
const fetchImpl = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
seenSignal = init?.signal as AbortSignal | undefined;
return {} as Response;
});
const fetchImpl = withFetchPreconnect(
vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
seenSignal = init?.signal as AbortSignal | undefined;
return {} as Response;
}),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
@@ -71,8 +76,8 @@ describe("wrapFetchWithAbortSignal", () => {
process.on("unhandledRejection", onUnhandled);
const fetchError = new TypeError("fetch failed");
const fetchImpl = vi.fn((_input: RequestInfo | URL, _init?: RequestInit) =>
Promise.reject(fetchError),
const fetchImpl = withFetchPreconnect(
vi.fn((_input: RequestInfo | URL, _init?: RequestInit) => Promise.reject(fetchError)),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
@@ -92,9 +97,11 @@ describe("wrapFetchWithAbortSignal", () => {
it("cleans up listener and rethrows when fetch throws synchronously", () => {
const syncError = new TypeError("sync fetch failure");
const fetchImpl = vi.fn(() => {
throw syncError;
});
const fetchImpl = withFetchPreconnect(
vi.fn(() => {
throw syncError;
}),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
const { fakeSignal, removeEventListener } = createForeignSignalHarness();
@@ -106,8 +113,8 @@ describe("wrapFetchWithAbortSignal", () => {
it("preserves original rejection when listener cleanup throws", async () => {
const fetchError = new TypeError("fetch failed");
const cleanupError = new TypeError("cleanup failed");
const fetchImpl = vi.fn((_input: RequestInfo | URL, _init?: RequestInit) =>
Promise.reject(fetchError),
const fetchImpl = withFetchPreconnect(
vi.fn((_input: RequestInfo | URL, _init?: RequestInit) => Promise.reject(fetchError)),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
@@ -128,9 +135,11 @@ describe("wrapFetchWithAbortSignal", () => {
it("preserves original sync throw when listener cleanup throws", () => {
const syncError = new TypeError("sync fetch failure");
const cleanupError = new TypeError("cleanup failed");
const fetchImpl = vi.fn(() => {
throw syncError;
});
const fetchImpl = withFetchPreconnect(
vi.fn(() => {
throw syncError;
}),
);
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
const removeEventListener = vi.fn(() => {
@@ -150,7 +159,7 @@ describe("wrapFetchWithAbortSignal", () => {
it("skips listener cleanup when foreign signal is already aborted", async () => {
const addEventListener = vi.fn();
const removeEventListener = vi.fn();
const fetchImpl = vi.fn(async () => ({ ok: true }) as Response);
const fetchImpl = withFetchPreconnect(vi.fn(async () => ({ ok: true }) as Response));
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
const fakeSignal = {
@@ -166,7 +175,7 @@ describe("wrapFetchWithAbortSignal", () => {
});
it("returns the same function when called with an already wrapped fetch", () => {
const fetchImpl = vi.fn(async () => ({ ok: true }) as Response);
const fetchImpl = withFetchPreconnect(vi.fn(async () => ({ ok: true }) as Response));
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
expect(wrapFetchWithAbortSignal(wrapped)).toBe(wrapped);