Files
Dune/tests/moritani-atomics-controls.test.ts
T

72 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test';
import assert from 'node:assert/strict';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { MoritaniEntry, MoritaniTerrorSupply } from '../components/moritani-terror';
import { TerrorBoardMarkers } from '../components/terror-board-markers';
import { createGame, joinGame, newPlayer, viewGame, type GameView } from '../game/engine';
import { createTerrorState, placeTerror, revealTerror } from '../game/moritani-terror';
function fixture() {
const game = createGame('ATOMICS-CONTROLS', newPlayer('m', 'Moritani', 'moritani'));
joinGame(game, newPlayer('a', 'Atreides', 'atreides'));
joinGame(game, newPlayer('f', 'Fremen', 'fremen'));
game.players.find((player) => player.id === 'm')!.ally = 'a';
game.players.find((player) => player.id === 'a')!.ally = 'm';
game.moritaniTerror = createTerrorState(() => 0);
const token = game.moritaniTerror.tokens.find((item) => item.kind === 'atomics')!;
game.moritaniTerror = placeTerror(game.moritaniTerror, token.id, 'arrakeen', 1);
return { game, token };
}
const supply = (view: GameView) =>
renderToStaticMarkup(createElement(MoritaniTerrorSupply, { game: view }));
const markers = (view: GameView) =>
renderToStaticMarkup(createElement('svg', null, createElement(TerrorBoardMarkers, {
tokens: view.moritaniTerror?.tokens ?? [], atomics: view.moritaniAtomics,
})));
void test('a placed hidden face stays private; only owner sees the Atomics reveal consequences', () => {
const { game } = fixture();
const owner = viewGame(game, 'm');
owner.decision = { kind: 'moritaniTerror', player: 'm', entrant: 'f', territory: 'arrakeen' };
owner.terrorEntry = {
entrant: 'f', territory: 'arrakeen', sector: 10, cause: 'shipment', stage: 'offer',
kind: 'atomics', canReveal: true, canOfferAlliance: false,
};
const offer = renderToStaticMarkup(createElement(MoritaniEntry, { game: owner, busy: false, act() {} }));
assert.match(offer, /Reveal Atomics/);
assert.match(offer, /every faction’s forces/);
assert.match(offer, /including Fremen reinforcements/);
assert.match(offer, /discards one random card per excess/);
const rival = viewGame(game, 'f');
assert.match(supply(rival), /Inspect Hidden Terror/);
assert.doesNotMatch(supply(rival), /Inspect Atomics|Atomics Aftermath/);
assert.match(markers(rival), /hidden Terror token in Arrakeen/);
assert.doesNotMatch(markers(rival), /Atomics Aftermath/);
assert.equal(renderToStaticMarkup(createElement(MoritaniEntry, { game: rival, busy: false, act() {} })), '');
});
void test('after revelation all seats see persistent Aftermath and its exact shipment and hand-limit consequences', () => {
const { game, token } = fixture();
game.moritaniTerror = revealTerror(game.moritaniTerror!, token.id);
game.moritaniAtomics = { territory: 'arrakeen', turn: 2, moritaniId: 'm',
allyAtActivation: 'a', alliancePolicy: 'unresolved' };
game.turn = 2;
game.players.find((player) => player.id === 'm')!.atomicsHandLimitPenalty = true;
game.players.find((player) => player.id === 'a')!.atomicsHandLimitPenalty = true;
for (const id of ['m', 'a', 'f']) {
const view = viewGame(game, id);
const notice = supply(view);
assert.match(notice, /Atomics Aftermath · Arrakeen/);
assert.match(notice, /From turn 2, no faction may ship forces/);
assert.match(notice, /including Fremen reinforcements/);
assert.match(notice, /ordinary movement and Sneak Attack remain possible/);
assert.match(notice, /Moritani and Atreides/);
assert.match(notice, /lasting hand-limit reduction of one/);
const board = markers(view);
assert.match(board, /Atomics Aftermath in Arrakeen: permanent shipment ban/);
assert.doesNotMatch(board, /hidden Terror token in Arrakeen/);
}
});