Files
Dune/tests/truth-no-field-shipment-guidance.test.tsx
T
Quintine 9dc339e726
Verify and publish checkpoint container / container (push) Successful in 11m0s
Expand Basic bribe windows and fix marker guidance
2026-10-29 10:11:18 +11:00

90 lines
4.4 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { Children, createElement, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactElement, type ReactNode } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { ShipmentPromises } from '../components/shipment-promises';
import { viewGame, type Action, type GameView } from '../game/engine';
import { deployRicheseNoField } from '../game/richese-no-field';
import type { TruthQuestion } from '../game/truthtrance';
import {
createTruthtranceRichesePromisesFixture as fixture,
actTruthtranceRichesePromises as act,
askTruthtranceRichesePromises as ask,
advanceTruthtranceRichesePromises as advance,
truthtranceRichesePromisesClean as clean,
truthtranceRichesePromisesPlayer as player,
} from './fixture-truthtrance-richese-promises';
const question: TruthQuestion = {
kind: 'shipment', target: 'richese',
claim: {kind: 'noField', territory: 'carthag', sector: 11},
};
/** Genuine public setup and Truthtrance action; the optional existing marker
* is staged in conserved custody to represent a previous turn. */
function promised(existing: boolean) {
const f = fixture();
const source = structuredClone(f.game);
if (existing) {
const owner = player(source), marker = owner.noField!.tokens.find(token => token.value === 3);
assert.ok(marker);
owner.noField = deployRicheseNoField(owner.noField!, {
tokenId: marker.id, controller: owner.id, location: {territory:'polar_sink', sector:0},
});
}
let game = ask(source, f, question);
game = act(game, f.target, {type:'truthAnswer', answer:'yes'});
game = advance(game, state => state.phase === 5 && state.active === f.target && clean(state));
return {f, game};
}
function button(game: GameView, actions: Action[], label: string) {
function find(node: ReactNode): ReactElement<ButtonHTMLAttributes<HTMLButtonElement>> | undefined {
if (!isValidElement<{children?: ReactNode; onClick?: unknown}>(node)) return;
if (node.props.children === label && typeof node.props.onClick === 'function')
return node as ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>;
return Children.toArray(node.props.children).map(find).find(Boolean);
}
const found = find(ShipmentPromises({game, busy:false, act: action => actions.push(action)}));
assert.ok(found, label);
found.props.onClick!({} as MouseEvent<HTMLButtonElement>);
}
function html(game: GameView) {
return renderToStaticMarkup(createElement(ShipmentPromises, {game, busy:false, act() {}}));
}
void test('a real No-Field promise offers a correctly priced one-marker shipment', () => {
const {f, game} = promised(false), projected = viewGame(game, f.target);
const witness = projected.shipmentCompletion?.actions[0];
assert.equal(witness?.type, 'ship'); assert.ok(witness.noField);
const output = html(projected);
assert.match(output, /Ship your No-Field to Carthag, sector 11/);
assert.match(output, /Cost: 1 spice/);
assert.doesNotMatch(output, /NaN|Ship 1 forces|Play your preparation card/);
const sent: Action[] = [];
button(projected, sent, 'Ship your No-Field to Carthag, sector 11');
assert.deepEqual(sent, [witness]);
const done = advance(act(game, f.target, sent[0]), clean);
assert.equal(done.shipmentPromises![0].fulfilled, true);
assert.equal(player(done).noField?.deployed?.tokenId, witness.noField);
});
void test('an existing marker is labeled as a reveal and the next shipment uses its fresh event', () => {
const {f, game: original} = promised(true), projected = viewGame(original, f.target);
const first = projected.shipmentCompletion?.actions[0];
assert.equal(first?.type, 'revealNoField');
const output = html(projected);
assert.match(output, /Reveal your current No-Field/);
assert.doesNotMatch(output, /NaN|Play your preparation card|Cost:/);
const sent: Action[] = [];
button(projected, sent, 'Reveal your current No-Field');
assert.deepEqual(sent, [first]);
const revealed = act(original, f.target, sent[0]);
const next = viewGame(revealed, f.target).shipmentCompletion?.actions[0];
assert.equal(next?.type, 'ship');
assert.notEqual(next?.noField, first?.token);
assert.equal(next?.event, player(revealed).noFieldEvent);
const done = advance(act(revealed, f.target, next!), clean);
assert.equal(done.shipmentPromises![0].fulfilled, true);
assert.equal(player(done).noField?.deployed?.tokenId, next?.noField);
});