import { expect, test } from "@playwright/test"; import type { PlaitElement } from "@plait/core"; import { replaceTopicText, searchTopics } from "@/lib/flow-board/topic-search"; const topic = (id: string, leaves: Record[], children: PlaitElement[] = []): PlaitElement => ({ id, type: "mind_child", data: { topic: { children: leaves } }, children, }); test("search includes folded descendants and counts literal matches across sheets", () => { const child = topic("c", [{ text: "C++ C++" }]); const parent = { ...topic("p", [{ text: "折叠分支" }], [child]), isCollapsed: true }; const sheets = [ { id: "a", title: "当前", children: [parent] }, { id: "b", title: "归档", children: [topic("b", [{ text: "c++" }])] }, ]; expect(searchTopics(sheets, "C++").map(item => [item.sheetId, item.id, item.occurrences])).toEqual([["a", "c", 2], ["b", "b", 1]]); expect(searchTopics(sheets, "C++", true)).toHaveLength(1); expect(searchTopics(sheets, "")).toEqual([]); }); test("replacement crosses styled leaves while preserving marks and literal replacement text", () => { const original = topic("a", [{ text: "start de", bold: true }, { text: "sign end", color: "#ff0000" }]); const before = JSON.stringify(original); expect(replaceTopicText(original, "design", "$& 新设计")).toEqual({ children: [ { text: "start $& 新设计", bold: true }, { text: " end", color: "#ff0000" }, ] }); expect(JSON.stringify(original)).toBe(before); }); test("adjacent matches replace once each, including matches spanning three leaves", () => { const original = topic("a", [{ text: "a" }, { text: "ba", italic: true }, { text: "bab" }]); const output = replaceTopicText(original, "ab", "X"); expect(output.children.map((leaf: {text: string}) => leaf.text).join("")).toBe("XXX"); expect(output.children[1].italic).toBe(true); expect(replaceTopicText(original, "", "X")).toEqual(original.data.topic); });