test: guard media understanding mock calls

This commit is contained in:
Peter Steinberger
2026-05-11 23:36:06 +01:00
parent bffa49705e
commit b433e643bb
4 changed files with 66 additions and 14 deletions
+41 -9
View File
@@ -48,6 +48,21 @@ type AuthRequestCall = {
store?: unknown;
};
function requireFirstMockCall(mock: { mock: { calls: unknown[][] } }, label: string): unknown[] {
const [call] = mock.mock.calls;
if (!call) {
throw new Error(`Expected ${label} call`);
}
return call;
}
function requireRecord(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`Expected ${label}`);
}
return value as Record<string, unknown>;
}
vi.mock("@earendil-works/pi-ai", async () => {
const actual =
await vi.importActual<typeof import("@earendil-works/pi-ai")>("@earendil-works/pi-ai");
@@ -180,7 +195,8 @@ describe("describeImageWithModel", () => {
expect(authRequest?.store).toBe(authStore);
expect(requireApiKeyMock).toHaveBeenCalled();
expect(setRuntimeApiKeyMock).toHaveBeenCalledWith("minimax-portal", "oauth-test");
const [fetchUrl, fetchOptions] = fetchMock.mock.calls[0] ?? [];
const [fetchUrl, fetchOptionsValue] = requireFirstMockCall(fetchMock, "fetch");
const fetchOptions = requireRecord(fetchOptionsValue, "fetch options");
expect(fetchUrl).toBe("https://api.minimax.io/v1/coding_plan/vlm");
expect(fetchOptions).toEqual({
method: "POST",
@@ -193,9 +209,9 @@ describe("describeImageWithModel", () => {
prompt: "Describe the image.",
image_url: `data:image/png;base64,${Buffer.from("png-bytes").toString("base64")}`,
}),
signal: fetchOptions?.signal,
signal: fetchOptions.signal,
});
expect(fetchOptions?.signal).toBeInstanceOf(AbortSignal);
expect(fetchOptions.signal).toBeInstanceOf(AbortSignal);
expect(timeoutSpy).toHaveBeenCalledWith(1000);
expect(completeMock).not.toHaveBeenCalled();
});
@@ -235,7 +251,10 @@ describe("describeImageWithModel", () => {
text: "generic ok",
model: "custom-vision",
});
const [streamRequest] = registerProviderStreamForModelMock.mock.calls[0] ?? [];
const [streamRequest] = requireFirstMockCall(
registerProviderStreamForModelMock,
"provider stream registration",
);
expect(streamRequest).toEqual({
model: {
provider: "minimax-portal",
@@ -309,11 +328,24 @@ describe("describeImageWithModel", () => {
model: "google/gemma-4-e2b",
});
expect(registryFind).not.toHaveBeenCalled();
const [resolveRequest] = resolveModelWithRegistryMock.mock.calls[0] ?? [];
expect(resolveRequest?.provider).toBe("lmstudio");
expect(resolveRequest?.modelId).toBe("google/gemma-4-e2b");
expect(resolveRequest?.agentDir).toBe("/tmp/openclaw-agent");
expect(resolveRequest?.cfg.models?.providers?.lmstudio?.baseUrl).toBe("http://127.0.0.1:1234");
const [resolveRequestValue] = requireFirstMockCall(
resolveModelWithRegistryMock,
"model registry resolution",
);
const resolveRequest = requireRecord(resolveRequestValue, "model registry request");
expect(resolveRequest.provider).toBe("lmstudio");
expect(resolveRequest.modelId).toBe("google/gemma-4-e2b");
expect(resolveRequest.agentDir).toBe("/tmp/openclaw-agent");
expect(
requireRecord(
requireRecord(
requireRecord(requireRecord(resolveRequest.cfg, "request config").models, "models")
.providers,
"model providers",
).lmstudio,
"lmstudio provider",
).baseUrl,
).toBe("http://127.0.0.1:1234");
expect(prepareProviderDynamicModelMock).not.toHaveBeenCalled();
expect(completeMock).toHaveBeenCalledOnce();
});
@@ -55,6 +55,14 @@ describe("media understanding attachments SSRF", () => {
vi.restoreAllMocks();
});
function requireFirstOpenCall(openSpy: ReturnType<typeof vi.spyOn>): unknown[] {
const [call] = openSpy.mock.calls;
if (!call) {
throw new Error("expected fs.open call");
}
return call;
}
it("blocks private IP URLs before fetching", async () => {
const fetchSpy = vi.fn();
globalThis.fetch = withFetchPreconnect(fetchSpy);
@@ -212,7 +220,7 @@ describe("media understanding attachments SSRF", () => {
await cache.getBuffer({ attachmentIndex: 0, maxBytes: 1024, timeoutMs: 1000 });
expect(openSpy).toHaveBeenCalled();
const [openedPath, openedFlags] = openSpy.mock.calls[0] ?? [];
const [openedPath, openedFlags] = requireFirstOpenCall(openSpy);
expect(await fs.realpath(String(openedPath)).catch(() => String(openedPath))).toBe(
canonicalAttachmentPath,
);
@@ -12,6 +12,14 @@ vi.mock("../process/exec.js", () => ({
let runCliEntry: typeof import("./runner.entries.js").runCliEntry;
function requireFirstRunExecCall(): unknown[] {
const [call] = runExecMock.mock.calls;
if (!call) {
throw new Error("expected runExec call");
}
return call;
}
describe("media-understanding CLI audio entry", () => {
beforeAll(async () => {
({ runCliEntry } = await import("./runner.entries.js"));
@@ -65,7 +73,7 @@ describe("media-understanding CLI audio entry", () => {
});
expect(runExecMock).toHaveBeenCalledTimes(1);
const [command, args, options] = runExecMock.mock.calls[0] ?? [];
const [command, args, options] = requireFirstRunExecCall();
expect(command).toBe("mock-transcriber");
expect(args).toEqual(["--prompt", "Focus on names", "--language", "en", "--file", mediaPath]);
expect(options).toEqual({
+7 -3
View File
@@ -48,11 +48,15 @@ afterEach(() => {
});
function getFirstGuardedFetchCall() {
const [call] = fetchWithSsrFGuardMock.mock.calls[0] ?? [];
if (!call) {
const [mockCall] = fetchWithSsrFGuardMock.mock.calls;
if (!mockCall) {
throw new Error("Expected fetchWithSsrFGuard to be called");
}
return call;
const [request] = mockCall;
if (!request || typeof request !== "object" || Array.isArray(request)) {
throw new Error("Expected fetchWithSsrFGuard request");
}
return request as Record<string, unknown>;
}
describe("provider operation deadlines", () => {