Files
Dune/tests/public-deals-paid-travel-pledge.test.ts
T
Quintine a1b2aacbac
Verify and publish checkpoint container / container (push) Successful in 10m34s
Support paid current-turn travel deals
2026-10-29 07:49:56 +11:00

51 lines
3.1 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { viewGame } from '../game/engine';
import { actTruthAlliance as act, advanceTruthAlliance as advance, createTruthAllianceFixture,
truthAllianceClean as clean, truthAllianceInventory as inventory, truthAlliancePlayer as player } from './fixture-truth-alliance';
import { declareTruthBribe } from './fixture-truth-bribe';
/** The original Basic H/A/E setup, real worm/Nexus alliance and later Bidding
* from the shared fixture. The offer, Truthtrance question, answer and final
* consent are all real actions; no wallet, pledge or commitment is staged. */
void test('a previously offered paid travel deal can release a later unaffordable pledge on recipient consent', () => {
const f = createTruthAllianceFixture({ consent: 'allied' });
let game = advance(f.game, state => state.phase === 3 && !!state.auction && clean(state));
assert.equal(player(game, f.target).ally, f.partner);
assert.equal(player(game, f.partner).ally, f.target);
assert.equal(player(game, f.asker).ally, null);
const minimum = 4, initialCash = player(game, f.target).spice;
const amount = initialCash - minimum + 1;
assert.ok(amount > 0);
game = act(game, f.target, { type: 'dealOffer', target: f.asker,
terms: 'Immediate payment for a current-turn travel restriction.',
payment: { kind: 'immediateBribe', payer: f.target, recipient: f.asker, amount },
travel: { kind: 'ship', territory: 'polar_sink', minimum: 1, answer: false } });
const offer = game.deals?.at(-1); assert.ok(offer);
game = declareTruthBribe(f, game).game;
assert.ok(viewGame(game, f.asker).truthPledgeTargets.includes(f.target));
game = act(game, f.asker, { type: 'truthAsk', question: { kind: 'pledgeAid', target: f.target,
turn: game.turn, phase: game.phase, ally: f.partner, minimum } });
assert.ok(viewGame(game, f.target).truthPledgeAnswers?.includes('yes'));
game = act(game, f.target, { type: 'truthAnswer', answer: 'yes' });
const pledge = game.pledgePromises?.at(-1); assert.ok(pledge);
assert.ok(!pledge.fulfilled && !pledge.released);
// A new voluntary payment cannot evade the later pledge, but the original
// offer already consented to payment before that answer was made.
const before = structuredClone(game);
assert.throws(() => act(game, f.target, { type: 'bribe', target: f.asker, amount }));
assert.deepEqual(game, before);
const incoming = player(game, f.asker).bribes;
const next = act(game, f.asker, { type: 'dealRespond', deal: offer.id, accept: true });
assert.equal(next.deals?.find(deal => deal.id === offer.id)?.status, 'active');
assert.equal(player(next, f.target).spice, initialCash - amount);
assert.equal(player(next, f.asker).bribes, incoming + amount);
assert.deepEqual(next.aid[f.target], before.aid[f.target]);
assert.equal(next.pledgePromises?.at(-1)?.released, true);
assert.ok(!next.pledgePromises?.at(-1)?.fulfilled);
assert.equal(next.travelPromises?.filter(row => row.sourceDeal === offer.id).length, 1);
assert.equal(viewGame(next, f.asker).dealTravelStatus[offer.id], 'pending');
assert.deepEqual(inventory(next), f.originalCards);
});