import { describe, expect, it } from "vitest"; import { ArcadeImportError, parseConnectionsImport, parseConnectionsImportBatch } from "@/lib/arcade/connectionsImport"; function validPack() { return { schemaVersion: 1, type: "connections", name: "Medication Connections", description: "Four medication groups", settings: { groupCount: 4, itemsPerGroup: 4, allowedMistakes: 4 }, content: Array.from({ length: 4 }, (_, groupIndex) => ({ category: `Category ${groupIndex + 1}`, items: Array.from({ length: 4 }, (_, itemIndex) => `Item ${groupIndex + 1}-${itemIndex + 1}`), explanation: `Explanation ${groupIndex + 1}`, })), }; } describe("Connections imports", () => { it("normalizes a valid board and creates stable ids", () => { const result = parseConnectionsImport(JSON.stringify(validPack())); expect(result.preview.itemCount).toBe(16); expect(result.preview.itemCount).toBe(16); expect(result.preview.normalized.content[0].id).toBe("group-1"); expect(result.preview.normalized.content[0].items[0].id).toBe("group-1-item-1"); }); it("rejects fences and surrounding prose", () => { expect(() => parseConnectionsImport(`\`\`\`json\n${JSON.stringify(validPack())}\n\`\`\``)).toThrow(ArcadeImportError); expect(() => parseConnectionsImport(`Here is the pack: ${JSON.stringify(validPack())}`)).toThrow(ArcadeImportError); }); it("rejects duplicate tiles case-insensitively", () => { const pack = validPack(); pack.content[1].items[0] = " item 1-1 "; expect(() => parseConnectionsImport(JSON.stringify(pack))).toThrow("Every tile must be unique"); }); it("rejects unknown keys", () => { const pack = { ...validPack(), extra: true }; expect(() => parseConnectionsImport(JSON.stringify(pack))).toThrow("does not match schema version 1"); }); it("reports long-tile warnings without changing the content", () => { const pack = validPack(); pack.content[0].items[0] = "This intentionally long tile contains too many words"; const result = parseConnectionsImport(JSON.stringify(pack)); expect(result.report.warnings.length).toBeGreaterThan(0); expect(result.preview.normalized.content[0].items[0].text).toBe(pack.content[0].items[0]); }); it("does not treat a shared generic word as a similar category", () => { const pack = validPack(); pack.content[0].category = "ACE Inhibitors"; pack.content[1].category = "Proton Pump Inhibitors"; const result = parseConnectionsImport(JSON.stringify(pack)); expect(result.report.warnings).not.toContain( "Categories “ACE Inhibitors” and “Proton Pump Inhibitors” may be too similar." ); }); it("previews multiple packs from one JSON array", () => { const first = validPack(); const second = { ...validPack(), name: "Second board" }; const result = parseConnectionsImportBatch(JSON.stringify([first, second])); expect(result.count).toBe(2); expect(result.packs.map((pack) => pack.name)).toEqual(["Medication Connections", "Second board"]); }); it("limits batch imports to ten packs", () => { const batch = Array.from({ length: 11 }, () => validPack()); expect(() => parseConnectionsImportBatch(JSON.stringify(batch))).toThrow("between 1 and 10"); }); });