mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 09:48:39 +00:00
test(fetch): align mocks openclaw#19194 thanks @sebslight
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import * as ssrf from "../../infra/net/ssrf.js";
|
import * as ssrf from "../../infra/net/ssrf.js";
|
||||||
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
|
import { type FetchMock, withFetchPreconnect } from "../../test-utils/fetch-mock.js";
|
||||||
|
|
||||||
const lookupMock = vi.fn();
|
const lookupMock = vi.fn();
|
||||||
const resolvePinnedHostname = ssrf.resolvePinnedHostname;
|
const resolvePinnedHostname = ssrf.resolvePinnedHostname;
|
||||||
@@ -29,8 +29,10 @@ function textResponse(body: string): Response {
|
|||||||
} as unknown as Response;
|
} as unknown as Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMockFetch(impl?: (...args: unknown[]) => unknown) {
|
function setMockFetch(
|
||||||
const fetchSpy = vi.fn(impl);
|
impl: FetchMock = async (_input: RequestInfo | URL, _init?: RequestInit) => textResponse(""),
|
||||||
|
) {
|
||||||
|
const fetchSpy = vi.fn<FetchMock>(impl);
|
||||||
global.fetch = withFetchPreconnect(fetchSpy);
|
global.fetch = withFetchPreconnect(fetchSpy);
|
||||||
return fetchSpy;
|
return fetchSpy;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
|
|
||||||
it("wraps Brave result descriptions", async () => {
|
it("wraps Brave result descriptions", async () => {
|
||||||
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -233,7 +233,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.("call-1", { query: "test" });
|
const result = await tool?.execute?.("call-1", { query: "test" });
|
||||||
@@ -254,7 +254,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
it("does not wrap Brave result urls (raw for tool chaining)", async () => {
|
it("does not wrap Brave result urls (raw for tool chaining)", async () => {
|
||||||
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
||||||
const url = "https://example.com/some-page";
|
const url = "https://example.com/some-page";
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -271,7 +271,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.("call-1", { query: "unique-test-url-not-wrapped" });
|
const result = await tool?.execute?.("call-1", { query: "unique-test-url-not-wrapped" });
|
||||||
@@ -284,7 +284,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
|
|
||||||
it("does not wrap Brave site names", async () => {
|
it("does not wrap Brave site names", async () => {
|
||||||
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -301,7 +301,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.("call-1", { query: "unique-test-site-name-wrapping" });
|
const result = await tool?.execute?.("call-1", { query: "unique-test-site-name-wrapping" });
|
||||||
@@ -313,7 +313,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
|
|
||||||
it("does not wrap Brave published ages", async () => {
|
it("does not wrap Brave published ages", async () => {
|
||||||
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
vi.stubEnv("BRAVE_API_KEY", "test-key");
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -331,7 +331,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.("call-1", {
|
const result = await tool?.execute?.("call-1", {
|
||||||
@@ -345,7 +345,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
|
|
||||||
it("wraps Perplexity content", async () => {
|
it("wraps Perplexity content", async () => {
|
||||||
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -355,7 +355,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({
|
const tool = createWebSearchTool({
|
||||||
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
||||||
@@ -371,7 +371,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
it("does not wrap Perplexity citations (raw for tool chaining)", async () => {
|
it("does not wrap Perplexity citations (raw for tool chaining)", async () => {
|
||||||
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
||||||
const citation = "https://example.com/some-article";
|
const citation = "https://example.com/some-article";
|
||||||
const mockFetch = vi.fn((_input?: unknown, _init?: unknown) =>
|
const mockFetch = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -381,7 +381,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
global.fetch = mockFetch;
|
global.fetch = withFetchPreconnect(mockFetch);
|
||||||
|
|
||||||
const tool = createWebSearchTool({
|
const tool = createWebSearchTool({
|
||||||
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function createOAuthFetchFn(params: {
|
|||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
username: string;
|
username: string;
|
||||||
passthrough?: boolean;
|
passthrough?: boolean;
|
||||||
}): typeof fetch {
|
}) {
|
||||||
return withFetchPreconnect(async (input, init) => {
|
return withFetchPreconnect(async (input, init) => {
|
||||||
const url = urlToString(input);
|
const url = urlToString(input);
|
||||||
if (url === CHUTES_TOKEN_ENDPOINT) {
|
if (url === CHUTES_TOKEN_ENDPOINT) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import * as authModule from "../agents/model-auth.js";
|
import * as authModule from "../agents/model-auth.js";
|
||||||
import { withFetchPreconnect } from "../test-utils/fetch-mock.js";
|
import { type FetchMock, withFetchPreconnect } from "../test-utils/fetch-mock.js";
|
||||||
import { createVoyageEmbeddingProvider, normalizeVoyageModel } from "./embeddings-voyage.js";
|
import { createVoyageEmbeddingProvider, normalizeVoyageModel } from "./embeddings-voyage.js";
|
||||||
|
|
||||||
vi.mock("../agents/model-auth.js", () => ({
|
vi.mock("../agents/model-auth.js", () => ({
|
||||||
@@ -14,13 +14,14 @@ vi.mock("../agents/model-auth.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const createFetchMock = () => {
|
const createFetchMock = () => {
|
||||||
const fetchMock = vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) => {
|
const fetchMock = vi.fn<FetchMock>(
|
||||||
return new Response(JSON.stringify({ data: [{ embedding: [0.1, 0.2, 0.3] }] }), {
|
async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
status: 200,
|
new Response(JSON.stringify({ data: [{ embedding: [0.1, 0.2, 0.3] }] }), {
|
||||||
headers: { "Content-Type": "application/json" },
|
status: 200,
|
||||||
});
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
}),
|
||||||
return withFetchPreconnect(fetchMock) as typeof fetch & typeof fetchMock;
|
);
|
||||||
|
return withFetchPreconnect(fetchMock);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("voyage embedding provider", () => {
|
describe("voyage embedding provider", () => {
|
||||||
@@ -95,6 +96,7 @@ describe("voyage embedding provider", () => {
|
|||||||
|
|
||||||
it("passes input_type=document for embedBatch", async () => {
|
it("passes input_type=document for embedBatch", async () => {
|
||||||
const fetchMock = withFetchPreconnect(
|
const fetchMock = withFetchPreconnect(
|
||||||
|
<<<<<<< HEAD
|
||||||
vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) => {
|
vi.fn(async (_input: RequestInfo | URL, _init?: RequestInit) => {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -106,6 +108,17 @@ describe("voyage embedding provider", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
=======
|
||||||
|
vi.fn<FetchMock>(
|
||||||
|
async (_input: RequestInfo | URL, _init?: RequestInit) =>
|
||||||
|
new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
data: [{ embedding: [0.1, 0.2] }, { embedding: [0.3, 0.4] }],
|
||||||
|
}),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
>>>>>>> 03a725142 (test(fetch): align mocks openclaw#19194 thanks @sebslight)
|
||||||
);
|
);
|
||||||
vi.stubGlobal("fetch", fetchMock);
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
import * as ssrf from "../../infra/net/ssrf.js";
|
import * as ssrf from "../../infra/net/ssrf.js";
|
||||||
import type { SavedMedia } from "../../media/store.js";
|
import type { SavedMedia } from "../../media/store.js";
|
||||||
import * as mediaStore from "../../media/store.js";
|
import * as mediaStore from "../../media/store.js";
|
||||||
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
|
import { type FetchMock, withFetchPreconnect } from "../../test-utils/fetch-mock.js";
|
||||||
import {
|
import {
|
||||||
fetchWithSlackAuth,
|
fetchWithSlackAuth,
|
||||||
resolveSlackAttachmentContent,
|
resolveSlackAttachmentContent,
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
|
|
||||||
// Store original fetch
|
// Store original fetch
|
||||||
const originalFetch = globalThis.fetch;
|
const originalFetch = globalThis.fetch;
|
||||||
let mockFetch: ReturnType<typeof vi.fn>;
|
let mockFetch: ReturnType<typeof vi.fn<FetchMock>>;
|
||||||
const createSavedMedia = (filePath: string, contentType: string): SavedMedia => ({
|
const createSavedMedia = (filePath: string, contentType: string): SavedMedia => ({
|
||||||
id: "saved-media-id",
|
id: "saved-media-id",
|
||||||
path: filePath,
|
path: filePath,
|
||||||
@@ -23,7 +23,9 @@ const createSavedMedia = (filePath: string, contentType: string): SavedMedia =>
|
|||||||
describe("fetchWithSlackAuth", () => {
|
describe("fetchWithSlackAuth", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Create a new mock for each test
|
// Create a new mock for each test
|
||||||
mockFetch = vi.fn();
|
mockFetch = vi.fn<FetchMock>(
|
||||||
|
async (_input: RequestInfo | URL, _init?: RequestInit) => new Response(),
|
||||||
|
);
|
||||||
globalThis.fetch = withFetchPreconnect(mockFetch);
|
globalThis.fetch = withFetchPreconnect(mockFetch);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -366,8 +368,9 @@ describe("resolveSlackMedia", () => {
|
|||||||
return createSavedMedia("/tmp/unknown", "application/octet-stream");
|
return createSavedMedia("/tmp/unknown", "application/octet-stream");
|
||||||
});
|
});
|
||||||
|
|
||||||
mockFetch.mockImplementation(async (input) => {
|
mockFetch.mockImplementation(async (input: RequestInfo | URL) => {
|
||||||
const url = String(input);
|
const url =
|
||||||
|
typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
||||||
if (url.includes("/a.jpg")) {
|
if (url.includes("/a.jpg")) {
|
||||||
return new Response(Buffer.from("image a"), {
|
return new Response(Buffer.from("image a"), {
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
|
export type FetchMock = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||||
|
|
||||||
|
type FetchPreconnectOptions = {
|
||||||
|
dns?: boolean;
|
||||||
|
tcp?: boolean;
|
||||||
|
http?: boolean;
|
||||||
|
https?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type FetchWithPreconnect = {
|
type FetchWithPreconnect = {
|
||||||
preconnect: (url: string, init?: { credentials?: RequestCredentials }) => void;
|
preconnect: (url: string | URL, options?: FetchPreconnectOptions) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function withFetchPreconnect<T extends typeof fetch>(fn: T): T & FetchWithPreconnect;
|
export function withFetchPreconnect<T extends typeof fetch>(fn: T): T & FetchWithPreconnect;
|
||||||
@@ -8,6 +17,6 @@ export function withFetchPreconnect<T extends object>(
|
|||||||
): T & FetchWithPreconnect & typeof fetch;
|
): T & FetchWithPreconnect & typeof fetch;
|
||||||
export function withFetchPreconnect(fn: object) {
|
export function withFetchPreconnect(fn: object) {
|
||||||
return Object.assign(fn, {
|
return Object.assign(fn, {
|
||||||
preconnect: (_url: string, _init?: { credentials?: RequestCredentials }) => {},
|
preconnect: (_url: string | URL, _options?: FetchPreconnectOptions) => {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user