import { describe, expect, it, vi } from "vitest"; import * as replyModule from "../auto-reply/reply.js"; import { createTelegramBot } from "./bot.js"; const useSpy = vi.fn(); const onSpy = vi.fn(); const stopSpy = vi.fn(); const sendChatActionSpy = vi.fn(); type ApiStub = { config: { use: (arg: unknown) => void }; sendChatAction: typeof sendChatActionSpy; }; const apiStub: ApiStub = { config: { use: useSpy }, sendChatAction: sendChatActionSpy, }; vi.mock("grammy", () => ({ Bot: class { api = apiStub; on = onSpy; stop = stopSpy; constructor(public token: string) {} }, InputFile: class {}, webhookCallback: vi.fn(), })); 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 }; }); describe("createTelegramBot", () => { it("installs grammY throttler", () => { createTelegramBot({ token: "tok" }); expect(throttlerSpy).toHaveBeenCalledTimes(1); expect(useSpy).toHaveBeenCalledWith("throttler"); }); it("wraps inbound message with Telegram envelope", async () => { onSpy.mockReset(); const replySpy = replyModule.__replySpy as unknown as ReturnType< typeof vi.fn >; replySpy.mockReset(); createTelegramBot({ token: "tok" }); expect(onSpy).toHaveBeenCalledWith("message", expect.any(Function)); const handler = onSpy.mock.calls[0][1] as ( ctx: Record, ) => Promise; const message = { chat: { id: 1234, type: "private" }, text: "hello world", date: 1736380800, // 2025-01-09T00:00:00Z from: { first_name: "Ada", last_name: "Lovelace", username: "ada_bot", }, }; await handler({ message, me: { username: "clawdis_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); expect(replySpy).toHaveBeenCalledTimes(1); const payload = replySpy.mock.calls[0][0]; expect(payload.Body).toMatch( /^\[Telegram Ada Lovelace \(@ada_bot\) id:1234 2025-01-09 00:00]/, ); expect(payload.Body).toContain("hello world"); }); it("triggers typing cue via onReplyStart", async () => { onSpy.mockReset(); sendChatActionSpy.mockReset(); createTelegramBot({ token: "tok" }); const handler = onSpy.mock.calls[0][1] as ( ctx: Record, ) => Promise; await handler({ message: { chat: { id: 42, type: "private" }, text: "hi" }, me: { username: "clawdis_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); expect(sendChatActionSpy).toHaveBeenCalledWith(42, "typing"); }); });