119 lines
4.2 KiB
TypeScript
119 lines
4.2 KiB
TypeScript
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("")
|
|
}
|
|
})
|
|
})
|
|
})
|