From 24578cf2cb3dc61a0571f58204fec86faed79d11 Mon Sep 17 00:00:00 2001 From: sganggs Date: Tue, 6 Oct 2026 22:00:26 +0800 Subject: [PATCH] =?UTF-8?q?feedback5=20WZ:=20the=20real-server=20equip-rep?= =?UTF-8?q?lace=20check=20waits=20until=20=E5=8F=96=E6=B6=88=20has=20drawn?= =?UTF-8?q?=20the=20item=20back=20on=20its=20bench=20slot=20before=20it=20?= =?UTF-8?q?drops=20it=20again=20(test/ui/leftovers.e2e.test.js)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.2.0 candidate's full pass failed at the second drop ('Waiting for selector `.eqr .eqr__opt` failed'). The view keeps a dropped piece on the drop tile for 1.3 s (render/app/tune.js DROP_PENDING_MS, unchanged since the first import) and then flies it back in a frame-timed tween. The test picked the item up again 0.5 s after 取消, where it had been drawn a moment before. Even alone the first try often grabbed nothing (the helper's retry hid it). With few frames (software-rendered headless Chrome on a loaded machine; reproduced with frames ~600 ms apart) the press grabbed the operator under the item, the operator dropped on its own tile opened the direction wheel, and the wheel swallowed the retry. The dialog itself opens and renders as before (补位 / i18n / 自选 not involved). Now 取消 is also checked to draw the item back on its bench slot, and the next drop waits for that; under the same slow frames the drop succeeds at the first try. Alone: 5/5 twice; mock.e2e 32/32, devices.e2e 26/26. A test timing flake, no product change; golden unchanged. --- test/ui/leftovers.e2e.test.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/ui/leftovers.e2e.test.js b/test/ui/leftovers.e2e.test.js index 4381b1ca..6095c964 100644 --- a/test/ui/leftovers.e2e.test.js +++ b/test/ui/leftovers.e2e.test.js @@ -10,7 +10,8 @@ // 4. solo battle: the pause button sends g.pause {on}, m.public.paused shows the overlay and freezes the countdown, // Space resumes; no pause control in co-op or in prep. // Real server (test/e2e/fastServer.mjs, real clicks and canvas drags): -// 1+4. a solo run: equip two items on an operator, drop a third → dialog → 取消 (nothing sent) → pick the OLDER item → +// 1+4. a solo run: equip two items on an operator, drop a third → dialog → 取消 (nothing sent, the item drawn back on its +// bench slot) → pick the OLDER item → // the real engine destroys exactly that one; then ready → the real local battle → pause (the battle clock and the // countdown stand still) → 继续作战; // 3. the server restarts while the briefing is on screen → 「服务器会话已重置,上一局模拟已结束」 and the lobby. @@ -275,6 +276,7 @@ describe('client leftovers — real server', { skip: !ENABLED && 'set SP_E2E=1 ( const equipped = await itemsOf(); assert.deepEqual(equipped.map((x) => x.id), KIT_ITEMS.slice(0, 2)); const third = await handItem(KIT_ITEMS[2]); + const benchSlot = await c.piecePoint(third.uid, 0.5); // where the view draws it in the hand // the third: dialog → 取消 → nothing sent / changed await dropItem(third); @@ -289,6 +291,15 @@ describe('client leftovers — real server', { skip: !ENABLED && 'set SP_E2E=1 ( assert.equal((await c.requests('g.equip')).length, sentBefore, '取消: no g.equip'); assert.deepEqual(await itemsOf(), equipped, '取消: unchanged'); assert.ok(await handItem(KIT_ITEMS[2]), '取消: the item stays in the hand'); + // ... and is drawn back on its bench slot before it is picked up again. The view keeps a dropped piece on the drop + // tile for 1.3 s (render/app/tune.js DROP_PENDING_MS), then flies it back in a frame-timed tween: with few frames + // (software-rendered headless Chrome on a loaded machine) the drag aimed where it stood a moment before grabbed the + // operator under it, whose direction wheel then swallowed the retry (the 0.2.0 candidate's full pass). + const back = await c.page.waitForFunction((uid, x, y) => { + const r = globalThis.__SP_VIEW__?.pieceScreenRect(uid); + return !!r && Math.abs(r.left + r.width / 2 - x) < 2 && Math.abs(r.top + r.height / 2 - y) < 2; + }, { timeout: 15000, polling: 100 }, third.uid, benchSlot.x, benchSlot.y).then(() => true, () => false); + assert.ok(back, '取消: the item is drawn back on its bench slot'); // again → pick the OLDER item (not the server's default either way: explicit replaceUid) → 确认替换 await dropItem(third);