feat(ts): 实现 Polaris 可交互首页
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
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("button", {
|
||||
name: "开发工具,分类页将在下一阶段提供",
|
||||
}),
|
||||
).toHaveAttribute("aria-disabled", "true")
|
||||
expect(
|
||||
screen.queryByRole("link", { name: /开发工具/ }),
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user