test: share web fetch header helpers

This commit is contained in:
Peter Steinberger 2026-03-14 01:33:09 +00:00
parent 231589ef66
commit d9a604f15f
4 changed files with 25 additions and 29 deletions

View File

@ -4,6 +4,7 @@ import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
import {
createBaseWebFetchToolConfig,
installWebFetchSsrfHarness,
makeFetchHeaders,
} from "./web-fetch.test-harness.js";
import "./web-fetch.test-mocks.js";
import { createWebFetchTool } from "./web-tools.js";
@ -11,17 +12,14 @@ import { createWebFetchTool } from "./web-tools.js";
const baseToolConfig = createBaseWebFetchToolConfig();
installWebFetchSsrfHarness();
function makeHeaders(map: Record<string, string>): { get: (key: string) => string | null } {
return {
get: (key) => map[key.toLowerCase()] ?? null,
};
}
function markdownResponse(body: string, extraHeaders: Record<string, string> = {}): Response {
return {
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/markdown; charset=utf-8", ...extraHeaders }),
headers: makeFetchHeaders({
"content-type": "text/markdown; charset=utf-8",
...extraHeaders,
}),
text: async () => body,
} as Response;
}
@ -30,7 +28,7 @@ function htmlResponse(body: string): Response {
return {
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/html; charset=utf-8" }),
headers: makeFetchHeaders({ "content-type": "text/html; charset=utf-8" }),
text: async () => body,
} as Response;
}

View File

@ -1,21 +1,16 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as ssrf from "../../infra/net/ssrf.js";
import { type FetchMock, withFetchPreconnect } from "../../test-utils/fetch-mock.js";
import { makeFetchHeaders } from "./web-fetch.test-harness.js";
const lookupMock = vi.fn();
const resolvePinnedHostname = ssrf.resolvePinnedHostname;
function makeHeaders(map: Record<string, string>): { get: (key: string) => string | null } {
return {
get: (key) => map[key.toLowerCase()] ?? null,
};
}
function redirectResponse(location: string): Response {
return {
ok: false,
status: 302,
headers: makeHeaders({ location }),
headers: makeFetchHeaders({ location }),
body: { cancel: vi.fn() },
} as unknown as Response;
}
@ -24,7 +19,7 @@ function textResponse(body: string): Response {
return {
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/plain" }),
headers: makeFetchHeaders({ "content-type": "text/plain" }),
text: async () => body,
} as unknown as Response;
}

View File

@ -1,6 +1,14 @@
import { afterEach, beforeEach, vi } from "vitest";
import * as ssrf from "../../infra/net/ssrf.js";
export function makeFetchHeaders(map: Record<string, string>): {
get: (key: string) => string | null;
} {
return {
get: (key) => map[key.toLowerCase()] ?? null,
};
}
export function installWebFetchSsrfHarness() {
const lookupMock = vi.fn();
const resolvePinnedHostname = ssrf.resolvePinnedHostname;

View File

@ -2,6 +2,7 @@ import { EnvHttpProxyAgent } from "undici";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as ssrf from "../../infra/net/ssrf.js";
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
import { makeFetchHeaders } from "./web-fetch.test-harness.js";
import { createWebFetchTool } from "./web-tools.js";
type MockResponse = {
@ -13,18 +14,12 @@ type MockResponse = {
json?: () => Promise<unknown>;
};
function makeHeaders(map: Record<string, string>): { get: (key: string) => string | null } {
return {
get: (key) => map[key.toLowerCase()] ?? null,
};
}
function htmlResponse(html: string, url = "https://example.com/"): MockResponse {
return {
ok: true,
status: 200,
url,
headers: makeHeaders({ "content-type": "text/html; charset=utf-8" }),
headers: makeFetchHeaders({ "content-type": "text/html; charset=utf-8" }),
text: async () => html,
};
}
@ -62,7 +57,7 @@ function textResponse(
ok: true,
status: 200,
url,
headers: makeHeaders({ "content-type": contentType }),
headers: makeFetchHeaders({ "content-type": contentType }),
text: async () => text,
};
}
@ -77,7 +72,7 @@ function errorHtmlResponse(
ok: false,
status,
url,
headers: contentType ? makeHeaders({ "content-type": contentType }) : makeHeaders({}),
headers: contentType ? makeFetchHeaders({ "content-type": contentType }) : makeFetchHeaders({}),
text: async () => html,
};
}
@ -125,7 +120,7 @@ function installPlainTextFetch(text: string) {
Promise.resolve({
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/plain" }),
headers: makeFetchHeaders({ "content-type": "text/plain" }),
text: async () => text,
url: requestUrl(input),
} as Response),
@ -215,7 +210,7 @@ describe("web_fetch extraction fallbacks", () => {
Promise.resolve({
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/plain" }),
headers: makeFetchHeaders({ "content-type": "text/plain" }),
text: async () => longText,
url: requestUrl(input),
} as Response),
@ -277,7 +272,7 @@ describe("web_fetch extraction fallbacks", () => {
Promise.resolve({
ok: true,
status: 200,
headers: makeHeaders({ "content-type": "text/plain" }),
headers: makeFetchHeaders({ "content-type": "text/plain" }),
text: async () => "proxy body",
url: requestUrl(input),
} as Response),
@ -385,7 +380,7 @@ describe("web_fetch extraction fallbacks", () => {
return Promise.resolve({
ok: false,
status: 403,
headers: makeHeaders({ "content-type": "text/html" }),
headers: makeFetchHeaders({ "content-type": "text/html" }),
text: async () => "blocked",
} as Response);
});