// 本次任务已有空间为 4;新验收任务需改成已创建的空间 ID。 // 只读调试快照作为触摸定位依据,不改游戏状态。 import assert from 'node:assert/strict'; import { writeFile } from 'node:fs/promises'; const task = await taskSpace(4); const page = task.page('p1'); const dir = process.env.BALLOON_QA_DIR || '/Users/wukaibing/Grok/number-swipe/modes/02-connect-1234/docs/qa-v2'; await page.reload(); await page.evaluate(() => {window.qaErrors=[];addEventListener('error',e=>window.qaErrors.push(e.message));addEventListener('unhandledrejection',e=>window.qaErrors.push(String(e.reason)));}); const snapshot = () => page.evaluate(() => window.__balloons.snapshot()); const targets = () => page.evaluate(() => {const api=window.__balloons, s=api.snapshot(), t=api.transform(), r=document.querySelector('#board').getBoundingClientRect();return api.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,id:0,radiusX:5,radiusY:5,force:1};});}); const touch = (type, points=[]) => page.cdp('Input.dispatchTouchEvent',{type,touchPoints:points}); const swipe = async(points,cancel=false) => { for(let i=0;i!window.__balloons.animating(),undefined,{timeout:7000}); const after=await snapshot(); assert.equal(after.stats.turns,before.stats.turns+1); assert(after.stats.score>before.stats.score); assert(await page.evaluate(()=>document.querySelector('#modal').hidden)); moves.push({turn:after.stats.turns,score:after.stats.score,combo:after.stats.lastCombo,peak:after.stats.maxNumber,flown:after.stats.flown,feverLeft:after.feverLeft}); if(i===0){ await page.screenshot({path:dir+'/first-merge.png'}); await page.click('#undo'); assert.deepEqual(await snapshot(),before); await swipe(await targets()); await page.waitForFunction(()=>!window.__balloons.animating(),undefined,{timeout:7000}); assert.deepEqual(await snapshot(),after); } if(after.feverLeft===5 && !moves.slice(0,-1).some(m=>m.feverLeft===5)) await page.screenshot({path:dir+'/rainbow.png'}); if(after.stats.flown===1 && !moves.slice(0,-1).some(m=>m.flown>0)) await page.screenshot({path:dir+'/flight.png'}); } const beforeBreeze=await snapshot(); await page.click('#shuffle'); await page.waitForFunction(()=>!window.__balloons.animating(),undefined,{timeout:7000}); assert.deepEqual((await snapshot()).stats,beforeBreeze.stats); await page.click('#undo'); assert.deepEqual(await snapshot(),beforeBreeze); const errors=await page.evaluate(()=>window.qaErrors); assert.deepEqual(errors,[]); assert(moves.some(m=>m.combo>=3)); assert(moves.some(m=>m.flown>0)); assert(moves.some(m=>m.feverLeft>0)); await writeFile(dir+'/browser.json',JSON.stringify({viewport:[390,844],input:'CDP touch events',invalidCancelBacktrack:true,undoDeterministic:true,breezeUndo:true,moves,errors},null,2)+'\n'); console.log(JSON.stringify({gestures:moves.length,final:moves.at(-1),errors})); console.log(await page.snapshot());