forked from EduCraft/curriculum-project-hub
294d51dbfe
- 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
105 lines
3.0 KiB
TypeScript
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);
|
|
}
|