Files
Dune/tests/stone-burner-allocation-controls.test.tsx
Quintine 6ccfaa1b4d Resolve ambiguous Stone battles with sealed physical totals
Add a provisional post-reveal physical-count commitment for new outcome-changing Basic/Advanced Stone and copied Mirror battles. Keep all original sides sealed until complete and retain matching later typed losses. Preserve legacy, ordinary and invariant-winner timing. Carry the same constraint through card cleanup and native casualty consumers.

Validation: frozen 16 files146/146, types/lint/build and14 original-action/rendered-control programmes; four minimal policies make both owned choices legally. Source timing is explicitly provisional. Wider combinations, assurance and deployed acceptance remain open. No saved-game, reset, restart or deployment operation.
2026-10-18 12:13:06 +11:00

42 lines
2.7 KiB
TypeScript

import assert from 'node:assert/strict';
import { test } from 'node:test';
import { createElement, type MouseEvent, type ReactElement, type ButtonHTMLAttributes } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { StoneBurnerAllocation } from '../components/stone-burner-allocation';
void test('Stone Burner allocation keeps explicit physical-total commitments and provisional sealed timing readable until chosen', () => {
const committed: number[] = [], props = { event: 'stone-original-event', totals: [5, 2, 5],
onCommit: (total: number) => committed.push(total), busy: false };
const html = renderToStaticMarkup(createElement(StoneBurnerAllocation, props));
assert.match(html, /aria-label="Stone Burner undialed force commitment"/);
assert.match(html, /Provisional timing/);
assert.match(html, /Choices stay sealed until everyone has committed/);
assert.match(html, /ordinary and elite losses afterward/);
assert.match(html, /Commit 2 undialed physical forces/);
assert.match(html, /Commit 5 undialed physical forces/);
assert.equal((html.match(/<button/g) ?? []).length, 2);
assert.deepEqual(committed, [], 'Rendering never commits or starts an automatic countdown');
const panel = StoneBurnerAllocation(props)!;
const buttons = panel.props.children[3].props.children as ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>[];
buttons[0].props.onClick!({} as MouseEvent<HTMLButtonElement>);
buttons[1].props.onClick!({} as MouseEvent<HTMLButtonElement>);
assert.deepEqual(committed, [2, 5]);
});
void test('busy Stone Burner commitments cannot submit through their callback, and a fresh event retains its own original choices', () => {
const committed: number[] = [], onCommit = (total: number) => committed.push(total);
const props = { event: 'first-original-event', totals: [1, 3], onCommit, busy: true };
const html = renderToStaticMarkup(createElement(StoneBurnerAllocation, props));
assert.equal((html.match(/<button\b[^>]*\sdisabled=""/g) ?? []).length, 2);
const panel = StoneBurnerAllocation(props)!;
const buttons = panel.props.children[3].props.children as ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>[];
for (const button of buttons) button.props.onClick!({} as MouseEvent<HTMLButtonElement>);
assert.deepEqual(committed, []);
const next = renderToStaticMarkup(createElement(StoneBurnerAllocation,
{ event: 'next-original-event', totals: [0, 4], onCommit, busy: false }));
assert.match(next, /data-event="next-original-event"/);
assert.match(next, /Commit 0 undialed physical forces/);
assert.match(next, /Commit 4 undialed physical forces/);
assert.doesNotMatch(next, /Commit 1 undialed|Commit 3 undialed/);
});