diff --git a/extensions/feishu/src/lifecycle.test-support.ts b/extensions/feishu/src/lifecycle.test-support.ts index fd6b0eb7865..9e42bd1acf2 100644 --- a/extensions/feishu/src/lifecycle.test-support.ts +++ b/extensions/feishu/src/lifecycle.test-support.ts @@ -85,6 +85,27 @@ export function getFeishuLifecycleTestMocks(): FeishuLifecycleTestMocks { return feishuLifecycleTestMocks; } +export function resetFeishuLifecycleTestMocks(): void { + for (const mock of Object.values(feishuLifecycleTestMocks)) { + mock.mockReset(); + } + feishuLifecycleTestMocks.monitorWebSocketMock.mockResolvedValue(undefined); + feishuLifecycleTestMocks.monitorWebhookMock.mockResolvedValue(undefined); + feishuLifecycleTestMocks.createFeishuThreadBindingManagerMock.mockReturnValue({ stop: vi.fn() }); + feishuLifecycleTestMocks.resolveBoundConversationMock.mockReturnValue(null); + feishuLifecycleTestMocks.finalizeInboundContextMock.mockImplementation((ctx) => ctx); + feishuLifecycleTestMocks.getMessageFeishuMock.mockResolvedValue(null); + feishuLifecycleTestMocks.listFeishuThreadMessagesMock.mockResolvedValue([]); + feishuLifecycleTestMocks.sendMessageFeishuMock.mockResolvedValue({ + messageId: "om_sent", + chatId: "chat_default", + }); + feishuLifecycleTestMocks.sendCardFeishuMock.mockResolvedValue({ + messageId: "om_card", + chatId: "chat_default", + }); +} + const { createEventDispatcherMock, monitorWebSocketMock, diff --git a/extensions/feishu/src/monitor.account.ts b/extensions/feishu/src/monitor.account.ts index 69ee33979f2..b636e89d24d 100644 --- a/extensions/feishu/src/monitor.account.ts +++ b/extensions/feishu/src/monitor.account.ts @@ -615,6 +615,7 @@ export type MonitorSingleAccountParams = { runtime?: RuntimeEnv; abortSignal?: AbortSignal; botOpenIdSource?: BotOpenIdSource; + fireAndForget?: boolean; }; export async function monitorSingleAccount(params: MonitorSingleAccountParams): Promise { @@ -658,7 +659,7 @@ export async function monitorSingleAccount(params: MonitorSingleAccountParams): accountId, runtime, chatHistories, - fireAndForget: true, + fireAndForget: params.fireAndForget ?? true, }); if (connectionMode === "webhook") { diff --git a/extensions/feishu/src/monitor.acp-init-failure.lifecycle.test.ts b/extensions/feishu/src/monitor.acp-init-failure.lifecycle.test-support.ts similarity index 97% rename from extensions/feishu/src/monitor.acp-init-failure.lifecycle.test.ts rename to extensions/feishu/src/monitor.acp-init-failure.lifecycle.test-support.ts index 246c31c4f5a..7a9bd1f7d61 100644 --- a/extensions/feishu/src/monitor.acp-init-failure.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.acp-init-failure.lifecycle.test-support.ts @@ -2,7 +2,10 @@ import "./lifecycle.test-support.js"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import type { ClawdbotConfig } from "../runtime-api.js"; -import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; +import { + getFeishuLifecycleTestMocks, + resetFeishuLifecycleTestMocks, +} from "./lifecycle.test-support.js"; import { createFeishuLifecycleFixture, createFeishuTextMessageEvent, @@ -73,7 +76,7 @@ async function setupLifecycleMonitor() { describe("Feishu ACP-init failure lifecycle", () => { beforeEach(() => { vi.useRealTimers(); - vi.clearAllMocks(); + resetFeishuLifecycleTestMocks(); _handlers = {}; lastRuntime = null; setFeishuLifecycleStateDir("openclaw-feishu-acp-failure"); diff --git a/extensions/feishu/src/monitor.bot-menu.lifecycle.test.ts b/extensions/feishu/src/monitor.bot-menu.lifecycle.test-support.ts similarity index 97% rename from extensions/feishu/src/monitor.bot-menu.lifecycle.test.ts rename to extensions/feishu/src/monitor.bot-menu.lifecycle.test-support.ts index 5f55a8737bd..22b03534496 100644 --- a/extensions/feishu/src/monitor.bot-menu.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.bot-menu.lifecycle.test-support.ts @@ -1,7 +1,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import "./lifecycle.test-support.js"; -import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; +import { + getFeishuLifecycleTestMocks, + resetFeishuLifecycleTestMocks, +} from "./lifecycle.test-support.js"; import { createFeishuLifecycleConfig, createFeishuLifecycleReplyDispatcher, @@ -85,7 +88,7 @@ async function setupLifecycleMonitor() { describe("Feishu bot-menu lifecycle", () => { beforeEach(() => { vi.useRealTimers(); - vi.clearAllMocks(); + resetFeishuLifecycleTestMocks(); _handlers = {}; lastRuntime = null; setFeishuLifecycleStateDir("openclaw-feishu-bot-menu"); diff --git a/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts b/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test-support.ts similarity index 98% rename from extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts rename to extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test-support.ts index 4f1159ce659..bd3afc357c2 100644 --- a/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.broadcast.reply-once.lifecycle.test-support.ts @@ -3,7 +3,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createNonExitingRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js"; import { FeishuConfigSchema } from "./config-schema.js"; -import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; +import { + getFeishuLifecycleTestMocks, + resetFeishuLifecycleTestMocks, +} from "./lifecycle.test-support.js"; import { createFeishuTextMessageEvent, createFeishuLifecycleReplyDispatcher, @@ -132,7 +135,7 @@ async function setupLifecycleMonitor(accountId: "account-A" | "account-B") { describe("Feishu broadcast reply-once lifecycle", () => { beforeEach(() => { vi.useRealTimers(); - vi.clearAllMocks(); + resetFeishuLifecycleTestMocks(); handlersByAccount = new Map(); runtimesByAccount = new Map(); setFeishuLifecycleStateDir("openclaw-feishu-broadcast"); diff --git a/extensions/feishu/src/monitor.card-action.lifecycle.test.ts b/extensions/feishu/src/monitor.card-action.lifecycle.test-support.ts similarity index 98% rename from extensions/feishu/src/monitor.card-action.lifecycle.test.ts rename to extensions/feishu/src/monitor.card-action.lifecycle.test-support.ts index 2d0c9be31c1..b7102bd2447 100644 --- a/extensions/feishu/src/monitor.card-action.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.card-action.lifecycle.test-support.ts @@ -3,7 +3,10 @@ import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import "./lifecycle.test-support.js"; import { resetProcessedFeishuCardActionTokensForTests } from "./card-action.js"; import { createFeishuCardInteractionEnvelope } from "./card-interaction.js"; -import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; +import { + getFeishuLifecycleTestMocks, + resetFeishuLifecycleTestMocks, +} from "./lifecycle.test-support.js"; import { createFeishuLifecycleConfig, createFeishuLifecycleReplyDispatcher, @@ -112,7 +115,7 @@ async function setupLifecycleMonitor() { describe("Feishu card-action lifecycle", () => { beforeEach(() => { vi.useRealTimers(); - vi.clearAllMocks(); + resetFeishuLifecycleTestMocks(); _handlers = {}; lastRuntime = null; resetProcessedFeishuCardActionTokensForTests(); diff --git a/extensions/feishu/src/monitor.lifecycle.test.ts b/extensions/feishu/src/monitor.lifecycle.test.ts new file mode 100644 index 00000000000..64044316c45 --- /dev/null +++ b/extensions/feishu/src/monitor.lifecycle.test.ts @@ -0,0 +1,6 @@ +import "./monitor.acp-init-failure.lifecycle.test-support.js"; +import "./monitor.bot-menu.lifecycle.test-support.js"; +import "./monitor.broadcast.reply-once.lifecycle.test-support.js"; +import "./monitor.card-action.lifecycle.test-support.js"; +import "./monitor.reaction.lifecycle.test-support.js"; +import "./monitor.reply-once.lifecycle.test-support.js"; diff --git a/extensions/feishu/src/monitor.reaction.lifecycle.test.ts b/extensions/feishu/src/monitor.reaction.lifecycle.test-support.ts similarity index 100% rename from extensions/feishu/src/monitor.reaction.lifecycle.test.ts rename to extensions/feishu/src/monitor.reaction.lifecycle.test-support.ts diff --git a/extensions/feishu/src/monitor.reply-once.lifecycle.test.ts b/extensions/feishu/src/monitor.reply-once.lifecycle.test-support.ts similarity index 97% rename from extensions/feishu/src/monitor.reply-once.lifecycle.test.ts rename to extensions/feishu/src/monitor.reply-once.lifecycle.test-support.ts index 48797d62950..a4c326b4173 100644 --- a/extensions/feishu/src/monitor.reply-once.lifecycle.test.ts +++ b/extensions/feishu/src/monitor.reply-once.lifecycle.test-support.ts @@ -1,7 +1,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import "./lifecycle.test-support.js"; -import { getFeishuLifecycleTestMocks } from "./lifecycle.test-support.js"; +import { + getFeishuLifecycleTestMocks, + resetFeishuLifecycleTestMocks, +} from "./lifecycle.test-support.js"; import { createFeishuLifecycleConfig, createFeishuLifecycleReplyDispatcher, @@ -62,7 +65,8 @@ async function setupLifecycleMonitor() { describe("Feishu reply-once lifecycle", () => { beforeEach(() => { vi.useRealTimers(); - vi.clearAllMocks(); + resetFeishuLifecycleTestMocks(); + handleMessageMock.mockReset(); lastRuntime = null; setFeishuLifecycleStateDir("openclaw-feishu-lifecycle"); diff --git a/extensions/feishu/src/test-support/lifecycle-test-support.ts b/extensions/feishu/src/test-support/lifecycle-test-support.ts index 911df89c8d8..d4893192eac 100644 --- a/extensions/feishu/src/test-support/lifecycle-test-support.ts +++ b/extensions/feishu/src/test-support/lifecycle-test-support.ts @@ -452,6 +452,7 @@ export async function setupFeishuLifecycleHandler(params: { account: params.account, runtime: params.runtime, botOpenIdSource: FEISHU_PREFETCHED_BOT_OPEN_ID_SOURCE, + fireAndForget: false, }); const handlers: Record Promise> = {};