Files
Dune/tests/coalition-nexus-controls.test.tsx
T
Quintine e529cc2d7a
Verify and publish checkpoint container / container (push) Successful in 11m0s
Extend Truthtrance bidding and prepare alliance controls
2026-10-28 22:06:55 +11:00

61 lines
3.4 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { CoalitionNexus, coalitionNexusOptions, type CoalitionNexusView } from '../components/coalition-nexus';
import type { CoalitionGroup } from '../game/coalition-alliance';
const pair: CoalitionGroup = { id: 'pair', members: ['a', 'b'], formedTurn: 2,
edges: [{ members: ['a', 'b'], formedTurn: 2 }] };
function view(me = 'a'): CoalitionNexusView {
return { me, revision: 4, groups: [pair], proposal: null, players: [
{ id: 'a', name: 'Atreides' }, { id: 'b', name: 'Emperor' },
{ id: 'c', name: 'Fremen' }, { id: 'd', name: 'Guild' },
] };
}
const html = (value: CoalitionNexusView, disabled = false) =>
renderToStaticMarkup(createElement(CoalitionNexus, { view: value, disabled, onIntent() {} }));
void test('only a pair member or the unallied entrant is offered an invitation', () => {
const member = coalitionNexusOptions(view('a'));
assert.deepEqual(member.invitations.map(({ entrant }) => entrant), ['c', 'd']);
assert.equal(member.mayLeave, true);
const entrant = coalitionNexusOptions(view('c'));
assert.deepEqual(entrant.invitations.map(({ entrant }) => entrant), ['c']);
assert.equal(entrant.mayLeave, false);
assert.match(html(view('a')), /Invite Fremen to Atreides, Emperor/);
assert.match(html(view('c')), /Ask to join Atreides, Emperor/);
assert.deepEqual(coalitionNexusOptions(view('missing')).invitations, []);
assert.doesNotMatch(html(view('missing')), /Invite Fremen|Ask to join|Leave Atreides/);
});
void test('pending invitation presents approval and withdrawal only to its participants', () => {
const v = view('c');
v.proposal = { event: 'offer', nexus: 'nexus', turn: 3, groupId: pair.id, original: pair,
entrant: 'c', proposer: 'a', approvals: ['a'] };
let options = coalitionNexusOptions(v);
assert.equal(options.mayAccept, true); assert.equal(options.mayDecline, true);
assert.deepEqual(options.invitations, []); assert.equal(options.mayLeave, false);
assert.match(html(v), /Approved: Atreides/); assert.match(html(v), /Waiting for: Emperor, Fremen/);
assert.match(html(v), /Accept invitation/); assert.match(html(v), /Decline and cancel invitation/);
v.me = 'a'; options = coalitionNexusOptions(v);
assert.equal(options.mayAccept, false); assert.equal(options.mayDecline, true);
assert.match(html(v), /Withdraw and cancel invitation/); assert.doesNotMatch(html(v), /Accept invitation/);
v.me = 'b'; v.proposal.approvals.push('b');
assert.match(html(v), /Withdraw approval and cancel invitation/);
assert.doesNotMatch(html(v), /Accept invitation/);
v.me = 'd'; options = coalitionNexusOptions(v);
assert.equal(options.mayAccept, false); assert.equal(options.mayDecline, false);
assert.doesNotMatch(html(v), /Accept invitation|cancel invitation/);
});
void test('three-member groups cannot receive another entrant and describe leaving policy', () => {
const v = view('a');
v.groups = [{ ...pair, members: ['a', 'b', 'c'] }];
const options = coalitionNexusOptions(v);
assert.deepEqual(options.invitations, []); assert.equal(options.mayLeave, true);
assert.match(html(v), /Leaving keeps the other two players allied/);
assert.match(html(v), /Leave Atreides, Emperor, Fremen/);
assert.match(html(v, true), /disabled=""[^>]*>Leave Atreides, Emperor, Fremen/);
});