/** * Adversarial Milestone 2 Challenger Stress & Fuzzing Suite * * Exhaustive empirical challenge of: * 1. Act Boss death drops with rank: 'boss' verifying monsterType = 4 resolution. * 2. demoteToNormal level reversion across Champion, Unique, Minion packs. * 3. Extreme negative and high Magic Find boundaries (mf <= -100 suppression, diminishing returns). * 4. setPlayers boundary clamping and chat command parsing. */ import { describe, expect, it } from 'vitest' import { monsterStatsOf, applyEliteModifiers, rollEliteModifiers, getMonsterTreasureClass, ELITE_HEALTH_MULTIPLIER, MONUMOD_CONSTANTS, type MonsterKind, type MonsterRank, } from '../src/game/monsters.ts' import { damageMonster, type CombatWorld, type MonsterStats } from '../src/game/combat.ts' import { GameEngine, type WorldMapProvider, type GameEngineOptions } from '../src/game/engine.ts' import { effectiveMF, calculateUniqueChance, calculateSetChance, calculateRareChance, calculateMagicChance, rollItemQuality, createItemRatioTable, type ItemRatioRow, } from '../src/game/item-ratio.ts' import { executeDropPipeline } from '../src/game/drop-pipeline.ts' import { ItemQuality } from '../src/game/items.ts' import { D2Rng } from '../src/game/d2-rng.ts' import { Rng } from '../src/game/rng.ts' import { computeEffectivePlayers, computeScaledNoDrop, } from '../src/game/treasure-engine.ts' import { handleActSceneChatCommand } from '../src/scene/act-scene.ts' import { getEmbeddedDropTables } from '../src/game/embedded-drop-tables.ts' const dropTables = getEmbeddedDropTables() const dummyTerrain: WorldMapProvider = { widthPx: 1000, heightPx: 1000, overlap: () => 0, } const dummyOpts: GameEngineOptions = { spawn: { x: 100, y: 100 }, stats: [], npcDefs: [], skills: [], dropTables, difficulty: 'normal', xpTable: [0, 0, 10, 30, 60], questDefs: [], combatOptions: { playerSpeed: 100, playerReach: 50, playerCooldownTicks: 10, playerDamage: 5, playerManaPerAttack: 0, respawnTicks: 100, }, talkRadius: 50, pickupRadius: 50, inventoryCols: 10, inventoryRows: 4, } const dummyInput = { movement: { x: 0, y: 0 }, attacking: false, pickingUp: false, talking: false, digits: [], saving: false, loading: false, } describe('Milestone 2 Adversarial Stress Suite', () => { // ============================================================================ // Challenge 1: Act Boss Death Drops & monsterType = 4 Resolution // ============================================================================ describe('Challenge 1: Act Boss death drops & monsterType = 4 resolution', () => { it('1.1 monsterStatsOf assigns rank: boss when kind.boss is true', () => { const realBossKind = dropTables.monsterKinds.get('andariel')! expect(realBossKind).toBeDefined() expect(realBossKind.boss).toBe(true) const rng = new Rng(42) const stats = monsterStatsOf(realBossKind, rng, 100) expect(stats.rank).toBe('boss') }) it('1.2 damageMonster creates killEvent with monsterRank: boss and monsterType: 4', () => { const world: CombatWorld = { monsters: [ { index: 0, x: 50, y: 50, hp: 100, state: 'alive', stats: { id: 'duriel', name: 'Duriel', hp: 100, damage: 50, speed: 10, reach: 2, aggroRadius: 15, cooldownTicks: 10, xp: 5000, level: 22, rank: 'boss', }, } as any, ], player: { x: 50, y: 50, hp: 100, maxHp: 100, xp: 0 } as any, events: [], kills: 0, } as any const killed = damageMonster(world, 0, 150) expect(killed).toBe(true) expect(world.events.length).toBeGreaterThan(0) const killEvent = world.events.find(e => e.kind === 'kill') expect(killEvent).toBeDefined() expect(killEvent?.monsterRank).toBe('boss') expect(killEvent?.monsterType).toBe(4) expect(killEvent?.monsterLevel).toBe(22) }) it('1.3 damageMonster maps all monster ranks to authentic 1.13c monsterType codes', () => { const ranks: { rank: MonsterRank; expectedType: number }[] = [ { rank: 'normal', expectedType: 1 }, { rank: 'champion', expectedType: 2 }, { rank: 'unique', expectedType: 3 }, { rank: 'minion', expectedType: 3 }, { rank: 'boss', expectedType: 4 }, ] for (const { rank, expectedType } of ranks) { const world: CombatWorld = { monsters: [ { index: 0, x: 0, y: 0, hp: 10, state: 'alive', stats: { id: 'test_mon', name: 'Test Monster', hp: 10, damage: 5, speed: 8, reach: 1, aggroRadius: 10, cooldownTicks: 10, xp: 10, level: 5, rank, }, } as any, ], player: { x: 0, y: 0, hp: 10, maxHp: 10, xp: 0 } as any, events: [], kills: 0, } as any damageMonster(world, 0, 20) const killEvent = world.events.find(e => e.kind === 'kill') expect(killEvent?.monsterType).toBe(expectedType) } }) it('1.4 rollEliteModifiers and applyEliteModifiers for boss rank', () => { const rng = new Rng(123) // Boss must never roll elite modifiers const mods = rollEliteModifiers('boss', rng) expect(mods).toEqual([]) const baseStats: MonsterStats = { id: 'mephisto', name: 'Mephisto', hp: 10000, damage: 200, speed: 12, reach: 3, aggroRadius: 20, cooldownTicks: 10, xp: 20000, level: 26, rank: 'boss', } const bossApplied = applyEliteModifiers(baseStats, 'boss') expect(bossApplied.level).toBe(26) // Level is NOT incremented by +2 or +3 expect(bossApplied.rank).toBe('boss') expect(bossApplied.hp).toBe(10000) }) it('1.5 GameEngine drop loop resolves boss rank to monsterType = 4 even when event.monsterType is missing', () => { const engine = new GameEngine(dummyTerrain, dummyOpts) const andarielStats: MonsterStats = { id: 'andariel', name: 'Andariel', hp: 100, damage: 10, speed: 10, reach: 2, aggroRadius: 15, cooldownTicks: 10, xp: 1000, level: 12, rank: 'boss', } engine.world.monsters.length = 0 engine.world.monsters.push({ index: 0, stats: andarielStats, x: 100, y: 100, hp: 100, state: 'alive', corpseTicks: 0, hitFlash: 0, facing: 0, cooldown: 0, } as any) // damageMonster kills Andariel and populates pendingKills and events damageMonster(engine.world, 0, 200) expect(() => engine.tick(dummyInput as any)).not.toThrow() expect(engine.metrics.dropsRolled).toBeGreaterThan(0) }) it('1.6 all 5 authentic Act Bosses resolve to valid TCs across 3 difficulties with monsterType = 4', () => { const bossIds = ['andariel', 'duriel', 'mephisto', 'diablo', 'baalcrab'] const difficulties = ['normal', 'nightmare', 'hell'] as const for (const id of bossIds) { const kind = dropTables.monsterKinds.get(id) expect(kind, `MonsterKind for ${id} must exist`).toBeDefined() expect(kind?.boss).toBe(true) for (const diff of difficulties) { const tc = getMonsterTreasureClass(kind!, diff, 4) expect(tc).toBeTruthy() expect(Boolean(dropTables.tcTable.get(tc) || dropTables.autoTcTable?.get(tc))).toBe(true) } } }) it('1.7 Act Boss drop execution with monsterType = 4 yields authentic high quality drops (no normal/low)', () => { const drops = executeDropPipeline(dropTables, { tcName: 'Andarielq', nLevel: 12, monsterType: 4, difficulty: 'normal', monsterRng: new D2Rng(999), }) expect(drops.length).toBeGreaterThan(0) // Quest first-kill / boss TC produces rare+ quality items (failed sets drop as magic with 2x durability) for (const d of drops) { expect(d.quality).toBeGreaterThanOrEqual(ItemQuality.MAGIC) expect(d.quality).not.toBe(ItemQuality.NORMAL) expect(d.quality).not.toBe(ItemQuality.LOW) } }) }) // ============================================================================ // Challenge 2: demoteToNormal Level Reversion Across Packs // ============================================================================ describe('Challenge 2: demoteToNormal level reversion across packs', () => { function localDemoteToNormal(pack: { members: MonsterStats[] }) { const members: MonsterStats[] = pack.members.map(m => { let hp = m.hp let level = m.level if (m.rank === 'champion') { hp = Math.max(1, Math.round(hp / ELITE_HEALTH_MULTIPLIER.champion)) if (level !== undefined) { level = Math.max(1, level - 2) } } else if (m.rank === 'unique') { hp = Math.max(1, Math.round(hp / ELITE_HEALTH_MULTIPLIER.unique)) if (level !== undefined) { level = Math.max(1, level - 3) } } else if (m.rank === 'minion') { hp = Math.max(1, Math.round(hp / (1 + MONUMOD_CONSTANTS.minionHpPct / 100))) if (level !== undefined) { level = Math.max(1, level - 3) } } return { ...m, hp, ...(level !== undefined ? { level } : {}), rank: 'normal' as MonsterRank, modifiers: [], } }) return { ...pack, members } } it('2.1 Round-trip promotion and demotion restores exact base level', () => { const baseMonster: MonsterStats = { id: 'quillrat', name: 'Quill Rat', hp: 100, damage: 10, speed: 8, reach: 1, aggroRadius: 10, cooldownTicks: 15, xp: 50, level: 15, rank: 'normal', } // Champion const champ = applyEliteModifiers(baseMonster, 'champion') expect(champ.level).toBe(17) const demotedChamp = localDemoteToNormal({ members: [champ] }) expect(demotedChamp.members[0].level).toBe(15) expect(demotedChamp.members[0].rank).toBe('normal') // Unique const unique = applyEliteModifiers(baseMonster, 'unique') expect(unique.level).toBe(18) const demotedUnique = localDemoteToNormal({ members: [unique] }) expect(demotedUnique.members[0].level).toBe(15) expect(demotedUnique.members[0].rank).toBe('normal') // Minion const minion = applyEliteModifiers(baseMonster, 'minion') expect(minion.level).toBe(18) const demotedMinion = localDemoteToNormal({ members: [minion] }) expect(demotedMinion.members[0].level).toBe(15) expect(demotedMinion.members[0].rank).toBe('normal') }) it('2.2 demoteToNormal clamps level to >= 1 at extreme low boundary', () => { const lowLevelChamp: MonsterStats = { id: 'fallen', name: 'Fallen', hp: 10, damage: 1, speed: 8, reach: 1, aggroRadius: 10, cooldownTicks: 15, xp: 5, level: 1, rank: 'champion', } const demoted = localDemoteToNormal({ members: [lowLevelChamp] }) expect(demoted.members[0].level).toBe(1) // Math.max(1, 1 - 2) = 1 }) it('2.3 demoteToNormal handles mixed pack containing leader, minions, and normal', () => { const mixedPack = { members: [ { id: 'zombie', name: 'Zombie Leader', hp: 400, damage: 20, speed: 6, reach: 1, aggroRadius: 10, cooldownTicks: 20, xp: 200, level: 13, rank: 'unique' as MonsterRank, }, { id: 'zombie', name: 'Zombie Minion 1', hp: 200, damage: 15, speed: 6, reach: 1, aggroRadius: 10, cooldownTicks: 20, xp: 100, level: 13, rank: 'minion' as MonsterRank, }, { id: 'zombie', name: 'Zombie Normal', hp: 100, damage: 10, speed: 6, reach: 1, aggroRadius: 10, cooldownTicks: 20, xp: 50, level: 10, rank: 'normal' as MonsterRank, }, ], } const demoted = localDemoteToNormal(mixedPack) expect(demoted.members[0].level).toBe(10) // 13 - 3 expect(demoted.members[0].rank).toBe('normal') expect(demoted.members[1].level).toBe(10) // 13 - 3 expect(demoted.members[1].rank).toBe('normal') expect(demoted.members[2].level).toBe(10) // untouched expect(demoted.members[2].rank).toBe('normal') }) it('2.4 demoteToNormal strips all elite modifiers', () => { const moddedMonster: MonsterStats = { id: 'skeleton', name: 'Skeleton', hp: 300, damage: 25, speed: 8, reach: 1, aggroRadius: 10, cooldownTicks: 15, xp: 150, level: 30, rank: 'unique', modifiers: ['strong', 'fast', 'fireenchant'], } const demoted = localDemoteToNormal({ members: [moddedMonster] }) expect(demoted.members[0].modifiers).toEqual([]) expect(demoted.members[0].rank).toBe('normal') }) }) // ============================================================================ // Challenge 3: Magic Find Boundary Conditions (Extreme Negative & High MF) // ============================================================================ describe('Challenge 3: Magic Find boundary conditions', () => { const mockRow: ItemRatioRow = { version: 1, uber: 0, classSpecific: 0, unique: 400, uniqueDiv: 1, uniqueMin: 6400, set: 160, setDiv: 2, setMin: 5600, rare: 100, rareDiv: 2, rareMin: 3200, magic: 34, magicDiv: 3, magicMin: 192, hiQual: 12, hiQualDiv: 8, normal: 2, normalDiv: 1, } const table = createItemRatioTable([mockRow]) it('3.1 effectiveMF values at negative boundaries (-20, -50, -99, -100, -200)', () => { // For mf <= 10, effectiveMF returns mf + 100 expect(effectiveMF(-20, 250)).toBe(80) expect(effectiveMF(-50, 250)).toBe(50) expect(effectiveMF(-99, 250)).toBe(1) expect(effectiveMF(-100, 250)).toBe(0) expect(effectiveMF(-200, 250)).toBe(-100) }) it('3.2 negative MF between (-100, 0) increases chance denominator (suppresses drop rate)', () => { const baseUniqueChance = calculateUniqueChance(mockRow, 50, 20, 0) const neg20Chance = calculateUniqueChance(mockRow, 50, 20, -20) const neg50Chance = calculateUniqueChance(mockRow, 50, 20, -50) const neg99Chance = calculateUniqueChance(mockRow, 50, 20, -99) // Lower chance denominator = higher chance. Therefore negative MF must INCREASE denominator. expect(neg20Chance).toBeGreaterThan(baseUniqueChance) expect(neg50Chance).toBeGreaterThan(neg20Chance) expect(neg99Chance).toBeGreaterThan(neg50Chance) }) it('3.3 mf <= -100 completely suppresses Unique/Set/Rare/Magic in rollItemQuality', () => { const testMfs = [-100, -101, -200, -9999] for (const mf of testMfs) { const qualityCounts: Record = { unique: 0, set: 0, rare: 0, magic: 0, superior: 0, normal: 0, low: 0, } const rng = new D2Rng(1000) const iterations = 5000 for (let i = 0; i < iterations; i++) { const q = rollItemQuality({ table, row: mockRow, ilvl: 99, qlvl: 1, mf, rng, tcUnique: 1024, // maximum tc bonus tcSet: 1024, tcRare: 1024, tcMagic: 1024, }) qualityCounts[q] = (qualityCounts[q] ?? 0) + 1 } expect(qualityCounts.unique).toBe(0) expect(qualityCounts.set).toBe(0) expect(qualityCounts.rare).toBe(0) expect(qualityCounts.magic).toBe(0) expect(qualityCounts.superior + qualityCounts.normal + qualityCounts.low).toBe(iterations) } }) it('3.4 executeDropPipeline with playerMf <= -100 produces 0% magic/rare/set/unique for standard equipment', () => { let magicOrBetter = 0 let baseQualityItems = 0 for (let seed = 1; seed <= 500; seed++) { const drops = executeDropPipeline(dropTables, { tcName: 'Act 1 Equip A', nLevel: 50, monsterType: 1, difficulty: 'normal', playerMf: -100, monsterRng: new D2Rng(seed), }) for (const drop of drops) { if ((drop.quality ?? 0) >= ItemQuality.MAGIC) { magicOrBetter++ } else { baseQualityItems++ } } } expect(magicOrBetter).toBe(0) expect(baseQualityItems).toBeGreaterThan(0) }) it('3.5 high MF values (100, 238, 500, 1000, 10000) follow exact diminishing returns curves', () => { // Unique factor 250: 100 + trunc((mf * 250) / (mf + 250)) expect(effectiveMF(100, 250)).toBe(171) // +71% expect(effectiveMF(238, 250)).toBe(221) // +121% expect(effectiveMF(500, 250)).toBe(266) // +166% expect(effectiveMF(1000, 250)).toBe(300) // +200% expect(effectiveMF(10_000, 250)).toBe(343) // +243% expect(effectiveMF(1_000_000, 250)).toBe(349) // asymptotic cap 350 (+250%) // Set factor 500: 100 + trunc((mf * 500) / (mf + 500)) expect(effectiveMF(100, 500)).toBe(183) expect(effectiveMF(238, 500)).toBe(261) expect(effectiveMF(500, 500)).toBe(350) expect(effectiveMF(1000, 500)).toBe(433) expect(effectiveMF(1_000_000, 500)).toBe(599) // asymptotic cap 600 (+500%) // Rare factor 600: 100 + trunc((mf * 600) / (mf + 600)) expect(effectiveMF(100, 600)).toBe(185) expect(effectiveMF(238, 600)).toBe(270) expect(effectiveMF(500, 600)).toBe(372) expect(effectiveMF(1000, 600)).toBe(475) expect(effectiveMF(1_000_000, 600)).toBe(699) // asymptotic cap 700 (+600%) }) it('3.6 high MF increases unique yield with diminishing returns', () => { function countUniques(mf: number, iterations = 10000): number { const rng = new D2Rng(555) let count = 0 for (let i = 0; i < iterations; i++) { const q = rollItemQuality({ table, row: mockRow, ilvl: 85, qlvl: 10, mf, rng, }) if (q === 'unique') count++ } return count } const count0 = countUniques(0) const count100 = countUniques(100) const count500 = countUniques(500) const count1000 = countUniques(1000) expect(count100).toBeGreaterThan(count0) expect(count500).toBeGreaterThan(count100) expect(count1000).toBeGreaterThan(count500) // Diminishing returns: the gain from 0 to 500 is much higher than from 500 to 1000 const gain1 = count500 - count0 const gain2 = count1000 - count500 expect(gain1).toBeGreaterThan(gain2) }) }) // ============================================================================ // Challenge 4: setPlayers Boundary Clamping & Chat Command Parsing // ============================================================================ describe('Challenge 4: setPlayers boundary clamping and chat command parsing', () => { it('4.1 setPlayers clamps players between 1 and 8 and partyPlayers between 1 and gamePlayers', () => { const engine = new GameEngine(dummyTerrain, dummyOpts) // Boundary: 0 clamped to 1 engine.setPlayers(0) expect(engine.gamePlayers).toBe(1) expect(engine.partyPlayers).toBe(1) // Boundary: 1 engine.setPlayers(1) expect(engine.gamePlayers).toBe(1) expect(engine.partyPlayers).toBe(1) // Boundary: 8 engine.setPlayers(8) expect(engine.gamePlayers).toBe(8) expect(engine.partyPlayers).toBe(1) // Boundary: 9 clamped to 8 engine.setPlayers(9) expect(engine.gamePlayers).toBe(8) expect(engine.partyPlayers).toBe(1) // Boundary: negative (-10) clamped to 1 engine.setPlayers(-10) expect(engine.gamePlayers).toBe(1) expect(engine.partyPlayers).toBe(1) // Floats truncated: 4.9 truncated to 4 engine.setPlayers(4.9) expect(engine.gamePlayers).toBe(4) expect(engine.partyPlayers).toBe(1) // Infinity clamped to 8, -Infinity clamped to 1 engine.setPlayers(Infinity) expect(engine.gamePlayers).toBe(8) engine.setPlayers(-Infinity) expect(engine.gamePlayers).toBe(1) // partyPlayers clamping engine.setPlayers(4, 8) // party cannot exceed gamePlayers expect(engine.gamePlayers).toBe(4) expect(engine.partyPlayers).toBe(4) engine.setPlayers(6, 0) // party cannot be < 1 expect(engine.gamePlayers).toBe(6) expect(engine.partyPlayers).toBe(1) engine.setPlayers(6, -5) // party cannot be < 1 expect(engine.gamePlayers).toBe(6) expect(engine.partyPlayers).toBe(1) engine.setPlayers(6, 3.8) // truncated expect(engine.gamePlayers).toBe(6) expect(engine.partyPlayers).toBe(3) }) it('4.2 adversarial vulnerability discovery: NaN input to setPlayers sets gamePlayers to NaN', () => { const engine = new GameEngine(dummyTerrain, dummyOpts) engine.setPlayers(NaN) // Math.max(1, Math.min(8, Math.trunc(NaN))) evaluates to NaN! expect(Number.isNaN(engine.gamePlayers)).toBe(true) expect(Number.isNaN(engine.partyPlayers)).toBe(true) }) it('4.3 computeEffectivePlayers correctly calculates effective player scaling count', () => { // Solo games expect(computeEffectivePlayers(1, 1)).toBe(1) expect(computeEffectivePlayers(2, 1)).toBe(1) // 1 + floor(1/2) = 1 expect(computeEffectivePlayers(3, 1)).toBe(2) // 1 + floor(2/2) = 2 expect(computeEffectivePlayers(4, 1)).toBe(2) // 1 + floor(3/2) = 2 expect(computeEffectivePlayers(5, 1)).toBe(3) // 1 + floor(4/2) = 3 expect(computeEffectivePlayers(6, 1)).toBe(3) // 1 + floor(5/2) = 3 expect(computeEffectivePlayers(7, 1)).toBe(4) // 1 + floor(6/2) = 4 expect(computeEffectivePlayers(8, 1)).toBe(4) // 1 + floor(7/2) = 4 // Fully partied games expect(computeEffectivePlayers(8, 8)).toBe(8) // 8 + floor(0/2) = 8 expect(computeEffectivePlayers(4, 4)).toBe(4) }) it('4.4 computeScaledNoDrop reduces NoDrop weight with increased players', () => { const baseNoDrop = 100 const totalProb = 100 const p1 = computeScaledNoDrop(baseNoDrop, totalProb, 1) const p2 = computeScaledNoDrop(baseNoDrop, totalProb, 2) const p3 = computeScaledNoDrop(baseNoDrop, totalProb, 3) const p4 = computeScaledNoDrop(baseNoDrop, totalProb, 4) const p8 = computeScaledNoDrop(baseNoDrop, totalProb, 8) expect(p1).toBe(100) expect(p2).toBeLessThan(p1) expect(p3).toBeLessThan(p2) expect(p4).toBeLessThan(p3) expect(p8).toBeLessThan(p4) }) it('4.5 handleActSceneChatCommand accepts valid /players commands', () => { const mockEngine = { gamePlayers: 1, setPlayers(p: number) { this.gamePlayers = p }, } const statusEl = { textContent: '' as string | null } expect(handleActSceneChatCommand('/players 1', mockEngine, statusEl)).toBe(true) expect(mockEngine.gamePlayers).toBe(1) expect(statusEl.textContent).toBe('Players set to 1') expect(handleActSceneChatCommand('/players 8', mockEngine, statusEl)).toBe(true) expect(mockEngine.gamePlayers).toBe(8) expect(statusEl.textContent).toBe('Players set to 8') expect(handleActSceneChatCommand('players 4', mockEngine, statusEl)).toBe(true) expect(mockEngine.gamePlayers).toBe(4) expect(statusEl.textContent).toBe('Players set to 4') expect(handleActSceneChatCommand(' /PLAYERS 6 ', mockEngine, statusEl)).toBe(true) expect(mockEngine.gamePlayers).toBe(6) expect(statusEl.textContent).toBe('Players set to 6') }) it('4.6 handleActSceneChatCommand queries current setting when called without number', () => { const mockEngine = { gamePlayers: 5, setPlayers: () => {}, } const statusEl = { textContent: '' as string | null } expect(handleActSceneChatCommand('/players', mockEngine, statusEl)).toBe(true) expect(statusEl.textContent).toBe('Players currently set to 5') expect(handleActSceneChatCommand('players', mockEngine, statusEl)).toBe(true) expect(statusEl.textContent).toBe('Players currently set to 5') }) it('4.7 handleActSceneChatCommand rejects invalid player numbers and non-commands', () => { const mockEngine = { gamePlayers: 1, setPlayers: () => {}, } const statusEl = { textContent: '' as string | null } // Out of bounds: 0 expect(handleActSceneChatCommand('/players 0', mockEngine, statusEl)).toBe(false) expect(statusEl.textContent).toContain('Invalid players count: 0') // Out of bounds: 9 expect(handleActSceneChatCommand('/players 9', mockEngine, statusEl)).toBe(false) expect(statusEl.textContent).toContain('Invalid players count: 9') // Non-matching inputs expect(handleActSceneChatCommand('/players -1', mockEngine, statusEl)).toBe(false) expect(handleActSceneChatCommand('/players abc', mockEngine, statusEl)).toBe(false) expect(handleActSceneChatCommand('/players 1.5', mockEngine, statusEl)).toBe(false) expect(handleActSceneChatCommand('/help', mockEngine, statusEl)).toBe(false) expect(handleActSceneChatCommand('', mockEngine, statusEl)).toBe(false) }) }) })