Files
Toolbox/dev_test_scripts/debug/debug_physics_balls_dom_smoke.js
T
yangxiangyuan 91148fe064 feat: 新增物理弹球实验室及配套功能
1. 新增物理弹球游戏全套代码,包含物理引擎、规则、渲染、游戏逻辑、存档、音效、UI
2. 新增物理弹球相关调试与单元测试脚本
3. 优化私有剪贴上传功能:增加200MB上传限制与错误提示
4. 修复复古弹球桌的光滑面防粘附与休眠逻辑
2026-08-08 22:31:33 +08:00

127 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
* debug_physics_balls_dom_smoke.js · 物理弹球 · 前端 DOM 桩冒烟
* 无浏览器环境下用最小 DOM/Canvas 桩加载全部前端脚本,
* 驱动主循环 + 模拟拖拽发射/暂停/记录等交互,捕获运行时错误。
* 运行:node dev_test_scripts/debug/debug_physics_balls_dom_smoke.js
* ============================================================ */
'use strict';
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const LAB_DIR = path.join(__dirname, '..', '..', 'public', 'tools', 'thought_lab', 'labs', 'physics_balls');
const FILES = ['pb_physics.js', 'pb_rules.js', 'pb_storage.js', 'pb_audio.js', 'pb_render.js', 'pb_game.js', 'pb_ui.js'];
function makeCtx() {
const store = {};
return new Proxy(store, {
get(t, k) {
if (k === 'createRadialGradient') return () => ({ addColorStop() {} });
if (k === 'measureText') return () => ({ width: 10 });
if (k in t) return t[k];
return function () {};
},
set(t, k, v) { t[k] = v; return true; }
});
}
function makeEl(id) {
const listeners = {};
return {
id,
style: {},
dataset: {},
classList: { add() {}, remove() {}, toggle() {}, contains() { return false; } },
children: [],
_html: '', _text: '',
set innerHTML(v) { this._html = v; this.children = []; },
get innerHTML() { return this._html; },
set textContent(v) { this._text = String(v); },
get textContent() { return this._text; },
appendChild(c) { this.children.push(c); },
addEventListener(t, f) { (listeners[t] = listeners[t] || []).push(f); },
dispatch(t, ev) { (listeners[t] || []).forEach(f => f(ev || {})); },
getBoundingClientRect() { return { left: 0, top: 0, width: 420, height: 880 }; },
getContext() { return makeCtx(); },
checked: true,
width: 420, height: 880
};
}
const els = {};
function getEl(id) { if (!els[id]) els[id] = makeEl(id); return els[id]; }
let rafCb = null;
const winListeners = {};
const sandbox = {
console, Math, Date, setTimeout, clearTimeout,
JSON, localStorage: { getItem: () => null, setItem: () => {}, removeItem: () => {} },
navigator: { clipboard: { writeText: () => ({ then: (a) => a && a() }) } },
requestAnimationFrame: (cb) => { rafCb = cb; return 1; },
document: {
getElementById: getEl,
createElement: (tag) => makeEl('dyn_' + tag)
},
addEventListener: (t, f) => { (winListeners[t] = winListeners[t] || []).push(f); },
dispatchWin: (t, ev) => { (winListeners[t] || []).forEach(f => f(ev || {})); },
window: null
};
sandbox.window = sandbox;
sandbox.globalThis = sandbox;
vm.createContext(sandbox);
for (const f of FILES) {
vm.runInContext(fs.readFileSync(path.join(LAB_DIR, f), 'utf-8'), sandbox, { filename: f });
}
function frames(n, t0) {
for (let i = 0; i < n; i++) {
const cb = rafCb; rafCb = null;
if (!cb) throw new Error('rAF chain broken');
cb(t0 + i * 16.7);
}
}
console.log('== 物理弹球 DOM 冒烟 ==');
// init(load 事件不会在 vm 里触发,手动调)
sandbox.PBUi.init();
frames(30, 0);
console.log(' ✓ init + 30 帧主菜单渲染');
// 模拟拖拽发射(pointermove/up 注册在 window 级)
const canvas = getEl('pb-canvas');
canvas.dispatch('pointerdown', { clientX: 260, clientY: 600 });
frames(5, 600);
sandbox.dispatchWin('pointermove', { clientX: 300, clientY: 650 });
sandbox.dispatchWin('pointerup', {});
frames(60 * 6, 700);
console.log(' ✓ 拖拽发射 + 6s 模拟');
// 暂停 / 继续
getEl('pb-pause-btn').dispatch('click');
getEl('pb-resume').dispatch('click');
frames(60, 60 * 7 * 16.7);
console.log(' ✓ 暂停/继续');
// 记录页 / 指南 / 设置 / 每日领取
getEl('pb-side-records').dispatch('click');
getEl('pb-records-close').dispatch('click');
getEl('pb-help').dispatch('click');
getEl('pb-guide-ok').dispatch('click');
getEl('pb-gear').dispatch('click');
getEl('pb-settings-close').dispatch('click');
getEl('pb-daily').dispatch('click');
console.log(' ✓ 记录/指南/设置/每日领取交互');
// 长时模拟 60s,覆盖回合推进/上升/回收
for (let s = 0; s < 60; s++) {
if (s % 7 === 0) {
canvas.dispatch('pointerdown', { clientX: 150 + (s * 13) % 200, clientY: 620 });
sandbox.dispatchWin('pointermove', { clientX: 190 + (s * 13) % 160, clientY: 660 });
sandbox.dispatchWin('pointerup', {});
}
frames(60, (10 + s) * 1000);
}
console.log(' ✓ 60s 长时模拟(含多次发射)');
console.log('\n冒烟通过,无运行时异常');