dd-timer/tests/regression/level-target-timer.test.ts
POL Mickaël 3e485fd09b chore: normalise fins de ligne CRLF → LF dans tout le repo
Applique .gitattributes sur tous les fichiers existants.
Élimine les différences fantômes entre WSL et Windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 08:55:10 +02:00

165 lines
6.1 KiB
TypeScript
Executable File

import { describe, it, expect } from 'vitest';
import { computeGaugeLive, enclosGlobalState, calcLevelEtaLive } from '@presentation/helpers/gauge-live';
import { xpForLevel } from '@domain/value-objects/XpTable';
import { timeToGain } from '@domain/services/GaugeCalculator';
import { createDragodinde } from '@domain/entities/Dragodinde';
import type { Enclos } from '@domain/entities/Enclos';
function makeEnclos(overrides: Partial<Enclos> = {}): Enclos {
return {
id: 1,
name: 'Test',
activeGauges: ['mangeoire'],
gaugeLevels: { baffeur: 0, caresseur: 0, foudroyeur: 0, abreuvoir: 0, dragofesse: 0, mangeoire: 50000 },
dragodindes: [createDragodinde(1)],
nextDdId: 2,
timer: { running: false, startTime: null, pausedAt: null, pausedMs: 0, snapGauges: {}, snapStats: {}, gaugeRecharges: {} },
alerted: {},
...overrides,
} as Enclos;
}
describe('Regression: timer prend en compte levelTarget', () => {
it('computeGaugeLive utilise levelTarget pour le countdown mangeoire', () => {
const enc = makeEnclos();
const dd = { ...enc.dragodindes[0]!, levelTarget: 10 };
const r = computeGaugeLive(enc, dd, 'mangeoire', 0, false);
// Avec levelTarget=10, xpNeeded = xpForLevel(10) - xpForLevel(1) = 809
const xpNeeded = xpForLevel(10) - xpForLevel(1);
expect(xpNeeded).toBe(809);
// Le countdown devrait être timeToGain(50000, 809)
const expectedSec = timeToGain(50000, 809);
expect(r.cntDown).toBe(expectedSec);
expect(r.done).toBe(false);
});
it('computeGaugeLive sans levelTarget utilise 200 par défaut', () => {
const enc = makeEnclos();
const dd = { ...enc.dragodindes[0]!, levelTarget: null };
const r = computeGaugeLive(enc, dd, 'mangeoire', 0, false);
// Avec levelTarget=null → 200, xpNeeded >> gauge level
// cntDown = timeToGain(50000, 50000) = drain time
const drainTime = timeToGain(50000, 50000);
expect(r.cntDown).toBe(drainTime);
});
it('levelTarget=10 donne un countdown beaucoup plus court que levelTarget=null', () => {
const enc = makeEnclos();
const ddWithTarget = { ...enc.dragodindes[0]!, levelTarget: 10 };
const ddWithoutTarget = { ...enc.dragodindes[0]!, levelTarget: null };
const rWith = computeGaugeLive(enc, ddWithTarget, 'mangeoire', 0, false);
const rWithout = computeGaugeLive(enc, ddWithoutTarget, 'mangeoire', 0, false);
// Avec target 10 : ~410 sec. Sans target (200) : ~45000 sec.
expect(rWith.cntDown).toBeLessThan(1000); // < ~16 minutes
expect(rWithout.cntDown).toBeGreaterThan(40000); // > ~11 heures
});
it('enclosGlobalState reflète le levelTarget dans globalMax', () => {
const enc = makeEnclos();
enc.dragodindes[0]!.levelTarget = 10;
const state = enclosGlobalState(enc);
// Avant démarrage, started=false → globalMax devrait refléter le target 10
expect(state.globalMax).toBeLessThan(1000);
});
it('enclosGlobalState sans levelTarget a un globalMax plus élevé', () => {
const enc = makeEnclos();
enc.dragodindes[0]!.levelTarget = null;
const state = enclosGlobalState(enc);
expect(state.globalMax).toBeGreaterThan(40000);
});
it('calcLevelEtaLive utilise levelTarget', () => {
const enc = makeEnclos();
const dd = { ...enc.dragodindes[0]!, levelTarget: 5 };
const eta = calcLevelEtaLive(enc, dd, 0, false);
// Level 1→5 needs 161 XP, timeToGain(50000, 161) = 90 sec
expect(eta).toContain('1m');
});
it('done=true quand estLevel >= levelTarget', () => {
const enc = makeEnclos();
// DD déjà au level 50, target 50
const dd = { ...enc.dragodindes[0]!, stats: { ...enc.dragodindes[0]!.stats, xp: 50 }, levelTarget: 50 };
const r = computeGaugeLive(enc, dd, 'mangeoire', 0, false);
expect(r.done).toBe(true);
expect(r.cntDown).toBe(0);
});
it('done=true quand estLevel > levelTarget', () => {
const enc = makeEnclos();
const dd = { ...enc.dragodindes[0]!, stats: { ...enc.dragodindes[0]!.stats, xp: 100 }, levelTarget: 50 };
const r = computeGaugeLive(enc, dd, 'mangeoire', 0, false);
expect(r.done).toBe(true);
});
it('timer en cours avec levelTarget=10 : countdown reflète le target', () => {
const now = Date.now();
const enc = makeEnclos({
timer: {
running: true,
startTime: now - 100_000, // 100 sec écoulées
pausedAt: null,
pausedMs: 0,
snapGauges: { mangeoire: 50000 },
snapStats: { '1': { serenite: 0, endurance: 0, maturite: 0, amour: 0, xp: 1 } },
gaugeRecharges: {},
},
});
const ddWithTarget = { ...enc.dragodindes[0]!, levelTarget: 10 };
const ddNoTarget = { ...enc.dragodindes[0]!, levelTarget: null };
const rWith = computeGaugeLive(enc, ddWithTarget, 'mangeoire', 100, true);
const rNo = computeGaugeLive(enc, ddNoTarget, 'mangeoire', 100, true);
// Avec target 10 : cntDown devrait être < 1000 (beaucoup moins que sans target)
// Sans target (200) : cntDown devrait être > 30000
expect(rWith.cntDown).toBeLessThan(rNo.cntDown);
// Plus spécifiquement, avec target 10 après 100sec, le target devrait presque être atteint
// xpNeeded = 809, et en 100sec (10 ticks) on gagne 10*20 = 200xp (tier 2)
// xpRestante = 809 - 200 = 609
expect(rWith.cntDown).toBeLessThan(500); // < 500 sec restantes
});
it('changer levelTarget pendant le timer met à jour le globalMax', () => {
const now = Date.now();
const enc = makeEnclos({
timer: {
running: true,
startTime: now - 50_000, // 50 sec écoulées
pausedAt: null,
pausedMs: 0,
snapGauges: { mangeoire: 50000 },
snapStats: { '1': { serenite: 0, endurance: 0, maturite: 0, amour: 0, xp: 1 } },
gaugeRecharges: {},
},
});
// D'abord sans target (level 200 par défaut)
enc.dragodindes[0]!.levelTarget = null;
const state1 = enclosGlobalState(enc);
// Puis avec target 10
enc.dragodindes[0]!.levelTarget = 10;
const state2 = enclosGlobalState(enc);
// Le globalMax devrait diminuer drastiquement
expect(state2.globalMax).toBeLessThan(state1.globalMax);
expect(state2.globalMax).toBeLessThan(1000);
});
});