Files
ark-stronghold-protocol/test/ui/bond-collapse.e2e.test.js
T
Alsan Jayson ede8e7e773 The bond bar can be folded, so the board stays tappable on phones (#149)
The fold state stays for the match; Space does not ready or pause at the same time. Closes #142. Contributed by @CELLOPOI.
2026-10-05 22:36:15 +08:00

98 lines
5.8 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.
// Issue #142: the real match HUD in the mock harness, using the DOM field so optional art / WebGL is not required.
// SP_E2E=1 CHROME_PATH=/path/to/chrome node --test test/ui/bond-collapse.e2e.test.js
import { test, describe, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { existsSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
const CHROME = process.env.CHROME_PATH || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
const ENABLED = process.env.SP_E2E === '1' && existsSync(CHROME);
const OUT = fileURLToPath(new URL('../e2e/out/', import.meta.url));
describe('collapsible bond strip (issue #142)', { skip: !ENABLED && 'set SP_E2E=1 and CHROME_PATH to run' }, () => {
let srv, browser;
before(async () => {
const { startServer } = await import('../../server/index.js');
const puppeteer = (await import('puppeteer-core')).default;
srv = await startServer({ port: 0, host: '127.0.0.1', quiet: true });
browser = await puppeteer.launch({ executablePath: CHROME, headless: true, args: ['--no-sandbox', '--no-proxy-server'] });
mkdirSync(OUT, { recursive: true });
});
after(async () => { await browser?.close(); await srv?.close(); });
for (const [width, height, touch] of [[1920, 1080, false], [640, 360, true]]) {
test(`collapse releases field input and keeps current bonds at ${width}×${height}`, async () => {
const page = await browser.newPage();
const errors = [];
page.on('pageerror', (e) => errors.push(e.message));
const activate = (selector) => touch ? page.tap(selector) : page.click(selector);
const expanded = () => page.$eval('.bonds-toggle', (el) => el.getAttribute('aria-expanded'));
try {
await page.setViewport({ width, height, isMobile: touch, hasTouch: touch });
await page.goto(`${srv.url}/dev/game-mock.html?shot=1&render=fallback&phase=PREP`, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('.ff-piece');
await page.waitForSelector('.bslot .bond');
assert.equal(await expanded(), 'true');
const toggle = await page.$eval('.bonds-toggle', (el) => {
const r = el.getBoundingClientRect();
return { width: r.width, height: r.height, controls: el.getAttribute('aria-controls') };
});
assert.ok(toggle.width >= 44 && toggle.height >= 44, 'visible touch target is at least 44×44');
assert.equal(toggle.controls, 'match-bond-strip');
const covered = await page.$eval('.bslot .bond', (el) => {
const r = el.getBoundingClientRect();
return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
});
await activate('.bslot .bond');
await page.waitForSelector('.bpop');
await activate('.bonds-toggle');
await page.waitForSelector('#match-bond-strip', { hidden: true });
assert.equal(await expanded(), 'false');
assert.equal(await page.$('.bpop'), null, 'collapsing closes the strip popup');
assert.equal(await page.$eval('.bonds-toggle', (el) => el.getAttribute('aria-label')), '展开盟约');
assert.ok(await page.evaluate(({ x, y }) => !!document.elementFromPoint(x, y)?.closest('.gm__field'), covered),
'the former bond position now hits the field');
await page.evaluate(() => {
globalThis.__fieldPresses = 0;
document.querySelector('.gm__field').addEventListener('pointerdown', () => globalThis.__fieldPresses++);
});
if (touch) await page.touchscreen.tap(covered.x, covered.y);
else await page.mouse.click(covered.x, covered.y);
assert.equal(await page.evaluate(() => globalThis.__fieldPresses), 1, 'pointer input reaches the field');
await page.screenshot({ path: `${OUT}/bonds-collapsed-${width}.png` });
// Hidden content must keep following state changes, including the empty-bonds state.
await page.evaluate(() => globalThis.__MOCK__.mutate((s) => { s.priv.board = []; s.priv.hand.fill(null); }));
await activate('.bonds-toggle');
await page.waitForSelector('.bstrip--empty', { visible: true });
assert.equal(await expanded(), 'true');
await page.focus('.bonds-toggle');
await page.keyboard.press('Space');
await page.waitForSelector('#match-bond-strip', { hidden: true });
assert.equal(await page.evaluate(() => globalThis.__MOCK__.S().priv.ready), false, 'Space on the toggle does not ready the player');
assert.equal(await page.$('.modal'), null, 'Space does not open the funds confirmation');
await page.keyboard.press('Enter');
await page.waitForSelector('.bstrip--empty', { visible: true });
await activate('.bonds-toggle');
await activate('.team__row:not(.is-self) .team__btn');
if (await page.$('.team__ob')) await activate('.team__ob');
await page.waitForSelector('.gm__watching');
assert.equal(await expanded(), 'false', 'watching a teammate preserves the collapse choice');
await activate('.bonds-toggle');
await page.waitForSelector('.bstrip__owner', { visible: true });
assert.ok(await page.$eval('.bstrip', (el) => el.getAttribute('data-owner')), 'expanded bonds belong to the watched teammate');
await activate('.bonds-toggle');
await page.evaluate(() => globalThis.__MOCK__.setPhase('COMBAT'));
await page.waitForSelector('.gm--combat');
assert.equal(await expanded(), 'false', 'phase changes preserve the collapse choice');
await activate('.bonds-toggle');
await page.waitForSelector('.bslot .bond', { visible: true });
assert.equal(await expanded(), 'true');
await page.screenshot({ path: `${OUT}/bonds-expanded-${width}.png` });
assert.deepEqual(errors, []);
} finally { await page.close(); }
});
}
});