From 79d7fdce932b3f88cc07173effe80d3ceb61e3d5 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Thu, 19 Mar 2026 06:30:38 -0700 Subject: [PATCH] test(telegram): inject media loader in delivery replies --- extensions/telegram/src/bot/delivery.replies.ts | 13 +++++++++---- extensions/telegram/src/bot/delivery.test.ts | 14 +++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/extensions/telegram/src/bot/delivery.replies.ts b/extensions/telegram/src/bot/delivery.replies.ts index 41dec78c70d..f773b3d1195 100644 --- a/extensions/telegram/src/bot/delivery.replies.ts +++ b/extensions/telegram/src/bot/delivery.replies.ts @@ -1,6 +1,8 @@ -import { type Bot, GrammyError, InputFile } from "grammy"; import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { type Bot, GrammyError, InputFile } from "grammy"; import { fireAndForgetHook } from "openclaw/plugin-sdk/hook-runtime"; import { createInternalHookEvent, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime"; import { @@ -14,9 +16,7 @@ import { buildOutboundMediaLoadOptions } from "openclaw/plugin-sdk/media-runtime import { isGifMedia, kindFromMime } from "openclaw/plugin-sdk/media-runtime"; import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime"; import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; -import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; -import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { loadWebMedia } from "openclaw/plugin-sdk/web-media"; import type { TelegramInlineButtons } from "../button-types.js"; import { splitTelegramCaption } from "../caption.js"; @@ -238,6 +238,7 @@ async function deliverMediaReply(params: { tableMode?: MarkdownTableMode; mediaLocalRoots?: readonly string[]; chunkText: ChunkTextFn; + mediaLoader: typeof loadWebMedia; onVoiceRecording?: () => Promise | void; linkPreview?: boolean; silent?: boolean; @@ -252,7 +253,7 @@ async function deliverMediaReply(params: { let pendingFollowUpText: string | undefined; for (const mediaUrl of params.mediaList) { const isFirstMedia = first; - const media = await loadWebMedia( + const media = await params.mediaLoader( mediaUrl, buildOutboundMediaLoadOptions({ mediaLocalRoots: params.mediaLocalRoots }), ); @@ -569,12 +570,15 @@ export async function deliverReplies(params: { silent?: boolean; /** Optional quote text for Telegram reply_parameters. */ replyQuoteText?: string; + /** Override media loader (tests). */ + mediaLoader?: typeof loadWebMedia; }): Promise<{ delivered: boolean }> { const progress: DeliveryProgress = { hasReplied: false, hasDelivered: false, deliveredCount: 0, }; + const mediaLoader = params.mediaLoader ?? loadWebMedia; const hookRunner = getGlobalHookRunner(); const hasMessageSendingHooks = hookRunner?.hasHooks("message_sending") ?? false; const hasMessageSentHooks = hookRunner?.hasHooks("message_sent") ?? false; @@ -663,6 +667,7 @@ export async function deliverReplies(params: { tableMode: params.tableMode, mediaLocalRoots: params.mediaLocalRoots, chunkText, + mediaLoader, onVoiceRecording: params.onVoiceRecording, linkPreview: params.linkPreview, silent: params.silent, diff --git a/extensions/telegram/src/bot/delivery.test.ts b/extensions/telegram/src/bot/delivery.test.ts index 20642a225ea..d22c97802cd 100644 --- a/extensions/telegram/src/bot/delivery.test.ts +++ b/extensions/telegram/src/bot/delivery.test.ts @@ -1,9 +1,10 @@ import type { Bot } from "grammy"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { RuntimeEnv } from "../../../../src/runtime.js"; -import { deliverReplies } from "./delivery.js"; -const loadWebMedia = vi.fn(); +const { loadWebMedia } = vi.hoisted(() => ({ + loadWebMedia: vi.fn(), +})); const triggerInternalHook = vi.hoisted(() => vi.fn(async () => {})); const messageHookRunner = vi.hoisted(() => ({ hasHooks: vi.fn<(name: string) => boolean>(() => false), @@ -21,12 +22,15 @@ type DeliverWithParams = Omit< DeliverRepliesParams, "chatId" | "token" | "replyToMode" | "textLimit" > & - Partial>; + Partial>; type RuntimeStub = Pick; vi.mock("openclaw/plugin-sdk/web-media", () => ({ loadWebMedia: (...args: unknown[]) => loadWebMedia(...args), })); +vi.mock("openclaw/plugin-sdk/web-media.js", () => ({ + loadWebMedia: (...args: unknown[]) => loadWebMedia(...args), +})); vi.mock("../../../../src/plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: () => messageHookRunner, @@ -42,6 +46,9 @@ vi.mock("../../../../src/hooks/internal-hooks.js", async () => { }; }); +vi.resetModules(); +const { deliverReplies } = await import("./delivery.js"); + vi.mock("grammy", () => ({ InputFile: class { constructor( @@ -70,6 +77,7 @@ async function deliverWith(params: DeliverWithParams) { await deliverReplies({ ...baseDeliveryParams, ...params, + mediaLoader: params.mediaLoader ?? loadWebMedia, }); }