import { beforeEach, describe, expect, it, vi } from "vitest"; import { monitorTelegramProvider } from "./monitor.js"; type MockCtx = { message: { chat: { id: number; type: string; title?: string }; text?: string; caption?: string; }; me?: { username: string }; getFile: () => Promise; }; // Fake bot to capture handler and API calls const handlers: Record Promise | void> = {}; const api = { sendMessage: vi.fn(), sendPhoto: vi.fn(), sendVideo: vi.fn(), sendAudio: vi.fn(), sendDocument: vi.fn(), setWebhook: vi.fn(), deleteWebhook: vi.fn(), }; const { initSpy, runSpy, loadConfig } = vi.hoisted(() => ({ initSpy: vi.fn(async () => undefined), runSpy: vi.fn(() => ({ task: () => Promise.resolve(), stop: vi.fn(), })), loadConfig: vi.fn(() => ({ agents: { defaults: { maxConcurrent: 2 } }, telegram: {}, })), })); vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, loadConfig, }; }); vi.mock("./bot.js", () => ({ createTelegramBot: () => { handlers.message = async (ctx: MockCtx) => { const chatId = ctx.message.chat.id; const isGroup = ctx.message.chat.type !== "private"; const text = ctx.message.text ?? ctx.message.caption ?? ""; if (isGroup && !text.includes("@mybot")) return; if (!text.trim()) return; await api.sendMessage(chatId, `echo:${text}`, { parse_mode: "HTML" }); }; return { on: vi.fn(), api, me: { username: "mybot" }, init: initSpy, stop: vi.fn(), start: vi.fn(), }; }, createTelegramWebhookCallback: vi.fn(), })); // Mock the grammyjs/runner to resolve immediately vi.mock("@grammyjs/runner", () => ({ run: runSpy, })); vi.mock("../auto-reply/reply.js", () => ({ getReplyFromConfig: async (ctx: { Body?: string }) => ({ text: `echo:${ctx.Body}`, }), })); describe("monitorTelegramProvider (grammY)", () => { beforeEach(() => { loadConfig.mockReturnValue({ agents: { defaults: { maxConcurrent: 2 } }, telegram: {}, }); initSpy.mockClear(); runSpy.mockClear(); }); it("processes a DM and sends reply", async () => { Object.values(api).forEach((fn) => { fn?.mockReset?.(); }); await monitorTelegramProvider({ token: "tok" }); expect(handlers.message).toBeDefined(); await handlers.message?.({ message: { message_id: 1, chat: { id: 123, type: "private" }, text: "hi", }, me: { username: "mybot" }, getFile: vi.fn(async () => ({})), }); expect(api.sendMessage).toHaveBeenCalledWith(123, "echo:hi", { parse_mode: "HTML", }); }); it("uses agent maxConcurrent for runner concurrency", async () => { runSpy.mockClear(); loadConfig.mockReturnValue({ agents: { defaults: { maxConcurrent: 3 } }, telegram: {}, }); await monitorTelegramProvider({ token: "tok" }); expect(runSpy).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ sink: { concurrency: 3 }, runner: expect.objectContaining({ silent: true }), }), ); }); it("requires mention in groups by default", async () => { Object.values(api).forEach((fn) => { fn?.mockReset?.(); }); await monitorTelegramProvider({ token: "tok" }); await handlers.message?.({ message: { message_id: 2, chat: { id: -99, type: "supergroup", title: "G" }, text: "hello all", }, me: { username: "mybot" }, getFile: vi.fn(async () => ({})), }); expect(api.sendMessage).not.toHaveBeenCalled(); }); });