

























1+// Feishu tests cover monitor.message handler plugin behavior.
2+import { describe, expect, it, vi } from "vitest";
3+import type { ClawdbotConfig, PluginRuntime } from "../runtime-api.js";
4+import type { FeishuMessageEvent } from "./event-types.js";
5+import { createFeishuMessageReceiveHandler } from "./monitor.message-handler.js";
6+7+type MessageReceiveHandlerContext = Parameters<typeof createFeishuMessageReceiveHandler>[0];
8+type HandleMessageParams = Parameters<MessageReceiveHandlerContext["handleMessage"]>[0];
9+10+function createTextEvent(params: {
11+messageId: string;
12+senderOpenId: string;
13+senderType: "bot" | "user";
14+}): FeishuMessageEvent {
15+return {
16+sender: {
17+sender_id: { open_id: params.senderOpenId },
18+sender_type: params.senderType,
19+},
20+message: {
21+message_id: params.messageId,
22+chat_id: "oc_chat_1",
23+chat_type: "p2p",
24+message_type: "text",
25+content: JSON.stringify({ text: "hello" }),
26+},
27+};
28+}
29+30+function createHandler() {
31+let onFlush: ((entries: FeishuMessageEvent[]) => Promise<void>) | undefined;
32+const enqueue = vi.fn(async (event: FeishuMessageEvent) => {
33+await onFlush?.([event]);
34+});
35+const channelRuntime = {
36+commands: {
37+isControlCommandMessage: () => false,
38+},
39+debounce: {
40+resolveInboundDebounceMs: () => 0,
41+createInboundDebouncer: vi.fn((params: { onFlush: typeof onFlush }) => {
42+onFlush = params.onFlush;
43+return { enqueue };
44+}),
45+},
46+} as unknown as PluginRuntime["channel"];
47+const handleMessage = vi.fn(async (_params: HandleMessageParams) => {});
48+49+const handler = createFeishuMessageReceiveHandler({
50+cfg: {} as ClawdbotConfig,
51+ channelRuntime,
52+accountId: "default",
53+chatHistories: new Map(),
54+ handleMessage,
55+resolveDebounceText: () => "hello",
56+hasProcessedMessage: vi.fn(async () => false),
57+recordProcessedMessage: vi.fn(async () => true),
58+getBotOpenId: () => "ou_bot",
59+});
60+61+return { handler, handleMessage, enqueue };
62+}
63+64+describe("createFeishuMessageReceiveHandler self-message filtering", () => {
65+it("drops the current bot before debounce and processing claims", async () => {
66+const { handler, handleMessage, enqueue } = createHandler();
67+68+await handler(
69+createTextEvent({
70+messageId: "om_reused",
71+senderOpenId: "ou_bot",
72+senderType: "bot",
73+}),
74+);
75+await handler(
76+createTextEvent({
77+messageId: "om_reused",
78+senderOpenId: "ou_user",
79+senderType: "user",
80+}),
81+);
82+83+expect(enqueue).toHaveBeenCalledTimes(1);
84+expect(handleMessage).toHaveBeenCalledTimes(1);
85+expect(handleMessage.mock.calls[0]?.[0]?.event.sender.sender_id.open_id).toBe("ou_user");
86+});
87+88+it("keeps peer bot and user messages flowing to dispatch", async () => {
89+const { handler, handleMessage, enqueue } = createHandler();
90+91+await handler(
92+createTextEvent({
93+messageId: "om_other_bot",
94+senderOpenId: "ou_other_bot",
95+senderType: "bot",
96+}),
97+);
98+await handler(
99+createTextEvent({
100+messageId: "om_user",
101+senderOpenId: "ou_user",
102+senderType: "user",
103+}),
104+);
105+106+expect(enqueue).toHaveBeenCalledTimes(2);
107+expect(handleMessage).toHaveBeenCalledTimes(2);
108+expect(
109+handleMessage.mock.calls.map(([params]) => params.event.sender.sender_id.open_id),
110+).toEqual(["ou_other_bot", "ou_user"]);
111+});
112+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。