




























11// Feishu tests cover send plugin behavior.
22import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
33import type { ClawdbotConfig } from "../runtime-api.js";
4-import { buildMarkdownCard } from "./send.js";
4+import { buildFeishuPostMessagePayload, buildMarkdownCard } from "./send.js";
5566const {
77 mockConvertMarkdownTables,
@@ -64,6 +64,49 @@ let listFeishuThreadMessages: typeof import("./send.js").listFeishuThreadMessage
6464let resolveFeishuCardTemplate: typeof import("./send.js").resolveFeishuCardTemplate;
6565let sendMessageFeishu: typeof import("./send.js").sendMessageFeishu;
666667+describe("buildFeishuPostMessagePayload", () => {
68+it("prepends structured mention targets as native post at elements", () => {
69+const payload = buildFeishuPostMessagePayload({
70+messageText: "hello **world**",
71+mentions: [
72+{ openId: "ou_alice", name: "Alice", key: "@_user_1" },
73+{ openId: " ou_bob ", name: " Bob ", key: "@_user_2" },
74+],
75+});
76+77+expect(payload.msgType).toBe("post");
78+expect(JSON.parse(payload.content)).toEqual({
79+zh_cn: {
80+content: [
81+[
82+{ tag: "at", user_id: "ou_alice", user_name: "Alice" },
83+{ tag: "at", user_id: "ou_bob", user_name: "Bob" },
84+{ tag: "md", text: "hello **world**" },
85+],
86+],
87+},
88+});
89+});
90+91+it("leaves body-supplied at tags literal in the markdown element", () => {
92+const payload = buildFeishuPostMessagePayload({
93+messageText: 'please keep <at user_id="ou_body">Body User</at> literal',
94+mentions: [{ openId: "ou_target", name: "Target User", key: "@_user_1" }],
95+});
96+97+expect(JSON.parse(payload.content)).toEqual({
98+zh_cn: {
99+content: [
100+[
101+{ tag: "at", user_id: "ou_target", user_name: "Target User" },
102+{ tag: "md", text: 'please keep <at user_id="ou_body">Body User</at> literal' },
103+],
104+],
105+},
106+});
107+});
108+});
109+67110describe("getMessageFeishu", () => {
68111beforeAll(async () => {
69112({
@@ -173,6 +216,51 @@ describe("getMessageFeishu", () => {
173216});
174217});
175218219+it("sends automatic mentions as native post elements without rewriting body text", async () => {
220+const create = vi.fn().mockResolvedValue({ code: 0, data: { message_id: "om_mentions" } });
221+mockCreateFeishuClient.mockReturnValue({
222+im: {
223+message: {
224+ create,
225+reply: vi.fn(),
226+get: mockClientGet,
227+list: mockClientList,
228+patch: mockClientPatch,
229+},
230+},
231+});
232+233+const result = await sendMessageFeishu({
234+cfg: {} as ClawdbotConfig,
235+to: "oc_send",
236+text: 'body <at user_id="ou_body">Body User</at>',
237+mentions: [{ openId: "ou_target", name: "Target User", key: "@_user_1" }],
238+});
239+240+expect(mockConvertMarkdownTables).toHaveBeenCalledWith(
241+'body <at user_id="ou_body">Body User</at>',
242+"preserve",
243+);
244+expect(create).toHaveBeenCalledWith({
245+params: { receive_id_type: "chat_id" },
246+data: {
247+receive_id: "oc_send",
248+msg_type: "post",
249+content: JSON.stringify({
250+zh_cn: {
251+content: [
252+[
253+{ tag: "at", user_id: "ou_target", user_name: "Target User" },
254+{ tag: "md", text: 'body <at user_id="ou_body">Body User</at>' },
255+],
256+],
257+},
258+}),
259+},
260+});
261+expect(result).toEqual({ messageId: "om_mentions", chatId: "oc_send" });
262+});
263+176264it("extracts text content from interactive card elements", async () => {
177265mockClientGet.mockResolvedValueOnce({
178266code: 0,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。