Files
initiative/packages/application/src/__tests__/helpers.ts
Lukas 5a262c66cd Add test coverage for all 17 application layer use cases
Tests verify the get→call→save wiring and error propagation for each
use case. The 15 formulaic use cases share a test file; rollInitiative
and rollAllInitiative have dedicated suites covering their multi-step
logic (creature lookup, modifier calculation, iteration, early return).

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

55 lines
1.4 KiB
TypeScript

import type { Encounter, PlayerCharacter } from "@initiative/domain";
import { isDomainError } from "@initiative/domain";
import type { EncounterStore, PlayerCharacterStore } from "../ports.js";
export function requireSaved<T>(value: T | null): T {
if (value === null) throw new Error("Expected store.saved to be non-null");
return value;
}
export function expectSuccess<T>(
result: T,
): asserts result is Exclude<T, { kind: "domain-error" }> {
if (isDomainError(result)) {
throw new Error(`Expected success, got domain error: ${result.message}`);
}
}
export function expectError(result: unknown): asserts result is {
kind: "domain-error";
code: string;
message: string;
} {
if (!isDomainError(result)) {
throw new Error("Expected domain error");
}
}
export function stubEncounterStore(
initial: Encounter,
): EncounterStore & { saved: Encounter | null } {
const stub = {
saved: null as Encounter | null,
get: () => initial,
save: (e: Encounter) => {
stub.saved = e;
stub.get = () => e;
},
};
return stub;
}
export function stubPlayerCharacterStore(
initial: readonly PlayerCharacter[],
): PlayerCharacterStore & { saved: readonly PlayerCharacter[] | null } {
const stub = {
saved: null as readonly PlayerCharacter[] | null,
getAll: () => [...initial],
save: (characters: PlayerCharacter[]) => {
stub.saved = characters;
stub.getAll = () => [...characters];
},
};
return stub;
}