Files
kidgo/tools/key-test.mjs
T
2026-10-20 22:21:26 +08:00

96 lines
4.0 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.
// 回归测试: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.window = {
addEventListener: addL, removeEventListener: noop,
AudioContext: null, webkitAudioContext: null, innerWidth: 1280, innerHeight: 800,
};
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);