import { launch, CDP } from './cdpshot.mjs'; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); const URL = 'http://localhost:8080/index.html'; const { url: wsUrl, kill } = await launch(URL, undefined, 1280, 720, 5000); const cdp = new CDP(wsUrl); await cdp.open(); await cdp.send('Runtime.enable'); const errors = []; cdp.on('Runtime.consoleAPICalled', (p) => { const txt = (p.args ?? []).map((a) => a.value ?? a.description ?? '').join(' '); errors.push(`${p.type}: ${txt}`.slice(0, 300)); }); cdp.on('Runtime.exceptionThrown', (p) => errors.push('EXC: ' + (p.exceptionDetails?.exception?.description ?? p.exceptionDetails?.text ?? '').slice(0, 300))); const ev = async (expression) => { const r = await cdp.send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) throw new Error('eval: ' + (r.exceptionDetails.exception?.description ?? r.exceptionDetails.text)); return r.result?.value; }; async function click(cx, cy) { await cdp.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: cx, y: cy }); await sleep(80); await cdp.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: cx, y: cy, button: 'left', clickCount: 1 }); await sleep(100); await cdp.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x: cx, y: cy, button: 'left', clickCount: 1 }); await sleep(80); } const toClient = (x, y) => `(() => { const c = window.game.canvas; const r = c.getBoundingClientRect(); const z = r.width / c.width; return [r.left + ${x} * z, r.top + ${y} * z]; })()`; // wait for menu, boot game let menuUp = false; for (let i = 0; i < 120 && !menuUp; i++) { await sleep(500); menuUp = await ev(`!!(window.game && window.game.scene.isActive('MenuScene'))`); } if (!menuUp) throw new Error('no menu'); await sleep(4200); const mb = await ev(`(() => { const m = window.game.scene.getScene('MenuScene'); return [m.newGameBtn.x, m.newGameBtn.y]; })()`); await click(...(await ev(toClient(mb[0], mb[1])))); let gameUp = false; for (let i = 0; i < 240 && !gameUp; i++) { await sleep(500); gameUp = await ev(`!!(window.game && window.game.scene.isActive('GameScene') && window.game.scene.getScene('GameScene').ship)`); } if (!gameUp) throw new Error('no game'); // instrument await ev(`(() => { const gs = window.game.scene.getScene('GameScene'); window.__log = []; const orig = gs.deckAction.bind(gs); gs.deckAction = (id) => { window.__log.push('deckAction:' + id); return orig(id); }; const press = gs.actionBar.press.bind(gs.actionBar); gs.actionBar.press = (s) => { window.__log.push('press:' + s.id + ' pressing=' + s.pressing + ' disabled=' + s.disabled); return press(s); }; return true; })()`); const menuBtn = await ev(`(() => { const gs = window.game.scene.getScene('GameScene'); const s = gs.actionBar.slots.find((s) => s.id === 'menu'); const r = gs.actionBar.slotHit(); return [s.slot.x, s.slot.y, r.width, r.height, gs.actionBar.rect]; })()`); console.log('MENU slot:', JSON.stringify(menuBtn)); const [cx, cy] = await ev(toClient(menuBtn[0], menuBtn[1])); console.log('client:', cx, cy, 'canvas rect:', await ev(`(() => { const r = window.game.canvas.getBoundingClientRect(); return { l: r.left, t: r.top, w: r.width, h: r.height, cw: window.game.canvas.width, ch: window.game.canvas.height }; })()`)); await click(cx, cy); await sleep(300); console.log('log after click 1:', await ev(`window.__log.slice()`)); console.log('subbar open:', await ev(`window.game.scene.getScene('GameScene').menuSubBar?.isOpen`)); await sleep(500); console.log('log:', await ev(`window.__log.slice()`)); console.log('subbar open:', await ev(`window.game.scene.getScene('GameScene').menuSubBar?.isOpen`)); console.log('errors:', errors.slice(-8)); // try a second click (toggle test) await click(cx, cy); await sleep(400); console.log('log after click 2:', await ev(`window.__log.slice()`)); console.log('subbar open:', await ev(`window.game.scene.getScene('GameScene').menuSubBar?.isOpen`)); cdp.close(); kill();