import type { CoverageCell, Subscription, SubscriptionSlotSummary } from "@umt/contracts"; import { describe, expect, it } from "vitest"; import { cellKind, draftFromSubscription, draftToParams, emptyDraft, foldNames, moveItem, progressText, seasonLabel, slotBadge, upgradeOf, } from "./model.ts"; const slot = (x: Partial): SubscriptionSlotSummary => ({ slotId: "s", name: "4K", primary: true, status: "empty", have: 0, inflight: 0, missing: 0, total: null, upgrading: false, minPri: null, targetPri: null, autoFill: true, ruleGroupIds: [], ...x, }); const cell = (x: Partial): CoverageCell => ({ unitKey: "s1e1", state: "missing", assetId: null, quality: null, pri: null, planId: null, planStage: null, reason: null, upgradable: false, deferred: false, ...x, }); describe("订阅总览文案", () => { it("进度总未知显示 ?", () => { expect(progressText({ have: 3, total: null, inflight: 0 })).toBe("3/?"); expect(progressText({ have: 3, total: 10, inflight: 1 })).toBe("3/10"); }); it("季标签:特别篇 / 接续 / 电影", () => { expect(seasonLabel({ mediaKind: "series", seasonNumber: 0, seasonScope: "current_season" })).toBe("特别篇"); expect(seasonLabel({ mediaKind: "series", seasonNumber: 2, seasonScope: "following_seasons" })).toBe("S2 起"); expect(seasonLabel({ mediaKind: "series", seasonNumber: 1, seasonScope: "current_season" })).toBe("S1"); expect(seasonLabel({ mediaKind: "movie", seasonNumber: null, seasonScope: "current_season" })).toBeNull(); }); it("版本徽标按 洗版 → 在途 → 缺 → 已齐 判定", () => { expect(slotBadge(slot({ upgrading: true, minPri: 97, targetPri: 100, missing: 2 })).label).toBe("洗版中 97→100"); expect(slotBadge(slot({ inflight: 2, missing: 3 }))).toEqual({ label: "在途 2", tone: "neutral" }); expect(slotBadge(slot({ missing: 3 })).tone).toBe("destructive"); expect(slotBadge(slot({ have: 10, total: 10 }))).toEqual({ label: "已齐", tone: "success" }); expect(slotBadge(slot({})).label).toBe("未开始"); }); it("名称折叠", () => { expect(foldNames([])).toBe("全部站点"); expect(foldNames(["a", "b", "c", "d"])).toBe("a、b +2"); }); }); describe("覆盖矩阵格", () => { it("state + 附带字段 → 显示类别", () => { expect(cellKind(cell({ state: "have" }))).toBe("have"); expect(cellKind(cell({ state: "have", upgradable: true }))).toBe("upgradable"); expect(cellKind(cell({ state: "missing", reason: "suspected" }))).toBe("suspected"); expect(cellKind(cell({ state: "missing", deferred: true }))).toBe("deferred"); expect(cellKind(cell({ state: "skipped", reason: "not_aired" }))).toBe("not_aired"); expect(cellKind(cell({ state: "skipped", reason: "out_of_range" }))).toBe("skipped"); expect(cellKind(cell({ state: "inflight" }))).toBe("inflight"); }); it("拖动排序", () => { expect(moveItem(["a", "b", "c"], 2, 0)).toEqual(["c", "a", "b"]); expect(moveItem(["a", "b"], 0, 5)).toEqual(["a", "b"]); }); it("升级策略取自版本目标", () => { expect(upgradeOf([{ upgradeThreshold: {} }], "series")).toBe("off"); expect(upgradeOf([{ upgradeThreshold: { enabled: true, mode: "full_pack" } }], "series")).toBe("full_pack"); expect(upgradeOf([{ upgradeThreshold: { enabled: true } }], "movie")).toBe("movie"); }); }); describe("表单 ↔ params", () => { it("保留未知键,空值不写,只在改动时带 best_version / total_episode", () => { const d = { ...emptyDraft("series"), siteIds: ["x"], episodeStart: "3", include: "中字\n\n 4K ", autoFill: "off" as const, unitsPerDay: "2", gbPerDay: "1.5", total: "12", upgrade: "full_pack" as const, }; const { params, errors } = draftToParams( d, { custom: 1, keywords: ["旧"] }, { upgradeChanged: true, totalChanged: true }, ); expect(errors).toEqual({}); expect(params).toEqual({ custom: 1, siteIds: ["x"], include: ["中字", "4K"], episodeRange: { start: 3 }, total_episode: 12, manual_total_episode: false, autoFill: "off", fillBudget: { unitsPerDay: 2, bytesPerDay: Math.round(1.5 * 1024 ** 3) }, best_version: true, best_version_full: true, }); const same = draftToParams(d, {}, { upgradeChanged: false, totalChanged: false }).params; expect(same.best_version).toBeUndefined(); expect(same.total_episode).toBeUndefined(); }); it("校验:结束集 < 开始集", () => { const { errors } = draftToParams( { ...emptyDraft("series"), episodeStart: "5", episodeEnd: "2" }, {}, { upgradeChanged: false, totalChanged: false }, ); expect(errors.episodeEnd).toBeTruthy(); }); it("从订阅回填", () => { const sub = { mediaKind: "series", seasonUnitId: null, seasonScope: "current_season", mode: "continuous", priority: "tracking", policyRevisionId: null, params: { episodeRange: { start: 2 }, autoFill: "on", fillBudget: { bytesPerDay: 2 * 1024 ** 3 }, keywords: ["a", "b"], }, } as unknown as Subscription; const d = draftFromSubscription(sub, "per_unit"); expect(d.episodeStart).toBe("2"); expect(d.autoFill).toBe("on"); expect(d.gbPerDay).toBe("2"); expect(d.keywords).toBe("a\nb"); expect(d.upgrade).toBe("per_unit"); }); });