Files
Dune/tests/public-deals-hajr-runtime.test.ts
T

70 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { applyAction, viewGame, type Game } from '../game/engine';
import {
completeHajrReplay, createHajrReplayFixture, hajrReplayPlayer,
} from './fixture-hajr-replay';
/** This reaches the native Advanced immediate-after-movement Hajr window via
* setup, auction, shipment, actual Hajr play, Box recovery and movement. The
* genuine fixture has spent its spice on those actions; only the payer's spice
* is explicitly staged so this independent deal payment can be exercised. */
function windowGame() {
const fixture = createHajrReplayFixture({ advanced: true });
const game = completeHajrReplay(fixture).beforeSecondHajr;
const payer = game.players.find(player => player.id === fixture.owner)!;
const recipient = game.players.find(player => player.id !== payer.id && !player.bot &&
player.id !== payer.ally && player.ally !== payer.id);
assert.ok(recipient);
assert.equal(payer.spice, 0, 'The original purchases, shipment and Box consumed the fixture spice.');
payer.spice = 4; // Controlled funding only; the native movement/window is not staged.
assert.ok(payer.hajrWindow);
assert.equal(available(game, payer.id), true);
return { fixture, game, payer: payer.id, recipient: recipient.id };
}
function available(game: Game, id: string) {
return viewGame(game, id).players.find(player => player.id === id)!.hajrAvailable;
}
function offer(game: Game, from: string, to: string, payer: string, recipient: string): Game {
return applyAction(game, from, {
type: 'dealOffer', target: to, terms: 'An immediate one-spice bribe.',
payment: { kind: 'immediateBribe', payer, recipient, amount: 1 },
});
}
void test('another seat accepting a prior-consented payment preserves the payer’s native Hajr opportunity', () => {
const { fixture, game: initial, payer, recipient } = windowGame();
const window = structuredClone(hajrReplayPlayer(initial).hajrWindow);
const beforeSpice = hajrReplayPlayer(initial).spice;
const beforeBribes = initial.players.find(player => player.id === recipient)!.bribes;
const offered = offer(initial, payer, recipient, payer, recipient);
assert.deepEqual(hajrReplayPlayer(offered).hajrWindow, window);
const deal = offered.deals!.at(-1)!;
const paid = applyAction(offered, recipient, { type: 'dealRespond', deal: deal.id, accept: true });
assert.equal(paid.deals!.at(-1)!.status, 'active');
assert.equal(hajrReplayPlayer(paid).spice, beforeSpice - 1);
assert.equal(paid.players.find(player => player.id === recipient)!.bribes, beforeBribes + 1);
assert.deepEqual(hajrReplayPlayer(paid).hajrWindow, window);
assert.equal(available(paid, payer), true);
const played = applyAction(paid, payer, { type: 'card', card: fixture.hajr });
assert.equal(hajrReplayPlayer(played).hajrPlays, 2);
assert.equal(hajrReplayPlayer(played).spice, beforeSpice - 1);
assert.equal(played.players.find(player => player.id === recipient)!.bribes, beforeBribes + 1);
});
void test('the payer’s own voluntary bribe or final acceptance closes the immediate Hajr window', () => {
const { game: initial, payer, recipient } = windowGame();
const direct = applyAction(initial, payer, { type: 'bribe', target: recipient, amount: 1 });
assert.equal(hajrReplayPlayer(direct).hajrWindow, undefined);
assert.equal(available(direct, payer), false);
const offered = offer(initial, recipient, payer, payer, recipient);
assert.equal(available(offered, payer), true);
const accepted = applyAction(offered, payer, { type: 'dealRespond', deal: offered.deals!.at(-1)!.id, accept: true });
assert.equal(hajrReplayPlayer(accepted).hajrWindow, undefined);
assert.equal(available(accepted, payer), false);
assert.equal(hajrReplayPlayer(accepted).spice, 3);
});