返回 DeepSeek-Reasonix
project-tree-pinned-shell-runtime.test.ts
根目录 / desktop / frontend / src / __tests__ / project-tree-pinned-shell-runtime.test.ts
1 import { mergeProjectTopicPage, projectTreeShellChildren, splitPinnedProjectTree } from "../components/ProjectTree";
2
3 type Equal = (actual: unknown, expected: unknown, label: string) => void;
4
5 export function runProjectTreePinnedShellRuntimeTests(eq: Equal, projectTreeSource: string) {
6 eq(
7 splitPinnedProjectTree(
8 [{
9 key: "global_folder",
10 kind: "global_folder",
11 label: "Global",
12 children: [
13 { key: "global_topic_duplicate", kind: "global_topic", label: "Pinned", topicId: "duplicate", pinned: true },
14 { key: "global_topic_duplicate_page", kind: "global_topic", label: "Pinned", topicId: "duplicate" },
15 // A live runtime projection can carry the same topic as a session row
16 // while the catalog still serves the original topic shell.
17 { key: "global_session_duplicate", kind: "global_session", label: "Pinned", topicId: "duplicate" },
18 ],
19 }],
20 "updated",
21 false,
22 ),
23 {
24 pinned: [
25 { key: "global_topic_duplicate", kind: "global_topic", label: "Pinned", topicId: "duplicate", pinned: true },
26 ],
27 projects: [{ key: "global_folder", kind: "global_folder", label: "Global", children: [] }],
28 },
29 "pinned conversations do not repeat as runtime session rows in their source folder",
30 );
31
32 eq(
33 splitPinnedProjectTree(
34 [
35 {
36 key: "project_a",
37 kind: "project",
38 label: "A",
39 root: "/repo/a",
40 children: [{ key: "topic_a", kind: "topic", label: "Pinned A", root: "/repo/a", topicId: "shared", pinned: true }],
41 },
42 {
43 key: "project_b",
44 kind: "project",
45 label: "B",
46 root: "/repo/b",
47 children: [{ key: "topic_b", kind: "topic", label: "Regular B", root: "/repo/b", topicId: "shared" }],
48 },
49 ],
50 "updated",
51 false,
52 ).projects.map((project) => asTopicKeys(project.children)),
53 [[], ["topic_b"]],
54 "a pinned topic does not hide the same topic ID from another project",
55 );
56
57 eq(
58 mergeProjectTopicPage(
59 [
60 { key: "topic-off-page-pin", kind: "topic", label: "Pinned", topicId: "pin", pinned: true },
61 { key: "topic-stale", kind: "topic", label: "Stale", topicId: "stale" },
62 ],
63 [{ key: "topic-page", kind: "topic", label: "First page", topicId: "page" }],
64 false,
65 ).map((node) => node.key),
66 ["topic-page", "topic-off-page-pin"],
67 "a bounded first page keeps pinned shells that fall beyond the page limit",
68 );
69
70 eq(
71 projectTreeShellChildren(undefined, [
72 { key: "topic_pin", kind: "topic", label: "Pinned", topicId: "pin", pinned: true },
73 ]).map((node) => node.topicId),
74 ["pin"],
75 "a cold collapsed tree paints pinned topic shells before any folder page loads",
76 );
77
78 eq(
79 projectTreeShellChildren(
80 [
81 { key: "topic_old", kind: "topic", label: "Old pin", topicId: "old", pinned: true },
82 { key: "topic_regular", kind: "topic", label: "Regular", topicId: "regular" },
83 ],
84 [{ key: "topic_new", kind: "topic", label: "New pin", topicId: "new", pinned: true }],
85 ).map((node) => ({ topicId: node.topicId, pinned: Boolean(node.pinned) })),
86 [
87 { topicId: "old", pinned: false },
88 { topicId: "regular", pinned: false },
89 { topicId: "new", pinned: true },
90 ],
91 "shell refresh removes stale pins and adds newly pinned collapsed topics",
92 );
93
94 eq(
95 projectTreeSource.includes("children: projectTreeShellChildren(previous?.children, project.children)"),
96 true,
97 "shell refresh preserves loaded folders while reconciling pinned topic shells",
98 );
99 }
100
101 function asTopicKeys(children: { key: string }[] | undefined): string[] {
102 return children?.map((node) => node.key) ?? [];
103 }
104
104 lines TYPESCRIPT