dd-timer/tests/regression/gauge-recharge-countdown.test.ts
POL Mickaël 203c423f19 test: 302 tests unitaires + 20 E2E Playwright (couverture 94%)
- Unit : domain (GaugeCalculator, Enclos, Dragodinde, XpTable, Race, Tier...)
- Unit : application (commands, queries, CommandBus)
- Fonctionnel : breeding-workflow, enclos-management, timer-workflow
- Régression : gauge-tier, gauge-recharge, xp-timer, level-target, breeding
- E2E Playwright + Electron : navigation, timer, recharge jauge,
  accouplement, persistance des données

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 05:43:29 +02:00

107 lines
3.5 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { computeGaugeLive, enclosGlobalState } from '@presentation/helpers/gauge-live';
import { createEnclos } from '@domain/entities/Enclos';
import { createDragodinde } from '@domain/entities/Dragodinde';
import type { Enclos } from '@domain/entities/Enclos';
import type { Dragodinde } from '@domain/entities/Dragodinde';
/**
* Régression : après une recharge de jauge en cours de timer,
* le countdown (cntDown) doit être fini (pas Infinity).
*
* Scénario reproduit : la jauge baffeur se vide complètement,
* le joueur la recharge → le countdown doit recalculer à partir
* du nouveau niveau de jauge, pas rester bloqué à ∞.
*/
describe('Régression: countdown fini après recharge de jauge vidée', () => {
const NOW = 1_700_000_000_000; // timestamp fixe
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(NOW);
});
afterEach(() => {
vi.useRealTimers();
});
function buildEnclos(dd: Dragodinde, opts: {
startGl: number;
elapsedSec: number;
recharges?: { atSec: number; level: number }[];
currentGl: number;
}): Enclos {
const enc = createEnclos(1, 'Test');
enc.activeGauges = ['baffeur'];
enc.gaugeLevels = { ...enc.gaugeLevels, baffeur: opts.currentGl };
enc.dragodindes = [dd];
enc.timer = {
running: true,
startTime: NOW - opts.elapsedSec * 1000,
pausedAt: null,
pausedMs: 0,
snapGauges: { baffeur: opts.startGl },
snapStats: { [dd.id]: { serenite: 0, endurance: 0, maturite: 0, amour: 0, xp: 1 } },
gaugeRecharges: opts.recharges
? { baffeur: opts.recharges }
: {},
};
return enc;
}
it('sans recharge et jauge vidée → cntDown est Infinity', () => {
const dd = createDragodinde(1);
// Jauge baffeur départ = 100, elapsed = 200s → largement vidée (100 pts = tier1 10/tick)
// timeToGain(100, 100) = ceil(100/10)*10 = 100s → à 200s la jauge est à 0
const enc = buildEnclos(dd, {
startGl: 100,
elapsedSec: 200,
currentGl: 0,
});
const result = computeGaugeLive(enc, dd, 'baffeur', 200, true);
expect(result.curGl).toBe(0);
expect(result.cntDown).toBe(Infinity);
});
it('après recharge de la jauge vidée → cntDown est fini et > 0', () => {
const dd = createDragodinde(1);
// Jauge baffeur départ = 100, elapsed = 200s
// Recharge à t=150s avec niveau 50000
// À t=200s, la jauge a été rechargée et n'est plus à 0
const enc = buildEnclos(dd, {
startGl: 100,
elapsedSec: 200,
recharges: [{ atSec: 150, level: 50000 }],
currentGl: 50000,
});
const result = computeGaugeLive(enc, dd, 'baffeur', 200, true);
// La jauge rechargée à 50000 a eu 50s pour se vider (200-150)
// Elle doit être > 0 (50000 pts se vide en bien plus de 50s)
expect(result.curGl).toBeGreaterThan(0);
// Le countdown doit être fini (pas Infinity) et positif
expect(isFinite(result.cntDown)).toBe(true);
expect(result.cntDown).toBeGreaterThan(0);
});
it('enclosGlobalState retourne un globalMax fini après recharge', () => {
const dd = createDragodinde(1);
const enc = buildEnclos(dd, {
startGl: 100,
elapsedSec: 200,
recharges: [{ atSec: 150, level: 50000 }],
currentGl: 50000,
});
const state = enclosGlobalState(enc);
expect(state.started).toBe(true);
expect(isFinite(state.globalMax)).toBe(true);
expect(state.globalMax).toBeGreaterThan(0);
});
});