From aa60fafcb048c2bd7b2579d30e7bf7c2d4c28b69 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 28 Jan 2026 14:12:23 +0000 Subject: [PATCH] fix: make sendMediaGroup injectable for tests + format --- .../plugins/outbound/telegram.test.ts | 64 +++++++++++++------ src/channels/plugins/outbound/telegram.ts | 3 +- src/telegram/send.ts | 8 +-- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/channels/plugins/outbound/telegram.test.ts b/src/channels/plugins/outbound/telegram.test.ts index 538cf4ff9..e6444310c 100644 --- a/src/channels/plugins/outbound/telegram.test.ts +++ b/src/channels/plugins/outbound/telegram.test.ts @@ -34,11 +34,9 @@ describe("telegramOutbound.sendPayload", () => { expect(result).toEqual({ channel: "telegram", messageId: "m1", chatId: "c1" }); }); - it("sends media payloads and attaches buttons only to first", async () => { - const sendTelegram = vi - .fn() - .mockResolvedValueOnce({ messageId: "m1", chatId: "c1" }) - .mockResolvedValueOnce({ messageId: "m2", chatId: "c1" }); + it("sends media payloads as album and buttons in follow-up", async () => { + const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m-btn", chatId: "c1" }); + const sendMediaGroup = vi.fn().mockResolvedValue({ messageIds: ["m1", "m2"], chatId: "c1" }); const result = await telegramOutbound.sendPayload?.({ cfg: {} as MoltbotConfig, @@ -53,12 +51,50 @@ describe("telegramOutbound.sendPayload", () => { }, }, }, + deps: { sendTelegram, sendMediaGroup }, + }); + + // Media group is sent with both URLs + expect(sendMediaGroup).toHaveBeenCalledTimes(1); + expect(sendMediaGroup).toHaveBeenCalledWith( + "telegram:123", + ["https://example.com/a.png", "https://example.com/b.png"], + "Caption", + expect.objectContaining({ accountId: undefined }), + ); + // Buttons sent in follow-up message (media groups don't support buttons) + expect(sendTelegram).toHaveBeenCalledTimes(1); + expect(sendTelegram).toHaveBeenCalledWith( + "telegram:123", + "", + expect.objectContaining({ + buttons: [[{ text: "Go", callback_data: "/go" }]], + }), + ); + expect(result).toEqual({ channel: "telegram", messageId: "m1", chatId: "c1" }); + }); + + it("sends single media with buttons directly", async () => { + const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" }); + + const result = await telegramOutbound.sendPayload?.({ + cfg: {} as MoltbotConfig, + to: "telegram:123", + text: "ignored", + payload: { + text: "Caption", + mediaUrls: ["https://example.com/a.png"], + channelData: { + telegram: { + buttons: [[{ text: "Go", callback_data: "/go" }]], + }, + }, + }, deps: { sendTelegram }, }); - expect(sendTelegram).toHaveBeenCalledTimes(2); - expect(sendTelegram).toHaveBeenNthCalledWith( - 1, + expect(sendTelegram).toHaveBeenCalledTimes(1); + expect(sendTelegram).toHaveBeenCalledWith( "telegram:123", "Caption", expect.objectContaining({ @@ -66,16 +102,6 @@ describe("telegramOutbound.sendPayload", () => { buttons: [[{ text: "Go", callback_data: "/go" }]], }), ); - const secondOpts = sendTelegram.mock.calls[1]?.[2] as { buttons?: unknown } | undefined; - expect(sendTelegram).toHaveBeenNthCalledWith( - 2, - "telegram:123", - "", - expect.objectContaining({ - mediaUrl: "https://example.com/b.png", - }), - ); - expect(secondOpts?.buttons).toBeUndefined(); - expect(result).toEqual({ channel: "telegram", messageId: "m2", chatId: "c1" }); + expect(result).toEqual({ channel: "telegram", messageId: "m1", chatId: "c1" }); }); }); diff --git a/src/channels/plugins/outbound/telegram.ts b/src/channels/plugins/outbound/telegram.ts index 1863c9128..5593a5feb 100644 --- a/src/channels/plugins/outbound/telegram.ts +++ b/src/channels/plugins/outbound/telegram.ts @@ -85,7 +85,8 @@ export const telegramOutbound: ChannelOutboundAdapter = { // Use media group (album) for 2-10 images - sends as a single album if (mediaUrls.length >= 2 && mediaUrls.length <= 10) { - const groupResult = await sendMediaGroupTelegram(to, mediaUrls, text, { + const sendGroup = deps?.sendMediaGroup ?? sendMediaGroupTelegram; + const groupResult = await sendGroup(to, mediaUrls, text, { messageThreadId, replyToMessageId, accountId: accountId ?? undefined, diff --git a/src/telegram/send.ts b/src/telegram/send.ts index 769492425..ee4935f21 100644 --- a/src/telegram/send.ts +++ b/src/telegram/send.ts @@ -745,7 +745,9 @@ export async function sendMediaGroupTelegram( // Media groups only support photos and videos if (kind !== "image" && kind !== "video" && !isGif) { - throw new Error(`Media group only supports photos and videos. Got: ${kind} for ${trimmedUrl}`); + throw new Error( + `Media group only supports photos and videos. Got: ${kind} for ${trimmedUrl}`, + ); } const fileName = media.fileName ?? inferFilename(kind) ?? "file"; @@ -765,9 +767,7 @@ export async function sendMediaGroupTelegram( const mediaGroup = mediaItems.map((item, index) => ({ type: item.type, media: item.media, - ...(index === 0 && htmlCaption - ? { caption: htmlCaption, parse_mode: "HTML" as const } - : {}), + ...(index === 0 && htmlCaption ? { caption: htmlCaption, parse_mode: "HTML" as const } : {}), })); const groupParams = {