Files
slop-game-opus5.5/tests/js/waveDirector.test.js
T
2026-09-24 17:57:54 +02:00

111 lines
3.6 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { WAVES } from '../../app/static/js/config.js';
import { createRng } from '../../app/static/js/logic/rng.js';
import { WaveDirector } from '../../app/static/js/logic/waveDirector.js';
/** Minimaler Spielersatz: zählt gespawnte Gegner und lässt sie auf Befehl sterben. */
function harness(cfgOverrides = {}) {
const log = { spawned: 0, started: [], cleared: [] };
let alive = 0;
const director = new WaveDirector({
rng: createRng(1),
cfg: { ...WAVES, ...cfgOverrides },
spawnGroup: (group) => {
log.spawned += group.count;
alive += group.count;
},
aliveCount: () => alive,
onWaveStart: (plan) => log.started.push(plan.number),
onWaveCleared: (n) => log.cleared.push(n),
});
return {
director,
log,
killAll: () => {
alive = 0;
},
get alive() {
return alive;
},
};
}
/** Lässt die Zeit in 50-ms-Schritten laufen. */
function run(director, from, until, step = 50) {
let now = from;
while (now < until) {
now += step;
director.update(now, step);
}
return now;
}
describe('WaveDirector', () => {
it('startet die erste Welle nach der Startverzögerung', () => {
const { director, log } = harness();
director.start(0);
expect(director.state).toBe('intermission');
run(director, 0, WAVES.firstWaveDelayMs - 50);
expect(log.started).toEqual([]);
run(director, WAVES.firstWaveDelayMs - 50, WAVES.firstWaveDelayMs);
expect(log.started).toEqual([1]);
expect(director.state).toBe('active');
});
it('spawnt alle Gruppen der Welle nach Plan', () => {
const { director, log } = harness();
director.start(0);
const now = run(director, 0, WAVES.firstWaveDelayMs);
const planned = director.plan.totalEnemies;
run(director, now, now + 60_000);
expect(log.spawned).toBe(planned);
expect(director.pendingEnemies).toBe(0);
});
it('meldet eine Welle erst als geschafft, wenn alle Gegner besiegt sind', () => {
const h = harness();
h.director.start(0);
let now = run(h.director, 0, 60_000);
expect(h.log.cleared).toEqual([]);
h.killAll();
now = run(h.director, now, now + 100);
expect(h.log.cleared).toEqual([1]);
expect(h.director.state).toBe('intermission');
expect(h.director.intermissionRemaining(now)).toBeGreaterThan(WAVES.intermissionMs - 200);
});
it('startet nach der Pause die nächste, größere Welle', () => {
const h = harness();
h.director.start(0);
let now = run(h.director, 0, 60_000);
const firstSize = h.director.plan.totalEnemies;
h.killAll();
now = run(h.director, now, now + WAVES.intermissionMs + 200);
expect(h.log.started).toEqual([1, 2]);
run(h.director, now, now + 60_000);
expect(h.director.plan.totalEnemies).toBeGreaterThan(firstSize);
});
it('hält den Spawn-Ablauf an, solange zu viele Gegner leben', () => {
const h = harness({ maxAliveEnemies: 3 });
h.director.start(0);
// Wellenstart plus ein Frame: Die erste Gruppe (≥4 Krabbler) überschreitet das Limit sofort.
let now = run(h.director, 0, WAVES.firstWaveDelayMs + 50);
const spawnedBefore = h.log.spawned;
expect(h.alive).toBeGreaterThanOrEqual(3);
now = run(h.director, now, now + 60_000);
expect(h.log.spawned).toBe(spawnedBefore);
h.killAll();
run(h.director, now, now + 60_000);
expect(h.log.spawned).toBeGreaterThan(spawnedBefore);
});
it('tut vor dem Start nichts', () => {
const { director, log } = harness();
run(director, 0, 10_000);
expect(log.started).toEqual([]);
expect(director.pendingEnemies).toBe(0);
});
});