Skip to content

Commit 343b38f

Browse files
committed
test(notes): pin page wiring of note derivations
收口 T4 报告 9-1 的覆盖缺口:focusGroupId 注入 => 只渲染该组条目 + 反向对照(不注入 => 两条都渲染)。既有 NotesPage.test.tsx 零改动(blob 未变);同一 W1 变异下既有 2 条仍绿、本判据必红。
1 parent 0611628 commit 343b38f

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// @vitest-environment jsdom
2+
/**
3+
* NotesPage.groupFilter.test.tsx — 页面「组过滤接线」的行为级判据(批 5 T4 收口 W1 缺口)。
4+
*
5+
* @ai-context: 为什么必须单独钉——`visibleNotes`(组过滤 + SE 封存)的派生在批 5 T4 从
6+
* `NotesPage` 搬进了 `utils/colorPalette.visibleNotesOf`,页面只剩「接线」
7+
* (把 `groupFilter` 作为实参传给派生函数)。T4 的探针 W1 实测:把那个实参
8+
* 换成常量 `null`(真实缺陷:组过滤静默失效)后,既有
9+
* `NotesPage.test.tsx` 的 2 条用例**仍 2/2 全绿** ⇒ 接线当时没有判据。
10+
* 本文件补上这条判据:用**既有的公共注入面** `focusGroupId` prop
11+
* (`useNotesDeepLink` → `setGroupFilter`)注入组过滤,断言**渲染出来的
12+
* 列表条目**随注入变化;再用反向对照排除「夹具里本来就只有一条」的空真。
13+
* @ai-context: 判据强度的来源(写清以防被弱化)——渲染层的组过滤**只有页面这一处**:
14+
* 实测 `utils/noteSectionModel.buildSections` 的 `groupFilter` 只决定
15+
* 「未分组」组头是否常驻(不删条目),`components/NoteListBody` 只把它用于
16+
* 组头 `active` 态 ⇒ 列表条目数完全由页面传下去的 `visibleNotes` 决定。
17+
* @ai-context: 夹具为什么必须给两个组——`treeMode`(无关键词/无标签/默认排序)为真时
18+
* `buildSections` **按组建节**,组不在 `list_note_groups` 里的笔记整节不渲染
19+
* ⇒ 只给笔记不给组会让两条判据同时失真(空真)。
20+
*/
21+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
22+
import { cleanup, render, screen, waitFor } from "@testing-library/react";
23+
import type { Note, NoteGroup } from "../types";
24+
25+
const { invokeMock } = vi.hoisted(() => ({ invokeMock: vi.fn() }));
26+
const { confirmMock } = vi.hoisted(() => ({ confirmMock: vi.fn() }));
27+
vi.mock("@tauri-apps/api/core", () => ({ invoke: invokeMock }));
28+
vi.mock("@tauri-apps/plugin-dialog", () => ({ confirm: confirmMock }));
29+
// EnrichPanel 挂载期 useAiTaskPolling 会 listen 事件——mock 返回解绑函数
30+
vi.mock("@tauri-apps/api/event", () => ({ listen: vi.fn(() => Promise.resolve(() => {})) }));
31+
32+
import NotesPage from "./NotesPage";
33+
34+
const noteIn = (id: number, title: string, groupId: number | null): Note => ({
35+
id, title, content: "正文", source: "manual", tags: "[]", properties: null,
36+
pin: 0, group_id: groupId, created_at: 1, updated_at: 2,
37+
});
38+
39+
const mkGroup = (id: number, name: string): NoteGroup => ({
40+
id, name, terrain: "container", kind: "topic", domainTag: null, source: "manual",
41+
seriesKey: null, routeReason: null, routeOverridden: 0, color: null, noteCount: 1, createdAt: 1, updatedAt: 2,
42+
});
43+
44+
/** 夹具:两条笔记分属两个组(组表必须同时给出两组,见文件头第三条 @ai-context) */
45+
const NOTES = [noteIn(1, "组7笔记", 7), noteIn(2, "组8笔记", 8)];
46+
const GROUPS = [mkGroup(7, "第七组"), mkGroup(8, "第八组")];
47+
48+
describe("NotesPage 组过滤接线(批 5 T4 收口:派生搬走后页面实参确被用上)", () => {
49+
beforeEach(() => {
50+
invokeMock.mockReset();
51+
confirmMock.mockReset();
52+
invokeMock.mockImplementation(async (cmd: string) => {
53+
switch (cmd) {
54+
case "list_notes":
55+
case "search_notes":
56+
return NOTES;
57+
case "list_note_groups":
58+
return GROUPS;
59+
case "list_fragments":
60+
return [];
61+
case "get_feature_flags":
62+
return { feedCapture: true };
63+
default:
64+
// 子面板(EnrichPanel/VersionPanel/NoteLinkToSystem 等)挂载期查询——空值兜底不抛错
65+
if (cmd === "note_versions_list") return [];
66+
if (cmd === "note_versions_usage") return [];
67+
if (cmd === "list_knowledge_systems") return [];
68+
if (cmd === "list_knowledge_links") return [];
69+
if (cmd === "list_tag_colors") return [];
70+
if (cmd === "list_links_by_target") return [];
71+
return null;
72+
}
73+
});
74+
});
75+
76+
afterEach(() => cleanup());
77+
78+
it("注入 focusGroupId=7 ⇒ 列表只渲染第 7 组条目(页面把 groupFilter 真的接进派生)", async () => {
79+
render(<NotesPage focusGroupId={7} />);
80+
expect(await screen.findByText("组7笔记")).toBeTruthy();
81+
await waitFor(() => expect(screen.queryByText("组8笔记")).toBeNull());
82+
});
83+
84+
it("反向对照:不注入 ⇒ 两条都渲染(排除「夹具本来就只有一条」的空真)", async () => {
85+
render(<NotesPage />);
86+
expect(await screen.findByText("组7笔记")).toBeTruthy();
87+
expect(await screen.findByText("组8笔记")).toBeTruthy();
88+
});
89+
});

0 commit comments

Comments
 (0)