72 lines
4.2 KiB
TypeScript
72 lines
4.2 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { CoalitionNexus, coalitionNexusOptions } from '../components/coalition-nexus';
|
|
import { botActions } from '../game/bots';
|
|
import { DIFFICULTIES } from '../game/bot-profiles';
|
|
import { coalitionOf, emptyCoalitionState } from '../game/coalition-alliance';
|
|
import { applyAction, viewGame, type Game } from '../game/engine';
|
|
import { createTruthAllianceFixture } from './fixture-truth-alliance';
|
|
|
|
/** Public Advanced Harkonnen/Atreides/Emperor setup, genuine first turn and
|
|
* ordinary worm Nexus. The fixture selects only unopened original deals,
|
|
* auction and Spice positions and scalar lotteries. The optional group's
|
|
* empty unexposed ledger is inserted at the real Nexus, before any offer. */
|
|
function pair(variant: 'three-short' | 'unlimited') {
|
|
const source = createTruthAllianceFixture({advanced:true, consent:'none'});
|
|
let game = structuredClone(source.game);
|
|
assert.equal(game.advanced, true);
|
|
assert.equal(game.nexus, true);
|
|
assert.ok(game.players.every(player => !player.ally));
|
|
game.coalitionState = emptyCoalitionState(variant);
|
|
game = applyAction(game, source.asker, {type:'alliance', target:source.opponent});
|
|
game = applyAction(game, source.opponent, {type:'alliance', target:source.asker});
|
|
return {game, source};
|
|
}
|
|
|
|
function answer(game: Game, player: string): Game {
|
|
const proposal = game.coalitionState!.proposal; assert.ok(proposal);
|
|
return applyAction(game, player, {type:'coalitionAnswer', event:proposal.event, nexus:proposal.nexus,
|
|
turn:proposal.turn, accept:true, expectedRevision:game.coalitionState!.revision});
|
|
}
|
|
|
|
for (const variant of ['three-short', 'unlimited'] as const) {
|
|
void test(`Advanced ${variant} genuine Nexus forms a three-player group with legal bot and human consent`, () => {
|
|
const {game, source} = pair(variant);
|
|
const group = coalitionOf(game.players, game.coalitionState, source.asker); assert.ok(group);
|
|
assert.deepEqual(new Set(group.members), new Set([source.asker, source.opponent]));
|
|
const controls = viewGame(game, source.target).coalitionNexus; assert.ok(controls);
|
|
assert.equal(controls.variant, variant);
|
|
assert.deepEqual(coalitionNexusOptions(controls).invitations.map(row => row.entrant), [source.target]);
|
|
const html = renderToStaticMarkup(createElement(CoalitionNexus, {view:controls, onIntent(){}}));
|
|
assert.match(html, /Ask to join/);
|
|
|
|
for (const difficulty of DIFFICULTIES) {
|
|
const view = viewGame(game, source.target);
|
|
view.players.find(seat => seat.id === source.target)!.bot = difficulty;
|
|
const propose = botActions(view).find(action => action.type === 'coalitionPropose');
|
|
assert.ok(propose, difficulty);
|
|
let pending = applyAction(game, source.target, propose);
|
|
assert.deepEqual(pending.coalitionState!.proposal!.approvals, [source.target]);
|
|
const projected = viewGame(pending, source.opponent).coalitionNexus; assert.ok(projected);
|
|
assert.equal(projected.proposal!.entrant, source.target);
|
|
assert.equal(coalitionNexusOptions(projected).mayAccept, true);
|
|
assert.match(renderToStaticMarkup(createElement(CoalitionNexus, {view:projected, onIntent(){}})), /Accept invitation/);
|
|
pending = answer(pending, source.asker);
|
|
assert.deepEqual(new Set(coalitionOf(pending.players, pending.coalitionState, source.asker)!.members),
|
|
new Set([source.asker, source.opponent]));
|
|
const approvalView = viewGame(pending, source.opponent);
|
|
approvalView.players.find(seat => seat.id === source.opponent)!.bot = difficulty;
|
|
const approval = botActions(approvalView).find(action => action.type === 'coalitionAnswer');
|
|
assert.ok(approval, difficulty);
|
|
assert.equal(approval.accept, true);
|
|
pending = applyAction(pending, source.opponent, approval);
|
|
assert.equal(pending.coalitionState!.proposal, null);
|
|
assert.deepEqual(new Set(coalitionOf(pending.players, pending.coalitionState, source.asker)!.members),
|
|
new Set([source.asker, source.opponent, source.target]));
|
|
assert.equal(viewGame(pending, source.target).coalitionNexus!.variant, variant);
|
|
}
|
|
});
|
|
}
|