

























@@ -20,6 +20,12 @@ import type { UploadCacheAdapter } from "./media.js";
2020import { UPLOAD_PREPARE_FALLBACK_CODE } from "./retry.js";
2121import type { TokenManager } from "./token.js";
222223+const fetchWithSsrFGuardMock = vi.hoisted(() => vi.fn());
24+25+vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
26+fetchWithSsrFGuard: fetchWithSsrFGuardMock,
27+}));
28+2329// ============ Test doubles ============
24302531/** Build a minimal ApiClient stub whose `request` is fully mockable. */
@@ -82,18 +88,17 @@ const FIXTURE_BUFFER = Buffer.from("0123456789abcdefghij"); // 20 bytes
8288let originalFetch: typeof globalThis.fetch;
83898490function stubFetchOk(): ReturnType<typeof vi.fn> {
85-const spy = vi.fn(
86-async () =>
87-new Response("", {
88-status: 200,
89-headers: {
90-ETag: '"etag-value"',
91-"x-cos-request-id": "req-id",
92-},
93-}),
94-);
95-globalThis.fetch = spy as unknown as typeof globalThis.fetch;
96-return spy;
91+fetchWithSsrFGuardMock.mockImplementation(async () => ({
92+response: new Response("", {
93+status: 200,
94+headers: {
95+ETag: '"etag-value"',
96+"x-cos-request-id": "req-id",
97+},
98+}),
99+release: vi.fn(),
100+}));
101+return fetchWithSsrFGuardMock;
97102}
9810399104// ============ Tests ============
@@ -122,6 +127,7 @@ describe("media-chunked: ChunkedMediaApi.uploadChunked", () => {
122127123128afterEach(() => {
124129globalThis.fetch = originalFetch;
130+fetchWithSsrFGuardMock.mockReset();
125131vi.restoreAllMocks();
126132});
127133@@ -235,7 +241,7 @@ describe("media-chunked: ChunkedMediaApi.uploadChunked", () => {
235241236242// 3 COS PUTs, one per part, each to the presigned URL.
237243expect(fetchSpy).toHaveBeenCalledTimes(3);
238-const putUrls = fetchSpy.mock.calls.map((c) => c[0]);
244+const putUrls = fetchSpy.mock.calls.map((c) => (c[0] as { url: string }).url);
239245expect(putUrls).toEqual(
240246expect.arrayContaining([
241247"https://cos.example.com/part-1",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。