import { describe, expect, it } from "vitest" import categories from "@/data/categories.json" import links from "@/data/links.json" import settings from "@/data/settings.json" import { SEARCH_PROVIDERS } from "@/types/search" const hasUniqueValues = (values: string[]) => new Set(values).size === values.length describe("Polaris 静态数据", () => { it("包含 7 个唯一且结构完整的分类", () => { expect(categories).toHaveLength(7) expect(hasUniqueValues(categories.map(({ id }) => id))).toBe(true) for (const category of categories) { expect(category).toEqual({ id: expect.any(String), title: expect.any(String), description: expect.any(String), icon: expect.any(String), sort: expect.any(Number), }) expect(category.id).not.toBe("") expect(category.title).not.toBe("") expect(Number.isFinite(category.sort)).toBe(true) } }) it("包含 45 条合法链接且分类引用均存在", () => { const categoryIds = new Set(categories.map(({ id }) => id)) expect(links).toHaveLength(45) expect(hasUniqueValues(links.map(({ id }) => id))).toBe(true) for (const link of links) { expect(link.id).toEqual(expect.any(String)) expect(link.title).toEqual(expect.any(String)) expect(link.description).toEqual(expect.any(String)) expect(link.url).toEqual(expect.any(String)) expect(link.categoryId).toEqual(expect.any(String)) expect(link.pinned).toEqual(expect.any(Boolean)) expect(link.keywords).toEqual(expect.any(Array)) expect(link.sort).toEqual(expect.any(Number)) expect(link.id).not.toBe("") expect(link.title).not.toBe("") expect(() => new URL(link.url)).not.toThrow() // 跨分类常用链接仍必须归属于真实分类,避免未来 API 出现悬空外键。 expect(categoryIds.has(link.categoryId)).toBe(true) expect( link.keywords.every((keyword) => typeof keyword === "string"), ).toBe(true) expect(Number.isFinite(link.sort)).toBe(true) if (link.icon !== undefined) expect(typeof link.icon).toBe("string") if (!link.pinned) expect(link.pinnedSort).toBeUndefined() } }) it("6 条常用链接拥有唯一 pinnedSort", () => { const pinned = links.filter(({ pinned }) => pinned) const pinnedSorts = pinned.map(({ pinnedSort }) => pinnedSort) expect(pinned).toHaveLength(6) expect(pinnedSorts.every(Number.isFinite)).toBe(true) expect(new Set(pinnedSorts).size).toBe(6) }) it("设置包含完整且合法的嵌套契约", () => { expect(settings).toEqual({ siteName: "Polaris", theme: "light-glass", search: { defaultProvider: "google", enabledProviders: [...SEARCH_PROVIDERS], }, background: { type: "gradient", url: null, blur: expect.any(Number), overlay: expect.any(Number), }, sidebar: { defaultCollapsed: expect.any(Boolean), }, }) expect(SEARCH_PROVIDERS).toContain(settings.search.defaultProvider) expect(Number.isFinite(settings.background.blur)).toBe(true) expect(Number.isFinite(settings.background.overlay)).toBe(true) }) describe("导入链接卫生检查", () => { const normalizeUrl = (url: string) => url.replace(/\/+$/, "") it("全部链接 URL 唯一(忽略末尾斜杠)", () => { const urls = links.map(({ url }) => normalizeUrl(url)) expect(hasUniqueValues(urls)).toBe(true) }) it("不包含本地或内网地址", () => { for (const link of links) { const { hostname } = new URL(link.url) expect(hostname).toMatch(/^[\w.-]+$/) expect(hostname).not.toBe("localhost") expect(hostname).not.toMatch(/\.(local|lan|internal)$/) expect(hostname).not.toMatch( /^(127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|169\.254\.|0\.0\.0\.0)/, ) } }) it("不携带查询参数或片段,防止 sid/jumpuin 等会话标识混入", () => { for (const link of links) { const url = new URL(link.url) expect([...url.searchParams.keys()]).toEqual([]) expect(url.hash).toBe("") } }) }) })