From d9a604f15f12c6072dc12e6faf753fbbbb14e9b9 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Mar 2026 01:33:09 +0000 Subject: [PATCH] test: share web fetch header helpers --- .../tools/web-fetch.cf-markdown.test.ts | 14 ++++++------- src/agents/tools/web-fetch.ssrf.test.ts | 11 +++------- src/agents/tools/web-fetch.test-harness.ts | 8 +++++++ src/agents/tools/web-tools.fetch.test.ts | 21 +++++++------------ 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/agents/tools/web-fetch.cf-markdown.test.ts b/src/agents/tools/web-fetch.cf-markdown.test.ts index f22dc10df52..4dd22714574 100644 --- a/src/agents/tools/web-fetch.cf-markdown.test.ts +++ b/src/agents/tools/web-fetch.cf-markdown.test.ts @@ -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): { get: (key: string) => string | null } { - return { - get: (key) => map[key.toLowerCase()] ?? null, - }; -} - function markdownResponse(body: string, extraHeaders: Record = {}): 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; } diff --git a/src/agents/tools/web-fetch.ssrf.test.ts b/src/agents/tools/web-fetch.ssrf.test.ts index eb868068ece..c0489c9b5ba 100644 --- a/src/agents/tools/web-fetch.ssrf.test.ts +++ b/src/agents/tools/web-fetch.ssrf.test.ts @@ -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): { 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; } diff --git a/src/agents/tools/web-fetch.test-harness.ts b/src/agents/tools/web-fetch.test-harness.ts index c86a028e155..1bd8e33e89b 100644 --- a/src/agents/tools/web-fetch.test-harness.ts +++ b/src/agents/tools/web-fetch.test-harness.ts @@ -1,6 +1,14 @@ import { afterEach, beforeEach, vi } from "vitest"; import * as ssrf from "../../infra/net/ssrf.js"; +export function makeFetchHeaders(map: Record): { + get: (key: string) => string | null; +} { + return { + get: (key) => map[key.toLowerCase()] ?? null, + }; +} + export function installWebFetchSsrfHarness() { const lookupMock = vi.fn(); const resolvePinnedHostname = ssrf.resolvePinnedHostname; diff --git a/src/agents/tools/web-tools.fetch.test.ts b/src/agents/tools/web-tools.fetch.test.ts index 9da57a35b45..da700ea537e 100644 --- a/src/agents/tools/web-tools.fetch.test.ts +++ b/src/agents/tools/web-tools.fetch.test.ts @@ -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; }; -function makeHeaders(map: Record): { 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); });