Files
Dune/tests/nexus-emperor-secret-ally-purchase-controls.test.ts

72 lines
3.8 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { NexusEmperorSecretAlly } from '../components/nexus-emperor-secret-ally';
import { botActions } from '../game/bots';
import { applyAction, viewGame, type GameView } from '../game/engine';
import { nexusEmperorPurchaseAction } from '../game/nexus-emperor-secret-ally-options';
import { wonEmperorNexusBankAuction } from './fixture-nexus-emperor-purchase';
const owner = 'q';
const html = (view: GameView, busy = false) =>
renderToStaticMarkup(createElement(NexusEmperorSecretAlly, { game: view, act() {}, busy }));
for (const advanced of [false, true])
void test(`${advanced ? 'Advanced' : 'Basic'} owner sees a private bank-paid choice and every bot profile can keep its own funded bid`, () => {
const g = wonEmperorNexusBankAuction(advanced);
const v = viewGame(g, owner);
assert.equal(v.nexusEmperorSecretAlly?.purchase?.blocked, null);
assert.equal(v.nexusEmperorSecretAlly?.purchase?.price, 2);
assert.deepEqual(nexusEmperorPurchaseAction(v), {
type: 'nexusEmperorPurchase', event: v.nexusEmperorSecretAlly!.event,
});
const text = html(v);
assert.match(text, /final bid is 2 spice/);
assert.match(text, /all 2 spice.*own supply without ally aid/);
assert.match(text, /keep that spice instead of paying the bank/);
assert.doesNotMatch(text, /disabled=""/);
assert.match(html(v, true), /disabled=""/);
assert.equal(text.includes(g.auction!.cards[g.auction!.index].name), false);
for (const difficulty of ['Easy', 'Medium', 'Hard', 'Brutal'] as const) {
const ownView = viewGame(g, owner);
ownView.players.find((player) => player.id === owner)!.bot = difficulty;
const [action] = botActions(ownView);
assert.deepEqual(action, nexusEmperorPurchaseAction(ownView));
const after = applyAction(g, owner, action);
assert.equal(after.players.find((player) => player.id === owner)!.spice, g.players.find((player) => player.id === owner)!.spice);
assert.ok(after.players.find((player) => player.id === owner)!.hand.some((card) => card.id === g.auction!.cards[g.auction!.index].id));
assert.equal(after.nexusCards!.cards!.hands[owner], null);
}
});
void test('blocked, underfunded, interrupted and foreign owners have no purchase control or bot candidate', () => {
const g = wonEmperorNexusBankAuction(false);
for (const id of ['p', 'r']) {
const v = viewGame(g, id);
assert.equal(v.nexusEmperorSecretAlly, null);
assert.equal(nexusEmperorPurchaseAction(v), null);
assert.equal(html(v), '');
assert.ok(!botActions(v).some((action) => action.type === 'nexusEmperorPurchase'));
}
const owned = viewGame(g, owner);
const blocked = structuredClone(owned);
blocked.nexusEmperorSecretAlly!.purchase!.blocked = 'Finish this payment first.';
assert.equal(nexusEmperorPurchaseAction(blocked), null);
assert.match(html(blocked), /Finish this payment first/);
assert.match(html(blocked), /disabled=""/);
const underfunded = structuredClone(owned);
underfunded.players.find((player) => player.id === owner)!.spice = 1;
assert.equal(nexusEmperorPurchaseAction(underfunded), null);
assert.match(html(underfunded), /disabled=""/);
assert.match(html(underfunded), /need 2 spice in your own supply/);
const interrupted = structuredClone(owned);
interrupted.automaticContinuationPending = true;
assert.equal(nexusEmperorPurchaseAction(interrupted), null);
assert.match(html(interrupted), /disabled=""/);
const foreignDecision = structuredClone(owned);
foreignDecision.decision = { kind: 'auctionPayment', player: 'r' };
assert.equal(nexusEmperorPurchaseAction(foreignDecision), null);
assert.equal(html(foreignDecision), '');
});