/* eslint-disable max-lines-per-function -- Test suites naturally have many cases */ /* eslint-disable @typescript-eslint/consistent-type-assertions -- Tests build minimal state objects */ import { describe, expect, it } from "vitest"; import { buildPostTranscendenceState, calculateEchoes, computeTranscendenceMultipliers, isEligibleForTranscendence, } from "../../src/services/transcendence.js"; import type { GameState } from "@elysium/types"; const makeMinimalState = (overrides: Partial = {}): GameState => ({ player: { discordId: "t", username: "u", discriminator: "0", avatar: null, totalGoldEarned: 0, totalClicks: 0, characterName: "T" }, resources: { gold: 0, essence: 0, crystals: 0, runestones: 0 }, adventurers: [], upgrades: [], quests: [], bosses: [], equipment: [], achievements: [], zones: [], exploration: { areas: [], materials: [], craftedRecipeIds: [], craftedGoldMultiplier: 1, craftedEssenceMultiplier: 1, craftedClickMultiplier: 1, craftedCombatMultiplier: 1 }, companions: { unlockedCompanionIds: [], activeCompanionId: null }, prestige: { count: 0, runestones: 0, productionMultiplier: 1, purchasedUpgradeIds: [] }, baseClickPower: 1, lastTickAt: 0, schemaVersion: 1, ...overrides, } as GameState); describe("computeTranscendenceMultipliers", () => { it("returns all 1s with empty ids", () => { const result = computeTranscendenceMultipliers([]); expect(result.echoIncomeMultiplier).toBe(1); expect(result.echoCombatMultiplier).toBe(1); expect(result.echoPrestigeThresholdMultiplier).toBe(1); expect(result.echoPrestigeRunestoneMultiplier).toBe(1); expect(result.echoMetaMultiplier).toBe(1); }); it("applies income upgrade when purchased", () => { const result = computeTranscendenceMultipliers(["echo_income_1"]); expect(result.echoIncomeMultiplier).toBeGreaterThan(1); expect(result.echoCombatMultiplier).toBe(1); }); it("applies combat upgrade when purchased", () => { const result = computeTranscendenceMultipliers(["echo_combat_1"]); expect(result.echoCombatMultiplier).toBeGreaterThan(1); expect(result.echoIncomeMultiplier).toBe(1); }); it("applies prestige_threshold upgrade when purchased", () => { const result = computeTranscendenceMultipliers(["echo_prestige_threshold_1"]); expect(result.echoPrestigeThresholdMultiplier).not.toBe(1); }); it("applies prestige_runestones upgrade when purchased", () => { const result = computeTranscendenceMultipliers(["echo_prestige_runestones_1"]); expect(result.echoPrestigeRunestoneMultiplier).toBeGreaterThan(1); }); it("applies echo_meta upgrade when purchased", () => { const result = computeTranscendenceMultipliers(["echo_meta_1"]); expect(result.echoMetaMultiplier).toBeGreaterThan(1); }); }); describe("isEligibleForTranscendence", () => { it("returns true when final boss is defeated", () => { const state = makeMinimalState({ bosses: [{ id: "the_absolute_one", status: "defeated" }] as GameState["bosses"], }); expect(isEligibleForTranscendence(state)).toBe(true); }); it("returns false when final boss is available but not defeated", () => { const state = makeMinimalState({ bosses: [{ id: "the_absolute_one", status: "available" }] as GameState["bosses"], }); expect(isEligibleForTranscendence(state)).toBe(false); }); it("returns false when final boss is not in the list", () => { const state = makeMinimalState({ bosses: [] }); expect(isEligibleForTranscendence(state)).toBe(false); }); it("returns false when a different boss is defeated", () => { const state = makeMinimalState({ bosses: [{ id: "some_other_boss", status: "defeated" }] as GameState["bosses"], }); expect(isEligibleForTranscendence(state)).toBe(false); }); }); describe("calculateEchoes", () => { it("handles prestige count of 0 by treating it as 1", () => { // safeCount = max(0, 1) = 1; floor(224 / sqrt(1)) = 224 expect(calculateEchoes(0, 1)).toBe(224); }); it("calculates echoes at count 1", () => { // floor(224 / sqrt(1)) = 224 expect(calculateEchoes(1, 1)).toBe(224); }); it("decreases echoes with higher prestige count", () => { const echoesAt1 = calculateEchoes(1, 1); const echoesAt4 = calculateEchoes(4, 1); expect(echoesAt4).toBeLessThan(echoesAt1); // floor(224 / sqrt(4)) = floor(224 / 2) = 112 expect(echoesAt4).toBe(112); }); it("applies echoMetaMultiplier", () => { const base = calculateEchoes(1, 1); const withMult = calculateEchoes(1, 2); expect(withMult).toBe(base * 2); }); it("returns 50 echoes at the target prestige 20", () => { // floor(224 / sqrt(20)) = floor(224 / 4.472) = floor(50.09) = 50 expect(calculateEchoes(20, 1)).toBe(50); }); }); describe("buildPostTranscendenceState", () => { it("increments transcendence count from 0", () => { const state = makeMinimalState(); const { transcendenceData } = buildPostTranscendenceState(state, "T"); expect(transcendenceData.count).toBe(1); }); it("accumulates echoes", () => { const state = makeMinimalState({ transcendence: { count: 1, echoes: 100, purchasedUpgradeIds: [], echoIncomeMultiplier: 1, echoCombatMultiplier: 1, echoPrestigeThresholdMultiplier: 1, echoPrestigeRunestoneMultiplier: 1, echoMetaMultiplier: 1, }, }); const { transcendenceData, echoesEarned } = buildPostTranscendenceState(state, "T"); expect(transcendenceData.echoes).toBe(100 + echoesEarned); }); it("persists codex from current state", () => { const codex = { entries: [{ id: "e1", unlockedAt: 1000, sourceType: "exploration" as const }] }; const state = makeMinimalState({ codex }); const { transcendenceState } = buildPostTranscendenceState(state, "T"); expect(transcendenceState.codex).toEqual(codex); }); it("persists story from current state", () => { const story = { unlockedChapterIds: ["ch1"], completedChapters: [] }; const state = makeMinimalState({ story }); const { transcendenceState } = buildPostTranscendenceState(state, "T"); expect(transcendenceState.story).toEqual(story); }); it("persists apotheosis from current state", () => { const apotheosis = { count: 2 }; const state = makeMinimalState({ apotheosis }); const { transcendenceState } = buildPostTranscendenceState(state, "T"); expect(transcendenceState.apotheosis).toEqual(apotheosis); }); it("resets prestige to fresh state", () => { const state = makeMinimalState({ prestige: { count: 5, runestones: 500, productionMultiplier: 2, purchasedUpgradeIds: [] }, }); const { transcendenceState } = buildPostTranscendenceState(state, "T"); expect(transcendenceState.prestige.count).toBe(0); expect(transcendenceState.prestige.runestones).toBe(0); }); });