Allow Emperor gifts during Basic Ix phase openings
Verify and publish checkpoint container / container (push) Canceled after 0s

This commit is contained in:
Quintine committed 2026-10-29 06:33:41 +11:00
1 parent 538247e777
commit d4abc6bb83
9 files changed
+294 -4

No files matched your search

@@ -7,6 +7,7 @@ import { renderToStaticMarkup } from 'react-dom/server';
import { applyAction, createGame, joinGame, newPlayer, viewGame, type Game, type GameView } from '../game/engine';
import { EmperorTimingGift } from '../components/emperor-timing-gift';
import { nextStrongholdFactionsNativeStep } from './fixture-stronghold-factions';
import { createTruthTurnAmalFixture } from './fixture-truth-turn-amal';
const aliases = registerHooks({
resolve(specifier, context, next) {
@@ -98,3 +99,31 @@ void test('an Extortion quote presents the recipient and restores its original d
assert.match(table(own), /Moritani Extortion decision resumes after the Karama response/);
assert.doesNotMatch(table(observer), /Share spice with Harkonnen/);
});
void test('a phase-opening quote gives only its owner the gift control', () => {
const game = fixture();
// Exercise the isolated projected contract; the engine owns its eligibility.
const own: GameView = {...viewGame(game, 'e'), emperorGuildTimingGift:null,
emperorExtortionGift:null, emperorPhaseOpeningGift:{recipient:'g', maximum:6}};
const observer: GameView = {...viewGame(game, 'h'), emperorGuildTimingGift:null,
emperorExtortionGift:null, emperorPhaseOpeningGift:null};
const html = component(own);
assert.match(html, /Share spice with Guild/);
assert.match(html, /Phase opening resumes after the Karama response to your gift/);
assert.match(html, /type="number"[^>]*min="1"[^>]*max="6"/);
assert.match(html, /<button\b(?![^>]*disabled)[^>]*>Share spice<\/button>/);
assert.match(component(own, true), /<button\b[^>]*disabled=""[^>]*>Share spice<\/button>/);
assert.equal(component(observer), '');
assert.equal(component({...own, emperorPhaseOpeningGift:null}), '');
});
void test('the real Basic Ix opening table exposes the control only to the Emperor', () => {
const {game} = createTruthTurnAmalFixture();
game.players.find(player => player.id === 'emperor')!.ally = 'atreides';
game.players.find(player => player.id === 'atreides')!.ally = 'emperor';
const own = table(viewGame(game, 'emperor'));
const observer = table(viewGame(game, 'harkonnen'));
assert.match(own, /Before Storm/);
assert.match(own, /Phase opening resumes after the Karama response to your gift/);
assert.doesNotMatch(observer, /Phase opening resumes after the Karama response to your gift/);
});