v0.5.6 — seats counted from 1, a name you can read, and a line that stops repeating
Three things off the first proper look at a live table.
The lobby listed chairs as Seat 0 to Seat 3. Zero-based is right inside —
it indexes seating, the seats array and every route, and none of that
changes — but nobody sitting at a table calls their chair "seat 0". There
were four of these rather than one: the lobby list, the topline's Seat N
for a remote session, the presence banner's fallback name, and the admin
summary's. All go through a single seatLabel now, and a test fails the
build if any "Seat ${...}" interpolates a raw seat again, since the
conversion has to happen in exactly one place or the two conventions drift
apart. Verified by mutation — putting the raw seat back fails the suite.
seatLabel lives in sim/view.ts, not web/game.ts. Putting it in game.ts was
the first attempt and test/session.test.ts caught it: the page may not
import values from that module, because they are the local engine by
another name and importing one reopens the Phase 1 boundary. The test was
right and the placement was wrong.
.bs-name.bs-turn carried font-weight:700 over a base of 600. At 11px a
monospace face has to be synthesised the rest of the way and the extra ink
lands as blur, so the one name you most need to read was the one you could
not. The bump is gone; amber against #e6e9ee was always doing the work, and
blue "(you)" and amber "their move" stay clearly distinct without it.
The west-to-east chain under the Division map now shows only during Day 1
Stage 1. It answers who is where and why, which is a question you have once
— at the start, when the chain has just been rolled and the names are new.
By Stage 2 the map has been answering it for a while and the line is
something to read past.
675 tests pass (673 + 2).
This commit is contained in:
+28
-1
@@ -14,11 +14,12 @@
|
||||
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { actionGroups, currentActor, handPlayable, newGame, overHandLimit, submit, toSave, view } from '../src/web/game.ts';
|
||||
import { createLocalSession } from '../src/web/session.ts';
|
||||
import { seatLabel } from '../src/sim/view.ts';
|
||||
|
||||
/**
|
||||
* Drive a session by always taking the first offered action.
|
||||
@@ -218,6 +219,32 @@ describe('the page stays on the near side of the boundary', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('seats are counted from 1 wherever a person reads them', () => {
|
||||
it('seatLabel shifts the zero-based index the whole engine uses', () => {
|
||||
assert.deepEqual([0, 1, 2, 3].map(seatLabel), [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
it('no user-facing "Seat N" bypasses it', () => {
|
||||
// The internal convention is zero-based and must stay that way — it indexes `seating`, the
|
||||
// seats array and every route. The DISPLAYED number is the one a player would say out loud, so
|
||||
// the two have to be converted at exactly one place; anything interpolating a raw seat into a
|
||||
// "Seat …" string has quietly reintroduced "Seat 0".
|
||||
const roots = ['src/web', 'src/sim', 'src/server'];
|
||||
const offenders: string[] = [];
|
||||
for (const dir of roots) {
|
||||
const base = join(import.meta.dirname, '..', dir);
|
||||
for (const name of readdirSync(base, { recursive: true, encoding: 'utf8' })) {
|
||||
if (!name.endsWith('.ts')) continue;
|
||||
const text = readFileSync(join(base, name), 'utf8');
|
||||
for (const m of text.matchAll(/`[^`]*Seat \$\{([^}]*)\}/g)) {
|
||||
if (!m[1]!.includes('seatLabel')) offenders.push(`${dir}/${name}: ${m[0]!.slice(0, 60)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.deepEqual(offenders, [], 'a seat is shown to a player without going through seatLabel');
|
||||
});
|
||||
});
|
||||
|
||||
describe('capabilities say what only a local session can do', () => {
|
||||
it('offers undo, a local save and a new deal', () => {
|
||||
// The page hides these rather than calling them and failing. A server can offer none of them: it
|
||||
|
||||
Reference in New Issue
Block a user