import { describe, expect, it } from "vitest"; import { WOW335_ABILITIES_BY_CLASS } from "./wow335AbilityCatalog"; import { WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS, WOW335_PALADIN_ILLUMINATION_TALENT_ID, wow335PaladinIlluminationRankMechanics, wow335PaladinIlluminationRefundPlan, } from "./wow335PaladinIlluminationRuntime"; const event = (overrides: Partial[1]> = {}) => ({ casterClassId: "paladin", abilityId: WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS["Holy Light"], abilityName: "Holy Light", criticalHeal: true, spellBaseManaCost: 1_000, roll: 0.5, ...overrides, }); describe("WoW 3.3.5a Paladin Illumination", () => { it("reads the exact generated rank chance and 50% base-mana refund", () => { expect(WOW335_PALADIN_ILLUMINATION_TALENT_ID).toBe("talent-1461"); expect(WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS).toEqual({ "Flash of Light": "wow335-paladin-flash-of-light", "Holy Light": "wow335-paladin-holy-light", "Holy Shock": "wow335-paladin-holy-shock", }); expect([1, 2, 3].map(wow335PaladinIlluminationRankMechanics)).toEqual([ expect.objectContaining({ procChancePercent: 33, baseManaRefundFraction: 0.5 }), expect.objectContaining({ procChancePercent: 66, baseManaRefundFraction: 0.5 }), expect.objectContaining({ procChancePercent: 100, baseManaRefundFraction: 0.5 }), ]); expect(wow335PaladinIlluminationRankMechanics(0)).toBeNull(); expect(wow335PaladinIlluminationRankMechanics(4)).toBeNull(); }); it("binds each tooltip heal name to a local 3.3.5a Paladin catalog row", () => { const rows = new Map(WOW335_ABILITIES_BY_CLASS.paladin.map((ability) => [ability.name, ability])); const rankOneSpellId = { "Flash of Light": 19_750, "Holy Light": 635, "Holy Shock": 20_473 }; for (const [name, id] of Object.entries(WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS)) { expect(rows.get(name)?.id).toBe(id); expect(rows.get(name)?.source).toBe("wow335-progression"); expect(rows.get(name)?.dbcSpellId).toBe(rankOneSpellId[name as keyof typeof rankOneSpellId]); expect(rows.get(name)?.ranks?.length).toBeGreaterThan(0); expect(rows.get(name)?.ranks?.[0]?.cost.resource).toBe("mana"); } }); it("uses only Flash of Light, Holy Light, and Holy Shock critical heals", () => { const mechanics = wow335PaladinIlluminationRankMechanics(3)!; expect(mechanics.eligibleHealNames).toEqual(["Flash of Light", "Holy Light", "Holy Shock"]); for (const abilityName of mechanics.eligibleHealNames) { expect(wow335PaladinIlluminationRefundPlan(3, event({ abilityName, abilityId: WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS[ abilityName as keyof typeof WOW335_PALADIN_ILLUMINATION_HEAL_ABILITY_IDS ], }))).toEqual({ manaRefund: 500, procChancePercent: 100, }); } expect(wow335PaladinIlluminationRefundPlan(3, event({ abilityName: "Divine Light" }))).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(3, event({ casterClassId: "mage", abilityId: "wow335-mage-holy-light", }))).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(3, event({ abilityId: "rom-priest-flash-of-light" }))).toBeNull(); }); it("applies rank chance to critical heals and treats the upper boundary as exclusive", () => { expect(wow335PaladinIlluminationRefundPlan(1, event({ roll: 0.3299 }))).toEqual({ manaRefund: 500, procChancePercent: 33, }); expect(wow335PaladinIlluminationRefundPlan(1, event({ roll: 0.33 }))).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(2, event({ roll: 0.6599 }))).not.toBeNull(); expect(wow335PaladinIlluminationRefundPlan(2, event({ roll: 0.66 }))).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(3, event({ roll: 0.9999 }))).not.toBeNull(); }); it("requires a critical heal but does not require effective healing above zero", () => { expect(wow335PaladinIlluminationRefundPlan(3, event({ criticalHeal: false }))).toBeNull(); // The source trigger is a critical heal, so an overheal remains eligible. expect(wow335PaladinIlluminationRefundPlan(3, event())).toEqual({ manaRefund: 500, procChancePercent: 100, }); }); it("rejects invalid rank, base cost, and random inputs", () => { expect(wow335PaladinIlluminationRefundPlan(0, event())).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(3, event({ spellBaseManaCost: 0 }))).toBeNull(); expect(wow335PaladinIlluminationRefundPlan(3, event({ spellBaseManaCost: Number.NaN }))).toBeNull(); for (const roll of [-0.01, 1, Number.NaN, Number.POSITIVE_INFINITY]) { expect(wow335PaladinIlluminationRefundPlan(3, event({ roll }))).toBeNull(); } }); it("calculates the refund from the DBC-derived base cost without inventing odd-cost rounding", () => { expect(wow335PaladinIlluminationRefundPlan(3, event({ spellBaseManaCost: 703 }))).toEqual({ manaRefund: 351.5, procChancePercent: 100, }); }); });