e68fe61e39
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 42s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 58s
Replace the flat chronological move list with a ruled matrix aligned under the score plaque: one column per seat, each seat's moves filling its column top to bottom. A cell is the move's word(s) and its score, "WORD (12)", centred; the player names and the running total are dropped (the plaque heads the column and shows the live total). Non-play moves keep their dim parenthesised tag; the awaited opponent's next cell shows a dim "thinking..." (never the viewer's own turn). Thin 1px rules between columns and rows match the panel's separator. Re-introduce a swipe-down-on-the-board gesture to open the history, gated to the zoom-out board scrolled to its top so it never fights the zoomed board's pan or the stage's own vertical scroll (the conflict that retired this gesture before). Grid layout extracted to lib/history.ts (unit-tested); add game.thinking to the EN/RU catalogs; e2e covers the gesture and the grid on Chromium and WebKit.
78 lines
3.4 KiB
TypeScript
78 lines
3.4 KiB
TypeScript
import { expect, test, type Page } from './fixtures';
|
||
|
||
// The redesigned move history: a ruled matrix with one column per seat (no player names, no
|
||
// running total), opened by a swipe-down on the zoom-out board. The gesture is touch-only and
|
||
// the desktop projects have no touch input, so the swipe is dispatched as PointerEvents with
|
||
// pointerType:'touch'; a phone viewport so the board fills the width.
|
||
test.use({ viewport: { width: 390, height: 844 } });
|
||
|
||
async function openGame(page: Page): Promise<void> {
|
||
await page.goto('/');
|
||
await page.getByRole('button', { name: /guest/i }).click();
|
||
await page.getByRole('button', { name: /Ann/ }).click(); // the seeded active game G1 (your turn)
|
||
await expect(page.locator('[data-cell]').first()).toBeVisible();
|
||
await expect(page.locator('.pane')).toHaveCount(1); // let the screen-slide settle
|
||
}
|
||
|
||
/** touchSwipeDown dispatches a single-finger vertical touch drag on the board wrapper. */
|
||
async function touchSwipeDown(page: Page, fromY: number, toY: number): Promise<void> {
|
||
const box = (await page.locator('.boardwrap').boundingBox())!;
|
||
const x = box.x + box.width / 2;
|
||
await page.locator('.boardwrap').evaluate(
|
||
(el, { x, fromY, toY }) => {
|
||
const fire = (type: string, y: number) =>
|
||
el.dispatchEvent(
|
||
new PointerEvent(type, { pointerType: 'touch', clientX: x, clientY: y, bubbles: true, cancelable: true }),
|
||
);
|
||
fire('pointerdown', fromY);
|
||
for (let i = 1; i <= 8; i++) fire('pointermove', fromY + ((toY - fromY) * i) / 8);
|
||
fire('pointerup', toY);
|
||
},
|
||
{ x, fromY, toY },
|
||
);
|
||
}
|
||
|
||
test('a swipe-down on the zoom-out board opens the history', async ({ page }) => {
|
||
await openGame(page);
|
||
await page.locator('.stage').evaluate((el) => (el.scrollTop = 0)); // the pull only opens at the top
|
||
const box = (await page.locator('.boardwrap').boundingBox())!;
|
||
|
||
await touchSwipeDown(page, box.y + 20, box.y + 180);
|
||
|
||
await expect(page.locator('.history')).toBeVisible();
|
||
await expect(page.locator('.boardwrap.slid')).toBeVisible();
|
||
});
|
||
|
||
test('the history is a per-seat grid with move scores but no names or running total', async ({ page }) => {
|
||
await openGame(page);
|
||
await page.locator('.scoreboard').click(); // open the history (gesture is covered separately)
|
||
|
||
const grid = page.locator('.hgrid');
|
||
await expect(grid).toBeVisible();
|
||
// G1: You [HELLO 16, RAT 3] vs Ann [WORLD 9, AND 4] — a 2×2 matrix, no empty/thinking cells.
|
||
await expect(page.locator('.hcell')).toHaveCount(4);
|
||
await expect(grid).toContainText('HELLO');
|
||
await expect(grid).toContainText('(3)'); // RAT's per-move score
|
||
// The running total (RAT's was 19) and the seat names no longer appear in the table.
|
||
await expect(grid).not.toContainText('19');
|
||
await expect(grid).not.toContainText('Ann');
|
||
});
|
||
|
||
test('a swipe-down on the zoomed-in board does not open the history (native scroll wins)', async ({ page }) => {
|
||
await openGame(page);
|
||
// Double-tap an empty cell to zoom in (two synchronous clicks = a double-tap).
|
||
await page
|
||
.locator('[data-cell]:not(.filled)')
|
||
.nth(20)
|
||
.evaluate((el: HTMLElement) => {
|
||
el.click();
|
||
el.click();
|
||
});
|
||
await expect(page.locator('.viewport.zoomed')).toBeVisible();
|
||
const box = (await page.locator('.boardwrap').boundingBox())!;
|
||
|
||
await touchSwipeDown(page, box.y + 20, box.y + 180);
|
||
|
||
await expect(page.locator('.history')).toHaveCount(0);
|
||
});
|