import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import type { MediaServerInventory, WorkInventory } from "@umt/contracts"; import { describe, expect, it } from "vitest"; import { parseWorkRef, type ReleaseFilterState, toApiFilters } from "./release-results.tsx"; import { resolvePick } from "./site-picker-dialog.tsx"; import { inventoryBadge, mediaServerSummary, releaseSearchPath, slotLine, workHref, workRef } from "./work-card.tsx"; // SEARCH-2:作品 → 详情 / 搜资源的地址,站点选择解析,资源查询参数,订阅入口只在作品详情页。 const inv = (p: Partial): WorkInventory => ({ state: "not_collected", subscribed: false, versionCount: 0, downloadingCount: 0, slotTotal: 0, slotSatisfied: 0, missing: [], ...p, }); const ID = "11111111-1111-4111-8111-111111111111"; describe("作品地址", () => { it("本地作品进媒体库详情;仅 TMDB 的进 TMDB 详情", () => { expect(workHref({ localEntityId: ID, tmdb: { entityType: "movie", externalId: "1" } })).toBe( `/console/library/${ID}`, ); expect(workHref({ localEntityId: null, tmdb: { entityType: "tv", externalId: "1399" } })).toBe( "/console/media/tmdb/tv/1399", ); }); it("搜资源引用与第二阶段地址可以往返", () => { const ref = workRef({ localEntityId: null, tmdb: { entityType: "movie", externalId: "157336" } }); expect(ref).toBe("tmdb:movie:157336"); expect(parseWorkRef(ref!)).toEqual({ tmdb: "movie:157336" }); expect(parseWorkRef(`local:${ID}`)).toEqual({ entityId: ID }); expect(parseWorkRef("q:Dune 2024")).toEqual({ q: "Dune 2024" }); expect(parseWorkRef("nope")).toBeNull(); const url = new URL(releaseSearchPath({ title: "星际穿越", ref: ref! }, ["a", "b"]), "http://x"); expect(url.pathname).toBe("/console/search"); expect(Object.fromEntries(url.searchParams)).toEqual({ q: "星际穿越", work: ref, t: "星际穿越", in: "a,b" }); }); }); describe("站点选择", () => { const sites = [ { id: "a", enabled: true, searchDefault: true }, { id: "b", enabled: true, searchDefault: false }, { id: "c", enabled: false, searchDefault: true }, ]; it("默认 = 启用且默认参与;全部 = 全部启用;指定 = 选中里仍启用的", () => { expect(resolvePick({ mode: "default", siteIds: [] }, sites)).toEqual(["a"]); expect(resolvePick({ mode: "all", siteIds: [] }, sites)).toEqual(["a", "b"]); expect(resolvePick({ mode: "custom", siteIds: ["b", "c"] }, sites)).toEqual(["b"]); }); it("资源查询:选中的站点进 sites,站点分面只进 siteFilter;按作品搜不带 q", () => { const f: ReleaseFilterState = { sites: "b", resolution: "", source: "", minGb: "", maxGb: "", free: "", hr: "", sort: "", order: "", }; expect(toApiFilters({ tmdb: "movie:1" }, f, "a,b")).toMatchObject({ tmdb: "movie:1", sites: "a,b", siteFilter: "b", }); expect(toApiFilters({ tmdb: "movie:1" }, { ...f, sites: "" }, "")).not.toHaveProperty("q"); }); }); describe("库内状态文案", () => { it("未收录 / 已建档 / 已收录 / 正在下载;版本目标满足与缺失", () => { expect(inventoryBadge(inv({})).label).toBe("未收录"); expect(inventoryBadge(inv({ state: "tracked" })).label).toBe("已建档 · 未入库"); expect(inventoryBadge(inv({ state: "owned", versionCount: 2 })).label).toBe("已收录 · 2 个版本"); expect(inventoryBadge(inv({ state: "downloading", downloadingCount: 1 })).label).toBe("正在下载 1 个"); expect( slotLine(inv({ state: "owned", slotTotal: 2, slotSatisfied: 1, missing: [{ slotId: ID, name: "2160p" }] })), ).toBe("版本目标满足 1/2 · 缺「2160p」"); expect(slotLine(inv({}))).toBeNull(); }); it("Emby:任一实例有 = 已有;全部没有 = 没有;有失败 = 未知(不等于缺失)", () => { const ms = (...st: ("present" | "not_found" | "unknown")[]): MediaServerInventory => ({ mediaEntityId: null, partial: false, instances: st.map((status, i) => ({ instanceId: `${ID.slice(0, -1)}${i}`, name: `E${i}`, status, reason: null, items: [], observedAt: "2026-09-29T00:00:00.000Z", })), }); expect(mediaServerSummary(ms())).toBeNull(); expect(mediaServerSummary(ms("present"))?.label).toBe("Emby 已有"); expect(mediaServerSummary(ms("not_found", "not_found"))?.label).toBe("Emby 没有"); expect(mediaServerSummary(ms("not_found", "unknown"))?.label).toBe("Emby 未知"); }); }); describe("订阅入口位置", () => { const src = (rel: string) => readFileSync(fileURLToPath(new URL(rel, import.meta.url)), "utf8"); it("搜索结果与 ⌘K 面板不能直接订阅", () => { for (const f of ["./command-palette.tsx", "./search-sections.tsx", "./work-card.tsx"]) { const s = src(f); expect(s, f).not.toMatch(/useCreateSubscription|SubscriptionFormDialog|useSubscribeTmdb/); } }); it("作品详情页(本地 / 仅 TMDB)有订阅入口", () => { for (const f of ["../../routes/console/library.$id.tsx", "../../routes/console/media.tmdb.$type.$id.tsx"]) { expect(src(f), f).toMatch(/