107 lines
5.0 KiB
TypeScript
107 lines
5.0 KiB
TypeScript
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<Parameters<typeof wow335PaladinIlluminationRefundPlan>[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,
|
|
});
|
|
});
|
|
});
|