// Full browser simulation test const fs = require('fs'); const vm = require('vm'); // Create browser context const context = { window: null, document: { currentScript: { src: '', getAttribute: function(a) { return null; } }, getElementsByTagName: function() { return []; }, }, location: { origin: 'http://localhost:3000' }, console: console, Math: Math, JSON: JSON, Array: Array, Object: Object, String: String, Number: Number, Function: Function, Error: Error, RegExp: RegExp, Set: Set, Map: Map, Promise: Promise, setTimeout: setTimeout, localStorage: { getItem: () => null, setItem: () => {}, removeItem: () => {} }, }; context.window = context; vm.createContext(context); var results = []; function assert(name, cond) { results.push((cond ? 'PASS' : 'FAIL') + ': ' + name); } function setScript(src) { context.document.currentScript = { src: 'http://localhost:3000' + src, getAttribute: () => null }; } function load(name, code) { setScript(name); try { vm.runInContext(code, context); console.log(' Loaded:', name); } catch(e) { console.error(' ERROR in', name + ':', e.message); } } // Load all scripts in order load('/src/browser-polyfill.js', fs.readFileSync('src/browser-polyfill.js', 'utf8')); load('/src/core/constants.js', fs.readFileSync('src/core/constants.js', 'utf8')); load('/src/core/rng.js', fs.readFileSync('src/core/rng.js', 'utf8')); load('/src/core/utils.js', fs.readFileSync('src/core/utils.js', 'utf8')); load('/src/data/themes.js', fs.readFileSync('src/data/themes.js', 'utf8')); load('/src/data/dungeons.js', fs.readFileSync('src/data/dungeons.js', 'utf8')); load('/src/data/enemies.js', fs.readFileSync('src/data/enemies.js', 'utf8')); load('/src/data/weapons.js', fs.readFileSync('src/data/weapons.js', 'utf8')); load('/src/data/bosses.js', fs.readFileSync('src/data/bosses.js', 'utf8')); load('/src/data/items.js', fs.readFileSync('src/data/items.js', 'utf8')); load('/src/generator/rooms.js', fs.readFileSync('src/generator/rooms.js', 'utf8')); load('/src/generator/puzzles.js', fs.readFileSync('src/generator/puzzles.js', 'utf8')); load('/src/generator/placement.js', fs.readFileSync('src/generator/placement.js', 'utf8')); load('/src/generator/dungeon.js', fs.readFileSync('src/generator/dungeon.js', 'utf8')); // Core tests assert('module exists', typeof context.module !== 'undefined'); assert('require is function', typeof context.require === 'function'); assert('TILE=32', context.window.TILE === 32); assert('COLS=32', context.window.COLS === 32); assert('ROWS=24', context.window.ROWS === 24); assert('TILE_TYPES object', context.window.TILE_TYPES && typeof context.window.TILE_TYPES === 'object'); assert('COLORS object', context.window.COLORS && typeof context.window.COLORS === 'object'); assert('createRNG function', typeof context.createRNG === 'function'); assert('createEmptyLayout function', typeof context.createEmptyLayout === 'function'); assert('createBorderLayout function', typeof context.createBorderLayout === 'function'); assert('isPassable function', typeof context.isPassable === 'function'); // Data tests assert('THEMES object', context.window.THEMES && typeof context.window.THEMES === 'object'); assert('DUNGEONS array', Array.isArray(context.window.DUNGEONS)); assert('DUNGEONS count=100', context.window.DUNGEONS && context.window.DUNGEONS.length === 100); assert('ENEMY_TYPES array', Array.isArray(context.window.ENEMY_TYPES)); assert('ENEMY_TYPES count=22', context.window.ENEMY_TYPES && context.window.ENEMY_TYPES.length === 22); assert('WEAPONS array', Array.isArray(context.window.WEAPONS)); assert('WEAPONS count=12', context.window.WEAPONS && context.window.WEAPONS.length === 12); assert('BOSS_TYPES array', Array.isArray(context.window.BOSS_TYPES)); assert('BOSS_TYPES count=100', context.window.BOSS_TYPES && context.window.BOSS_TYPES.length === 100); assert('ITEMS array', Array.isArray(context.window.ITEMS)); assert('getItem function', typeof context.getItem === 'function'); assert('getEnemyType function', typeof context.getEnemyType === 'function'); assert('getBossType function', typeof context.getBossType === 'function'); assert('getWeapon function', typeof context.getWeapon === 'function'); // Generator tests assert('generateDungeon function', typeof context.generateDungeon === 'function'); assert('generateRoomLayout function', typeof context.generateRoomLayout === 'function'); assert('generatePuzzles function', typeof context.generatePuzzles === 'function'); assert('generatePlacement function', typeof context.generatePlacement === 'function'); // Require resolution tests context.document.currentScript = { src: 'http://localhost:3000/src/generator/placement.js', getAttribute: () => null }; var roomsMod = context.require('./rooms'); assert('require ./rooms generateRoomLayout', roomsMod.generateRoomLayout !== undefined); var enemiesMod = context.require('../data/enemies'); assert('require ../data/enemies ENEMY_TYPES', Array.isArray(enemiesMod.ENEMY_TYPES)); // Dungeon generation test var dungeon0 = context.window.DUNGEONS[0]; var rooms = context.generateDungeon(dungeon0); assert('generateDungeon returns rooms', Array.isArray(rooms) && rooms.length > 0); assert('dungeon #0 rooms ~20', rooms.length >= 17 && rooms.length <= 25); assert('entrance assigned', rooms[0].type === 'entrance'); assert('boss assigned', rooms[rooms.length - 1].type === 'boss'); assert('all rooms connected', rooms.every(function(r) { return r.connections && r.connections.length >= 1; })); assert('rooms have tiles', rooms.every(function(r) { return Array.isArray(r.tiles); })); console.log('\n=== Results ==='); results.forEach(r => console.log(r)); var passed = results.filter(r => r.startsWith('PASS')).length; var failed = results.filter(r => r.startsWith('FAIL')).length; console.log('\n' + passed + ' passed, ' + failed + ' failed'); process.exit(failed > 0 ? 1 : 0);