Files
healer-man/src/ui/partyResurrection.test.ts
T
2026-09-12 21:14:41 -04:00

88 lines
4.2 KiB
TypeScript

import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { useCombatStore } from "../game/combatStore";
import { activateDungeonEncounterDefinitions, resetDungeonEncounters } from "../game/dungeonEncounterRuntime";
import { requireDungeonDefinition } from "../game/dungeonRegistry";
import { usePartyStore } from "../game/partyStore";
import { useGameStore } from "../game/store";
import { PartyFrames } from "./PartyFrames";
// Exercise the client HUD against live stores rather than their initial SSR snapshots.
vi.mock("../game/partyStore", async (importOriginal) => {
const actual = await importOriginal<typeof import("../game/partyStore")>();
return { ...actual, usePartyStore: Object.assign(
(select: (state: ReturnType<typeof actual.usePartyStore.getState>) => unknown) => select(actual.usePartyStore.getState()), actual.usePartyStore,
) };
});
vi.mock("../game/combatStore", async (importOriginal) => {
const actual = await importOriginal<typeof import("../game/combatStore")>();
return { ...actual, useCombatStore: Object.assign(
(select: (state: ReturnType<typeof actual.useCombatStore.getState>) => unknown) => select(actual.useCombatStore.getState()), actual.useCombatStore,
) };
});
vi.mock("../game/store", async (importOriginal) => {
const actual = await importOriginal<typeof import("../game/store")>();
return { ...actual, useGameStore: Object.assign(
(select: (state: ReturnType<typeof actual.useGameStore.getState>) => unknown) => select(actual.useGameStore.getState()), actual.useGameStore,
) };
});
const dungeon = requireDungeonDefinition("stormwind-stockade");
const render = () => renderToStaticMarkup(createElement(PartyFrames));
function killMember() {
const member = usePartyStore.getState().members[0];
useCombatStore.getState().commitCompanionActors([{ ...member, health: 0, status: "down" }]);
}
describe("party resurrection UI", () => {
beforeEach(() => {
useGameStore.getState().activateDungeon("stormwind-stockade");
activateDungeonEncounterDefinitions(dungeon.id, dungeon.encounters ?? []);
resetDungeonEncounters("dungeon", dungeon.id);
useCombatStore.getState().initializeCharacter({ classId: "priest", level: 16 });
useCombatStore.setState({ mobs: {} });
usePartyStore.getState().initializeParty("rez-ui", 16, useCombatStore.getState().health);
useCombatStore.getState().synchronizeActors();
});
it("hides the control when all NPCs are alive, even if only the player is dead", () => {
expect(render()).not.toContain("Rez dead members");
useCombatStore.getState().damagePlayer(useCombatStore.getState().maxHealth * 10);
expect(render()).not.toContain("Rez dead members");
});
it("places the button and labeled destination selector below every party frame", () => {
killMember();
const markup = render();
expect(markup).toContain("Rez dead members");
expect(markup).toContain("Resurrect at");
expect(markup).toContain("Dungeon entrance");
expect(markup.indexOf("party-resurrection")).toBeGreaterThan(markup.lastIndexOf("party-frame__identity"));
expect(markup).not.toMatch(/class="party-rez-button" disabled/);
});
it("shows why resurrection is disabled during a living boss encounter", () => {
killMember();
useCombatStore.getState().registerMob("boss", { name: "Boss", boss: true, maxHealth: 100 });
useCombatStore.getState().damageMob("boss", 1, 100);
expect(render()).toMatch(/class="party-rez-button" disabled=""/);
expect(render()).toContain("Unavailable during boss combat");
});
it("offers killed boss destinations but not bosses that are still alive", () => {
killMember();
const boss = dungeon.bosses[0];
expect(render()).not.toContain(`value="boss:${boss.id}"`);
useCombatStore.getState().registerMob(boss.id, { name: boss.name, boss: true, maxHealth: 1 });
useCombatStore.getState().damageMob(boss.id, 1, 100);
expect(render()).toContain(`value="boss:${boss.id}"`);
});
it("does not offer free resurrection in Manastorm", () => {
killMember();
useGameStore.setState({ gameMode: "manastorm" });
expect(render()).not.toContain("Rez dead members");
});
});