test: guard telegram bot core mock calls

This commit is contained in:
Peter Steinberger
2026-05-12 11:50:44 +01:00
parent 4ea089b7fe
commit 0586da70db

View File

@@ -4,6 +4,7 @@ import {
clearPluginInteractiveHandlers,
registerPluginInteractiveHandler,
} from "openclaw/plugin-sdk/plugin-runtime";
import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime";
import { loadSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
import { mockPinnedHostnameResolution } from "openclaw/plugin-sdk/test-env";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -84,7 +85,7 @@ async function loadInboundContextContract() {
type MockCallSource = {
mock: {
calls: ArrayLike<ReadonlyArray<unknown>>;
calls: ReadonlyArray<ReadonlyArray<unknown>>;
};
};
@@ -101,13 +102,22 @@ function requireArray(value: unknown, label: string): unknown[] {
}
function mockArg(source: MockCallSource, callIndex: number, argIndex: number, label: string) {
const call = source.mock.calls[callIndex];
const call = source.mock.calls.at(callIndex);
if (!call) {
throw new Error(`expected mock call: ${label}`);
}
return call[argIndex];
}
function mockMsgContextArg(
source: MockCallSource,
callIndex: number,
argIndex: number,
label: string,
): MsgContext {
return mockArg(source, callIndex, argIndex, label) as MsgContext;
}
function execApprovalCall(index = 0) {
return requireRecord(
mockArg(resolveExecApprovalSpy as unknown as MockCallSource, index, 0, "exec approval call"),
@@ -553,7 +563,7 @@ describe("createTelegramBot", () => {
});
expect(editMessageReplyMarkupSpy).toHaveBeenCalledTimes(1);
const [chatId, messageId, replyMarkup] = editMessageReplyMarkupSpy.mock.calls[0] ?? [];
const [chatId, messageId, replyMarkup] = editMessageReplyMarkupSpy.mock.calls.at(0) ?? [];
expect(chatId).toBe(1234);
expect(messageId).toBe(21);
expect(replyMarkup).toEqual({ reply_markup: { inline_keyboard: [] } });
@@ -988,7 +998,7 @@ describe("createTelegramBot", () => {
expect(listCall.cfg).toBeTypeOf("object");
expect(listCall.agentIds).toEqual(["main"]);
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
const [chatId, messageId, text, params] = editMessageTextSpy.mock.calls[0] ?? [];
const [chatId, messageId, text, params] = editMessageTextSpy.mock.calls.at(0) ?? [];
expect(chatId).toBe(1234);
expect(messageId).toBe(12);
expect(String(text)).toContain(`${INFO_EMOJI} Commands (2/`);
@@ -1143,10 +1153,10 @@ describe("createTelegramBot", () => {
expect(replySpy).not.toHaveBeenCalled();
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain(
expect(editMessageTextSpy.mock.calls.at(0)?.[2]).toContain(
`${CHECK_MARK_EMOJI} Model reset to default`,
);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain(
expect(editMessageTextSpy.mock.calls.at(0)?.[2]).toContain(
"Session selection cleared. Runtime unchanged. New replies use the agent's configured default.",
);
@@ -1219,7 +1229,7 @@ describe("createTelegramBot", () => {
expect(replySpy).not.toHaveBeenCalled();
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
const [, , , params] = editMessageTextSpy.mock.calls[0] ?? [];
const [, , , params] = editMessageTextSpy.mock.calls.at(0) ?? [];
const inlineKeyboard = (
params as {
reply_markup?: {
@@ -1293,10 +1303,10 @@ describe("createTelegramBot", () => {
expect(replySpy).not.toHaveBeenCalled();
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain(
expect(editMessageTextSpy.mock.calls.at(0)?.[2]).toContain(
`${CHECK_MARK_EMOJI} Model reset to default`,
);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain(
expect(editMessageTextSpy.mock.calls.at(0)?.[2]).toContain(
"Session selection cleared. Runtime unchanged. New replies use the agent's configured default.",
);
@@ -1368,7 +1378,7 @@ describe("createTelegramBot", () => {
expect(replySpy).not.toHaveBeenCalled();
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
const editCall = editMessageTextSpy.mock.calls[0];
const editCall = editMessageTextSpy.mock.calls.at(0);
expect(editCall?.[0]).toBe(1234);
expect(editCall?.[1]).toBe(17);
expect(editCall?.[2]).toBe(
@@ -1523,7 +1533,7 @@ describe("createTelegramBot", () => {
expect(replySpy).not.toHaveBeenCalled();
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain(
expect(editMessageTextSpy.mock.calls.at(0)?.[2]).toContain(
'Could not resolve model "shared-model".',
);
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-compact-2");
@@ -1568,7 +1578,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
const { expectChannelInboundContextContract: expectInboundContextContract } =
await loadInboundContextContract();
const { escapeRegExp, formatEnvelopeTimestamp } = await loadEnvelopeTimestampHelpers();
@@ -1659,7 +1669,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
const [conversationContext] = requireArray(
payload.UntrustedStructuredContext,
"structured context",
@@ -1762,7 +1772,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
const [conversationContext] = requireArray(
payload.UntrustedStructuredContext,
"structured context",
@@ -1807,7 +1817,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.Body).toContain("[Reply chain - nearest first]");
expect(payload.Body).toContain("[1. Ada id:9001]");
expect(payload.Body).toContain('"summarize this"');
@@ -1845,7 +1855,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.Body).toContain("[Reply chain - nearest first]");
expect(payload.Body).toContain("[1. Ada id:9001]");
expect(payload.Body).not.toContain("PK");
@@ -1900,7 +1910,12 @@ describe("createTelegramBot", () => {
}
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0] as {
const payload = mockMsgContextArg(
replySpy as unknown as MockCallSource,
0,
0,
"replySpy call",
) as {
MediaPath?: string;
MediaPaths?: string[];
ReplyToBody?: string;
@@ -1990,7 +2005,12 @@ describe("createTelegramBot", () => {
}
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0] as {
const payload = mockMsgContextArg(
replySpy as unknown as MockCallSource,
0,
0,
"replySpy call",
) as {
ReplyChain?: Array<{
messageId?: string;
body?: string;
@@ -2178,7 +2198,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.Body).toContain("[Reply chain - nearest first]");
expect(payload.Body).toContain("[1. unknown sender]");
expect(payload.Body).toContain('"summarize this"');
@@ -2214,7 +2234,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.Body).toContain("[Reply chain - nearest first]");
expect(payload.Body).toContain("[1. Ada id:9002]");
expect(payload.Body).toContain('"summarize this"');
@@ -2262,7 +2282,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.ReplyToForwardedFrom).toBe("Bob Smith (@bobsmith)");
expect(payload.ReplyToForwardedFromType).toBe("user");
expect(payload.ReplyToForwardedFromId).toBe("999");
@@ -2325,7 +2345,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.ReplyToId).toBe("9003");
expect(payload.ReplyToBody).toBe("forwarded text");
expect(payload.ReplyToSender).toBe("Ada");
@@ -2365,7 +2385,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.WasMentioned).toBe(true);
});
@@ -2837,7 +2857,7 @@ describe("createTelegramBot", () => {
});
expect(replySpy).toHaveBeenCalledTimes(1);
const payload = replySpy.mock.calls[0][0];
const payload = mockMsgContextArg(replySpy as unknown as MockCallSource, 0, 0, "replySpy call");
expect(payload.CommandTargetSessionKey).toBe("agent:main:main");
});
@@ -3019,7 +3039,7 @@ describe("createTelegramBot", () => {
});
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
expect(enqueueSystemEventSpy.mock.calls[0]?.[0]).toBe(
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[0]).toBe(
`Telegram reaction added: ${THUMBS_UP_EMOJI} by Ada (@ada_bot) on msg 42`,
);
expect(String(systemEventOptions().contextKey)).toContain("telegram:reaction:add:1234:42:9");
@@ -3247,10 +3267,10 @@ describe("createTelegramBot", () => {
});
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
expect(enqueueSystemEventSpy.mock.calls[0]?.[0]).toBe(
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[0]).toBe(
`Telegram reaction added: ${PARTY_EMOJI} by Ada on msg 99`,
);
expect(enqueueSystemEventSpy.mock.calls[0]?.[1]).toBeTypeOf("object");
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[1]).toBeTypeOf("object");
});
it("skips reaction in own mode when message is not sent by bot", async () => {
@@ -3444,7 +3464,7 @@ describe("createTelegramBot", () => {
});
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
expect(enqueueSystemEventSpy.mock.calls[0]?.[0]).toBe(
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[0]).toBe(
`Telegram reaction added: ${FIRE_EMOJI} by Bob (@bob_user) on msg 100`,
);
expect(String(systemEventOptions().sessionKey)).toContain("telegram:group:5678:topic:1");
@@ -3480,7 +3500,7 @@ describe("createTelegramBot", () => {
});
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
expect(enqueueSystemEventSpy.mock.calls[0]?.[0]).toBe(
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[0]).toBe(
`Telegram reaction added: ${EYES_EMOJI} by Bob on msg 101`,
);
expect(String(systemEventOptions().sessionKey)).toContain("telegram:group:5678:topic:1");
@@ -3515,13 +3535,13 @@ describe("createTelegramBot", () => {
});
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
expect(enqueueSystemEventSpy.mock.calls[0]?.[0]).toBe(
expect(enqueueSystemEventSpy.mock.calls.at(0)?.[0]).toBe(
`Telegram reaction added: ${HEART_EMOJI} by Charlie on msg 200`,
);
expect(String(systemEventOptions().sessionKey)).toContain("telegram:group:9999");
expect(String(systemEventOptions().contextKey)).toContain("telegram:reaction:add:9999:200:11");
// Verify session key does NOT contain :topic:
const eventOptions = enqueueSystemEventSpy.mock.calls[0]?.[1] as {
const eventOptions = enqueueSystemEventSpy.mock.calls.at(0)?.[1] as {
sessionKey?: string;
};
const sessionKey = eventOptions.sessionKey ?? "";