初始提交:三玩法 Web 原型与设计文档
- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试 - 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本 - 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试 - 产品文档、UI 设计规范、各玩法 GDD / HANDOFF - 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// 通过 ego-browser nodejs < tools/browser-smoke.mjs 运行;仅访问本地测试页面。
|
||||
// 空间编号由首次 browser QA 建立,同一任务一直复用该空间。
|
||||
const space = Number(process.env.GARDEN_SPACE);
|
||||
if (!space || !process.env.GARDEN_QA_DIR) throw new Error('请设置 GARDEN_SPACE 与 GARDEN_QA_DIR,复用当前 QA 空间。');
|
||||
const task = await taskSpace(space), page = task.page('p1');
|
||||
await page.reload();
|
||||
await page.waitForFunction(() => !!window.__garden);
|
||||
const fs = await import('node:fs/promises');
|
||||
const root = process.env.GARDEN_QA_DIR;
|
||||
const report = { checks: [], levels: [] };
|
||||
await page.evaluate(() => { window.__qaErrors = []; window.addEventListener('error', e => window.__qaErrors.push(e.message)); window.addEventListener('unhandledrejection', e => window.__qaErrors.push(String(e.reason))); });
|
||||
const info = () => page.evaluate(() => {
|
||||
const g = window.__garden, s = g.snapshot(), t = g.transform(), r = document.getElementById('board').getBoundingClientRect();
|
||||
return { snapshot: s, level: g.level(), hint: g.hint(), points: g.hint().map(id => { const b = s.balls.find(b => b.id === id); return { x: r.left + t.x + b.x * t.scale, y: r.top + t.y + b.y * t.scale }; }) };
|
||||
});
|
||||
const send = async (type, points) => page.cdp('Input.dispatchTouchEvent', { type, touchPoints: points.map((p, id) => ({...p, id, radiusX: 5, radiusY: 5, force: 1})) });
|
||||
let initial = await info();
|
||||
if (initial.level.id !== 1) throw new Error('QA expects an untouched campaign');
|
||||
// 两颗松手、系统取消、回滑撤回均不得扣步。
|
||||
await send('touchStart', [initial.points[0]]); await send('touchMove', [initial.points[1]]); await send('touchEnd', []);
|
||||
if ((await info()).snapshot.stats.merges !== 0) throw new Error('short gesture committed');
|
||||
report.checks.push('两颗松手不扣步');
|
||||
await send('touchStart', [initial.points[0]]); await send('touchMove', [initial.points[1]]); await send('touchCancel', []);
|
||||
if ((await info()).snapshot.stats.merges !== 0) throw new Error('cancel committed');
|
||||
report.checks.push('触摸取消不提交');
|
||||
await send('touchStart', [initial.points[0]]); await send('touchMove', [initial.points[1]]); await send('touchMove', [initial.points[2]]); await send('touchMove', [initial.points[1]]); await send('touchEnd', []);
|
||||
if ((await info()).snapshot.stats.merges !== 0) throw new Error('backtrack failed');
|
||||
report.checks.push('回滑撤回');
|
||||
await page.click('#sound');
|
||||
await page.click('#hint');
|
||||
await page.screenshot({path: `${root}/mobile-initial.png`});
|
||||
for (let expected = 1; expected <= 10; expected++) {
|
||||
let data = await info();
|
||||
if (data.level.id !== expected) throw new Error(`Expected L${expected}, got ${data.level.id}`);
|
||||
for (let turn = 0; turn < data.level.moves; turn++) {
|
||||
data = await info();
|
||||
if (data.snapshot.status === 'won') break;
|
||||
if (data.snapshot.status !== 'playing') throw new Error(`L${expected} prematurely ${data.snapshot.status}`);
|
||||
const previous = data.snapshot.stats.merges;
|
||||
await send('touchStart', [data.points[0]]);
|
||||
for (const p of data.points.slice(1)) await send('touchMove', [p]);
|
||||
await send('touchEnd', []);
|
||||
await page.waitForFunction(previous => window.__garden.snapshot().stats.merges > previous && !window.__garden.animating(), previous, { timeout: 5000 });
|
||||
}
|
||||
data = await info();
|
||||
if (data.snapshot.status !== 'won') throw new Error(`L${expected} not won`);
|
||||
report.levels.push({ level: expected, moves: data.snapshot.stats.merges, score: data.snapshot.stats.score });
|
||||
console.log(`触摸通关 L${expected} ${data.snapshot.stats.merges} 步 ${data.snapshot.stats.score} 分`);
|
||||
if (expected === 7) await page.screenshot({path: `${root}/mobile-result.png`});
|
||||
if (expected < 10) {
|
||||
await page.click('[data-action="next"]');
|
||||
if (expected === 7) await page.screenshot({path: `${root}/mobile-level8.png`});
|
||||
}
|
||||
}
|
||||
await page.screenshot({path: `${root}/mobile-all-clear.png`});
|
||||
report.errors = await page.evaluate(() => window.__qaErrors);
|
||||
if (report.errors.length) throw new Error(JSON.stringify(report.errors));
|
||||
await fs.writeFile(`${root}/browser.json`, JSON.stringify(report, null, 2));
|
||||
console.log(await page.snapshot());
|
||||
Reference in New Issue
Block a user