13 new test files for untested components (color-palette, player-management, stat-block, settings-modal, export/import dialogs, bulk-import-prompt, source-fetch-prompt, player-character-section) and hooks (use-long-press, use-swipe-to-dismiss, use-bulk-import, use-initiative-rolls). Expand combatant-row tests with inline editing, HP popover, and condition picker. Component coverage: 59% → 80% lines, 55% → 71% branches Hook coverage: 72% → 83% lines, 55% → 66% branches Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
// @vitest-environment jsdom
|
|
import "@testing-library/jest-dom/vitest";
|
|
|
|
import { type CreatureId, combatantId } from "@initiative/domain";
|
|
import { act, renderHook } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { useInitiativeRolls } from "../use-initiative-rolls.js";
|
|
|
|
const mockMakeStore = vi.fn(() => ({}));
|
|
const mockWithUndo = vi.fn((fn: () => unknown) => fn());
|
|
const mockGetCreature = vi.fn();
|
|
const mockShowCreature = vi.fn();
|
|
|
|
vi.mock("../../contexts/encounter-context.js", () => ({
|
|
useEncounterContext: () => ({
|
|
encounter: {
|
|
combatants: [
|
|
{
|
|
id: combatantId("c1"),
|
|
name: "Goblin",
|
|
creatureId: "srd:goblin" as CreatureId,
|
|
},
|
|
],
|
|
activeIndex: 0,
|
|
roundNumber: 1,
|
|
},
|
|
makeStore: mockMakeStore,
|
|
withUndo: mockWithUndo,
|
|
}),
|
|
}));
|
|
|
|
vi.mock("../../contexts/bestiary-context.js", () => ({
|
|
useBestiaryContext: () => ({
|
|
getCreature: mockGetCreature,
|
|
}),
|
|
}));
|
|
|
|
vi.mock("../../contexts/side-panel-context.js", () => ({
|
|
useSidePanelContext: () => ({
|
|
showCreature: mockShowCreature,
|
|
}),
|
|
}));
|
|
|
|
const mockRollInitiativeUseCase = vi.fn();
|
|
const mockRollAllInitiativeUseCase = vi.fn();
|
|
|
|
vi.mock("@initiative/application", () => ({
|
|
rollInitiativeUseCase: (...args: unknown[]) =>
|
|
mockRollInitiativeUseCase(...args),
|
|
rollAllInitiativeUseCase: (...args: unknown[]) =>
|
|
mockRollAllInitiativeUseCase(...args),
|
|
}));
|
|
|
|
function wrapper({ children }: { children: ReactNode }) {
|
|
return children;
|
|
}
|
|
|
|
describe("useInitiativeRolls", () => {
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("handleRollInitiative calls rollInitiativeUseCase via withUndo", () => {
|
|
mockRollInitiativeUseCase.mockReturnValue({ initiative: 15 });
|
|
const { result } = renderHook(() => useInitiativeRolls(), { wrapper });
|
|
|
|
act(() => result.current.handleRollInitiative(combatantId("c1")));
|
|
|
|
expect(mockWithUndo).toHaveBeenCalled();
|
|
expect(mockRollInitiativeUseCase).toHaveBeenCalled();
|
|
});
|
|
|
|
it("sets rollSingleSkipped on domain error", () => {
|
|
mockRollInitiativeUseCase.mockReturnValue({
|
|
kind: "domain-error",
|
|
code: "missing-source",
|
|
message: "no source",
|
|
});
|
|
const { result } = renderHook(() => useInitiativeRolls(), { wrapper });
|
|
|
|
act(() => result.current.handleRollInitiative(combatantId("c1")));
|
|
expect(result.current.rollSingleSkipped).toBe(true);
|
|
expect(mockShowCreature).toHaveBeenCalledWith("srd:goblin");
|
|
});
|
|
|
|
it("dismissRollSingleSkipped resets the flag", () => {
|
|
mockRollInitiativeUseCase.mockReturnValue({
|
|
kind: "domain-error",
|
|
code: "missing-source",
|
|
message: "no source",
|
|
});
|
|
const { result } = renderHook(() => useInitiativeRolls(), { wrapper });
|
|
|
|
act(() => result.current.handleRollInitiative(combatantId("c1")));
|
|
expect(result.current.rollSingleSkipped).toBe(true);
|
|
|
|
act(() => result.current.dismissRollSingleSkipped());
|
|
expect(result.current.rollSingleSkipped).toBe(false);
|
|
});
|
|
|
|
it("handleRollAllInitiative sets rollSkippedCount when sources missing", () => {
|
|
mockRollAllInitiativeUseCase.mockReturnValue({ skippedNoSource: 3 });
|
|
const { result } = renderHook(() => useInitiativeRolls(), { wrapper });
|
|
|
|
act(() => result.current.handleRollAllInitiative());
|
|
expect(result.current.rollSkippedCount).toBe(3);
|
|
});
|
|
|
|
it("dismissRollSkipped resets the count", () => {
|
|
mockRollAllInitiativeUseCase.mockReturnValue({ skippedNoSource: 2 });
|
|
const { result } = renderHook(() => useInitiativeRolls(), { wrapper });
|
|
|
|
act(() => result.current.handleRollAllInitiative());
|
|
act(() => result.current.dismissRollSkipped());
|
|
expect(result.current.rollSkippedCount).toBe(0);
|
|
});
|
|
});
|