feedback7 G-UI: Enter on the equip-replace dialog's buttons keeps its native behaviour (PR #358 by @Xinglan233)

Applied as-is. The replace dialog no longer treats Enter that started on a button as confirm. Enter or Space on 取消 closes the dialog and leaves the chosen equipment in place. Enter on an option only changes the selection. Enter on the confirm button still sends g.equip with that replaceUid. This matches the guard already used by DialogHost.

Tests: node --test test/ui/mock.e2e.test.js test/ui/leftovers.test.js test/ui/standin-ui.test.js — 31 pass, 0 fail. The mock e2e suite skipped because SP_E2E is unset. eslint on the touched files: 0 errors (one pre-existing unused-assignment warning in mock.e2e.test.js).
This commit is contained in:
Xinglan233 authored and sganggs committed 2026-10-08 18:44:09 +08:00
1 parent 5952539046
commit bc22f9cbe6
2 files changed
+66 -1

No files matched your search

+64
View File
@@ -95,6 +95,70 @@ describe('in-match UI (mock harness, headless Chrome)', { skip: !ENABLED && 'set
});
}
test('equip replace: focused buttons keep their native Enter action', async () => {
const { page, problems } = await open('phase=PREP', { render: 'fallback' });
const initial = await mockState(page);
const target = initial.board.find((p) => p.kind === 'chess' && p.items?.length === 2);
assert.ok(target, 'the fixture has an operator with two equipped items');
const item = initial.hand.find((p) => p?.kind === 'item' && !target.items.some((x) => x.id === p.id));
assert.ok(item, 'the fixture has a loose equipment item');
const requests = () => page.evaluate(() => globalThis.__MOCK__.S().requests.filter(([t]) => t === 'g.equip'));
const center = (sel) => page.$eval(sel, (el) => { const r = el.getBoundingClientRect(); return { x: r.left + r.width / 2, y: r.top + r.height / 2 }; });
const openReplace = async () => {
const from = await center(`.ff-piece[data-uid="${item.uid}"]`);
const to = await center(`.ff-piece[data-uid="${target.uid}"]`);
await page.mouse.move(from.x, from.y);
await page.mouse.down();
await page.mouse.move(to.x, to.y, { steps: 8 });
await sleep(80);
await page.mouse.up();
await page.waitForSelector('.eqr__opt');
await sleep(500); // let the dialog's mount effect settle before selecting an item
await page.click(`.eqr__opt[data-uid="${target.items[1].uid}"]`);
await page.waitForSelector('.eqr__opt[aria-checked="true"]');
};
const tabToCancel = async () => {
for (let i = 0; i < 8; i++) {
if (await page.evaluate(() => document.activeElement?.matches('.eqr__cancel'))) return;
await page.keyboard.press('Tab');
}
assert.fail('Tab did not focus Cancel');
};
for (const key of ['Space', 'Enter']) {
await openReplace();
await tabToCancel();
await page.keyboard.press(key);
await page.waitForFunction(() => !document.querySelector('.eqr'));
await sleep(200);
assert.deepEqual(await requests(), [], `${key} on Cancel sends no equipment intent`);
const state = await mockState(page);
assert.deepEqual(state.board.find((p) => p.uid === target.uid).items, target.items, 'both equipped items remain');
assert.ok(state.hand.some((p) => p?.uid === item.uid), 'the new item remains in the hand');
}
// Enter on an equipment option toggles its selection; only the confirmation button replaces it.
await openReplace();
await page.keyboard.press('Enter');
await page.waitForFunction(() => !document.querySelector('.eqr__opt[aria-checked="true"]'));
await page.keyboard.press('Enter');
await page.waitForSelector('.eqr__opt[aria-checked="true"]');
assert.deepEqual(await requests(), [], 'Enter on an option only changes the selected item');
await tabToCancel();
await page.keyboard.press('Tab');
assert.equal(await page.evaluate(() => document.activeElement?.matches('.eqr__ok')), true);
await page.keyboard.press('Enter');
await page.waitForFunction(() => !document.querySelector('.eqr'));
await sleep(200);
assert.deepEqual(await requests(), [['g.equip', { itemUid: item.uid, targetUid: target.uid, replaceUid: target.items[1].uid }]]);
const replaced = await mockState(page);
assert.deepEqual(replaced.board.find((p) => p.uid === target.uid).items.map((x) => x.uid), [target.items[0].uid, item.uid]);
assert.ok(!replaced.hand.some((p) => p?.uid === item.uid), 'the confirmed equipment leaves the hand');
// This keyboard regression also runs without optional art/fonts; JavaScript exceptions still fail it.
assert.deepEqual(problems.filter((p) => p.startsWith('pageerror:')), []);
await page.close();
});
test('prep: buy, shortcuts, ready, Esc', async () => {
const { page, problems } = await open('phase=PREP');
let s = await mockState(page);