diff --git a/src/telegram/bot/delivery.resolve-media-retry.test.ts b/src/telegram/bot/delivery.resolve-media-retry.test.ts index e265d265d70..ce8f50abbbe 100644 --- a/src/telegram/bot/delivery.resolve-media-retry.test.ts +++ b/src/telegram/bot/delivery.resolve-media-retry.test.ts @@ -31,7 +31,7 @@ const MAX_MEDIA_BYTES = 10_000_000; const BOT_TOKEN = "tok123"; function makeCtx( - mediaField: "voice" | "audio" | "photo" | "video" | "document" | "animation", + mediaField: "voice" | "audio" | "photo" | "video" | "document" | "animation" | "sticker", getFile: TelegramContext["getFile"], opts?: { file_name?: string }, ): TelegramContext { @@ -79,6 +79,17 @@ function makeCtx( ...(opts?.file_name && { file_name: opts.file_name }), }; } + if (mediaField === "sticker") { + msg.sticker = { + file_id: "stk1", + file_unique_id: "ustk1", + type: "regular", + width: 512, + height: 512, + is_animated: false, + is_video: false, + }; + } return { message: msg as unknown as Message, me: { @@ -243,6 +254,45 @@ describe("resolveMedia getFile retry", () => { // Should retry transient errors. expect(result).not.toBeNull(); }); + + it("retries getFile for stickers on transient failure", async () => { + const getFile = vi + .fn() + .mockRejectedValueOnce(new Error("Network request for 'getFile' failed!")) + .mockResolvedValueOnce({ file_path: "stickers/file_0.webp" }); + + fetchRemoteMedia.mockResolvedValueOnce({ + buffer: Buffer.from("sticker-data"), + contentType: "image/webp", + fileName: "file_0.webp", + }); + saveMediaBuffer.mockResolvedValueOnce({ + path: "/tmp/file_0.webp", + contentType: "image/webp", + }); + + const ctx = makeCtx("sticker", getFile); + const promise = resolveMedia(ctx, MAX_MEDIA_BYTES, BOT_TOKEN); + await flushRetryTimers(); + const result = await promise; + + expect(getFile).toHaveBeenCalledTimes(2); + expect(result).toEqual( + expect.objectContaining({ path: "/tmp/file_0.webp", placeholder: "" }), + ); + }); + + it("returns null for sticker when getFile exhausts retries", async () => { + const getFile = vi.fn().mockRejectedValue(new Error("Network request for 'getFile' failed!")); + + const ctx = makeCtx("sticker", getFile); + const promise = resolveMedia(ctx, MAX_MEDIA_BYTES, BOT_TOKEN); + await flushRetryTimers(); + const result = await promise; + + expect(getFile).toHaveBeenCalledTimes(3); + expect(result).toBeNull(); + }); }); describe("resolveMedia original filename preservation", () => { diff --git a/src/telegram/bot/delivery.resolve-media.ts b/src/telegram/bot/delivery.resolve-media.ts index 50112236c90..e0f8d46abbd 100644 --- a/src/telegram/bot/delivery.resolve-media.ts +++ b/src/telegram/bot/delivery.resolve-media.ts @@ -156,8 +156,8 @@ async function resolveStickerMedia(params: { } try { - const file = await ctx.getFile(); - if (!file.file_path) { + const file = await resolveTelegramFileWithRetry(ctx); + if (!file?.file_path) { logVerbose("telegram: getFile returned no file_path for sticker"); return null; }