Stage 7: regression tests for the polished UI (logic + behaviour)
Lock the polish branch's behaviour so a future UI edit surfaces as a failing
assertion to re-agree or fix.
Unit (vitest, node env):
- placement: recallIndex, cellOccupied/isBlankSlot, non-linear direction, the
single-tile submit default, and placementFromHint blank-fallback / rack-exhausted.
- banner: the marquee scroll-cycle repeat-then-advance, stop(), root-relative and
multiple links.
- client.GatewayError. Extract the check-word constraints out of Game.svelte into a
pure lib/checkword.ts (sanitize + canCheck) and cover them.
E2E (playwright mock, Chromium + WebKit):
- commit via the 🏁 control, history slide-down + close, the exchange dialog,
check-word input sanitising + verdict, resign-to-finished, and the Settings
board-label mode changing the on-board labels.
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
BLANK,
|
||||
cellOccupied,
|
||||
direction,
|
||||
isBlankSlot,
|
||||
newPlacement,
|
||||
place,
|
||||
placementFromHint,
|
||||
rackView,
|
||||
recallAt,
|
||||
recallIndex,
|
||||
reset,
|
||||
toSubmit,
|
||||
} from './placement';
|
||||
@@ -62,6 +65,29 @@ describe('placement state machine', () => {
|
||||
expect(toSubmit(place(newPlacement(rack), 0, 7, 7), 'V')?.dir).toBe('V');
|
||||
expect(toSubmit(newPlacement(rack))).toBeNull();
|
||||
});
|
||||
|
||||
it('recalls a tile by rack index and reports occupied cells / blank slots', () => {
|
||||
let p = place(newPlacement(rack), 0, 7, 7);
|
||||
p = place(p, 1, 7, 8);
|
||||
expect(cellOccupied(p, 7, 7)).toBe(true);
|
||||
expect(cellOccupied(p, 6, 6)).toBe(false);
|
||||
p = recallIndex(p, 0);
|
||||
expect(p.pending.map((t) => t.rackIndex)).toEqual([1]);
|
||||
expect(isBlankSlot(newPlacement(rack), 2)).toBe(true); // '?' slot
|
||||
expect(isBlankSlot(newPlacement(rack), 0)).toBe(false);
|
||||
});
|
||||
|
||||
it('treats a non-linear placement as no inferred direction', () => {
|
||||
let p = place(newPlacement(rack), 0, 7, 7);
|
||||
p = place(p, 1, 8, 8); // diagonal
|
||||
expect(direction(p)).toBeNull();
|
||||
});
|
||||
|
||||
it('defaults a single-tile submit to H without an override', () => {
|
||||
const sub = toSubmit(place(newPlacement(rack), 0, 7, 7));
|
||||
expect(sub?.dir).toBe('H');
|
||||
expect(sub?.tiles).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('placementFromHint', () => {
|
||||
@@ -78,4 +104,21 @@ describe('placementFromHint', () => {
|
||||
expect(p.pending[0]).toMatchObject({ rackIndex: 0, letter: 'C', blank: false });
|
||||
expect(p.pending[2]).toMatchObject({ rackIndex: 2, letter: 'B', blank: true });
|
||||
});
|
||||
|
||||
it('falls back to a blank slot when the hint letter is not in the rack', () => {
|
||||
const p = placementFromHint([{ row: 7, col: 7, letter: 'Z', blank: false }], ['A', BLANK]);
|
||||
expect(p.pending).toHaveLength(1);
|
||||
expect(p.pending[0]).toMatchObject({ rackIndex: 1, letter: 'Z', blank: true });
|
||||
});
|
||||
|
||||
it('skips hint tiles once the rack is exhausted', () => {
|
||||
const p = placementFromHint(
|
||||
[
|
||||
{ row: 7, col: 7, letter: 'A', blank: false },
|
||||
{ row: 7, col: 8, letter: 'B', blank: false },
|
||||
],
|
||||
['A'],
|
||||
);
|
||||
expect(p.pending.map((t) => t.letter)).toEqual(['A']);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user