v0.4.8 — the Limits bound the whole district, the nine spots really are nine, and an action points at its square
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQAJ4dND7enLj54eLyiF2C
This commit is contained in:
+86
-2
@@ -598,6 +598,54 @@ describe('the board shows freight work happening', () => {
|
||||
assert.ok(y > 48, `the caption at y=${y} prints over the rail`);
|
||||
});
|
||||
|
||||
it('draws the Limits as the edge of the buildable district, at every row', () => {
|
||||
/**
|
||||
* Track may not be laid outside the Limits at ANY row now (§2.1), and two signs sitting on the
|
||||
* Running Track could not say that: a player looking at open ground beyond a sign had no way to
|
||||
* know nothing of his would ever go there until the square failed to light up.
|
||||
*
|
||||
* Just OUTSIDE the sign's own column, because the sign stands ON the boundary — a siding may run
|
||||
* under it — so a line drawn inside the sign would teach the opposite of the rule.
|
||||
*/
|
||||
const game = newGame(555);
|
||||
const area = game.state.officeAreas.get(0)!;
|
||||
const f = view(game);
|
||||
assert.deepEqual(
|
||||
f.limits,
|
||||
{ west: area.limitsWest.col, east: area.limitsEast.col },
|
||||
'the Frame does not carry the district edges a remote client cannot look up',
|
||||
);
|
||||
|
||||
const svg = officeSvg(f.cells, f.runningRow, [], [], f.limits);
|
||||
const xs = [...svg.matchAll(/class="bs-limitline" x1="(-?[\d.]+)"/g)].map((m) => Number(m[1]));
|
||||
assert.equal(xs.length, 2, 'the district was drawn without both of its edges');
|
||||
|
||||
// The sign cards themselves must fall INSIDE the two lines.
|
||||
const signX = [...svg.matchAll(/data-cell="(-?\d+),(-?\d+)"[^>]*transform="translate\((-?[\d.]+)/g)]
|
||||
.filter((m) => Number(m[2]) === area.limitsWest.col || Number(m[2]) === area.limitsEast.col)
|
||||
.map((m) => Number(m[3]));
|
||||
assert.ok(signX.length > 0, 'no Limits sign was drawn to check the boundary against');
|
||||
for (const x of signX) {
|
||||
assert.ok(
|
||||
x >= Math.min(...xs) && x <= Math.max(...xs),
|
||||
`a Limits sign at x=${x} sits outside its own boundary (${xs.join(', ')})`,
|
||||
);
|
||||
}
|
||||
assert.match(svg, /bs-limitlab/, 'the boundary is drawn but never named');
|
||||
|
||||
// AND ON THE CANVAS. The west sign is the leftmost card, so a line drawn outside its column sits
|
||||
// at a negative x — off a viewBox that starts at 0, which is a boundary nobody can see.
|
||||
const vb = /viewBox="(-?[\d.]+) (-?[\d.]+) ([\d.]+) ([\d.]+)"/.exec(svg);
|
||||
assert.ok(vb, 'the board produced no viewBox');
|
||||
const x0 = Number(vb![1]);
|
||||
for (const x of xs) {
|
||||
assert.ok(
|
||||
x >= x0 && x <= x0 + Number(vb![3]),
|
||||
`the boundary at x=${x} is drawn outside the canvas (${x0} to ${x0 + Number(vb![3])})`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('says on the card which way an industry runs, and how many workers it has', () => {
|
||||
/**
|
||||
* TWO REPORTS, ONE CARD.
|
||||
@@ -1314,7 +1362,7 @@ describe('the static build', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('renders clickable highlights on the board when a card is picked', async () => {
|
||||
it('renders clickable highlights on the board, and points at the square an action names', async () => {
|
||||
// The real check: load the EMITTED bundle with a DOM stub, click a card, and confirm the board
|
||||
// came back with highlighted squares wired to handlers. Asserting the data has coordinates says
|
||||
// nothing about whether the page draws them.
|
||||
@@ -1366,7 +1414,12 @@ describe('the static build', () => {
|
||||
const classes = new Set<string>();
|
||||
found.set(key, {
|
||||
onclick: null,
|
||||
classList: { add: (c: string) => void classes.add(c), has: (c: string) => classes.has(c) },
|
||||
classList: {
|
||||
add: (c: string) => void classes.add(c),
|
||||
// Pointing at a square is a HOVER: it has to come off again when the cursor leaves.
|
||||
remove: (c: string) => void classes.delete(c),
|
||||
has: (c: string) => classes.has(c),
|
||||
},
|
||||
classes,
|
||||
});
|
||||
}
|
||||
@@ -1493,6 +1546,37 @@ describe('the static build', () => {
|
||||
const lit = (grid['highlighted'] as () => unknown[])();
|
||||
const ghosts = /data-ghost="/.test(html);
|
||||
assert.ok(lit.length > 0 || ghosts, 'picking a card highlighted nothing on the board');
|
||||
|
||||
/**
|
||||
* POINTING AT THE SQUARE A BUTTON MEANS — wired on the emitted bundle, not asserted off the menu.
|
||||
*
|
||||
* The menu carrying a coordinate proves nothing about whether the page draws it, which is the
|
||||
* same reason the highlight check above loads the real bundle. Reported by Jesse: the action list
|
||||
* is a column of near-identical sentences separated by "(1,3)" against "(-1,3)", and picking the
|
||||
* wrong one is a click to undo in solitaire and unrecoverable in a multiplayer game.
|
||||
*/
|
||||
const withSquare = (
|
||||
(actions['querySelectorAll'] as (s: string) => Record<string, unknown>[])
|
||||
.call(actions, 'button.act')
|
||||
.filter((n) => (n['dataset'] as Record<string, string>)['square'])
|
||||
);
|
||||
assert.ok(withSquare.length > 0, 'no action button carries the square it acts on');
|
||||
const btn = withSquare[0]!;
|
||||
const key = (btn['dataset'] as Record<string, string>)['square']!;
|
||||
assert.match(key, /^-?\d+,-?\d+$/, `"${key}" is not a grid coordinate`);
|
||||
(btn['onmouseenter'] as (() => void) | null)?.();
|
||||
const pointed = (grid['highlighted'] as () => Record<string, unknown>[])().filter((g) =>
|
||||
(g['classes'] as Set<string>).has('bs-point'),
|
||||
);
|
||||
assert.equal(pointed.length, 1, `hovering the action for (${key}) marked ${pointed.length} squares`);
|
||||
(btn['onmouseleave'] as (() => void) | null)?.();
|
||||
assert.equal(
|
||||
(grid['highlighted'] as () => Record<string, unknown>[])().filter((g) =>
|
||||
(g['classes'] as Set<string>).has('bs-point'),
|
||||
).length,
|
||||
0,
|
||||
'the square stayed lit after the cursor left the button',
|
||||
);
|
||||
});
|
||||
|
||||
it('busts the cache on every module, so a deploy cannot half-load', () => {
|
||||
|
||||
Reference in New Issue
Block a user