import { describe, expect, it } from "vitest"; import { editPlayerCharacter } from "../edit-player-character.js"; import type { PlayerCharacter } from "../player-character-types.js"; import { playerCharacterId } from "../player-character-types.js"; import { isDomainError } from "../types.js"; import { expectDomainError } from "./test-helpers.js"; const id = playerCharacterId("pc-1"); function makePC(overrides?: Partial): PlayerCharacter { return { id, name: "Aragorn", ac: 16, maxHp: 120, color: "green", icon: "sword", ...overrides, }; } describe("editPlayerCharacter", () => { it("edits name successfully", () => { const result = editPlayerCharacter([makePC()], id, { name: "Strider" }); if (isDomainError(result)) throw new Error(result.message); expect(result.characters[0].name).toBe("Strider"); expect(result.events[0].type).toBe("PlayerCharacterUpdated"); }); it("edits multiple fields", () => { const result = editPlayerCharacter([makePC()], id, { name: "Strider", ac: 18, }); if (isDomainError(result)) throw new Error(result.message); expect(result.characters[0].name).toBe("Strider"); expect(result.characters[0].ac).toBe(18); }); it("returns error for not-found id", () => { const result = editPlayerCharacter( [makePC()], playerCharacterId("pc-999"), { name: "Nope" }, ); expectDomainError(result, "player-character-not-found"); }); it("rejects empty name", () => { const result = editPlayerCharacter([makePC()], id, { name: "" }); expectDomainError(result, "invalid-name"); }); it("rejects invalid AC", () => { const result = editPlayerCharacter([makePC()], id, { ac: -1 }); expectDomainError(result, "invalid-ac"); }); it("rejects invalid maxHp", () => { const result = editPlayerCharacter([makePC()], id, { maxHp: 0 }); expectDomainError(result, "invalid-max-hp"); }); it("rejects invalid color", () => { const result = editPlayerCharacter([makePC()], id, { color: "neon" }); expectDomainError(result, "invalid-color"); }); it("rejects invalid icon", () => { const result = editPlayerCharacter([makePC()], id, { icon: "banana" }); expectDomainError(result, "invalid-icon"); }); it("returns error when no fields changed", () => { const pc = makePC(); const result = editPlayerCharacter([pc], id, { name: pc.name, ac: pc.ac, }); expectDomainError(result, "no-changes"); }); it("emits exactly one event on success", () => { const result = editPlayerCharacter([makePC()], id, { name: "Strider" }); if (isDomainError(result)) throw new Error(result.message); expect(result.events).toHaveLength(1); }); it("clears color when set to null", () => { const result = editPlayerCharacter([makePC({ color: "green" })], id, { color: null, }); if (isDomainError(result)) throw new Error(result.message); expect(result.characters[0].color).toBeUndefined(); }); it("clears icon when set to null", () => { const result = editPlayerCharacter([makePC({ icon: "sword" })], id, { icon: null, }); if (isDomainError(result)) throw new Error(result.message); expect(result.characters[0].icon).toBeUndefined(); }); it("event includes old and new name", () => { const result = editPlayerCharacter([makePC()], id, { name: "Strider" }); if (isDomainError(result)) throw new Error(result.message); const event = result.events[0]; if (event.type !== "PlayerCharacterUpdated") throw new Error("wrong event"); expect(event.oldName).toBe("Aragorn"); expect(event.newName).toBe("Strider"); }); });