72 lines
3.8 KiB
TypeScript
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), '');
|
|
});
|