import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { Dashboard, SystemHealth, SystemResources } from "@umt/contracts"; import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { MemoryRouter } from "react-router"; import { describe, expect, it } from "vitest"; import { qk } from "~/lib/query-keys.ts"; import { HomeRuntime } from "./home-runtime.tsx"; // 首页运行状态简版卡:整体健康、CPU、内存、磁盘,以及下载器 / 站点 / 媒体库目录摘要,点进去是运行状态页。 const health = (over: Partial = {}): SystemHealth => ({ level: "warn", checkedAt: new Date().toISOString(), api: { version: "t", startedAt: new Date().toISOString(), uptimeSec: 10 }, processes: [], retiredProcesses: [], sse: { connections: 0 }, db: { level: "ok", latencyMs: 1, sizeBytes: 1, connections: null, error: null }, disks: [ { scope: "library_root", id: "r1", name: "电影", path: "/media/movies", level: "warn", totalBytes: 1000, usedBytes: 870, availableBytes: 130, usedRatio: 0.87, error: null, }, ], diskThresholds: { warnPercent: 85, criticalPercent: 90 }, mounts: [ { kind: "library_root", id: "r1", name: "电影", path: "/m", status: "online", reason: null, sentinelChecked: true, }, { kind: "library_root", id: "r2", name: "剧集", path: "/t", status: "offline", reason: "root_missing", sentinelChecked: true, }, ], engine: { level: "ok", pending: 0, running: 0, oldestPendingAgeSec: null, finished24h: 0, failed24h: 0, failureRate24h: null, }, schedules: { level: "ok", total: 0, enabled: 0, running: 0, failing: [], failedRuns24h: 0 }, storage: { level: "ok", alerts: [] }, ...over, }) as SystemHealth; const resources: SystemResources = { at: new Date().toISOString(), intervalSec: 5, bucketSec: 5, cpu: { scope: "cgroup", percent: 42.4, cores: 4, hostPercent: 30, load: [1, 1, 1] }, memory: { scope: "cgroup", usedBytes: 900, limitBytes: 1000, percent: 92, hostTotalBytes: 2000, hostAvailableBytes: 800, swapUsedBytes: 0, }, network: { scope: "cgroup", rxBps: 1, txBps: 1, rxTotalBytes: 1, txTotalBytes: 1 }, diskIo: { scope: "cgroup", readBps: 1, writeBps: 1 }, hostUptimeSec: 100, samples: [], }; function render(h: SystemHealth, downloaders: Dashboard["sources"]["downloaders"]) { const client = new QueryClient(); client.setQueryData(qk.sub("system", "health"), h); client.setQueryData(qk.sub("system", "resources", 30), resources); client.setQueryData([...qk.dashboard, "sites-accounts"], { items: [ { id: "s1", enabled: true, accountStatus: "ok" }, { id: "s2", enabled: true, accountStatus: "expired" }, { id: "s3", enabled: false, accountStatus: "expired" }, ], nextCursor: null, }); return renderToStaticMarkup( createElement( QueryClientProvider, { client }, createElement(MemoryRouter, null, createElement(HomeRuntime, { downloaders })), ), ); } describe("首页运行状态卡", () => { it("整体健康、CPU / 内存、磁盘、下载器 / 站点 / 媒体库目录摘要,链到运行状态页", () => { const html = render(health(), [ { id: "d1", name: "qb", enabled: true, health: "healthy", lastSeenAt: null }, { id: "d2", name: "qb2", enabled: true, health: "offline", lastSeenAt: null }, ] as Dashboard["sources"]["downloaders"]); expect(html).toContain("运行状态"); expect(html).toContain('href="/console/status"'); expect(html).toContain("需要关注"); expect(html).toContain("42%"); // 内存 ≥ 90% 标红 expect(html).toMatch(/text-destructive[^"]*">92%/); expect(html).toContain("电影"); expect(html).toContain("87%"); // 摘要:正常数 / 总数(停用的不算) expect(html).toMatch(/下载器]*>1\/2/); expect(html).toMatch(/站点]*>1\/2/); expect(html).toMatch(/媒体库目录]*>1\/2/); }); it("全部正常时写「全部正常」,没有配置的项不列", () => { const html = render(health({ level: "ok", mounts: [] }), []); expect(html).toContain("全部正常"); expect(html).not.toContain("媒体库目录<"); expect(html).not.toContain("下载器