import assert from 'node:assert/strict'; import test from 'node:test'; import { createElement } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import { GholaLeaderPromises, GholaLeaderPromiseGuideButton } from '../components/ghola-leader-promises'; import { createGame, joinGame, newPlayer, viewGame, type Action } from '../game/engine'; function projected() { const source = createGame('GHOLAGUIDECONTROLS', newPlayer('p', 'Player', 'emperor'), false); joinGame(source, newPlayer('a', 'Asker', 'atreides')); const game = viewGame(source, 'p'); game.status = 'playing'; game.turn = 2; game.phase = 4; game.allLeaders = [{ id: 'named', name: 'Named Commander', faction: 'emperor', strength: 3 }]; const me = game.players.find(p => p.id === 'p')!; me.hand = [{ id: 'ghola', name: 'Ghola', kind: 'special', effect: 'ghola' }]; game.ghola = { cards: ['ghola'], leaders: [{ id: 'named', name: 'Named Commander', strength: 3 }], kwisatz: false, maxForces: 0, eliteRemaining: 0, eliteBlock: null, available: true, reason: null }; game.gholaLeaderPromises = [{ event: 'event', turn: 2, player: 'p', asker: 'a', leader: 'named', answer: true }]; game.gholaLeaderPromiseGuide = { action: { type: 'card', card: 'ghola', leader: 'named' } }; return game; } void test('private Ghola promises describe the named actual return and statuses', () => { const game = projected(); game.gholaLeaderPromises.push({ event: 'foreign', turn: 2, player: 'a', asker: 'p', leader: 'secret', answer: false }); const html = renderToStaticMarkup(createElement(GholaLeaderPromises, { game, busy: false, send() {} })); assert.match(html, /Named Commander/); assert.match(html, /ordinary return, a force return, or an earlier Ghola play does not fulfill it/); assert.doesNotMatch(html, /secret|foreign/); }); void test('the Ghola guide forwards only the current legal card and leader', () => { const game = projected(), sent: Action[] = []; const props = { game, busy: false, send(action: Action) { sent.push(action); } }; const button = GholaLeaderPromiseGuideButton(props); assert.ok(button); assert.equal(button.props.disabled, false); button.props.onClick(); assert.deepEqual(sent, [game.gholaLeaderPromiseGuide!.action]); game.ghola.available = false; button.props.onClick(); assert.equal(sent.length, 1); game.ghola.available = true; game.truthtrance = { stage: 'priority', queue: [], passed: [], question: null } as typeof game.truthtrance; button.props.onClick(); assert.equal(sent.length, 1); }); void test('Ghola guide starts the current Box and rejects a stale quote', () => { const game = projected(), me = game.players.find(player => player.id === 'p')!; const box = { id: 'box', name: 'Nullentropy Box', kind: 'special' as const, effect: 'nullentropyBox' }; me.hand = [box]; game.nullentropy = { card: box, blocked: null, search: null }; game.gholaLeaderPromiseGuide = { action: { type: 'card', card: box.id } }; const sent: Action[] = [], button = GholaLeaderPromiseGuideButton({ game, busy: false, send(action) { sent.push(action); } }); assert.ok(button); assert.equal(button.props.disabled, false); button.props.onClick(); assert.deepEqual(sent, [game.gholaLeaderPromiseGuide.action]); game.nullentropy.blocked = 'The search is no longer available.'; button.props.onClick(); assert.equal(sent.length, 1); }); void test('Ghola guide selects only its current paid Box search card', () => { const game = projected(), box = { id: 'box', name: 'Nullentropy Box', kind: 'special' as const, effect: 'nullentropyBox' }; const ghola = { id: 'recovered', name: 'Ghola', kind: 'special' as const, effect: 'ghola' }; game.decision = { kind: 'nullentropy', player: 'p' }; game.nullentropy = { card: box, blocked: null, search: { event: 'paid', cards: [ghola] } }; game.gholaLeaderPromiseGuide = { action: { type: 'decision', event: 'paid', card: ghola.id } }; const sent: Action[] = [], button = GholaLeaderPromiseGuideButton({ game, busy: false, send(action) { sent.push(action); } }); assert.ok(button); assert.equal(button.props.disabled, false); button.props.onClick(); assert.deepEqual(sent, [game.gholaLeaderPromiseGuide.action]); game.nullentropy.search!.cards = []; button.props.onClick(); assert.equal(sent.length, 1); });