diff --git a/extensions/feishu/src/bot.broadcast.test.ts b/extensions/feishu/src/bot.broadcast.test.ts index c3ffb0a8b90..8f718ad8e21 100644 --- a/extensions/feishu/src/bot.broadcast.test.ts +++ b/extensions/feishu/src/bot.broadcast.test.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import { createPluginRuntimeMock } from "../../../test/helpers/extensions/plugin-runtime-mock.js"; import { createRuntimeEnv } from "../../../test/helpers/extensions/runtime-env.js"; import type { ClawdbotConfig, PluginRuntime } from "../runtime-api.js"; import type { FeishuMessageEvent } from "./bot.js"; @@ -73,7 +74,7 @@ describe("broadcast dispatch", () => { }, }, }, - } as unknown as ClawdbotConfig; + }; } function createBroadcastEvent(options: { @@ -122,38 +123,40 @@ describe("broadcast dispatch", () => { }, }, }); - setFeishuRuntime({ - system: { - enqueueSystemEvent: vi.fn(), - }, - channel: { - routing: { - resolveAgentRoute: mockResolveAgentRoute, + setFeishuRuntime( + createPluginRuntimeMock({ + system: { + enqueueSystemEvent: vi.fn(), }, - reply: { - resolveEnvelopeFormatOptions: vi.fn(() => ({ template: "channel+name+time" })), - formatAgentEnvelope: vi.fn((params: { body: string }) => params.body), - finalizeInboundContext: mockFinalizeInboundContext, - dispatchReplyFromConfig: mockDispatchReplyFromConfig, - withReplyDispatcher: mockWithReplyDispatcher, - }, - commands: { - shouldComputeCommandAuthorized: mockShouldComputeCommandAuthorized, - resolveCommandAuthorizedFromAuthorizers: vi.fn(() => false), + channel: { + routing: { + resolveAgentRoute: (params) => mockResolveAgentRoute(params), + }, + reply: { + resolveEnvelopeFormatOptions: vi.fn(() => ({ template: "channel+name+time" })), + formatAgentEnvelope: vi.fn((params: { body: string }) => params.body), + finalizeInboundContext: mockFinalizeInboundContext, + dispatchReplyFromConfig: mockDispatchReplyFromConfig, + withReplyDispatcher: mockWithReplyDispatcher, + }, + commands: { + shouldComputeCommandAuthorized: mockShouldComputeCommandAuthorized, + resolveCommandAuthorizedFromAuthorizers: vi.fn(() => false), + }, + media: { + saveMediaBuffer: mockSaveMediaBuffer, + }, + pairing: { + readAllowFromStore: vi.fn().mockResolvedValue([]), + upsertPairingRequest: vi.fn().mockResolvedValue({ code: "ABCDEFGH", created: false }), + buildPairingReply: vi.fn(() => "Pairing response"), + }, }, media: { - saveMediaBuffer: mockSaveMediaBuffer, + detectMime: vi.fn(async () => "application/octet-stream"), }, - pairing: { - readAllowFromStore: vi.fn().mockResolvedValue([]), - upsertPairingRequest: vi.fn().mockResolvedValue({ code: "ABCDEFGH", created: false }), - buildPairingReply: vi.fn(() => "Pairing response"), - }, - }, - media: { - detectMime: vi.fn(async () => "application/octet-stream"), - }, - } as unknown as PluginRuntime); + }), + ); }); it("dispatches to all broadcast agents when bot is mentioned", async () => { @@ -229,7 +232,7 @@ describe("broadcast dispatch", () => { }, }, }, - } as ClawdbotConfig; + }; const event: FeishuMessageEvent = { sender: { sender_id: { open_id: "ou-sender" } }, @@ -270,7 +273,7 @@ describe("broadcast dispatch", () => { }, }, }, - } as unknown as ClawdbotConfig; + }; const event: FeishuMessageEvent = { sender: { sender_id: { open_id: "ou-sender" } }, @@ -316,7 +319,7 @@ describe("broadcast dispatch", () => { }, }, }, - } as unknown as ClawdbotConfig; + }; const event: FeishuMessageEvent = { sender: { sender_id: { open_id: "ou-sender" } }, diff --git a/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts b/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts index cf20cf7a5e2..eeae4a80412 100644 --- a/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts @@ -13,7 +13,7 @@ import { import { createNonExitingRuntimeEnv } from "../../../test/helpers/extensions/runtime-env.js"; import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js"; import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; -import type { ResolvedFeishuAccount } from "./types.js"; +import type { FeishuConfig, ResolvedFeishuAccount } from "./types.js"; const { createEventDispatcherMock, @@ -88,6 +88,18 @@ function createLifecycleConfig(): ClawdbotConfig { } function createLifecycleAccount(accountId: "account-A" | "account-B"): ResolvedFeishuAccount { + const config: FeishuConfig = { + enabled: true, + connectionMode: "websocket", + groupPolicy: "open", + requireMention: false, + resolveSenderNames: false, + groups: { + oc_broadcast_group: { + requireMention: false, + }, + }, + }; return { accountId, selectionSource: "explicit", @@ -96,19 +108,8 @@ function createLifecycleAccount(accountId: "account-A" | "account-B"): ResolvedF appId: accountId === "account-A" ? "cli_a" : "cli_b", appSecret: accountId === "account-A" ? "secret_a" : "secret_b", // pragma: allowlist secret domain: "feishu", - config: { - enabled: true, - connectionMode: "websocket", - groupPolicy: "open", - requireMention: false, - resolveSenderNames: false, - groups: { - oc_broadcast_group: { - requireMention: false, - }, - }, - }, - } as unknown as ResolvedFeishuAccount; + config, + }; } async function setupLifecycleMonitor(accountId: "account-A" | "account-B") { diff --git a/extensions/feishu/src/reply-dispatcher.test.ts b/extensions/feishu/src/reply-dispatcher.test.ts index 656ee8b3928..8d40e18413c 100644 --- a/extensions/feishu/src/reply-dispatcher.test.ts +++ b/extensions/feishu/src/reply-dispatcher.test.ts @@ -1,5 +1,13 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +type StreamingSessionStub = { + active: boolean; + start: ReturnType; + update: ReturnType; + close: ReturnType; + isActive: ReturnType; +}; + const resolveFeishuAccountMock = vi.hoisted(() => vi.fn()); const getFeishuRuntimeMock = vi.hoisted(() => vi.fn()); const sendMessageFeishuMock = vi.hoisted(() => vi.fn()); @@ -11,7 +19,7 @@ const resolveReceiveIdTypeMock = vi.hoisted(() => vi.fn()); const createReplyDispatcherWithTypingMock = vi.hoisted(() => vi.fn()); const addTypingIndicatorMock = vi.hoisted(() => vi.fn(async () => ({ messageId: "om_msg" }))); const removeTypingIndicatorMock = vi.hoisted(() => vi.fn(async () => {})); -const streamingInstances = vi.hoisted(() => [] as any[]); +const streamingInstances = vi.hoisted((): StreamingSessionStub[] => []); vi.mock("./accounts.js", () => ({ resolveFeishuAccount: resolveFeishuAccountMock, @@ -667,16 +675,16 @@ describe("createFeishuReplyDispatcher streaming behavior", () => { let shouldFailStart = true; // Intercept streaming instance creation to make first start() reject - const origPush = streamingInstances.push; - streamingInstances.push = function (this: any[], ...args: any[]) { + const origPush = streamingInstances.push.bind(streamingInstances); + streamingInstances.push = (...args: StreamingSessionStub[]) => { if (shouldFailStart) { args[0].start = vi .fn() .mockRejectedValue(new Error("Create card request failed with HTTP 400")); shouldFailStart = false; } - return origPush.apply(this, args); - } as any; + return origPush(...args); + }; try { createFeishuReplyDispatcher({