Files
dino-isle-online/test/visual.mjs
T
deepseek 764da2ee6c Dino Isle Online: multiplayer dino survival game (The Isle-like)
- Zero-dependency Node server: HTTP static + hand-rolled RFC6455 WebSocket + 20Hz authoritative simulation
- Seeded island worldgen (tiles, forest decor, spawns)
- 4 playable species, needs (food/water/stamina), rest, growth stages Hatchling->Apex
- AI fauna: critters, fish shoals, Dryosaurus/Psittacosaurus herds; carcass feasting
- PvP with knockback, kill feed, chat, leaderboard, minimap, day/night cycle
- True top-down procedural dino renderer shared by menu cards and in-game
- Developer mode (` key): god-mode, x6 XP, instant evolve, spawn AI, Alt+Click tp
- Headless smoke tests, real-browser visual tests, pixel match checks
2026-08-23 07:00:08 +00:00

85 lines
3.8 KiB
JavaScript

// Visual verification: load the real game in headless Chromium, capture
// console/page errors, join with two players, screenshot menu + gameplay.
'use strict';
import { createRequire } from 'node:module';
import { readdirSync, existsSync } from 'node:fs';
const require = createRequire('/root/kidcraft/node_modules/');
const { chromium } = require('playwright-core');
// auto-discover the headless shell binary (cache version changes over time)
function findBrowserExe() {
const root = '/root/.cache/ms-playwright';
try {
for (const dir of readdirSync(root)) {
if (!dir.startsWith('chromium')) continue;
for (const sub of ['chrome-headless-shell-linux64/chrome-headless-shell', 'chrome-linux/headless_shell', 'chrome-linux/chrome']) {
const p = `${root}/${dir}/${sub}`;
if (existsSync(p)) return p;
}
}
} catch {}
return null;
}
const EXE = findBrowserExe();
if (!EXE) { console.log('FAIL no chromium binary found in ms-playwright cache'); process.exit(1); }
const URL = 'http://127.0.0.1:8095/';
let failures = 0;
const ok = (c, l) => { console.log(`${c ? 'PASS' : 'FAIL'} ${l}`); if (!c) failures++; };
const browser = await chromium.launch({ executablePath: EXE, args: ['--no-sandbox'] });
const ctxA = await browser.newContext({ viewport: { width: 1280, height: 800 } });
const pageA = await ctxA.newPage();
const errors = [];
pageA.on('pageerror', (e) => errors.push('pageerror: ' + e.message));
pageA.on('console', (m) => { if (m.type() === 'error') errors.push('console: ' + m.text()); });
await pageA.goto(URL, { waitUntil: 'networkidle' });
await pageA.waitForTimeout(1200);
ok((await pageA.title()) === 'Dino Isle Online', 'page title loads');
ok(await pageA.isVisible('#menu'), 'menu overlay visible');
const cardCount = await pageA.locator('.card').count();
ok(cardCount === 4, `4 species cards rendered (got ${cardCount})`);
await pageA.screenshot({ path: '/tmp/shot-menu.png' });
// join as player A
await pageA.fill('#nameInput', 'VisRex');
await pageA.click('.card[data-key="rex"]');
await pageA.click('#playBtn');
await pageA.waitForTimeout(2500);
ok(await pageA.isHidden('#menu'), 'menu hides after Play');
ok(!(await pageA.evaluate(() => document.getElementById('hud').classList.contains('hidden'))), 'HUD visible in game');
// canvas actually drawing? sample a pixel region via 2d readback
const painted = await pageA.evaluate(() => {
const cv = document.getElementById('game');
const c = document.createElement('canvas');
c.width = cv.width; c.height = cv.height;
c.getContext('2d').drawImage(cv, 0, 0);
const d = c.getContext('2d').getImageData(c.width >> 1, c.height >> 1, 1, 1).data;
return d[0] + d[1] + d[2] > 0;
});
ok(painted, 'game canvas has painted pixels');
await pageA.screenshot({ path: '/tmp/shot-game-a.png' });
// second player joins on another "tab"
const pageB = await (await browser.newContext({ viewport: { width: 1100, height: 700 } })).newPage();
pageB.on('pageerror', (e) => errors.push('B pageerror: ' + e.message));
await pageB.goto(URL, { waitUntil: 'networkidle' });
await pageB.fill('#nameInput', 'VisRaptor');
await pageB.click('.card[data-key="raptor"]');
await pageB.click('#playBtn');
await pageB.waitForTimeout(2000);
// A walks a bit & bites; then screenshot again (multiplayer HUD state)
for (const key of ['KeyW', 'KeyW', 'Space']) { await pageA.keyboard.press(key); await pageA.waitForTimeout(350); }
await pageA.waitForTimeout(1200);
const online = await pageA.textContent('#onlineCount');
ok(parseInt(online) >= 2, `server reports ${online} players online`);
await pageA.screenshot({ path: '/tmp/shot-game-mp.png' });
ok(errors.length === 0, 'no browser console/page errors' + (errors.length ? ' -> ' + errors.slice(0, 4).join(' | ') : ''));
await browser.close();
console.log(failures === 0 ? '\nALL VISUAL TESTS PASSED' : `\n${failures} VISUAL TEST(S) FAILED`);
process.exit(failures ? 1 : 0);