Files
Dune/tests/selected-nexus-no-cards-runtime.test.ts
T
Quintine 91d45d1dec
Verify and publish checkpoint container / container (push) Canceled after 0s
Support unused selected decks with Nexus and Discovery
2026-10-29 20:19:58 +11:00

66 lines
4.3 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { applyAction, viewGame } from '../game/engine';
import { botActions } from '../game/bots';
import { TERRITORIES } from '../game/board';
import { treacheryDeck } from '../game/cards';
import { nexusCoreProfile, selectedNexusWithoutCardsProfile } from '../game/faction-module-profile';
import { validateNexusCards } from '../game/nexus-cards';
import { validateDiscoveryState } from '../game/discoveries';
import { advanceSelectedIndependentNexus } from './fixture-selected-independent-nexus-cards';
import { createSelectedNexusNoCards, selectedNexusNoCardsDraw,
type SelectedNexusNoCardsOptions } from './fixture-selected-nexus-no-cards';
const setups: SelectedNexusNoCardsOptions[] = [
{ factions: ['atreides', 'guild', 'emperor'] as const },
{ factions: ['atreides', 'guild', 'emperor'] as const, advanced: true },
{ factions: ['ixians', 'ecaz', 'guild'] as const },
{ factions: ['ixians', 'ecaz', 'guild'] as const, advanced: true, discovery: true },
];
for (const options of setups) void test(`public ${options.advanced ? 'Advanced' : 'Basic'} selected Nexus without independent cards: ${options.factions.join('/')}${options.discovery ? ' Discovery' : ''}`, () => {
const { lobby, setup, game, actions } = createSelectedNexusNoCards(options);
assert.ok(actions.some(step => step.action.type === 'moduleOption' && step.action.module === 'nexusCards'));
assert.ok(!actions.some(step => step.action.type === 'moduleOption' && step.action.module === 'ecazTreachery'));
assert.notEqual(lobby.lobbyOptions?.ecazTreachery, true);
assert.ok(selectedNexusWithoutCardsProfile(setup));
assert.ok(selectedNexusWithoutCardsProfile(game));
assert.ok(nexusCoreProfile(game));
assert.notEqual(game.ecazTreachery, true);
assert.equal(game.leaderSkills, undefined);
assert.deepEqual(game.expansions, ['ix', 'choam', 'ecaz']);
assert.equal(game.phase, 0);
validateNexusCards(game.nexusCards!.cards!, game.players);
assert.equal(game.nexusCards!.cards!.deck.length, 12);
assert.ok(Object.values(game.nexusCards!.cards!.hands).every(card => card === null));
assert.deepEqual([...game.deck, ...game.discard, ...game.players.flatMap(player => player.hand)]
.map(card => card.id).sort(), treacheryDeck(game.expansions).map(card => card.id).sort());
if (options.discovery) { assert.ok(game.discoveries); validateDiscoveryState(game.discoveries); }
if (options.factions.includes('ixians')) assert.equal(game.nexusIxianBetrayalPreview, true);
if (options.factions.includes('ecaz')) assert.equal(game.ecazOccupyPreview, true);
});
for (const advanced of [false, true]) void test(`${advanced ? 'Advanced' : 'Basic'} selected decks deal a real Nexus card and spend its shipment power`, () => {
const fixture = selectedNexusNoCardsDraw(advanced);
const { beforeDraw, afterDraw } = fixture;
assert.equal(beforeDraw.nexusCards!.phase!.stage, 'drawing');
assert.equal(beforeDraw.nexusCards!.cards!.hands.atreides, null);
const botView = viewGame(beforeDraw, 'atreides');
botView.players.find(player => player.id === 'atreides')!.bot = 'Easy';
const botChoice = botActions(botView).find(action => action.type === 'nexusCardChoice');
assert.ok(botChoice, 'The real eligible player has a legal bot choice');
assert.doesNotThrow(() => applyAction(beforeDraw, 'atreides', botChoice));
assert.equal(afterDraw.nexusCards!.cards!.hands.atreides, 'richese');
const offer = viewGame(fixture.game, 'atreides').nexusRichese;
assert.ok(offer && !offer.blocked);
const place = TERRITORIES.find(territory => territory.type === 'stronghold' &&
!territory.sectors.includes(fixture.game.storm) && fixture.game.players.every(player =>
Object.keys(player.forces).every(key => !key.startsWith(`${territory.id}:`))));
assert.ok(place);
let game = applyAction(fixture.game, 'atreides', { type: 'ship', territory: place.id,
sector: place.sectors[0], amount: 1, elite: 0, allyPayment: 0, nexus: offer.event });
game = advanceSelectedIndependentNexus(game, state => state.nexusRicheseLast?.stage === 'shipped');
assert.equal(game.nexusCards!.cards!.hands.atreides, null);
assert.equal(game.nexusCards!.cards!.discard.filter(card => card === 'richese').length, 1);
assert.equal(game.players.find(player => player.id === 'atreides')!.forces[`${place.id}:${place.sectors[0]}`], 1);
});