169 lines
6.6 KiB
TypeScript
169 lines
6.6 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import type { OnlineGroupActivity } from "./onlineGroupTypes";
|
|
import { enterOnlineGroupActivity, onlineGroupActivityNeedsEntry } from "./OnlineGroupCoordinator";
|
|
import { SHELVED_MODES_ENABLED } from "./releaseFeatures";
|
|
|
|
const normalReleaseIt = SHELVED_MODES_ENABLED ? it.skip : it;
|
|
const shelvedModeIt = SHELVED_MODES_ENABLED ? it : it.skip;
|
|
|
|
const DUNGEON_ACTIVITY: OnlineGroupActivity = {
|
|
id: "activity-dungeon-1",
|
|
type: "dungeon",
|
|
contentId: "deadmines",
|
|
fillWithAi: true,
|
|
partySize: 5,
|
|
startingLevel: null,
|
|
startedAt: 1,
|
|
};
|
|
|
|
const MANASTORM_ACTIVITY: OnlineGroupActivity = {
|
|
...DUNGEON_ACTIVITY,
|
|
id: "activity-manastorm-1",
|
|
type: "manastorm",
|
|
partySize: 3,
|
|
startingLevel: 6,
|
|
};
|
|
|
|
function entryDependencies(enterDungeon: () => boolean) {
|
|
return {
|
|
prepareDungeonContent: vi.fn(async () => undefined),
|
|
prepareRandomizedDungeonContent: vi.fn(async () => undefined),
|
|
installDungeonRuntime: vi.fn(async () => undefined),
|
|
enterDungeon: vi.fn(enterDungeon),
|
|
installManastormRuntime: vi.fn(async () => undefined),
|
|
enterManastorm: vi.fn(() => true),
|
|
};
|
|
}
|
|
|
|
describe("online group activity entry", () => {
|
|
it("recognizes a newly published activity while the previous activity is still active", () => {
|
|
const next = { ...DUNGEON_ACTIVITY, id: "activity-dungeon-2", startedAt: 10_000 };
|
|
expect(onlineGroupActivityNeedsEntry(next, DUNGEON_ACTIVITY, [DUNGEON_ACTIVITY.id], 10_100)).toBe(true);
|
|
expect(onlineGroupActivityNeedsEntry(DUNGEON_ACTIVITY, DUNGEON_ACTIVITY, [], 10_100)).toBe(false);
|
|
});
|
|
|
|
it("enters with the leader's source variant and boss difficulty as a fresh shared run", async () => {
|
|
const dependencies = entryDependencies(() => true);
|
|
await enterOnlineGroupActivity({ ...DUNGEON_ACTIVITY, difficultyId: "heroic", bossDifficulty: 9 },
|
|
"damage", vi.fn(), dependencies);
|
|
expect(dependencies.prepareDungeonContent).toHaveBeenCalledWith("deadmines");
|
|
expect(dependencies.prepareDungeonContent.mock.invocationCallOrder[0])
|
|
.toBeLessThan(dependencies.enterDungeon.mock.invocationCallOrder[0]);
|
|
expect(dependencies.enterDungeon).toHaveBeenCalledWith("deadmines", "damage", {
|
|
difficultyId: "heroic", bossDifficulty: 9, freshRun: true, runId: DUNGEON_ACTIVITY.id,
|
|
});
|
|
});
|
|
it("downloads the seeded randomized creature packs before shared entry", async () => {
|
|
const dependencies = entryDependencies(() => true);
|
|
const activity = {
|
|
...DUNGEON_ACTIVITY,
|
|
id: "shared-randomized-seed",
|
|
contentId: "randomized-bite-sized-stormwind-stockade",
|
|
};
|
|
|
|
await enterOnlineGroupActivity(activity, "healer", vi.fn(), dependencies);
|
|
|
|
expect(dependencies.prepareDungeonContent).toHaveBeenCalledWith(activity.contentId);
|
|
expect(dependencies.prepareRandomizedDungeonContent).toHaveBeenCalledWith(activity.id, activity.contentId);
|
|
expect(dependencies.prepareRandomizedDungeonContent.mock.invocationCallOrder[0])
|
|
.toBeLessThan(dependencies.enterDungeon.mock.invocationCallOrder[0]);
|
|
});
|
|
it("does not enter a shared dungeon when its content download fails", async () => {
|
|
const dependencies = entryDependencies(() => true);
|
|
dependencies.prepareDungeonContent.mockRejectedValueOnce(new Error("Download failed"));
|
|
const consumeActivity = vi.fn();
|
|
|
|
await expect(enterOnlineGroupActivity(DUNGEON_ACTIVITY, "healer", consumeActivity, dependencies))
|
|
.rejects.toThrow("Download failed");
|
|
expect(dependencies.enterDungeon).not.toHaveBeenCalled();
|
|
expect(consumeActivity).not.toHaveBeenCalled();
|
|
});
|
|
it("leaves a dungeon activity unconsumed when dungeon entry fails", async () => {
|
|
const consumeActivity = vi.fn();
|
|
const dependencies = entryDependencies(() => false);
|
|
|
|
await expect(enterOnlineGroupActivity(
|
|
DUNGEON_ACTIVITY,
|
|
"healer",
|
|
consumeActivity,
|
|
dependencies,
|
|
)).resolves.toBe(false);
|
|
|
|
expect(dependencies.installDungeonRuntime).toHaveBeenCalledOnce();
|
|
expect(dependencies.enterDungeon).toHaveBeenCalledWith("deadmines", "healer", {
|
|
difficultyId: undefined, bossDifficulty: undefined, freshRun: true, runId: DUNGEON_ACTIVITY.id,
|
|
});
|
|
expect(consumeActivity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("can retry the same dungeon activity and consumes it only after entry succeeds", async () => {
|
|
const consumeActivity = vi.fn();
|
|
const enterDungeon = vi.fn()
|
|
.mockReturnValueOnce(false)
|
|
.mockReturnValueOnce(true);
|
|
const dependencies = entryDependencies(enterDungeon);
|
|
|
|
await enterOnlineGroupActivity(DUNGEON_ACTIVITY, "tank", consumeActivity, dependencies);
|
|
expect(consumeActivity).not.toHaveBeenCalled();
|
|
|
|
await expect(enterOnlineGroupActivity(
|
|
DUNGEON_ACTIVITY,
|
|
"tank",
|
|
consumeActivity,
|
|
dependencies,
|
|
)).resolves.toBe(true);
|
|
|
|
expect(dependencies.enterDungeon).toHaveBeenCalledTimes(2);
|
|
expect(consumeActivity).toHaveBeenCalledOnce();
|
|
expect(consumeActivity).toHaveBeenCalledWith(DUNGEON_ACTIVITY.id);
|
|
});
|
|
|
|
it("does not consume the activity when loading the dungeon runtime throws", async () => {
|
|
const consumeActivity = vi.fn();
|
|
const dependencies = entryDependencies(() => true);
|
|
dependencies.installDungeonRuntime.mockRejectedValueOnce(new Error("runtime unavailable"));
|
|
|
|
await expect(enterOnlineGroupActivity(
|
|
DUNGEON_ACTIVITY,
|
|
"damage",
|
|
consumeActivity,
|
|
dependencies,
|
|
)).rejects.toThrow("runtime unavailable");
|
|
|
|
expect(dependencies.enterDungeon).not.toHaveBeenCalled();
|
|
expect(consumeActivity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
normalReleaseIt("does not load or enter a shelved group activity", async () => {
|
|
const consumeActivity = vi.fn();
|
|
const dependencies = entryDependencies(() => true);
|
|
|
|
await expect(enterOnlineGroupActivity(
|
|
MANASTORM_ACTIVITY,
|
|
"healer",
|
|
consumeActivity,
|
|
dependencies,
|
|
)).resolves.toBe(false);
|
|
|
|
expect(dependencies.installManastormRuntime).not.toHaveBeenCalled();
|
|
expect(dependencies.enterManastorm).not.toHaveBeenCalled();
|
|
expect(consumeActivity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
shelvedModeIt("restores Manastorm group entry in the developer mode", async () => {
|
|
const consumeActivity = vi.fn();
|
|
const dependencies = entryDependencies(() => true);
|
|
|
|
await expect(enterOnlineGroupActivity(
|
|
MANASTORM_ACTIVITY,
|
|
"healer",
|
|
consumeActivity,
|
|
dependencies,
|
|
)).resolves.toBe(true);
|
|
|
|
expect(dependencies.installManastormRuntime).toHaveBeenCalledOnce();
|
|
expect(dependencies.enterManastorm).toHaveBeenCalledWith("healer", 3, 6);
|
|
expect(consumeActivity).toHaveBeenCalledWith(MANASTORM_ACTIVITY.id);
|
|
});
|
|
});
|