Files
rogue/src/scenes/__tests__/GameScene.test.ts
2026-01-06 20:58:53 +11:00

188 lines
4.7 KiB
TypeScript

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');
});
});