Retain selected decks and original optional modules through normal setup, distinguish native Ixian Betrayal from absent-faction replacement, route explicit CHOAM fuel before printed effects, and preserve native No-Field invoices and pair continuation. Connect canonical native cancellation stock and existing human/minimal AI consumers. Validation: 194 affected tests across 19 files, types/lint/build, bounded native invoice review and seven finite original-action/rendered-control programmes. Runtime ec5ad6c18996d8d958ec0d01132ef3e3ea6d23d36188902eca9a63d4db2efbf8; documentation-only proof overlay a5892004937434429916496497c07a3838a324b4a5d64d4a0eb804ab5212d5bd. Other envelopes, full combinations, comprehensive assurance and deployed acceptance remain open. No saved-room/provider changes.
58 lines
3.9 KiB
TypeScript
58 lines
3.9 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { selectedIndependentNexusProfile, nexusCoreProfile } from '../game/faction-module-profile';
|
|
import { createTechTokens } from '../game/tech-tokens';
|
|
import { createSelectedIndependentEntry, type SelectedIndependentEntryOptions } from './fixture-selected-independent-nexus-entry';
|
|
|
|
const entries: SelectedIndependentEntryOptions[] = [
|
|
{expansions:['ix'], factions:['ixians','tleilaxu','atreides']},
|
|
{expansions:['choam'], factions:['richese','choam','guild'], advanced:true, skills:true, homeworlds:true, tech:true, strongholds:true},
|
|
{expansions:['ix','choam'], factions:['ixians','richese','harkonnen','atreides'], advanced:true, skills:true, homeworlds:true, tech:true, strongholds:true},
|
|
{expansions:['ix','choam'], factions:['atreides','guild']},
|
|
{expansions:['choam'], factions:['emperor','atreides'], advanced:true, homeworlds:true, strongholds:true},
|
|
{expansions:['ix'], factions:['tleilaxu','guild'], homeworlds:true},
|
|
];
|
|
for (const options of entries) void test(`normal independent Nexus entry ${options.expansions.join('+')}/${options.factions.join('+')} retains selected components`, () => {
|
|
const {lobby, setup, game} = createSelectedIndependentEntry(options);
|
|
assert.equal(lobby.lobbyOptions?.ecazTreachery, true);
|
|
assert.equal(lobby.nexusCards?.cards, null);
|
|
assert.equal(game.ecazTreachery, true);
|
|
assert.deepEqual(game.expansions, options.expansions);
|
|
assert.equal(nexusCoreProfile(game), true);
|
|
assert.equal(selectedIndependentNexusProfile(game), true);
|
|
assert.equal(!!game.leaderSkills, !!options.skills);
|
|
assert.equal(!!game.homeworlds, !!options.homeworlds);
|
|
assert.equal(!!game.techTokens, !!options.tech);
|
|
assert.equal(!!game.strongholdCards, !!options.strongholds);
|
|
assert.equal(game.phase, 0);
|
|
assert.equal(game.nexusCards!.cards!.deck.length, 12);
|
|
assert.ok(Object.values(game.nexusCards!.cards!.hands).every(card => card === null));
|
|
const ordinary = game.deck.length + game.discard.length + game.players.reduce((sum, player) => sum + player.hand.length, 0);
|
|
assert.equal(ordinary, options.expansions.includes('ix') ? 50 : 38);
|
|
assert.equal(game.richeseCache?.length ?? 0, options.factions.includes('richese') ? 10 : 0);
|
|
assert.equal(!!game.nexusIxianReplacementPreview, !options.factions.includes('ixians'));
|
|
assert.equal(!!game.nexusIxianBetrayalPreview, options.factions.includes('ixians'));
|
|
assert.equal(!!game.nexusHarkonnenBetrayalPreview, options.factions.includes('harkonnen'));
|
|
assert.equal(!!game.guildBetrayalPreview, options.factions.includes('guild'));
|
|
if (options.skills) assert.ok(['skillTreachery','leaderSkills'].includes(setup.setupStage!),
|
|
'The original Ixian starting-card choice may precede skill training');
|
|
if (setup.techTokens) {
|
|
assert.ok(Object.values(lobby.techTokens!).every(token => token.owner === null));
|
|
assert.deepEqual(setup.techTokens, createTechTokens(setup.players),
|
|
'Original setup assigns each seated native its printed Tech token; missing natives wait for Storm');
|
|
}
|
|
if (game.strongholdCards) assert.ok(Object.values(game.strongholdCards.owners).every(owner => owner === null));
|
|
});
|
|
|
|
void test('selected core capability requires real independent cards and selected registered seats', () => {
|
|
const base = {advanced:true, expansions:['ix'], players:[{faction:'ixians'},{faction:'atreides'}], nexusCards:true, ecazTreachery:true};
|
|
assert.equal(selectedIndependentNexusProfile(base), true);
|
|
for (const invalid of [
|
|
{...base, ecazTreachery:false}, {...base, expansions:['ix','ix']},
|
|
{...base, players:[{faction:'ixians'},{faction:'richese'}]},
|
|
{...base, players:[{faction:'ixians'},{faction:'ixians'}]},
|
|
{...base, techTokens:true}, {...base, advanced:false, strongholdCards:true},
|
|
{...base, discoveryEnabled:true}, {...base, semutaPreview:true},
|
|
]) assert.equal(selectedIndependentNexusProfile(invalid), false);
|
|
});
|