mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 21:44:32 +00:00
perf: consolidate telegram bot test harness
This commit is contained in:
@@ -76,6 +76,35 @@ vi.mock("../pairing/pairing-store.js", () => ({
|
|||||||
upsertChannelPairingRequest,
|
upsertChannelPairingRequest,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const skillCommandsHoisted = vi.hoisted(() => ({
|
||||||
|
listSkillCommandsForAgents: vi.fn(() => []),
|
||||||
|
}));
|
||||||
|
export const listSkillCommandsForAgents = skillCommandsHoisted.listSkillCommandsForAgents;
|
||||||
|
|
||||||
|
vi.mock("../auto-reply/skill-commands.js", () => ({
|
||||||
|
listSkillCommandsForAgents,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const systemEventsHoisted = vi.hoisted(() => ({
|
||||||
|
enqueueSystemEventSpy: vi.fn(),
|
||||||
|
}));
|
||||||
|
export const enqueueSystemEventSpy = systemEventsHoisted.enqueueSystemEventSpy;
|
||||||
|
|
||||||
|
vi.mock("../infra/system-events.js", () => ({
|
||||||
|
enqueueSystemEvent: enqueueSystemEventSpy,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sentMessageCacheHoisted = vi.hoisted(() => ({
|
||||||
|
wasSentByBot: vi.fn(() => false),
|
||||||
|
}));
|
||||||
|
export const wasSentByBot = sentMessageCacheHoisted.wasSentByBot;
|
||||||
|
|
||||||
|
vi.mock("./sent-message-cache.js", () => ({
|
||||||
|
wasSentByBot,
|
||||||
|
recordSentMessage: vi.fn(),
|
||||||
|
clearSentMessageCache: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
export const useSpy: MockFn<(arg: unknown) => void> = vi.fn();
|
export const useSpy: MockFn<(arg: unknown) => void> = vi.fn();
|
||||||
export const middlewareUseSpy: AnyMock = vi.fn();
|
export const middlewareUseSpy: AnyMock = vi.fn();
|
||||||
export const onSpy: AnyMock = vi.fn();
|
export const onSpy: AnyMock = vi.fn();
|
||||||
@@ -84,9 +113,9 @@ export const commandSpy: AnyMock = vi.fn();
|
|||||||
export const botCtorSpy: AnyMock = vi.fn();
|
export const botCtorSpy: AnyMock = vi.fn();
|
||||||
export const answerCallbackQuerySpy: AnyAsyncMock = vi.fn(async () => undefined);
|
export const answerCallbackQuerySpy: AnyAsyncMock = vi.fn(async () => undefined);
|
||||||
export const sendChatActionSpy: AnyMock = vi.fn();
|
export const sendChatActionSpy: AnyMock = vi.fn();
|
||||||
|
export const editMessageTextSpy: AnyAsyncMock = vi.fn(async () => ({ message_id: 88 }));
|
||||||
export const setMessageReactionSpy: AnyAsyncMock = vi.fn(async () => undefined);
|
export const setMessageReactionSpy: AnyAsyncMock = vi.fn(async () => undefined);
|
||||||
export const setMyCommandsSpy: AnyAsyncMock = vi.fn(async () => undefined);
|
export const setMyCommandsSpy: AnyAsyncMock = vi.fn(async () => undefined);
|
||||||
export const deleteMyCommandsSpy: AnyAsyncMock = vi.fn(async () => undefined);
|
|
||||||
export const getMeSpy: AnyAsyncMock = vi.fn(async () => ({
|
export const getMeSpy: AnyAsyncMock = vi.fn(async () => ({
|
||||||
username: "openclaw_bot",
|
username: "openclaw_bot",
|
||||||
has_topics_enabled: true,
|
has_topics_enabled: true,
|
||||||
@@ -99,9 +128,9 @@ type ApiStub = {
|
|||||||
config: { use: (arg: unknown) => void };
|
config: { use: (arg: unknown) => void };
|
||||||
answerCallbackQuery: typeof answerCallbackQuerySpy;
|
answerCallbackQuery: typeof answerCallbackQuerySpy;
|
||||||
sendChatAction: typeof sendChatActionSpy;
|
sendChatAction: typeof sendChatActionSpy;
|
||||||
|
editMessageText: typeof editMessageTextSpy;
|
||||||
setMessageReaction: typeof setMessageReactionSpy;
|
setMessageReaction: typeof setMessageReactionSpy;
|
||||||
setMyCommands: typeof setMyCommandsSpy;
|
setMyCommands: typeof setMyCommandsSpy;
|
||||||
deleteMyCommands: typeof deleteMyCommandsSpy;
|
|
||||||
getMe: typeof getMeSpy;
|
getMe: typeof getMeSpy;
|
||||||
sendMessage: typeof sendMessageSpy;
|
sendMessage: typeof sendMessageSpy;
|
||||||
sendAnimation: typeof sendAnimationSpy;
|
sendAnimation: typeof sendAnimationSpy;
|
||||||
@@ -112,9 +141,9 @@ const apiStub: ApiStub = {
|
|||||||
config: { use: useSpy },
|
config: { use: useSpy },
|
||||||
answerCallbackQuery: answerCallbackQuerySpy,
|
answerCallbackQuery: answerCallbackQuerySpy,
|
||||||
sendChatAction: sendChatActionSpy,
|
sendChatAction: sendChatActionSpy,
|
||||||
|
editMessageText: editMessageTextSpy,
|
||||||
setMessageReaction: setMessageReactionSpy,
|
setMessageReaction: setMessageReactionSpy,
|
||||||
setMyCommands: setMyCommandsSpy,
|
setMyCommands: setMyCommandsSpy,
|
||||||
deleteMyCommands: deleteMyCommandsSpy,
|
|
||||||
getMe: getMeSpy,
|
getMe: getMeSpy,
|
||||||
sendMessage: sendMessageSpy,
|
sendMessage: sendMessageSpy,
|
||||||
sendAnimation: sendAnimationSpy,
|
sendAnimation: sendAnimationSpy,
|
||||||
@@ -269,13 +298,18 @@ beforeEach(() => {
|
|||||||
sendChatActionSpy.mockResolvedValue(undefined);
|
sendChatActionSpy.mockResolvedValue(undefined);
|
||||||
setMyCommandsSpy.mockReset();
|
setMyCommandsSpy.mockReset();
|
||||||
setMyCommandsSpy.mockResolvedValue(undefined);
|
setMyCommandsSpy.mockResolvedValue(undefined);
|
||||||
deleteMyCommandsSpy.mockReset();
|
|
||||||
deleteMyCommandsSpy.mockResolvedValue(undefined);
|
|
||||||
getMeSpy.mockReset();
|
getMeSpy.mockReset();
|
||||||
getMeSpy.mockResolvedValue({
|
getMeSpy.mockResolvedValue({
|
||||||
username: "openclaw_bot",
|
username: "openclaw_bot",
|
||||||
has_topics_enabled: true,
|
has_topics_enabled: true,
|
||||||
});
|
});
|
||||||
|
editMessageTextSpy.mockReset();
|
||||||
|
editMessageTextSpy.mockResolvedValue({ message_id: 88 });
|
||||||
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
wasSentByBot.mockReset();
|
||||||
|
wasSentByBot.mockReturnValue(false);
|
||||||
|
listSkillCommandsForAgents.mockReset();
|
||||||
|
listSkillCommandsForAgents.mockReturnValue([]);
|
||||||
middlewareUseSpy.mockReset();
|
middlewareUseSpy.mockReset();
|
||||||
sequentializeSpy.mockReset();
|
sequentializeSpy.mockReset();
|
||||||
botCtorSpy.mockReset();
|
botCtorSpy.mockReset();
|
||||||
|
|||||||
@@ -1,180 +1,38 @@
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { escapeRegExp, formatEnvelopeTimestamp } from "../../test/helpers/envelope-timestamp.js";
|
import { escapeRegExp, formatEnvelopeTimestamp } from "../../test/helpers/envelope-timestamp.js";
|
||||||
import { expectInboundContextContract } from "../../test/helpers/inbound-contract.js";
|
import { expectInboundContextContract } from "../../test/helpers/inbound-contract.js";
|
||||||
import {
|
import {
|
||||||
listNativeCommandSpecs,
|
listNativeCommandSpecs,
|
||||||
listNativeCommandSpecsForConfig,
|
listNativeCommandSpecsForConfig,
|
||||||
} from "../auto-reply/commands-registry.js";
|
} from "../auto-reply/commands-registry.js";
|
||||||
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
|
import {
|
||||||
|
answerCallbackQuerySpy,
|
||||||
|
commandSpy,
|
||||||
|
editMessageTextSpy,
|
||||||
|
enqueueSystemEventSpy,
|
||||||
|
getLoadConfigMock,
|
||||||
|
getReadChannelAllowFromStoreMock,
|
||||||
|
getOnHandler,
|
||||||
|
listSkillCommandsForAgents,
|
||||||
|
onSpy,
|
||||||
|
replySpy,
|
||||||
|
sendMessageSpy,
|
||||||
|
setMyCommandsSpy,
|
||||||
|
wasSentByBot,
|
||||||
|
} from "./bot.create-telegram-bot.test-harness.js";
|
||||||
import { createTelegramBot } from "./bot.js";
|
import { createTelegramBot } from "./bot.js";
|
||||||
|
|
||||||
let replyModule: typeof import("../auto-reply/reply.js");
|
const loadConfig = getLoadConfigMock();
|
||||||
const { listSkillCommandsForAgents } = vi.hoisted(() => ({
|
const readChannelAllowFromStore = getReadChannelAllowFromStoreMock();
|
||||||
listSkillCommandsForAgents: vi.fn(() => []),
|
|
||||||
}));
|
|
||||||
vi.mock("../auto-reply/skill-commands.js", () => ({
|
|
||||||
listSkillCommandsForAgents,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { sessionStorePath } = vi.hoisted(() => ({
|
|
||||||
sessionStorePath: `/tmp/openclaw-telegram-bot-${Math.random().toString(16).slice(2)}.json`,
|
|
||||||
}));
|
|
||||||
|
|
||||||
function resolveSkillCommands(config: Parameters<typeof listNativeCommandSpecsForConfig>[0]) {
|
function resolveSkillCommands(config: Parameters<typeof listNativeCommandSpecsForConfig>[0]) {
|
||||||
return listSkillCommandsForAgents({ cfg: config });
|
return listSkillCommandsForAgents({ cfg: config });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { loadWebMedia } = vi.hoisted(() => ({
|
|
||||||
loadWebMedia: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../web/media.js", () => ({
|
|
||||||
loadWebMedia,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { loadConfig } = vi.hoisted(() => ({
|
|
||||||
loadConfig: vi.fn(() => ({})),
|
|
||||||
}));
|
|
||||||
vi.mock("../config/config.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
loadConfig,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
vi.mock("../config/sessions.js", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("../config/sessions.js")>();
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
resolveStorePath: vi.fn((storePath) => storePath ?? sessionStorePath),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const { readChannelAllowFromStore, upsertChannelPairingRequest } = vi.hoisted(() => ({
|
|
||||||
readChannelAllowFromStore: vi.fn(async () => [] as string[]),
|
|
||||||
upsertChannelPairingRequest: vi.fn(async () => ({
|
|
||||||
code: "PAIRCODE",
|
|
||||||
created: true,
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../pairing/pairing-store.js", () => ({
|
|
||||||
readChannelAllowFromStore,
|
|
||||||
upsertChannelPairingRequest,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { enqueueSystemEvent } = vi.hoisted(() => ({
|
|
||||||
enqueueSystemEvent: vi.fn(),
|
|
||||||
}));
|
|
||||||
vi.mock("../infra/system-events.js", () => ({
|
|
||||||
enqueueSystemEvent,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { wasSentByBot } = vi.hoisted(() => ({
|
|
||||||
wasSentByBot: vi.fn(() => false),
|
|
||||||
}));
|
|
||||||
vi.mock("./sent-message-cache.js", () => ({
|
|
||||||
wasSentByBot,
|
|
||||||
recordSentMessage: vi.fn(),
|
|
||||||
clearSentMessageCache: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const useSpy = vi.fn();
|
|
||||||
const middlewareUseSpy = vi.fn();
|
|
||||||
const onSpy = vi.fn();
|
|
||||||
const stopSpy = vi.fn();
|
|
||||||
const commandSpy = vi.fn();
|
|
||||||
const botCtorSpy = vi.fn();
|
|
||||||
const answerCallbackQuerySpy = vi.fn(async () => undefined);
|
|
||||||
const sendChatActionSpy = vi.fn();
|
|
||||||
const editMessageTextSpy = vi.fn(async () => ({ message_id: 88 }));
|
|
||||||
const setMessageReactionSpy = vi.fn(async () => undefined);
|
|
||||||
const setMyCommandsSpy = vi.fn(async () => undefined);
|
|
||||||
const sendMessageSpy = vi.fn(async () => ({ message_id: 77 }));
|
|
||||||
const sendAnimationSpy = vi.fn(async () => ({ message_id: 78 }));
|
|
||||||
const sendPhotoSpy = vi.fn(async () => ({ message_id: 79 }));
|
|
||||||
type ApiStub = {
|
|
||||||
config: { use: (arg: unknown) => void };
|
|
||||||
answerCallbackQuery: typeof answerCallbackQuerySpy;
|
|
||||||
sendChatAction: typeof sendChatActionSpy;
|
|
||||||
editMessageText: typeof editMessageTextSpy;
|
|
||||||
setMessageReaction: typeof setMessageReactionSpy;
|
|
||||||
setMyCommands: typeof setMyCommandsSpy;
|
|
||||||
sendMessage: typeof sendMessageSpy;
|
|
||||||
sendAnimation: typeof sendAnimationSpy;
|
|
||||||
sendPhoto: typeof sendPhotoSpy;
|
|
||||||
};
|
|
||||||
const apiStub: ApiStub = {
|
|
||||||
config: { use: useSpy },
|
|
||||||
answerCallbackQuery: answerCallbackQuerySpy,
|
|
||||||
sendChatAction: sendChatActionSpy,
|
|
||||||
editMessageText: editMessageTextSpy,
|
|
||||||
setMessageReaction: setMessageReactionSpy,
|
|
||||||
setMyCommands: setMyCommandsSpy,
|
|
||||||
sendMessage: sendMessageSpy,
|
|
||||||
sendAnimation: sendAnimationSpy,
|
|
||||||
sendPhoto: sendPhotoSpy,
|
|
||||||
};
|
|
||||||
|
|
||||||
vi.mock("grammy", () => ({
|
|
||||||
Bot: class {
|
|
||||||
api = apiStub;
|
|
||||||
use = middlewareUseSpy;
|
|
||||||
on = onSpy;
|
|
||||||
stop = stopSpy;
|
|
||||||
command = commandSpy;
|
|
||||||
catch = vi.fn();
|
|
||||||
constructor(
|
|
||||||
public token: string,
|
|
||||||
public options?: { client?: { fetch?: typeof fetch } },
|
|
||||||
) {
|
|
||||||
botCtorSpy(token, options);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InputFile: class {},
|
|
||||||
webhookCallback: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const sequentializeMiddleware = vi.fn();
|
|
||||||
const sequentializeSpy = vi.fn(() => sequentializeMiddleware);
|
|
||||||
vi.mock("@grammyjs/runner", () => ({
|
|
||||||
sequentialize: (_keyFn: (ctx: unknown) => string) => {
|
|
||||||
return sequentializeSpy();
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const throttlerSpy = vi.fn(() => "throttler");
|
|
||||||
|
|
||||||
vi.mock("@grammyjs/transformer-throttler", () => ({
|
|
||||||
apiThrottler: () => throttlerSpy(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("../auto-reply/reply.js", () => {
|
|
||||||
const replySpy = vi.fn(async (_ctx, opts) => {
|
|
||||||
await opts?.onReplyStart?.();
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
return { getReplyFromConfig: replySpy, __replySpy: replySpy };
|
|
||||||
});
|
|
||||||
|
|
||||||
const getOnHandler = (event: string) => {
|
|
||||||
const handler = onSpy.mock.calls.find((call) => call[0] === event)?.[1];
|
|
||||||
if (!handler) {
|
|
||||||
throw new Error(`Missing handler for event: ${event}`);
|
|
||||||
}
|
|
||||||
return handler as (ctx: Record<string, unknown>) => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ORIGINAL_TZ = process.env.TZ;
|
const ORIGINAL_TZ = process.env.TZ;
|
||||||
describe("createTelegramBot", () => {
|
describe("createTelegramBot", () => {
|
||||||
beforeAll(async () => {
|
|
||||||
replyModule = await import("../auto-reply/reply.js");
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
process.env.TZ = "UTC";
|
process.env.TZ = "UTC";
|
||||||
resetInboundDedupe();
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
@@ -185,17 +43,6 @@ describe("createTelegramBot", () => {
|
|||||||
telegram: { dmPolicy: "open", allowFrom: ["*"] },
|
telegram: { dmPolicy: "open", allowFrom: ["*"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
loadWebMedia.mockReset();
|
|
||||||
sendAnimationSpy.mockReset();
|
|
||||||
sendPhotoSpy.mockReset();
|
|
||||||
setMessageReactionSpy.mockReset();
|
|
||||||
answerCallbackQuerySpy.mockReset();
|
|
||||||
editMessageTextSpy.mockReset();
|
|
||||||
setMyCommandsSpy.mockReset();
|
|
||||||
wasSentByBot.mockReset();
|
|
||||||
middlewareUseSpy.mockReset();
|
|
||||||
sequentializeSpy.mockReset();
|
|
||||||
botCtorSpy.mockReset();
|
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
process.env.TZ = ORIGINAL_TZ;
|
process.env.TZ = ORIGINAL_TZ;
|
||||||
@@ -304,7 +151,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("blocks callback_query when inline buttons are allowlist-only and sender not authorized", async () => {
|
it("blocks callback_query when inline buttons are allowlist-only and sender not authorized", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
createTelegramBot({
|
createTelegramBot({
|
||||||
@@ -426,7 +272,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("includes sender identity in group envelope headers", async () => {
|
it("includes sender identity in group envelope headers", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -479,7 +324,6 @@ describe("createTelegramBot", () => {
|
|||||||
it("uses quote text when a Telegram partial reply is received", async () => {
|
it("uses quote text when a Telegram partial reply is received", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
createTelegramBot({ token: "tok" });
|
||||||
@@ -515,7 +359,6 @@ describe("createTelegramBot", () => {
|
|||||||
it("handles quote-only replies without reply metadata", async () => {
|
it("handles quote-only replies without reply metadata", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
createTelegramBot({ token: "tok" });
|
||||||
@@ -546,7 +389,6 @@ describe("createTelegramBot", () => {
|
|||||||
it("uses external_reply quote text for partial replies", async () => {
|
it("uses external_reply quote text for partial replies", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
createTelegramBot({ token: "tok" });
|
createTelegramBot({ token: "tok" });
|
||||||
@@ -581,7 +423,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("accepts group replies to the bot without explicit mention when requireMention is enabled", async () => {
|
it("accepts group replies to the bot without explicit mention when requireMention is enabled", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -614,7 +455,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("inherits group allowlist + requireMention in topics", async () => {
|
it("inherits group allowlist + requireMention in topics", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -658,7 +498,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("prefers topic allowFrom over group allowFrom", async () => {
|
it("prefers topic allowFrom over group allowFrom", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -701,7 +540,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("allows group messages for per-group groupPolicy open override (global groupPolicy allowlist)", async () => {
|
it("allows group messages for per-group groupPolicy open override (global groupPolicy allowlist)", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -737,7 +575,6 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("blocks control commands from unauthorized senders in per-group open groups", async () => {
|
it("blocks control commands from unauthorized senders in per-group open groups", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -774,7 +611,6 @@ describe("createTelegramBot", () => {
|
|||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
commandSpy.mockReset();
|
commandSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
replySpy.mockResolvedValue({ text: "response" });
|
replySpy.mockResolvedValue({ text: "response" });
|
||||||
|
|
||||||
@@ -817,7 +653,6 @@ describe("createTelegramBot", () => {
|
|||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
commandSpy.mockReset();
|
commandSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
replySpy.mockResolvedValue({ text: "response" });
|
replySpy.mockResolvedValue({ text: "response" });
|
||||||
|
|
||||||
@@ -862,7 +697,6 @@ describe("createTelegramBot", () => {
|
|||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
sendMessageSpy.mockReset();
|
sendMessageSpy.mockReset();
|
||||||
commandSpy.mockReset();
|
commandSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -910,7 +744,7 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("enqueues system event for reaction", async () => {
|
it("enqueues system event for reaction", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -935,8 +769,8 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledWith(
|
expect(enqueueSystemEventSpy).toHaveBeenCalledWith(
|
||||||
"Telegram reaction added: 👍 by Ada (@ada_bot) on msg 42",
|
"Telegram reaction added: 👍 by Ada (@ada_bot) on msg 42",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
contextKey: expect.stringContaining("telegram:reaction:add:1234:42:9"),
|
contextKey: expect.stringContaining("telegram:reaction:add:1234:42:9"),
|
||||||
@@ -946,7 +780,7 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("skips reaction when reactionNotifications is off", async () => {
|
it("skips reaction when reactionNotifications is off", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(true);
|
wasSentByBot.mockReturnValue(true);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -972,12 +806,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults reactionNotifications to own", async () => {
|
it("defaults reactionNotifications to own", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(true);
|
wasSentByBot.mockReturnValue(true);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -1003,12 +837,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows reaction in all mode regardless of message sender", async () => {
|
it("allows reaction in all mode regardless of message sender", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(false);
|
wasSentByBot.mockReturnValue(false);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -1034,8 +868,8 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledWith(
|
expect(enqueueSystemEventSpy).toHaveBeenCalledWith(
|
||||||
"Telegram reaction added: 🎉 by Ada on msg 99",
|
"Telegram reaction added: 🎉 by Ada on msg 99",
|
||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
);
|
);
|
||||||
@@ -1043,7 +877,7 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("skips reaction in own mode when message is not sent by bot", async () => {
|
it("skips reaction in own mode when message is not sent by bot", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(false);
|
wasSentByBot.mockReturnValue(false);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -1069,12 +903,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows reaction in own mode when message is sent by bot", async () => {
|
it("allows reaction in own mode when message is sent by bot", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(true);
|
wasSentByBot.mockReturnValue(true);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -1100,12 +934,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips reaction from bot users", async () => {
|
it("skips reaction from bot users", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
wasSentByBot.mockReturnValue(true);
|
wasSentByBot.mockReturnValue(true);
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
@@ -1131,12 +965,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips reaction removal (only processes added reactions)", async () => {
|
it("skips reaction removal (only processes added reactions)", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -1161,12 +995,12 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).not.toHaveBeenCalled();
|
expect(enqueueSystemEventSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("routes forum group reactions to the general topic (thread id not available on reactions)", async () => {
|
it("routes forum group reactions to the general topic (thread id not available on reactions)", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -1193,8 +1027,8 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledWith(
|
expect(enqueueSystemEventSpy).toHaveBeenCalledWith(
|
||||||
"Telegram reaction added: 🔥 by Bob (@bob_user) on msg 100",
|
"Telegram reaction added: 🔥 by Bob (@bob_user) on msg 100",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
sessionKey: expect.stringContaining("telegram:group:5678:topic:1"),
|
sessionKey: expect.stringContaining("telegram:group:5678:topic:1"),
|
||||||
@@ -1205,7 +1039,7 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("uses correct session key for forum group reactions in general topic", async () => {
|
it("uses correct session key for forum group reactions in general topic", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -1231,8 +1065,8 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledWith(
|
expect(enqueueSystemEventSpy).toHaveBeenCalledWith(
|
||||||
"Telegram reaction added: 👀 by Bob on msg 101",
|
"Telegram reaction added: 👀 by Bob on msg 101",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
sessionKey: expect.stringContaining("telegram:group:5678:topic:1"),
|
sessionKey: expect.stringContaining("telegram:group:5678:topic:1"),
|
||||||
@@ -1243,7 +1077,7 @@ describe("createTelegramBot", () => {
|
|||||||
|
|
||||||
it("uses correct session key for regular group reactions without topic", async () => {
|
it("uses correct session key for regular group reactions without topic", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
enqueueSystemEvent.mockReset();
|
enqueueSystemEventSpy.mockReset();
|
||||||
|
|
||||||
loadConfig.mockReturnValue({
|
loadConfig.mockReturnValue({
|
||||||
channels: {
|
channels: {
|
||||||
@@ -1268,8 +1102,8 @@ describe("createTelegramBot", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(enqueueSystemEvent).toHaveBeenCalledWith(
|
expect(enqueueSystemEventSpy).toHaveBeenCalledWith(
|
||||||
"Telegram reaction added: ❤️ by Charlie on msg 200",
|
"Telegram reaction added: ❤️ by Charlie on msg 200",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
sessionKey: expect.stringContaining("telegram:group:9999"),
|
sessionKey: expect.stringContaining("telegram:group:9999"),
|
||||||
@@ -1277,7 +1111,7 @@ describe("createTelegramBot", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
// Verify session key does NOT contain :topic:
|
// Verify session key does NOT contain :topic:
|
||||||
const sessionKey = enqueueSystemEvent.mock.calls[0][1].sessionKey;
|
const sessionKey = enqueueSystemEventSpy.mock.calls[0][1].sessionKey;
|
||||||
expect(sessionKey).not.toContain(":topic:");
|
expect(sessionKey).not.toContain(":topic:");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user