Workers P2: Engine-Rauchtest (19 anklickbar, 150 s Ereignisfeed)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-18 03:46:47 +00:00
1 parent cb31d1476b
commit f4ce410345
1 file changed
+118
+118
View File
@@ -0,0 +1,118 @@
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)
})