Update Healer Man server

This commit is contained in:
phenom committed 2026-09-26 18:57:44 -04:00
1 parent bd073fb00f
commit 83eac6d476
15 files changed
+438 -272

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useDungeonRaceStore, type RaceServerState } from "./dungeonRaceStore";
import type { CharacterProfile, PlayerSession } from "./types";
const request = vi.hoisted(() => vi.fn());
vi.mock("./onlineAccountClient", () => ({ requestOnlineJson: request }));
const session: PlayerSession = {
kind: "account", ownerId: "player-1", displayName: "Racer", accessToken: "race-token",
};
const character = { id: "character-1" } as CharacterProfile;
const queued: RaceServerState = { status: "queued", serverTime: Date.now(), joinedAt: Date.now() };
function deferred<T>() {
let resolve!: (value: T) => void;
const promise = new Promise<T>((done) => { resolve = done; });
return { promise, resolve };
}
describe("dungeon race exit", () => {
beforeEach(() => {
request.mockReset();
useDungeonRaceStore.getState().reset();
});
afterEach(() => useDungeonRaceStore.getState().reset());
it("clears an active race immediately and waits for the server leave before requeuing", async () => {
const deleteRequest = deferred<RaceServerState>();
request.mockImplementation((path: string, init: RequestInit) =>
path === "/api/dungeon-races/queue" && init.method === "DELETE"
? deleteRequest.promise : Promise.resolve(queued));
await useDungeonRaceStore.getState().startOnline(session, character, "healer", "authored");
useDungeonRaceStore.setState({ status: "active", inGame: true, matchId: "old-match",
dungeonId: "bite-sized-stormwind-stockade", startAt: Date.now() - 10_000 });
const leaving = useDungeonRaceStore.getState().leave();
expect(useDungeonRaceStore.getState()).toMatchObject({ mode: null, status: "idle", inGame: false,
matchId: null, startAt: null });
const requeue = useDungeonRaceStore.getState().startOnline(session, character, "healer", "authored");
await Promise.resolve();
expect(request.mock.calls.filter(([, init]) => init.method === "POST")).toHaveLength(1);
deleteRequest.resolve(queued);
await Promise.all([leaving, requeue]);
expect(request.mock.calls.map(([, init]) => init.method)).toEqual(["POST", "DELETE", "POST"]);
expect(useDungeonRaceStore.getState().status).toBe("queued");
});
it("cancels a queue request in flight without restoring its late response", async () => {
const firstQueue = deferred<RaceServerState>();
request.mockImplementation((path: string, init: RequestInit) =>
path === "/api/dungeon-races/queue" && init.method === "POST"
? firstQueue.promise : Promise.resolve(queued));
const starting = useDungeonRaceStore.getState().startOnline(session, character, "healer", "authored");
const leaving = useDungeonRaceStore.getState().leave();
expect(useDungeonRaceStore.getState().mode).toBeNull();
firstQueue.resolve(queued);
await Promise.all([starting, leaving]);
expect(useDungeonRaceStore.getState()).toMatchObject({ mode: null, status: "idle", matchId: null });
expect(request.mock.calls.map(([, init]) => init.method)).toEqual(["POST", "DELETE"]);
});
it("ignores an older preparation response after the match has started", async () => {
const stale = deferred<RaceServerState>();
request.mockImplementation((path: string) => path === "/api/dungeon-races/state"
? stale.promise : Promise.resolve(queued));
await useDungeonRaceStore.getState().startOnline(session, character, "healer", "authored");
useDungeonRaceStore.setState({ status: "active", matchId: "race-1", inGame: true });
const syncing = useDungeonRaceStore.getState().sync();
stale.resolve({ status: "preparing", matchId: "race-1", serverTime: Date.now() });
await syncing;
expect(useDungeonRaceStore.getState().status).toBe("active");
});
it("ends offline practice locally without a server request", async () => {
useDungeonRaceStore.setState({ mode: "practice", status: "settled", inGame: true,
matchId: "practice-1", startAt: Date.now() - 30_000, result: "loss" });
await useDungeonRaceStore.getState().leave();
expect(useDungeonRaceStore.getState()).toMatchObject({ mode: null, status: "idle", inGame: false,
matchId: null, startAt: null, result: null });
expect(request).not.toHaveBeenCalled();
});
});