77a690fcf6
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) Failing after 13s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Failing after 0s
CI / deploy (pull_request) Has been skipped
Remove the under-board status strip and relocate its signals: - bag count -> a badge on the exchange/pass control + the foot of the move table - whose-turn / win-lose -> a thin strip above the score plaques - the tentative-move caption -> the board itself: staged tiles tint green (legal) or pink (illegal), the board tiles a formed word runs through go a shade darker, and an orange score badge sits on the main word (digit sized like a tile value, clamped on-board) The word geometry (covered cells + badge anchor) is a new pure client-side helper (ui/src/lib/formed.ts), independent of the move evaluator, so it works on the local or network preview path alike; the badge's number still comes from the preview score. Rack: a seven-column grid filling the tray width in both layouts — square, full-width tiles — with the confirm control in the fixed 7th slot. Settings: a touch-only "Zoom the board" toggle (default on, device-local) gates the tile-placement auto-zoom; taking a hint while zoomed in now zooms out so the highlighted hint word is never left off-screen. Docs (FUNCTIONAL +_ru, UI_DESIGN, ARCHITECTURE) and e2e/unit tests updated.
48 lines
2.2 KiB
TypeScript
48 lines
2.2 KiB
TypeScript
import { expect, test } from './fixtures';
|
|
|
|
// The playable-slice smoke against the mock transport: guest login -> lobby shows the
|
|
// seeded active game -> open it -> the board renders committed tiles -> place a rack
|
|
// tile (tap) and see the score preview.
|
|
test('guest reaches a board and previews a placement', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
await page.getByRole('button', { name: /guest/i }).click();
|
|
|
|
await expect(page.getByText('Your turn')).toBeVisible();
|
|
const activeRow = page.getByRole('button', { name: /Ann/ });
|
|
await expect(activeRow).toBeVisible();
|
|
await activeRow.click();
|
|
|
|
// Board renders, including a committed tile from the seeded HELLO play.
|
|
await expect(page.locator('[data-cell]').first()).toBeVisible();
|
|
await expect(page.locator('[data-cell] .letter', { hasText: 'H' }).first()).toBeVisible();
|
|
|
|
// Tap a rack tile, then an empty board cell -> a pending tile + score preview.
|
|
const rackTile = page.locator('.rack .tile').first();
|
|
await rackTile.click();
|
|
await page.locator('[data-cell]:not(.filled)').nth(30).click();
|
|
await expect(page.locator('[data-cell].pending')).toHaveCount(1);
|
|
// The move-score badge appears on the board for the staged play.
|
|
await expect(page.locator('.scorebadge')).toContainText(/\d/);
|
|
|
|
// The contextual MakeMove control (✅) appears once a tile is pending.
|
|
await expect(page.locator('.make')).toBeVisible();
|
|
});
|
|
|
|
// The SPA pins the document so iOS/WKWebView cannot rubber-band the whole page on a vertical
|
|
// drag (the elastic bounce that fought the board's swipe-to-open-history). The native bounce
|
|
// itself is not reproducible in Playwright, so we assert the CSS contract that suppresses it.
|
|
test('the app pins the document so the page cannot rubber-band', async ({ page }) => {
|
|
await page.goto('/');
|
|
await expect(page.getByRole('button', { name: /guest/i })).toBeVisible();
|
|
|
|
const lock = await page.evaluate(() => ({
|
|
shell: document.documentElement.classList.contains('app-shell'),
|
|
htmlOverflow: getComputedStyle(document.documentElement).overflowY,
|
|
bodyPosition: getComputedStyle(document.body).position,
|
|
}));
|
|
expect(lock.shell).toBe(true);
|
|
expect(lock.htmlOverflow).toBe('hidden');
|
|
expect(lock.bodyPosition).toBe('fixed');
|
|
});
|