// Rôle : vérifie les correspondances des guides et la validité des associations de session. import assert from "node:assert/strict"; import test from "node:test"; import { aniimoChecklistEntries, matchGuideChecklist, normalizeGuideLabel, toggleGuideChecklistRows, validGuideAssociations } from "../website/src/features/games/guideChecklist.js"; const variants = [{ key: "1:base", name: "emberpup", form: "base" }, { key: "1:mountain", name: "emberpup", form: "mountain" }]; const entries = aniimoChecklistEntries(variants, { emberpup: "Loufeuteau", base: "Forme de base", mountain: "Montagnes" }, { emberpup: "Emberpup", base: "Basic form", mountain: "Mountain form" }); test("full names normalize accents, case and whitespace without approximate matching", () => { assert.equal(normalizeGuideLabel(" ŒUF Écarlate \n"), "oeuf ecarlate"); const result = matchGuideChecklist([{ key: "egg", labels: ["Œuf écarlate"] }], { items: [ { label: "OEUF ECARLATE", qtyCurrent: 1 }, { label: "Œuf", qtyCurrent: 0 } ] }); assert.equal(result.count, 1); assert.ok(result.completed.has("egg")); assert.equal(matchGuideChecklist(entries, { items: [{ label: "Loufeu", qtyCurrent: 1 }] }).count, 0); }); test("species completion covers forms, but a specific French or English row takes priority", () => { const data = { sections: [{ items: [ { label: "EMBERPUP", qtyCurrent: 1 }, { label: "Loufeuteau — forme de base", qtyCurrent: 0 } ] }] }; const result = matchGuideChecklist(entries, data); assert.equal(result.count, 2); assert.deepEqual([...result.completed], ["1:mountain"]); const english = matchGuideChecklist(entries, { items: [{ label: "Emberpup — Basic form", qtyCurrent: 1 }] }); assert.equal(english.count, 1); assert.deepEqual([...english.completed], ["1:base"]); }); test("all duplicate lines must reach their own target, including translated aliases", () => { const data = { items: [ { label: "Loufeuteau", qtyTarget: 3, qtyCurrent: 2 }, { label: "Emberpup", qtyCurrent: 1 }, { label: "Unrelated", qtyCurrent: 1 } ] }; assert.equal(matchGuideChecklist(entries, data).completed.size, 0); data.items[0].qtyCurrent = 3; assert.equal(matchGuideChecklist(entries, data).completed.size, 2); data.items.push({ label: "Loufeuteau" }); assert.equal(matchGuideChecklist(entries, data).completed.size, 0); assert.equal(matchGuideChecklist(entries, {}).count, 0); }); test("card toggles update every exact matching row to its target or zero", () => { const data = { sections: [{ id: "s1", items: [ { id: "a", label: "Loufeuteau", qtyTarget: 3, qtyCurrent: 1 }, { id: "b", label: "Emberpup", qtyTarget: 2, qtyCurrent: 0 }, { id: "c", label: "Unrelated", qtyCurrent: 1 } ] }] }; const match = matchGuideChecklist(entries, data); assert.deepEqual(match.rowIds.get("1:base"), ["a", "b"]); const completed = toggleGuideChecklistRows(data, match.rowIds.get("1:base"), true); assert.deepEqual(completed.sections[0].items.map((item) => item.qtyCurrent), [3, 2, 1]); const cleared = toggleGuideChecklistRows(completed, match.rowIds.get("1:base"), false); assert.deepEqual(cleared.sections[0].items.map((item) => item.qtyCurrent), [0, 0, 1]); assert.equal(data.sections[0].items[0].qtyCurrent, 1); }); test("session associations require the current linked toolbox and an existing checklist", () => { const toolbox = { id: "tb", modules: [{ id: "capture", type: "checklist" }, { id: "notes", type: "notepad" }] }; const association = { toolboxId: "tb", moduleId: "capture", hideCompleted: true }; const state = { "aniimo/aniimos": association, "mhwilds/monsters": { ...association, moduleId: "notes" }, unknown: association }; assert.deepEqual(validGuideAssociations(state, [toolbox], { aniimo: "tb", mhwilds: "tb" }), { "aniimo/aniimos": association }); assert.deepEqual(validGuideAssociations(state, [toolbox], { aniimo: "other" }), {}); assert.deepEqual(validGuideAssociations(state, [], { aniimo: "tb" }), {}); assert.deepEqual(validGuideAssociations({ "aniimo/aniimos": null }, [toolbox], { aniimo: "tb" }), {}); });