Files
initiative/packages/domain/src/__tests__/set-ac.test.ts
Lukas 36768d3aa1 Upgrade Biome to 2.4.7 and enable 54 additional lint rules
Add rules covering bug prevention (noLeakedRender, noFloatingPromises,
noImportCycles, noReactForwardRef), security (noScriptUrl, noAlert),
performance (noAwaitInLoops, useTopLevelRegex), and code style
(noNestedTernary, useGlobalThis, useNullishCoalescing, useSortedClasses,
plus ~40 more). Fix all violations: extract top-level regex constants,
guard React && renders with boolean coercion, refactor nested ternaries,
replace window with globalThis, sort Tailwind classes, and introduce
expectDomainError test helper to eliminate conditional expects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 14:25:09 +01:00

136 lines
3.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { setAc } from "../set-ac.js";
import type { Combatant, Encounter } from "../types.js";
import { combatantId, isDomainError } from "../types.js";
import { expectDomainError } from "./test-helpers.js";
function makeCombatant(name: string, ac?: number): Combatant {
return ac === undefined
? { id: combatantId(name), name }
: { id: combatantId(name), name, ac };
}
function enc(
combatants: Combatant[],
activeIndex = 0,
roundNumber = 1,
): Encounter {
return { combatants, activeIndex, roundNumber };
}
function successResult(
encounter: Encounter,
id: string,
value: number | undefined,
) {
const result = setAc(encounter, combatantId(id), value);
if (isDomainError(result)) {
throw new Error(`Expected success, got error: ${result.message}`);
}
return result;
}
describe("setAc", () => {
it("sets AC to a valid value", () => {
const e = enc([makeCombatant("A"), makeCombatant("B")]);
const { encounter, events } = successResult(e, "A", 15);
expect(encounter.combatants[0].ac).toBe(15);
expect(events).toEqual([
{
type: "AcSet",
combatantId: combatantId("A"),
previousAc: undefined,
newAc: 15,
},
]);
});
it("sets AC to 0", () => {
const e = enc([makeCombatant("A")]);
const { encounter } = successResult(e, "A", 0);
expect(encounter.combatants[0].ac).toBe(0);
});
it("clears AC with undefined", () => {
const e = enc([makeCombatant("A", 15)]);
const { encounter, events } = successResult(e, "A", undefined);
expect(encounter.combatants[0].ac).toBeUndefined();
expect(events[0]).toMatchObject({
previousAc: 15,
newAc: undefined,
});
});
it("returns error for nonexistent combatant", () => {
const e = enc([makeCombatant("A")]);
const result = setAc(e, combatantId("nonexistent"), 10);
expectDomainError(result, "combatant-not-found");
});
it("returns error for negative AC", () => {
const e = enc([makeCombatant("A")]);
const result = setAc(e, combatantId("A"), -1);
expectDomainError(result, "invalid-ac");
});
it("returns error for non-integer AC", () => {
const e = enc([makeCombatant("A")]);
const result = setAc(e, combatantId("A"), 3.5);
expectDomainError(result, "invalid-ac");
});
it("returns error for NaN", () => {
const e = enc([makeCombatant("A")]);
const result = setAc(e, combatantId("A"), Number.NaN);
expect(isDomainError(result)).toBe(true);
});
it("preserves other fields when setting AC", () => {
const combatant: Combatant = {
id: combatantId("A"),
name: "Aria",
initiative: 15,
maxHp: 20,
currentHp: 18,
};
const e = enc([combatant]);
const { encounter } = successResult(e, "A", 16);
const updated = encounter.combatants[0];
expect(updated.ac).toBe(16);
expect(updated.name).toBe("Aria");
expect(updated.initiative).toBe(15);
expect(updated.maxHp).toBe(20);
expect(updated.currentHp).toBe(18);
});
it("does not reorder combatants", () => {
const e = enc([makeCombatant("A"), makeCombatant("B")]);
const { encounter } = successResult(e, "B", 18);
expect(encounter.combatants[0].id).toBe(combatantId("A"));
expect(encounter.combatants[1].id).toBe(combatantId("B"));
});
it("preserves activeIndex and roundNumber", () => {
const e = enc([makeCombatant("A"), makeCombatant("B")], 1, 5);
const { encounter } = successResult(e, "A", 14);
expect(encounter.activeIndex).toBe(1);
expect(encounter.roundNumber).toBe(5);
});
it("does not mutate input encounter", () => {
const e = enc([makeCombatant("A")]);
const original = JSON.parse(JSON.stringify(e));
setAc(e, combatantId("A"), 10);
expect(e).toEqual(original);
});
});