import test from 'node:test' import assert from 'node:assert/strict' import { createEngineSandbox } from './helpers/engineVm.mjs' import { makeState, ev, IDS } from './helpers/workersFixtures.mjs' import { loadModule } from './load.mjs' // Rauchtest der Engine ohne Browser (Muster: entwuerfe/smoke.js): 19 Figuren sind anklickbar, 150 simulierte Sekunden // mit allen 26 Ereignisarten und einem Stoß von 120 Übergaben laufen ohne Wurf und beruhigen sich danach wieder. const { EVENT_KINDS } = await loadModule('src/lib/workersEvents.js') // Eine Art alle 5 s ab Sekunde 3, in dieser Reihenfolge: [Art, Arbeiter, Zusatzfelder] const PLAN = [ ['gelesen', 'kim'], ['fund', 'rita'], ['doppelt', 'arne'], ['uebergabe', 'rita', { to: 'bea' }], ['bewertet', 'bea'], ['top3', 'bea'], ['botlead', 'arne'], ['entwurf', 'max'], ['pult', 'clara'], ['gesendet', 'max'], ['eingang', 'nora'], ['sortiert', 'nora'], ['bau_start', 'bob'], ['bau_fertig', 'bob'], ['pruefung_zurueck', 'paul', { to: 'bob', meta: { round: 1 } }], ['pruefung_ok', 'paul'], ['vorschau_link', 'max'], ['angebot', 'theo'], ['deal', 'system'], ['gesperrt', 'system'], ['budget_warnung', 'otto'], ['budget_stopp', 'otto'], ['pause', 'system'], ['fehler', 'ben'], ['auftrag', 'otto', { to: 'kim' }], ['leerlauf', 'pia'], ] const FIRST_SEC = 3 const EVERY_SEC = 5 const BURST_SEC = 100 const BURST_SIZE = 120 // Die Ereignisse für Sekunde `sec`: höchstens eine Art aus dem Plan, ab Sekunde 100 zusätzlich der Stoß (einmalig) function scripted(sec) { const out = [] const slot = (sec - FIRST_SEC) / EVERY_SEC if (Number.isInteger(slot) && slot >= 0 && slot < PLAN.length) { const [kind, who, extra] = PLAN[slot] out.push(ev(kind, who, extra)) } if (sec === BURST_SEC) { for (let i = 0; i < BURST_SIZE; i++) out.push(ev('uebergabe', IDS[i % IDS.length], { to: IDS[(i + 4) % IDS.length] })) } return out } const OFF = { kim: false, pia: false, finn: false } test('alle 19 Worker sind anklickbar (Auswahl liefert die richtige workerId)', async () => { const sb = await createEngineSandbox() const picked = [] const h = sb.mountTower(sb.canvas, sb.opts({ onSelect: (id) => picked.push(id) })) h.setState(makeState()) for (const id of IDS) { const p = h.locate(id) assert.ok(p, id) sb.click(p.x, p.y) assert.equal(picked.at(-1), id) } assert.deepEqual([...new Set(picked)].sort(), [...IDS].sort()) h.destroy() }) test('150 s mit allen 26 Ereignisarten: kein Wurf, alle endlich und im Bild, danach ruhig', async () => { const sb = await createEngineSandbox() const h = sb.mountTower(sb.canvas, sb.opts({ onSelect() {} })) h.setState(makeState({ connected: OFF })) const fed = [] for (let s = 0; s < 150; s++) { const evs = scripted(s) if (evs.length) { fed.push(...evs) h.pushEvents(evs) } if (s % 15 === 0) { h.setState(makeState({ connected: OFF, kpis: { pultOpen: s % 7, dealsMonth: 3 + Math.floor(s / 40), botLeads: 112 + s } })) } sb.tick(1) // alle zwei Sekunden ein Raster von Klicks über die ganze Leinwand if (s % 2 === 0) { for (let x = 10; x < 960; x += 40) { for (let y = 10; y < 768; y += 40) sb.click(x, y) } } } // der Plan deckt die geschlossene Liste vollständig ab, der Stoß kam genau einmal assert.equal(PLAN.length, 26) assert.deepEqual([...new Set(fed.map((e) => e.kind))].sort(), [...EVENT_KINDS].sort()) assert.equal(fed.length, PLAN.length + BURST_SIZE) assert.equal(fed.filter((e) => e.kind === 'uebergabe').length, BURST_SIZE + 1) // danach 90 ruhige Sekunden: Warteschlangen, Aufzug und Effekte laufen leer for (let s = 0; s < 90; s++) sb.tick(1) const dbg = h.debug() assert.equal(dbg.pending, 0) assert.equal(dbg.lift, 'idle') assert.equal(dbg.fx, 0) for (const a of dbg.agents) { assert.ok(Number.isFinite(a.x) && Number.isFinite(a.y) && a.x > -30 && a.x < 350 && a.floor >= 0 && a.floor <= 9, a.id) } assert.ok(sb.counts.fillRect > 100000) assert.ok(sb.counts.fillText > 1000) assert.ok(sb.seenTexts.has('noch nicht angeschlossen')) h.destroy() assert.equal(Object.values(sb.listeners).flat().length, 0) })