import assert from 'node:assert/strict'; import test from 'node:test'; import { Children, createElement, isValidElement } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import type { Action } from '../game/engine'; import { EmperorExtortionPriority, type EmperorExtortionPriorityProps } from '../components/emperor-extortion-priority'; function props(): EmperorExtortionPriorityProps & { sent: Action[] } { const sent: Action[] = []; return {game:{emperorExtortionPriority:{event:'extortion-event',recipient:'ally',canContinue:true}, players:[{id:'ally',name:'Ally'}]}, busy:false, sent, act(action) {sent.push(action);}}; } const render = (input: EmperorExtortionPriorityProps) => renderToStaticMarkup(createElement(EmperorExtortionPriority, input)); function button(input: EmperorExtortionPriorityProps) { const section = EmperorExtortionPriority(input); assert.ok(section); const match = Children.toArray(section.props.children).find(child => isValidElement(child) && (child.props as {'data-testid'?: string})['data-testid'] === 'emperor-extortion-continue'); assert.ok(isValidElement<{onClick:() => void; disabled:boolean}>(match)); return match; } void test('the Emperor sees a persistent, event-bound Extortion opportunity', () => { const input = props(), html = render(input); assert.match(html, /Before Ally makes the Extortion choice/); assert.match(html, /Continue to Extortion/); assert.equal(button(input).props.disabled, false); button(input).props.onClick(); assert.deepEqual(input.sent, [{type:'emperorExtortionContinue',event:'extortion-event'}]); }); void test('other viewers see the same neutral opportunity without a Continue control or private data', () => { const input = props(); input.game.emperorExtortionPriority!.canContinue = false; Object.assign(input.game, {privateSpice:19, privateCard:'secret-card'}); const html = render(input); assert.match(html, /Waiting for the Emperor/); assert.doesNotMatch(html, /emperor-extortion-continue|secret-card|19/); assert.deepEqual(input.sent, []); input.game.emperorExtortionPriority = null; assert.equal(render(input), ''); }); void test('busy, invalid, stale or consumed opportunities cannot submit', () => { for (const change of ['busy','empty','event','permission','replace','close'] as const) { const input = props(); if (change === 'busy') input.busy = true; if (change === 'empty') input.game.emperorExtortionPriority!.event = ''; const control = button(input); if (change === 'busy' || change === 'empty') assert.equal(control.props.disabled, true); if (change === 'event') input.game.emperorExtortionPriority!.event = 'other'; if (change === 'permission') input.game.emperorExtortionPriority!.canContinue = false; if (change === 'replace') input.game.emperorExtortionPriority = {...input.game.emperorExtortionPriority!}; if (change === 'close') input.game.emperorExtortionPriority = null; control.props.onClick(); assert.deepEqual(input.sent, [], change); } });