fix: make sendMediaGroup injectable for tests + format

This commit is contained in:
Ubuntu 2026-01-28 14:12:23 +00:00
parent 74b867084e
commit aa60fafcb0
3 changed files with 51 additions and 24 deletions

View File

@ -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" });
});
});

View File

@ -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,

View File

@ -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 = {