101 lines
4.4 KiB
JavaScript
101 lines
4.4 KiB
JavaScript
// 回归测试:R 键必须"自杀回存档点",不能把整关重开(否则存档点白碰)
|
||
const noop = () => { };
|
||
const els = new Map();
|
||
function mkEl(id = '') {
|
||
return {
|
||
id, tagName: 'DIV', value: '', textContent: '', innerHTML: '',
|
||
style: {}, dataset: {}, children: [], width: 800, height: 608,
|
||
classList: { add: noop, remove: noop, toggle: noop, contains: () => false },
|
||
addEventListener: noop, removeEventListener: noop, appendChild: noop,
|
||
querySelector: () => mkEl(), querySelectorAll: () => [],
|
||
getBoundingClientRect: () => ({ left: 0, top: 0, width: 800, height: 608 }),
|
||
getContext: () => ctx2d, focus: noop, click: noop,
|
||
};
|
||
}
|
||
const ctx2d = new Proxy({
|
||
canvas: { width: 800, height: 608 },
|
||
measureText: () => ({ width: 12 }),
|
||
createLinearGradient: () => ({ addColorStop: noop }),
|
||
createRadialGradient: () => ({ addColorStop: noop }),
|
||
getImageData: () => ({ data: [] }),
|
||
}, { get(t, k) { return k in t ? t[k] : noop; }, set(t, k, v) { t[k] = v; return true; } });
|
||
|
||
const handlers = {};
|
||
const addL = (t, fn) => { (handlers[t] = handlers[t] || []).push(fn); };
|
||
const key = (t, c) => (handlers[t] || []).forEach(fn => fn({ code: c, preventDefault() { }, repeat: false }));
|
||
|
||
let clock = 1000;
|
||
globalThis.performance = { now: () => clock };
|
||
let rafCb = null;
|
||
globalThis.requestAnimationFrame = fn => { rafCb = fn; return 1; };
|
||
|
||
globalThis.location = { search: '', href: 'http://localhost/', pathname: '/', reload: noop };
|
||
Object.defineProperty(globalThis, 'navigator', { value: { maxTouchPoints: 0, userAgent: 'node' }, configurable: true });
|
||
globalThis.matchMedia = q => ({ matches: false, media: q, addEventListener: noop, removeEventListener: noop });
|
||
globalThis.window = {
|
||
addEventListener: addL, removeEventListener: noop,
|
||
AudioContext: null, webkitAudioContext: null, innerWidth: 1280, innerHeight: 800,
|
||
location: globalThis.location, navigator: globalThis.navigator,
|
||
matchMedia: globalThis.matchMedia,
|
||
};
|
||
globalThis.addEventListener = addL;
|
||
globalThis.removeEventListener = noop;
|
||
globalThis.confirm = () => true;
|
||
globalThis.alert = noop;
|
||
globalThis.localStorage = {
|
||
_d: {}, getItem(k) { return this._d[k] ?? null; },
|
||
setItem(k, v) { this._d[k] = String(v); }, removeItem(k) { delete this._d[k]; },
|
||
};
|
||
globalThis.document = {
|
||
getElementById(id) { if (!els.has(id)) els.set(id, mkEl(id)); return els.get(id); },
|
||
querySelector: s => mkEl(s), querySelectorAll: () => [],
|
||
createElement: t => mkEl(), addEventListener: addL, body: mkEl('body'),
|
||
};
|
||
|
||
await import('../js/main.js');
|
||
const { LEVELS } = await import('../js/levels/index.js');
|
||
const api = globalThis.window.__IW;
|
||
|
||
let fail = 0;
|
||
const err = m => { console.log(' ✗ ' + m); fail++; };
|
||
const step = n => { for (let i = 0; i < n; i++) { clock += 17; const f = rafCb; rafCb = null; if (f) f(clock); } };
|
||
|
||
const d = LEVELS.find(l => l.id === 'j1');
|
||
api.startLevel(d, 0);
|
||
step(10);
|
||
|
||
const L0 = api.G.level, P = api.G.player;
|
||
// 手动吃一个存档点(模拟玩家走到那里)
|
||
const s = L0.entities.filter(e => e.type === 'save')[1];
|
||
P.x = s.x + s.w / 2 - P.w / 2; P.y = s.y + s.h - P.h;
|
||
step(3);
|
||
const cp = P.savePoint;
|
||
console.log(` 存档点激活=${!!cp} 位置=(${cp?.x.toFixed(0)},${cp?.y.toFixed(0)}) 关卡出生点x=${L0.spawn.x.toFixed(0)}`);
|
||
if (!cp) err('存档点未激活');
|
||
|
||
// ---- 按 R ----
|
||
const deaths0 = api.G.deaths;
|
||
key('keydown', 'KeyR');
|
||
step(2);
|
||
key('keyup', 'KeyR');
|
||
step(60);
|
||
|
||
const survivedLevel = api.G.level === L0;
|
||
console.log(` 按 R 后:关卡对象未被重建=${survivedLevel} 玩家x=${api.G.player.x.toFixed(0)} 死亡=${deaths0}→${api.G.deaths}`);
|
||
if (!survivedLevel) err('R 键把整关重开了,存档进度丢失');
|
||
if (Math.abs(api.G.player.x - cp.x) > 4) err(`R 键后没有回到存档点(x=${api.G.player.x.toFixed(0)} 期望 ${cp.x.toFixed(0)})`);
|
||
if (api.G.deaths !== deaths0 + 1) err('R 键没有计入死亡数');
|
||
if (Math.abs(api.G.player.x - L0.spawn.x) < 4) err('R 键后被送回了关卡起点');
|
||
|
||
// ---- 按 Backspace = 整关重来 ----
|
||
key('keydown', 'Backspace');
|
||
step(2);
|
||
key('keyup', 'Backspace');
|
||
step(10);
|
||
console.log(` 按 Backspace 后:关卡对象被重建=${api.G.level !== L0} 玩家x=${api.G.player.x.toFixed(0)}`);
|
||
if (api.G.level === L0) err('Backspace 没有整关重开');
|
||
if (Math.abs(api.G.player.x - api.G.level.spawn.x) > 4) err('Backspace 后玩家不在出生点');
|
||
|
||
console.log(fail ? `\n❌ ${fail} 项失败` : '\n✅ 按键语义正确:R=回存档点,Backspace=整关重来');
|
||
process.exit(fail ? 1 : 0);
|