From be93d44275263b205a6b405ebdfd49756fdd9c6f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 31 Jul 2026 11:46:34 -0700 Subject: [PATCH] fix(telegram): preserve explicit empty media captions (#116984) Co-authored-by: Peter Steinberger --- .../telegram/src/action-runtime.test.ts | 13 +++-- extensions/telegram/src/action-runtime.ts | 3 +- .../telegram/src/send-caption-editing.test.ts | 49 +++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 extensions/telegram/src/send-caption-editing.test.ts diff --git a/extensions/telegram/src/action-runtime.test.ts b/extensions/telegram/src/action-runtime.test.ts index fbdef4e9e1cb..e207863054a7 100644 --- a/extensions/telegram/src/action-runtime.test.ts +++ b/extensions/telegram/src/action-runtime.test.ts @@ -1854,21 +1854,26 @@ describe("handleTelegramAction", () => { expect(requireRecord(call[3], "reply markup edit options").token).toBe("tok"); }); - it("uses Telegram caption edits when editMessage receives a caption", async () => { + it.each([ + { description: "non-empty", caption: "Updated caption", richMessages: false }, + { description: "empty", caption: "", richMessages: false }, + { description: "non-empty rich", caption: "Updated caption", richMessages: true }, + { description: "empty rich", caption: "", richMessages: true }, + ])("uses Telegram caption edits for $description captions", async ({ caption, richMessages }) => { await handleTelegramAction( { action: "editMessage", chatId: "123456", messageId: 321, - caption: "Updated caption", + caption, }, - telegramConfig(), + telegramConfig(richMessages ? { richMessages: true } : undefined), ); const call = mockCall(editMessageTelegram, 0, "caption edit"); expect(call[0]).toBe("123456"); expect(call[1]).toBe(321); - expect(call[2]).toBe("Updated caption"); + expect(call[2]).toBe(caption); expect(requireRecord(call[3], "caption edit options").editMode).toBe("caption"); }); diff --git a/extensions/telegram/src/action-runtime.ts b/extensions/telegram/src/action-runtime.ts index 36325bef9612..7c38358291f4 100644 --- a/extensions/telegram/src/action-runtime.ts +++ b/extensions/telegram/src/action-runtime.ts @@ -739,7 +739,8 @@ export async function handleTelegramAction( const content = readStringParam(params, "content", { allowEmpty: false }) ?? readStringParam(params, "message", { allowEmpty: false }); - const caption = readStringParam(params, "caption", { allowEmpty: false }); + // Telegram treats an explicit empty caption as a request to remove it. + const caption = readStringParam(params, "caption", { allowEmpty: true }); const buttons = resolveTelegramButtonsFromParams(params, undefined, { allowWebAppButtons: resolveTelegramTargetChatType(chatId ?? "") === "direct", }); diff --git a/extensions/telegram/src/send-caption-editing.test.ts b/extensions/telegram/src/send-caption-editing.test.ts new file mode 100644 index 000000000000..efa02385094e --- /dev/null +++ b/extensions/telegram/src/send-caption-editing.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, it } from "vitest"; +import { + getTelegramSendTestMocks, + importTelegramSendModule, + installTelegramSendTestHooks, +} from "./send.test-harness.js"; + +installTelegramSendTestHooks(); + +const { botApi, loadConfig } = getTelegramSendTestMocks(); +const { editMessageTelegram } = await importTelegramSendModule(); + +describe("Telegram caption edits", () => { + it.each([ + { + description: "non-empty plain", + caption: "Updated **caption**", + expected: "Updated caption", + richMessages: false, + }, + { description: "empty plain", caption: "", expected: "", richMessages: false }, + { + description: "non-empty rich", + caption: "Updated **caption**", + expected: "Updated caption", + richMessages: true, + }, + { description: "empty rich", caption: "", expected: "", richMessages: true }, + ])( + "preserves $description captions at the Bot API boundary", + async ({ caption, expected, richMessages }) => { + loadConfig.mockReturnValue({ channels: { telegram: { botToken: "tok", richMessages } } }); + botApi.editMessageCaption.mockResolvedValue({ message_id: 321, chat: { id: "123456" } }); + + await editMessageTelegram("123456", 321, caption, { + cfg: { channels: { telegram: { botToken: "tok", richMessages } } }, + token: "tok", + accountId: "default", + editMode: "caption", + }); + + expect(botApi.editMessageText).not.toHaveBeenCalled(); + expect(botApi.editMessageCaption).toHaveBeenCalledWith("123456", 321, { + caption: expected, + parse_mode: "HTML", + }); + }, + ); +});