Files
healer-man/src/game/dpsMeter.test.ts
T
2026-09-12 21:14:41 -04:00

43 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { advanceDpsMeter, dpsMeterSnapshot, emptyDpsMeter, recordDpsDamage } from "./dpsMeter";
import type { StructuredCombatEvent } from "./combatEvents";
const actor = { id: "player", name: "You", color: "#fff" };
function damage(id: number, effectiveAmount = 10): StructuredCombatEvent {
return { id, occurredAt: 1_000 + id * 10, kind: "damage", sourceActorId: actor.id,
targetActorId: "enemy", rawAmount: 100, effectiveAmount, overheal: 0, absorbed: 30, critical: false };
}
describe("DPS fight recorder", () => {
it("keeps effective damage from more than 200 events and ranks everyone over the same fight duration", () => {
let state = advanceDpsMeter(emptyDpsMeter(), 1_000, true);
for (let id = 1; id <= 1_000; id++) state = recordDpsDamage(state, damage(id), actor);
const ally = { id: "ally", name: "Ally", color: "#f00" };
state = recordDpsDamage(state, { ...damage(1_000), effectiveAmount: 5_000 }, ally);
const snapshot = dpsMeterSnapshot(state, [{ id: "healer", name: "Healer", color: "#0f0" }]);
expect(snapshot).toMatchObject({ totalDamage: 15_000, totalDps: 1_500, durationSeconds: 10 });
expect(snapshot.rows.map((row) => [row.id, row.dps, row.percent])).toEqual([
["player", 1_000, 100], ["ally", 500, 50], ["healer", 0, 0],
]);
});
it("freezes the last fight, starts fresh on the next pull, and excludes menu time", () => {
let state = recordDpsDamage(emptyDpsMeter(), damage(0, 100), actor);
state = advanceDpsMeter(state, 2_000, true);
state = advanceDpsMeter(state, 12_000, true, true);
state = advanceDpsMeter(state, 13_000, false);
expect(dpsMeterSnapshot(state)).toMatchObject({ active: false, durationSeconds: 2, totalDps: 50 });
expect(advanceDpsMeter(state, 30_000, false)).toBe(state);
state = recordDpsDamage(state, { ...damage(0, 20), occurredAt: 31_000 }, actor);
expect(dpsMeterSnapshot(state)).toMatchObject({ active: true, durationSeconds: 0, totalDamage: 20, totalDps: 20 });
});
it("ignores misses, healing, invalid damage, and clock regressions", () => {
const empty = emptyDpsMeter();
expect(recordDpsDamage(empty, damage(0, 0), actor)).toBe(empty);
expect(recordDpsDamage(empty, damage(0, NaN), actor)).toBe(empty);
expect(recordDpsDamage(empty, { ...damage(0), kind: "healing" }, actor)).toBe(empty);
let state = recordDpsDamage(empty, damage(0), actor);
state = advanceDpsMeter(state, 900, true);
expect(state.elapsedMs).toBe(0);
});
});