Files
mnote/wolai-frontend/src/components/editor/use-page-head-title.test.tsx
T
lix-2026 8353aea2f9 feat(editor): save leptos island and page aggregate alignment progress
- switch main document flow toward leptos tiptap island host and generated runtime assets

- align page aggregate loading, page head single-source updates, and AI tool result recovery

- add tests and smoke scripts for title sync, AI route recovery, and editor host cutover
2026-04-22 05:57:06 +08:00

157 lines
5.0 KiB
TypeScript

import { act } from "react";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { createRoot, type Root } from "react-dom/client";
import { PreferredSidebarSnapshotProvider } from "@/components/sidebar/preferred-sidebar-snapshot-context";
import type { SidebarInitialData } from "@/components/sidebar/types";
import { buildSidebarInitialData } from "@/lib/sidebar-data";
import type { DocumentRecord } from "@/lib/documents";
import { usePageHeadTitle } from "./use-page-head-title";
function buildDocument(overrides: Partial<DocumentRecord> = {}): DocumentRecord {
return {
access_scope: "private",
id: "doc-1",
workspace_id: "ws-1",
title: "标题 A",
parent_id: null,
sort_order: 0,
is_starred: false,
is_template: false,
created_at: "2026-04-21T00:00:00.000Z",
updated_at: "2026-04-21T00:00:00.000Z",
...overrides,
};
}
function buildSidebarData(documents: DocumentRecord[]): SidebarInitialData {
return buildSidebarInitialData({
activeWorkspaceId: "ws-1",
workspaces: [],
documents,
trashedDocuments: [],
mindmaps: [],
mediaAssets: [],
trashedMediaAssets: [],
tables: [],
});
}
function HookProbe(props: { documentId: string; fallbackTitle: string }) {
const state = usePageHeadTitle(props);
return (
<>
<div
data-testid="page-head-title"
data-display-title={state.displayTitle}
data-committed-title={state.committedTitle}
data-has-draft={state.hasDraft ? "1" : "0"}
/>
<button type="button" data-testid="set-draft" onClick={() => state.setDraftTitle(" 新标题 ")}>
设草稿
</button>
<button type="button" data-testid="commit-persisted" onClick={() => state.commitPersistedTitle("新标题")}>
提交持久化
</button>
</>
);
}
describe("usePageHeadTitle", () => {
let container: HTMLDivElement;
let root: Root;
beforeEach(() => {
(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT =
true;
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
});
afterEach(() => {
act(() => {
root.unmount();
});
container.remove();
});
it("应优先使用 live sidebar snapshot 中的标题作为 committed title", async () => {
const snapshot = buildSidebarData([
buildDocument({
id: "doc-1",
title: "树标题",
}),
]);
await act(async () => {
root.render(
<PreferredSidebarSnapshotProvider data={snapshot}>
<HookProbe documentId="doc-1" fallbackTitle="SSR 标题" />
</PreferredSidebarSnapshotProvider>,
);
});
const probe = container.querySelector("[data-testid='page-head-title']");
expect(probe?.getAttribute("data-committed-title")).toBe("树标题");
expect(probe?.getAttribute("data-display-title")).toBe("树标题");
expect(probe?.getAttribute("data-has-draft")).toBe("0");
});
it("应只把本地输入保留为短暂 draft,并在 live 标题追平后自动清空", async () => {
const initialSnapshot = buildSidebarData([
buildDocument({
id: "doc-1",
title: "旧标题",
}),
]);
await act(async () => {
root.render(
<PreferredSidebarSnapshotProvider data={initialSnapshot}>
<HookProbe documentId="doc-1" fallbackTitle="SSR 标题" />
</PreferredSidebarSnapshotProvider>,
);
});
const setDraftButton = container.querySelector<HTMLButtonElement>("[data-testid='set-draft']");
act(() => {
setDraftButton?.click();
});
let probe = container.querySelector("[data-testid='page-head-title']");
expect(probe?.getAttribute("data-display-title")).toBe(" 新标题 ");
expect(probe?.getAttribute("data-committed-title")).toBe("旧标题");
expect(probe?.getAttribute("data-has-draft")).toBe("1");
const commitPersistedButton = container.querySelector<HTMLButtonElement>("[data-testid='commit-persisted']");
act(() => {
commitPersistedButton?.click();
});
probe = container.querySelector("[data-testid='page-head-title']");
expect(probe?.getAttribute("data-display-title")).toBe("新标题");
expect(probe?.getAttribute("data-has-draft")).toBe("1");
const syncedSnapshot = buildSidebarData([
buildDocument({
id: "doc-1",
title: "新标题",
updated_at: "2026-04-21T00:00:02.000Z",
}),
]);
await act(async () => {
root.render(
<PreferredSidebarSnapshotProvider data={syncedSnapshot}>
<HookProbe documentId="doc-1" fallbackTitle="SSR 标题" />
</PreferredSidebarSnapshotProvider>,
);
});
probe = container.querySelector("[data-testid='page-head-title']");
expect(probe?.getAttribute("data-display-title")).toBe("新标题");
expect(probe?.getAttribute("data-committed-title")).toBe("新标题");
expect(probe?.getAttribute("data-has-draft")).toBe("0");
});
});