import { describe, it, expect, vi, beforeEach } from 'vitest'; import { GameScene } from '../GameScene'; import * as simulation from '../../engine/simulation/simulation'; import * as generator from '../../engine/world/generator'; // Mock Phaser vi.mock('phaser', () => { const mockEventEmitter = { on: vi.fn(), emit: vi.fn(), off: vi.fn(), }; return { default: { Scene: class { events = mockEventEmitter; input = { keyboard: { createCursorKeys: vi.fn(() => ({})), on: vi.fn(), }, on: vi.fn(), }; cameras = { main: { setZoom: vi.fn(), setBounds: vi.fn(), centerOn: vi.fn(), fadeIn: vi.fn(), }, }; scene = { launch: vi.fn(), get: vi.fn(), }; add = { graphics: vi.fn(() => ({ setDepth: vi.fn().mockReturnThis(), clear: vi.fn(), lineStyle: vi.fn(), lineBetween: vi.fn(), strokeRect: vi.fn(), })), text: vi.fn(() => ({})), rectangle: vi.fn(() => ({})), container: vi.fn(() => ({})), }; load = { spritesheet: vi.fn(), }; anims = { create: vi.fn(), exists: vi.fn(() => true), generateFrameNumbers: vi.fn(), }; }, Input: { Keyboard: { JustDown: vi.fn(), }, }, }, }; }); // Mock other modules vi.mock('../../rendering/DungeonRenderer', () => ({ DungeonRenderer: vi.fn().mockImplementation(function() { return { initializeFloor: vi.fn(), computeFov: vi.fn(), render: vi.fn(), showDamage: vi.fn(), spawnCorpse: vi.fn(), showWait: vi.fn(), isMinimapVisible: vi.fn(() => false), }; }), })); vi.mock('../../engine/simulation/simulation', () => ({ applyAction: vi.fn(), stepUntilPlayerTurn: vi.fn(), })); vi.mock('../../engine/world/generator', () => ({ generateWorld: vi.fn(), })); vi.mock('../../engine/world/world-logic', () => ({ inBounds: vi.fn(() => true), isBlocked: vi.fn(() => false), isPlayerOnExit: vi.fn(() => false), idx: vi.fn((w, x, y) => y * w.width + x), })); describe('GameScene', () => { let scene: GameScene; let mockWorld: any; let mockUI: any; beforeEach(() => { vi.clearAllMocks(); // Setup mock UI mockUI = { showDeathScreen: vi.fn(), }; // Initialize Scene scene = new GameScene(); // Mock the Phaser scene system to return our mock UI (scene as any).scene = { launch: vi.fn(), get: vi.fn((key) => { if (key === 'GameUI') return mockUI; return null; }), }; // Mock initial world state mockWorld = { width: 10, height: 10, tiles: new Array(100).fill(0), actors: new Map(), exit: { x: 9, y: 9 }, }; const mockPlayer = { id: 1, isPlayer: true, pos: { x: 1, y: 1 }, speed: 100, stats: { hp: 10, maxHp: 10, attack: 5, defense: 2 }, inventory: { gold: 0, items: [] }, }; mockWorld.actors.set(1, mockPlayer); (generator.generateWorld as any).mockReturnValue({ world: mockWorld, playerId: 1, }); (simulation.stepUntilPlayerTurn as any).mockReturnValue({ awaitingPlayerId: 1, events: [], }); // Run create to initialize some things scene.create(); }); it('should trigger death screen when player is killed', () => { // 1. Mock simulation so that after action, player is gone from world (simulation.applyAction as any).mockImplementation((world: any) => { // simulate player being killed world.actors.delete(1); return [{ type: 'killed', targetId: 1, victimType: 'player', x: 1, y: 1 }]; }); (simulation.stepUntilPlayerTurn as any).mockReturnValue({ awaitingPlayerId: null, events: [], }); // 2. Commit an action // We need to access private method or trigger it via public interface // commitPlayerAction is private, let's cast to any to call it (scene as any).commitPlayerAction({ type: 'wait' }); // 3. Verify showDeathScreen was called on the mock UI expect(mockUI.showDeathScreen).toHaveBeenCalled(); // Verify it was called with some stats const callArgs = mockUI.showDeathScreen.mock.calls[0][0]; expect(callArgs).toHaveProperty('floor'); expect(callArgs).toHaveProperty('gold'); expect(callArgs).toHaveProperty('stats'); }); });