import { describe, expect, it } from "vitest"; import type { OutlineChapterView, WorldEntityCardView } from "@/lib/api/types"; import { CONTEXT_TABS, contextTabHref, toCodexGroups, toOutlineRows, } from "./contextDrawer"; const entity = ( type: string, name: string, rules: string[] = [], ): WorldEntityCardView => ({ type, name, rules }); describe("contextTabHref", () => { it("按 Tab key 拼出完整编辑页路由", () => { // Arrange / Act / Assert expect(contextTabHref("p1", "codex")).toBe("/projects/p1/codex"); expect(contextTabHref("p1", "foreshadow")).toBe("/projects/p1/foreshadow"); expect(contextTabHref("p1", "style")).toBe("/projects/p1/style"); }); it("五个 Tab 覆盖全部读为主入口", () => { expect(CONTEXT_TABS.map((t) => t.key)).toEqual([ "codex", "outline", "foreshadow", "rules", "style", ]); }); }); describe("toCodexGroups", () => { it("空列表返回空分组", () => { expect(toCodexGroups([])).toEqual([]); }); it("按 type 归组并保持首次出现顺序", () => { const entities = [ entity("势力", "雾港议会"), entity("地理", "北境"), entity("势力", "红手会"), ]; const groups = toCodexGroups(entities); expect(groups.map((g) => g.type)).toEqual(["势力", "地理"]); expect(groups[0]?.entities.map((e) => e.name)).toEqual([ "雾港议会", "红手会", ]); expect(groups[1]?.entities.map((e) => e.name)).toEqual(["北境"]); }); it("空白/缺省 type 归入「未分类」", () => { const groups = toCodexGroups([entity(" ", "无名之物")]); expect(groups[0]?.type).toBe("未分类"); }); it("不修改入参数组", () => { const entities = [entity("势力", "甲"), entity("势力", "乙")]; const snapshot = [...entities]; toCodexGroups(entities); expect(entities).toEqual(snapshot); }); }); describe("toOutlineRows", () => { const chapter = ( no: number, volume: number, beats: string[], codes: string[] = [], ): OutlineChapterView => ({ no, volume, beats, foreshadow_windows: codes.map((code) => ({ code })), }); it("空列表返回空数组", () => { expect(toOutlineRows([])).toEqual([]); }); it("按章号升序整形并抽出节拍与伏笔代号", () => { const rows = toOutlineRows([ chapter(2, 1, ["决战"], ["F2"]), chapter(1, 1, ["开场", "引入"], ["F1"]), ]); expect(rows.map((r) => r.no)).toEqual([1, 2]); expect(rows[0]?.beats).toEqual(["开场", "引入"]); expect(rows[0]?.foreshadowCodes).toEqual(["F1"]); expect(rows[1]?.foreshadowCodes).toEqual(["F2"]); }); it("缺省 beats / foreshadow_windows 回退为空数组", () => { const rows = toOutlineRows([{ no: 1, volume: 1 }]); expect(rows[0]?.beats).toEqual([]); expect(rows[0]?.foreshadowCodes).toEqual([]); }); it("不修改入参数组", () => { const chapters = [chapter(2, 1, []), chapter(1, 1, [])]; const snapshot = chapters.map((c) => c.no); toOutlineRows(chapters); expect(chapters.map((c) => c.no)).toEqual(snapshot); }); });