Files
hongjr03 294d51dbfe feat: parse inbound post (rich text) messages
- parsePostMessage: full Feishu post payload parser with locale fallback,
  supports text/a/at/img/media/file/code_block/br/hr/emotion elements
- Trigger accepts post messages, extracts text + downloads attachments
- Post messages with attachments bypass batching, text-only posts batch
- Add unit tests (10) for all element types and edge cases
2026-07-08 17:05:51 +08:00

105 lines
3.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parsePostMessage } from "../../src/feishu/client.js";
describe("parsePostMessage", () => {
it("parses a simple text post", () => {
const result = parsePostMessage(postContent({
zh_cn: { content: [[{ tag: "text", text: "Hello" }]] },
}));
expect(result).toEqual({ text: "Hello", imageKeys: [], fileKeys: [] });
});
it("prepends a post title as a markdown header", () => {
const result = parsePostMessage(postContent({
zh_cn: { title: "Lesson Notes", content: [[{ tag: "text", text: "Hello" }]] },
}));
expect(result.text).toBe("# Lesson Notes\n\nHello");
});
it("converts links to markdown", () => {
const result = parsePostMessage(postContent({
zh_cn: {
content: [[
{ tag: "text", text: "Read " },
{ tag: "a", text: "docs", href: "https://example.com" },
]],
},
}));
expect(result.text).toBe("Read [docs](https://example.com)");
});
it("converts mentions to readable @names", () => {
const result = parsePostMessage(postContent({
zh_cn: { content: [[{ tag: "at", user_id: "@_user_1", user_name: "John" }]] },
}));
expect(result.text).toBe("@John");
});
it("converts code blocks to fenced markdown", () => {
const result = parsePostMessage(postContent({
zh_cn: { content: [[{ tag: "code_block", language: "ts", text: "const x = 1;" }]] },
}));
expect(result.text).toBe("```ts\nconst x = 1;\n```");
});
it("collects image keys and inserts an image placeholder", () => {
const result = parsePostMessage(postContent({
zh_cn: { content: [[{ tag: "img", image_key: "img_key_here" }]] },
}));
expect(result).toEqual({ text: "[Image]", imageKeys: ["img_key_here"], fileKeys: [] });
});
it("collects file keys and inserts an attachment placeholder", () => {
const result = parsePostMessage(postContent({
zh_cn: { content: [[{ tag: "file", file_key: "file_key_here", file_name: "worksheet.pdf" }]] },
}));
expect(result).toEqual({
text: "[Attachment: worksheet.pdf]",
imageKeys: [],
fileKeys: ["file_key_here"],
});
});
it("falls back to en_us when zh_cn is missing", () => {
const result = parsePostMessage(postContent({
en_us: { content: [[{ tag: "text", text: "Hello from English" }]] },
}));
expect(result.text).toBe("Hello from English");
});
it("unwraps content nested under a post key", () => {
const result = parsePostMessage(postContent({
post: {
zh_cn: { content: [[{ tag: "text", text: "Wrapped" }]] },
},
}));
expect(result.text).toBe("Wrapped");
});
it("joins multiple rows with newlines", () => {
const result = parsePostMessage(postContent({
zh_cn: {
content: [
[{ tag: "text", text: "First row" }],
[{ tag: "text", text: "Second row" }],
],
},
}));
expect(result.text).toBe("First row\nSecond row");
});
});
function postContent(value: unknown): string {
return JSON.stringify(value);
}