import { afterEach, describe, expect, it, vi } from "vitest"; import { buildGuideImportDraft, charactersFromCombo, parseCsv, type GuideImportSource, type ImportCatalog, } from "@/lib/guides/google-sheet-import"; afterEach(() => vi.unstubAllGlobals()); describe("Google Sheet guide import", () => { it("parses quoted commas, escaped quotes, and multiline cells", () => { expect(parseCsv('"name","note"\n"A, B","line 1\nline ""2"""\n')).toEqual([ ["name", "note"], ["A, B", 'line 1\nline "2"'], ]); }); it("builds supported compact fields and reports missing catalog rows", async () => { const source: GuideImportSource = { characterName: "Hero", overview: "Guide Hero", workbookId: "sheet-id", coverId: "cover-id", layout: "compact", infoSheet: "Hero Info", teamSheets: [], comboSheets: [], weaponMetric: "overall-personal", }; const catalog: ImportCatalog = { characters: [{ key: "hero", name: "Hero", constellations: [] }], weapons: [{ key: "weapon", name: "Known Weapon" }], artifacts: [{ key: "artifact", name: "Known Set" }], }; const rows = Array.from({ length: 24 }, () => Array.from({ length: 21 }, () => "")); rows[0][10] = "Weapons อาวุธที่แนะนำ"; rows[1][11] = "Known Weapon R5"; rows[1][13] = "110%"; rows[1][14] = "105%"; rows[3][11] = "Missing Weapon R1"; rows[3][13] = "100%"; rows[5][10] = "Artifacts อาร์ติแฟกต์ที่แนะนำ (เลทเกม)"; rows[6][11] = "4 Known Set"; rows[6][13] = "100%"; rows[8][5] = "ATK (พลังโจมตี)"; rows[8][6] = "2000+"; rows[8][7] = "สแตทที่แนะนำ เลทเกม (AR 45+)"; vi.stubGlobal("fetch", vi.fn(async () => new Response(rows.map((row) => row.map((cell) => `"${cell}"`).join(",")).join("\n")))); const draft = await buildGuideImportDraft(source, catalog); expect(draft.weapons).toEqual([expect.objectContaining({ weaponKey: "weapon", refinement: 5, overallPercent: 110, personalPercent: 105 })]); expect(draft.artifacts.groups[0].rows).toEqual([expect.objectContaining({ firstArtifactKey: "artifact", percent: 100 })]); expect(draft.artifacts.targets).toEqual([{ stat: "ATK", value: "2000+" }]); expect(draft.skipped).toContain("weapon not in catalog: Missing Weapon R1"); }); it("does not fetch or populate a keep-existing source", async () => { const fetchMock = vi.fn(); vi.stubGlobal("fetch", fetchMock); const draft = await buildGuideImportDraft({ characterName: "Yumemizuki Mizuki", overview: "existing", workbookId: "sheet-id", coverId: "cover-id", layout: "full", infoSheet: "Mizuki Info", teamSheets: [], comboSheets: [], skipWrite: true, }, { characters: [{ key: "mizuki", name: "Yumemizuki Mizuki", constellations: [] }], weapons: [], artifacts: [], }); expect(fetchMock).not.toHaveBeenCalled(); expect(draft.weapons).toEqual([]); }); it("resolves the unique characters named by a combo", () => { const characters = ["Yae Miko", "Odette", "Alyosha", "Sandrone"].map((name, index) => ({ key: String(index), name, constellations: [], })); expect(charactersFromCombo("Yae EEE > Odette EE > Alyosha EQ > Sandrone 3CE Q", { characters, weapons: [], artifacts: [], }).map((item) => item.name)).toEqual(["Yae Miko", "Odette", "Alyosha", "Sandrone"]); }); });