Files
lab/ts/web/nextjs/polaris/src/features/navigation/components/app-shell.test.tsx
T
labmemandClaude Opus 5 d015a53a12 feat(polaris): 实现静态分类页
新增七个预生成分类路由、工具卡片网格与空状态。启用侧栏分类导航和当前分类选中态,修复 Windows 静态导出 RSC 路径并补充产物验证,保持静态导出与安全外链约束。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 19:24:57 +08:00

202 lines
5.1 KiB
TypeScript

import { fireEvent, render, screen, waitFor } from "@testing-library/react"
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import type { Category } from "@/types/navigation"
import { AppShell } from "./app-shell"
const categories: Category[] = [
{ id: "dev", title: "开发工具", description: "开发", icon: "code", sort: 10 },
]
describe("AppShell", () => {
beforeEach(() => window.localStorage.clear())
afterEach(() => vi.restoreAllMocks())
it("切换侧栏并持久化状态", () => {
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
const toggle = screen.getByRole("button", { name: "折叠侧边栏" })
fireEvent.click(toggle)
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-sidebar-collapsed",
"true",
)
expect(window.localStorage.getItem("polaris.sidebar.collapsed")).toBe(
"true",
)
})
it("hydration 后恢复持久化状态", async () => {
window.localStorage.setItem("polaris.sidebar.collapsed", "true")
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
await waitFor(() => {
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-sidebar-collapsed",
"true",
)
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-hydrated",
"true",
)
})
})
it("写入失败时内存偏好优先于旧持久化值", () => {
window.localStorage.setItem("polaris.sidebar.collapsed", "false")
vi.spyOn(Storage.prototype, "setItem").mockImplementation(() => {
throw new Error("storage unavailable")
})
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
fireEvent.click(screen.getByRole("button", { name: "折叠侧边栏" }))
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-sidebar-collapsed",
"true",
)
})
it("忽略 sessionStorage 的同名 storage 事件", () => {
window.localStorage.setItem("polaris.sidebar.collapsed", "false")
vi.spyOn(Storage.prototype, "setItem").mockImplementation(() => {
throw new Error("storage unavailable")
})
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
fireEvent.click(screen.getByRole("button", { name: "折叠侧边栏" }))
fireEvent(
window,
new StorageEvent("storage", {
key: "polaris.sidebar.collapsed",
storageArea: window.sessionStorage,
}),
)
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-sidebar-collapsed",
"true",
)
})
it("存储不可用时仍保留当前会话内交互", () => {
vi.spyOn(Storage.prototype, "getItem").mockImplementation(() => {
throw new Error("storage unavailable")
})
vi.spyOn(Storage.prototype, "setItem").mockImplementation(() => {
throw new Error("storage unavailable")
})
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
fireEvent.click(screen.getByRole("button", { name: "折叠侧边栏" }))
expect(screen.getByTestId("app-shell")).toHaveAttribute(
"data-sidebar-collapsed",
"true",
)
})
it("首页默认选中并启用分类链接", () => {
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
>
<main>首页内容</main>
</AppShell>,
)
expect(screen.getByRole("link", { name: "首页" })).toHaveAttribute(
"aria-current",
"page",
)
expect(screen.getByRole("link", { name: "开发工具" })).toHaveAttribute(
"href",
"/categories/dev",
)
})
it("分类页只选中当前分类", () => {
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={false}
activeCategoryId="dev"
>
<main>分类内容</main>
</AppShell>,
)
expect(screen.getByRole("link", { name: "首页" })).not.toHaveAttribute(
"aria-current",
)
expect(screen.getByRole("link", { name: "开发工具" })).toHaveAttribute(
"aria-current",
"page",
)
})
it("折叠状态仍保留分类链接的可访问名称", () => {
render(
<AppShell
categories={categories}
siteName="Polaris"
defaultCollapsed={true}
activeCategoryId="dev"
>
<main>分类内容</main>
</AppShell>,
)
expect(screen.getByRole("link", { name: "开发工具" })).toHaveAttribute(
"aria-current",
"page",
)
})
})