forked from phenom/healer-man
105 lines
6.1 KiB
TypeScript
105 lines
6.1 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import type { PlayerSession } from "./types";
|
|
|
|
function storage() {
|
|
const values = new Map<string, string>();
|
|
return {
|
|
getItem: (key: string) => values.get(key) ?? null,
|
|
setItem: (key: string, value: string) => { values.set(key, value); },
|
|
removeItem: (key: string) => { values.delete(key); },
|
|
};
|
|
}
|
|
|
|
const draft = {
|
|
ownerId: "account-one", name: "Collector", raceId: "human" as const,
|
|
classId: "priest" as const, specializationId: "priest:holy", gender: "female" as const,
|
|
appearance: { skinColor: 0, face: 0, hairStyle: 0, hairColor: 0, feature: 0 },
|
|
};
|
|
const session: PlayerSession = { kind: "account", ownerId: draft.ownerId, displayName: "Collector", accessToken: "test-token" };
|
|
const cards = { counts: { "wow:lady anacondra": { normal: 7, rare: 1 } }, lastClaims: { spawn: "200:1:spawn" } };
|
|
|
|
beforeEach(() => { vi.useFakeTimers(); });
|
|
afterEach(() => { vi.useRealTimers(); vi.unstubAllGlobals(); });
|
|
|
|
describe("account boss card integration", () => {
|
|
it("keeps earned cards when switching characters and isolates account sign-in", async () => {
|
|
vi.stubGlobal("window", { localStorage: storage(), sessionStorage: storage() });
|
|
const repository = await import("./accountRepository");
|
|
const { useShellStore } = await import("./shellStore");
|
|
const { useCombatStore } = await import("../game/combatStore");
|
|
const first = repository.createCharacter(draft).character!;
|
|
const second = repository.createCharacter({ ...draft, name: "Other" }).character!;
|
|
const offlineSession: PlayerSession = { ...session, accessToken: undefined };
|
|
const shell = useShellStore.getState();
|
|
shell.beginSession(offlineSession);
|
|
useShellStore.setState({ phase: "game", activeCharacter: first });
|
|
shell.saveAccountBossCards(cards);
|
|
shell.returnToCharacters();
|
|
shell.selectCharacter(second.id);
|
|
expect(useShellStore.getState().bossCards).toEqual(cards);
|
|
useCombatStore.getState().initializeCharacter({ ...second, bossCards: useShellStore.getState().bossCards });
|
|
useCombatStore.getState().collectSharedBossCards({ bossKey: "wow:lady anacondra", spawnId: "spawn", claimId: "300:1:spawn", rarities: ["normal"] }, "Lady Anacondra", 300);
|
|
shell.saveAccountBossCards(useCombatStore.getState().bossCards);
|
|
shell.selectCharacter(first.id);
|
|
expect(useShellStore.getState().bossCards.counts["wow:lady anacondra"]?.normal).toBe(8);
|
|
expect(repository.listCharacters(session.ownerId).every((character) => character.bossCards === undefined)).toBe(true);
|
|
shell.signOut();
|
|
expect(useShellStore.getState().bossCards.counts).toEqual({});
|
|
shell.beginSession({ ...offlineSession, ownerId: "account-two" });
|
|
expect(useShellStore.getState().bossCards.counts).toEqual({});
|
|
shell.beginSession(offlineSession);
|
|
expect(useShellStore.getState().bossCards.counts["wow:lady anacondra"]?.normal).toBe(8);
|
|
});
|
|
|
|
it("uploads the account collection without characters and restores it on another device", async () => {
|
|
const firstDevice = storage();
|
|
const secondDevice = storage();
|
|
vi.stubGlobal("window", { localStorage: firstDevice });
|
|
let cloudData: unknown = { version: 1, characters: [] };
|
|
const fetchMock = vi.fn(async (_url: string, init: RequestInit) => {
|
|
if (init.method === "PUT") cloudData = JSON.parse(String(init.body)).data;
|
|
return new Response(JSON.stringify({ revision: 1, updatedAt: 1, data: cloudData }), { status: 200 });
|
|
});
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
const repository = await import("./accountRepository");
|
|
const client = await import("./onlineAccountClient");
|
|
client.activateOnlineSession(session);
|
|
repository.saveAccountBossCards(session.ownerId, cards);
|
|
await vi.advanceTimersByTimeAsync(501);
|
|
expect(cloudData).toMatchObject({ version: 2, characters: [], bossCards: cards });
|
|
expect(client.useCloudSaveStatus.getState().state).toBe("synced");
|
|
vi.stubGlobal("window", { localStorage: secondDevice });
|
|
await client.hydrateOnlineSession(session);
|
|
expect(repository.loadAccountBossCards(session.ownerId)).toEqual(cards);
|
|
expect(repository.loadAccountBossCards("different-account").counts).toEqual({});
|
|
const { collectBossCardDrop } = await import("../game/bossCards");
|
|
const restored = repository.loadAccountBossCards(session.ownerId);
|
|
expect(collectBossCardDrop(restored, { bossKey: "wow:lady anacondra", spawnId: "spawn", claimId: "200:1:spawn", rarities: ["normal", "rare"] })).toBe(restored);
|
|
await client.logoutOnlineSession(session);
|
|
});
|
|
|
|
it("publishes legacy cloud migration once and preserves it through repeated downloads", async () => {
|
|
vi.stubGlobal("window", { localStorage: storage() });
|
|
const repository = await import("./accountRepository");
|
|
const first = repository.createCharacter(draft).character!;
|
|
const second = repository.createCharacter({ ...draft, name: "Other" }).character!;
|
|
let cloudData: unknown = { version: 1, characters: [
|
|
{ ...first, bossCards: cards },
|
|
{ ...second, bossCards: { counts: { "wow:lady anacondra": { normal: 3 } }, lastClaims: {} } },
|
|
] };
|
|
vi.stubGlobal("fetch", vi.fn(async (_url: string, init: RequestInit) => {
|
|
if (init.method === "PUT") cloudData = JSON.parse(String(init.body)).data;
|
|
return new Response(JSON.stringify({ revision: 1, updatedAt: 1, data: cloudData }), { status: 200 });
|
|
}));
|
|
const client = await import("./onlineAccountClient");
|
|
await client.hydrateOnlineSession(session);
|
|
expect(repository.loadAccountBossCards(session.ownerId).counts["wow:lady anacondra"]?.normal).toBe(10);
|
|
await vi.advanceTimersByTimeAsync(501);
|
|
expect(cloudData).toMatchObject({ version: 2, bossCards: { counts: { "wow:lady anacondra": { normal: 10, rare: 1 } } } });
|
|
expect((cloudData as { characters: { bossCards?: unknown }[] }).characters.every((character) => character.bossCards === undefined)).toBe(true);
|
|
await client.hydrateOnlineSession(session);
|
|
expect(repository.loadAccountBossCards(session.ownerId).counts["wow:lady anacondra"]?.normal).toBe(10);
|
|
await client.logoutOnlineSession(session);
|
|
});
|
|
});
|