Files
llm-wiki/workbench/web/test/search-panel.test.tsx
2026-07-12 21:26:08 +08:00

156 lines
4.4 KiB
TypeScript

import { describe, it } from "node:test";
import assert from "node:assert/strict";
import React from "react";
import { SearchPanel } from "../src/components/SearchPanel";
import type { PageRef } from "../src/lib/api";
import { changeText, click, pressKey, render, screen } from "./render";
describe("SearchPanel", () => {
it("filters current library refs and opens the selected result with keyboard", async () => {
const opened: string[] = [];
const closed: string[] = [];
render(
<SearchPanel
open
refs={[
ref("wiki/alpha.md", "alpha", "Alpha Notes"),
ref("wiki/paper-ui.md", "paper-ui", "Paper UI 移植"),
ref("raw/source.md", "source", "Source Material"),
]}
knowledgeBaseName="AI学习知识库"
onOpenPage={(path) => opened.push(path)}
onClose={() => closed.push("closed")}
/>,
);
await changeText(screen.getByLabelText("搜索当前库页面"), "paper");
assert.equal(searchResultPaths(), "wiki/paper-ui.md");
await pressKey(screen.getByLabelText("搜索当前库页面"), "Enter");
assert.deepEqual(opened, ["wiki/paper-ui.md"]);
assert.deepEqual(closed, ["closed"]);
});
it("supports arrow selection, click open, and insert reference actions", async () => {
const opened: string[] = [];
const inserted: string[] = [];
const closed: string[] = [];
const first = render(
<SearchPanel
open
refs={[
ref("wiki/alpha.md", "alpha", "Alpha Notes"),
ref("wiki/beta.md", "beta", "Beta Notes"),
]}
knowledgeBaseName="AI学习知识库"
onOpenPage={(path) => opened.push(path)}
onInsertRef={(path) => inserted.push(path)}
onClose={() => closed.push("closed")}
/>,
);
await pressKey(screen.getByLabelText("搜索当前库页面"), "ArrowDown");
await pressKey(screen.getByLabelText("搜索当前库页面"), "Enter");
assert.deepEqual(opened, ["wiki/beta.md"]);
assert.deepEqual(closed, ["closed"]);
first.unmount();
const second = render(
<SearchPanel
open
refs={[
ref("wiki/alpha.md", "alpha", "Alpha Notes"),
ref("wiki/beta.md", "beta", "Beta Notes"),
]}
knowledgeBaseName="AI学习知识库"
onOpenPage={(path) => opened.push(path)}
onInsertRef={(path) => inserted.push(path)}
onClose={() => closed.push("closed")}
/>,
);
await click(screen.getByRole("button", { name: /Alpha Notes/ }));
assert.deepEqual(opened, ["wiki/beta.md", "wiki/alpha.md"]);
second.unmount();
render(
<SearchPanel
open
refs={[
ref("wiki/alpha.md", "alpha", "Alpha Notes"),
ref("wiki/beta.md", "beta", "Beta Notes"),
]}
knowledgeBaseName="AI学习知识库"
onOpenPage={(path) => opened.push(path)}
onInsertRef={(path) => inserted.push(path)}
onClose={() => closed.push("closed")}
/>,
);
await click(screen.getAllByRole("button", { name: "插入" })[1]!);
assert.deepEqual(inserted, ["wiki/beta.md"]);
});
it("renders loading, error, no library, and empty-result states", async () => {
const loading = render(
<SearchPanel
open
refs={[]}
loading
knowledgeBaseName="AI学习知识库"
onOpenPage={noop}
onClose={noop}
/>,
);
assert.equal(searchState(), "正在加载当前库页面...");
loading.unmount();
const error = render(
<SearchPanel
open
refs={[]}
error="接口失败"
knowledgeBaseName="AI学习知识库"
onOpenPage={noop}
onClose={noop}
/>,
);
assert.equal(searchState(), "接口失败");
error.unmount();
const noLibrary = render(<SearchPanel open refs={[]} onOpenPage={noop} onClose={noop} />);
assert.equal(searchState(), "请先选择知识库");
noLibrary.unmount();
render(
<SearchPanel
open
refs={[ref("wiki/alpha.md", "alpha", "Alpha Notes")]}
knowledgeBaseName="AI学习知识库"
onOpenPage={noop}
onClose={noop}
/>,
);
await changeText(screen.getByLabelText("搜索当前库页面"), "zzzz-no-hit");
assert.equal(searchState(), "没有匹配结果");
});
});
function searchResultPaths(): string {
return Array.from(document.querySelectorAll(".search-result-path"))
.map((node) => node.textContent ?? "")
.join("|");
}
function searchState(): string {
return document.querySelector(".search-state")?.textContent ?? "";
}
function ref(path: string, name: string, title: string): PageRef {
return { path, name, title, category: path.startsWith("wiki/") ? "wiki" : "raw" };
}
function noop() {}