test: guard extension channel mock calls

This commit is contained in:
Peter Steinberger
2026-05-12 11:19:53 +01:00
parent 6a230a108a
commit 2ec1a27c9f
10 changed files with 30 additions and 31 deletions
@@ -431,7 +431,7 @@ describe("CodexAppServerEventProjector", () => {
},
}),
);
const toolProgressText = onToolResult.mock.calls[0]?.[0]?.text;
const toolProgressText = onToolResult.mock.calls.at(0)?.[0]?.text;
expect(toolProgressText).toBe("🛠️ `run tests (workspace)`");
await projector.handleNotification(
@@ -452,7 +452,6 @@ describe("CodexAppServerEventProjector", () => {
expect(result.lastAssistant).toBeUndefined();
});
it("does not fail a completed reply after a retryable app-server error notification", async () => {
const projector = await createProjector();
@@ -1458,7 +1457,7 @@ describe("CodexAppServerEventProjector", () => {
}),
);
const text = onToolResult.mock.calls[0]?.[0]?.text;
const text = onToolResult.mock.calls.at(0)?.[0]?.text;
expect(text).toContain("sk-123…ZZZZ");
expect(text).not.toContain("sk-1234567890abcdefZZZZ");
});
@@ -1590,7 +1589,7 @@ describe("CodexAppServerEventProjector", () => {
);
expect(onToolResult).toHaveBeenCalledTimes(21);
expect(onToolResult.mock.calls[19]?.[0]?.text).toContain("...(truncated)...");
expect(onToolResult.mock.calls.at(19)?.[0]?.text).toContain("...(truncated)...");
expect(JSON.stringify(onToolResult.mock.calls)).not.toContain(
"final output should not duplicate",
);
+3 -3
View File
@@ -128,7 +128,7 @@ describe("PlaywrightDiffScreenshotter", () => {
expect(launchMock).toHaveBeenCalledTimes(1);
expect(pages).toHaveLength(1);
expect(pages[0]?.pdf).toHaveBeenCalledTimes(1);
const pdfCall = pages[0]?.pdf.mock.calls[0]?.[0] as Record<string, unknown> | undefined;
const pdfCall = pages[0]?.pdf.mock.calls.at(0)?.[0] as Record<string, unknown> | undefined;
if (!pdfCall) {
throw new Error("expected PDF render call");
}
@@ -404,8 +404,8 @@ describe("diffs plugin registration", () => {
registerDiffsPlugin(api as unknown as OpenClawPluginApi);
expect(on).toHaveBeenCalledTimes(1);
expect(on.mock.calls[0]?.[0]).toBe("before_prompt_build");
const beforePromptBuild = on.mock.calls[0]?.[1];
expect(on.mock.calls.at(0)?.[0]).toBe("before_prompt_build");
const beforePromptBuild = on.mock.calls.at(0)?.[1];
const promptResult = await beforePromptBuild?.({}, {});
expect(promptResult?.prependSystemContext).toBe(
[
@@ -82,7 +82,7 @@ describe("Feishu bot menu handler", () => {
await onBotMenu(createBotMenuEvent({ eventKey: "quick-actions", timestamp: "1700000000000" }));
expect(sendCardFeishuMock).toHaveBeenCalledTimes(1);
const sendArgs = sendCardFeishuMock.mock.calls[0]?.[0] as
const sendArgs = sendCardFeishuMock.mock.calls.at(0)?.[0] as
| {
accountId?: string;
card?: {
@@ -131,7 +131,7 @@ describe("Feishu bot menu handler", () => {
await onBotMenu(createBotMenuEvent({ eventKey: "custom-key", timestamp: "1700000000002" }));
expect(handleFeishuMessageMock).toHaveBeenCalledTimes(1);
const handleArgs = handleFeishuMessageMock.mock.calls[0]?.[0] as
const handleArgs = handleFeishuMessageMock.mock.calls.at(0)?.[0] as
| { event?: { message?: { content?: string } } }
| undefined;
expect(handleArgs?.event?.message?.content).toBe('{"text":"/menu custom-key"}');
@@ -147,7 +147,7 @@ describe("Feishu bot menu handler", () => {
await vi.waitFor(() => {
expect(handleFeishuMessageMock).toHaveBeenCalledTimes(1);
});
const handleArgs = handleFeishuMessageMock.mock.calls[0]?.[0] as
const handleArgs = handleFeishuMessageMock.mock.calls.at(0)?.[0] as
| { event?: { message?: { content?: string } } }
| undefined;
expect(handleArgs?.event?.message?.content).toBe('{"text":"/menu quick-actions"}');
@@ -199,7 +199,7 @@ async function setupDebounceMonitor(params?: {
}
function getFirstDispatchedEvent(): FeishuMessageEvent {
const firstCall = handleFeishuMessageMock.mock.calls[0];
const firstCall = handleFeishuMessageMock.mock.calls.at(0);
if (!firstCall) {
throw new Error("missing dispatch call");
}
@@ -576,7 +576,7 @@ describe("Feishu inbound debounce regressions", () => {
await vi.advanceTimersByTimeAsync(25);
expect(handleFeishuMessageMock).toHaveBeenCalledTimes(1);
const firstParams = handleFeishuMessageMock.mock.calls[0]?.[0] as
const firstParams = handleFeishuMessageMock.mock.calls.at(0)?.[0] as
| { botName?: string }
| undefined;
expect(firstParams?.botName).toBe("OpenClaw Bot");
@@ -680,7 +680,7 @@ describe("Feishu inbound debounce regressions", () => {
const combined = JSON.parse(dispatched.message.content) as { text?: string };
expect(combined.text).toBe("fresh");
expect(recordSpy).toHaveBeenCalledTimes(1);
const [recordedMessageId, recordedNamespace, recordedLogger] = recordSpy.mock.calls[0] ?? [];
const [recordedMessageId, recordedNamespace, recordedLogger] = recordSpy.mock.calls.at(0) ?? [];
expect(recordedMessageId).toBe("om_old_latest_fresh");
expect(recordedNamespace).toBe("default");
expect(typeof recordedLogger).toBe("function");
+3 -3
View File
@@ -52,7 +52,7 @@ describe("gradium speech provider", () => {
});
expect(fetchMock).toHaveBeenCalledOnce();
const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit];
const [url, init] = fetchMock.mock.calls.at(0) as [string, RequestInit];
expect(url).toBe("https://api.gradium.ai/api/post/speech/tts");
const headers = new Headers(init.headers);
expect(headers.get("x-api-key")).toBe("gsk_test123");
@@ -82,7 +82,7 @@ describe("gradium speech provider", () => {
timeoutMs: 30_000,
});
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
const [, init] = fetchMock.mock.calls.at(0) as [string, RequestInit];
expect(JSON.parse(init.body as string).output_format).toBe("opus");
expect(result.outputFormat).toBe("opus");
expect(result.fileExtension).toBe(".opus");
@@ -107,7 +107,7 @@ describe("gradium speech provider", () => {
timeoutMs: 30_000,
});
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
const [, init] = fetchMock.mock.calls.at(0) as [string, RequestInit];
expect(JSON.parse(init.body as string)).toEqual({
text: "Telephony test",
voice_id: "override-voice",
+3 -3
View File
@@ -235,7 +235,7 @@ async function expectSignedRawBodyWins(params: { rawBody: string | Buffer; signe
expect(res.status).toHaveBeenCalledWith(200);
expect(onEvents).toHaveBeenCalledTimes(1);
const processedBody = (
onEvents.mock.calls[0] as unknown as [{ events?: Array<{ source?: { userId?: string } }> }]
onEvents.mock.calls.at(0) as unknown as [{ events?: Array<{ source?: { userId?: string } }> }]
)?.[0];
expect(processedBody?.events?.[0]?.source?.userId).toBe(params.signedUserId);
expect(processedBody?.events?.[0]?.source?.userId).not.toBe("tampered-user");
@@ -414,7 +414,7 @@ describe("createLineNodeWebhookHandler", () => {
expect(res.statusCode).toBe(200);
expect(bot.handleWebhook).toHaveBeenCalledTimes(1);
const [payload] = bot.handleWebhook.mock.calls[0] as unknown as [ParsedLineWebhookPayload];
const [payload] = bot.handleWebhook.mock.calls.at(0) as unknown as [ParsedLineWebhookPayload];
expect(payload.events).toEqual([{ type: "message" }]);
});
@@ -494,7 +494,7 @@ describe("createLineWebhookMiddleware", () => {
const { res, onEvents } = await invokeWebhook({ body });
expect(res.status).toHaveBeenCalledWith(200);
expect(onEvents).toHaveBeenCalledTimes(1);
const [payload] = onEvents.mock.calls[0] as unknown as [ParsedLineWebhookPayload];
const [payload] = onEvents.mock.calls.at(0) as unknown as [ParsedLineWebhookPayload];
expect(payload.events).toEqual(expectedEvents);
});
+3 -3
View File
@@ -394,7 +394,7 @@ describe("lmstudio setup", () => {
const result = await configureLmstudioNonInteractive(ctx);
const setupCall = requireRecord(
configureSelfHostedNonInteractiveMock.mock.calls[0]?.[0],
configureSelfHostedNonInteractiveMock.mock.calls.at(0)?.[0],
"self-hosted setup call",
);
const setupCtx = requireRecord(setupCall.ctx, "self-hosted setup context");
@@ -653,7 +653,7 @@ describe("lmstudio setup", () => {
await configureLmstudioNonInteractive(ctx);
expectRecordFields(ctx.resolveApiKey.mock.calls[0]?.[0], "resolveApiKey options", {
expectRecordFields(ctx.resolveApiKey.mock.calls.at(0)?.[0], "resolveApiKey options", {
flagValue: "new-lmstudio-key",
flagName: "--lmstudio-api-key",
});
@@ -831,7 +831,7 @@ describe("lmstudio setup", () => {
prompter,
});
const firstTextCall = requireRecord(text.mock.calls[0]?.[0], "first text prompt");
const firstTextCall = requireRecord(text.mock.calls.at(0)?.[0], "first text prompt");
expectRecordFields(firstTextCall, "first text prompt", {
initialValue: "http://host.docker.internal:1234",
placeholder: "http://host.docker.internal:1234",
@@ -56,7 +56,7 @@ describe("matrix profile actions", () => {
});
expect(withResolvedActionClientMock).toHaveBeenCalledTimes(1);
const [wrapperOpts, run, mode] = withResolvedActionClientMock.mock.calls[0] ?? [];
const [wrapperOpts, run, mode] = withResolvedActionClientMock.mock.calls.at(0) ?? [];
expect(wrapperOpts).toEqual({
accountId: "ops",
displayName: " Ops Bot ",
@@ -67,7 +67,7 @@ describe("matrix profile actions", () => {
expect(mode).toBe("persist");
expect(syncMatrixOwnProfileMock).toHaveBeenCalledTimes(1);
const syncCall = syncMatrixOwnProfileMock.mock.calls[0]?.[0] as
const syncCall = syncMatrixOwnProfileMock.mock.calls.at(0)?.[0] as
| {
client: unknown;
userId: string;
@@ -105,7 +105,7 @@ describe("matrix profile actions", () => {
avatarPath: "/tmp/avatar.png",
});
const call = syncMatrixOwnProfileMock.mock.calls[0]?.[0] as
const call = syncMatrixOwnProfileMock.mock.calls.at(0)?.[0] as
| {
loadAvatarFromUrl: (url: string, maxBytes: number) => Promise<unknown>;
loadAvatarFromPath: (path: string, maxBytes: number) => Promise<unknown>;
@@ -78,7 +78,7 @@ type MockWithCalls = {
};
function firstObjectArg(mock: MockWithCalls): Record<string, unknown> {
const value = mock.mock.calls[0]?.[0];
const value = mock.mock.calls.at(0)?.[0];
if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
throw new Error("expected first mock call object argument");
}
@@ -86,7 +86,7 @@ function firstObjectArg(mock: MockWithCalls): Record<string, unknown> {
}
function objectArgAt(mock: MockWithCalls, index: number): Record<string, unknown> {
const value = mock.mock.calls[0]?.[index];
const value = mock.mock.calls.at(0)?.[index];
if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`expected first mock call argument ${index} to be an object`);
}
@@ -171,7 +171,7 @@ describe("createMatrixRoomMessageHandler media failures", () => {
expect(ctx.RawBody).toBe("[matrix image attachment unavailable]");
expect(ctx.CommandBody).toBe("[matrix image attachment unavailable]");
expect(ctx.MediaPath).toBeUndefined();
expect(logger.warn.mock.calls[0]?.[0]).toBe("matrix media download failed");
expect(logger.warn.mock.calls.at(0)?.[0]).toBe("matrix media download failed");
const warningMetadata = objectArgAt(logger.warn, 1);
expect(warningMetadata.eventId).toBe("$event1");
expect(warningMetadata.msgtype).toBe("m.image");
@@ -628,7 +628,7 @@ describe("slash-http", () => {
).resolves.toBe(false);
expect(log).toHaveBeenCalledTimes(1);
const message = log.mock.calls[0]?.[0] ?? "";
const message = log.mock.calls.at(0)?.[0] ?? "";
expect(message).not.toMatch(/[\r\n\t]/u);
expect(message).toContain("deleted command cmd-1 spoofed");
expect(message).toContain("using team list fallback");
@@ -753,7 +753,7 @@ describe("slash-http", () => {
).resolves.toBe(true);
expect(log).toHaveBeenCalledTimes(1);
const message = log.mock.calls[0]?.[0] ?? "";
const message = log.mock.calls.at(0)?.[0] ?? "";
expect(message).not.toMatch(/[\r\n\t]/u);
expect(message).toContain("/oc_status spoofed");
expect(message).toContain("primary token=[redacted]");
@@ -792,7 +792,7 @@ describe("slash-http", () => {
).resolves.toBe(false);
expect(log).toHaveBeenCalledTimes(1);
const message = log.mock.calls[0]?.[0] ?? "";
const message = log.mock.calls.at(0)?.[0] ?? "";
expect(message).not.toMatch(/[\r\n\t]/u);
expect(message).toContain("fallback second-line");
expect(message).toContain("botToken: [redacted]");