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>
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
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>): 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");
|
|
});
|
|
});
|