72 lines
4.5 KiB
TypeScript
72 lines
4.5 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { ShipmentPromises } from '../components/shipment-promises';
|
|
import { botActions } from '../game/bots';
|
|
import { DIFFICULTIES } from '../game/bot-profiles';
|
|
import { viewGame, type Action, type Game } from '../game/engine';
|
|
import { liveShipmentPromises, matchesShipment } from '../game/shipment-promises';
|
|
import { declareTruthTurnAction, settleTruthTurnAction, truthTurnActionInventory, truthTurnActionPlayer } from './fixture-truth-turn-action';
|
|
import { actTruthShipmentSector as act, createTruthShipmentSectorFixture as fixture,
|
|
type TruthShipmentSectorFixture } from './fixture-truth-shipment-sector';
|
|
|
|
function asked(f: TruthShipmentSectorFixture): Game {
|
|
const declared = declareTruthTurnAction(f.base).game;
|
|
return act(declared, f.asker, { type: 'truthAsk', question: {
|
|
kind: 'shipment', target: f.target, territory: f.territory, minimum: 1, sector: f.sector,
|
|
} });
|
|
}
|
|
function rejected(game: Game, actor: string, action: Action) {
|
|
const before = structuredClone(game); assert.throws(() => act(game, actor, action)); assert.deepEqual(game, before);
|
|
}
|
|
|
|
void test('standalone exact-sector shipment Yes exposes the native witness and all bot profiles honor it', () => {
|
|
const f = fixture(), question = asked(f);
|
|
assert.ok(viewGame(question, f.target).truthShipmentAnswers?.includes('yes'));
|
|
let game = act(question, f.target, { type: 'truthAnswer', answer: 'yes' });
|
|
assert.equal(game.shipmentPromises?.[0].sector, f.sector);
|
|
const view = viewGame(game, f.target), witness = view.shipmentCompletion?.actions[0]; assert.ok(witness);
|
|
assert.equal(witness.type, 'ship'); assert.equal(witness.territory, f.territory); assert.equal(witness.sector, f.sector);
|
|
assert.ok(Number(witness.amount) >= 1);
|
|
const html = renderToStaticMarkup(createElement(ShipmentPromises, { game: view, busy: false, act() {} }));
|
|
assert.match(html, /Suggested next step/); assert.match(html, new RegExp(`sector ${f.sector}`));
|
|
assert.match(html, /Cost:/);
|
|
for (const difficulty of DIFFICULTIES) {
|
|
const bot = viewGame(game, f.target); bot.players.find(player => player.id === f.target)!.bot = difficulty;
|
|
assert.deepEqual(botActions(bot)[0], witness);
|
|
}
|
|
rejected(game, f.target, f.shipment(f.alternative));
|
|
const beforeSpice = truthTurnActionPlayer(game, f.target).spice, beforeReserves = truthTurnActionPlayer(game, f.target).reserves;
|
|
game = settleTruthTurnAction(act(game, f.target, witness));
|
|
const count = Number(witness.amount);
|
|
assert.equal(truthTurnActionPlayer(game, f.target).forces[`${f.territory}:${f.sector}`], count);
|
|
assert.equal(truthTurnActionPlayer(game, f.target).reserves, beforeReserves - count);
|
|
assert.equal(truthTurnActionPlayer(game, f.target).spice, beforeSpice - count * 2);
|
|
assert.equal(game.shipmentPromises?.[0].fulfilled, true);
|
|
assert.deepEqual(truthTurnActionInventory(game), f.originalCards);
|
|
});
|
|
|
|
void test('standalone No excludes the named sector, permits another sector and keeps all bot candidates legal', () => {
|
|
const f = fixture(), question = asked(f);
|
|
assert.ok(viewGame(question, f.target).truthShipmentAnswers?.includes('no'));
|
|
let game = act(question, f.target, { type: 'truthAnswer', answer: 'no' });
|
|
const promises = liveShipmentPromises(game.shipmentPromises ?? [], f.target, game.turn);
|
|
assert.equal(promises.length, 1); assert.equal(promises[0].sector, f.sector);
|
|
rejected(game, f.target, f.shipment(f.sector));
|
|
for (const difficulty of DIFFICULTIES) {
|
|
const bot = viewGame(game, f.target); bot.players.find(player => player.id === f.target)!.bot = difficulty;
|
|
for (const action of botActions(bot)) {
|
|
if (action.type !== 'ship' && !(action.type === 'guildShip' && action.from === 'reserves')) continue;
|
|
const shipment = { territory: String(action.territory), sector: Number(action.sector), amount: Number(action.amount) };
|
|
assert.ok(promises.every(promise => matchesShipment(promise, shipment) === promise.answer));
|
|
}
|
|
}
|
|
const beforeSpice = truthTurnActionPlayer(game, f.target).spice;
|
|
game = settleTruthTurnAction(act(game, f.target, f.shipment(f.alternative)));
|
|
assert.equal(truthTurnActionPlayer(game, f.target).forces[`${f.territory}:${f.alternative}`], 1);
|
|
assert.equal(truthTurnActionPlayer(game, f.target).spice, beforeSpice - 2);
|
|
assert.equal(game.shipmentPromises?.[0].fulfilled, true);
|
|
assert.deepEqual(truthTurnActionInventory(game), f.originalCards);
|
|
});
|