122 lines
5.9 KiB
TypeScript
122 lines
5.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { FreeformFactPreview, Truthtrance } from '../components/truthtrance';
|
|
import { applyAction, viewGame, type Game } from '../game/engine';
|
|
import { knowledgeGame } from './truthtrance-knowledge-fixture';
|
|
|
|
/** Actual native game and Truthtrance actions, with the target's scalar
|
|
* spice staged to show both personalized result branches. */
|
|
function pending(spice: number, text = 'Do you have at least 5 spice?'): Game {
|
|
let game = knowledgeGame();
|
|
game.players.find(player => player.id === 'b')!.spice = spice;
|
|
const card = game.players[0].hand.find(item => item.effect === 'truthtrance');
|
|
assert.ok(card);
|
|
game = applyAction(game,'a',{type:'card',card:card.id});
|
|
while (game.truthtrance?.stage === 'priority') {
|
|
const voter = game.players.find(player => !game.truthtrance!.passed.includes(player.id));
|
|
assert.ok(voter); game = applyAction(game,voter.id,{type:'truthPass'});
|
|
}
|
|
return applyAction(game,'a',{type:'truthAsk',question:{kind:'freeform',target:'b',
|
|
scope:'fact',text}});
|
|
}
|
|
function markup(game: Game, seat: string) {
|
|
return renderToStaticMarkup(createElement(Truthtrance, {game:viewGame(game,seat), busy:false, act() {}}));
|
|
}
|
|
|
|
for (const [spice, answer] of [[5,'Yes'],[4,'No']] as const) {
|
|
void test(`recognized freeform shows checked meaning to the table and private ${answer} to the target`, () => {
|
|
const game = pending(spice);
|
|
const target = markup(game,'b');
|
|
const observer = markup(game,'o');
|
|
for (const html of [target, observer]) {
|
|
assert.match(html, /Do you have at least 5 spice\?/);
|
|
assert.match(html, /Checked as:/);
|
|
assert.match(html, /you currently hold at least 5 spice/);
|
|
}
|
|
assert.match(target, /Your current game information establishes:/);
|
|
assert.match(target, new RegExp(`<strong>${answer}</strong>`));
|
|
assert.match(target, /Only you see this until you answer/);
|
|
assert.match(target, /Publish my answer/);
|
|
assert.doesNotMatch(observer, /Your current game information establishes:/);
|
|
assert.doesNotMatch(observer, /Publish my answer/);
|
|
assert.match(observer, /Waiting for .* to answer/);
|
|
});
|
|
}
|
|
|
|
void test('a compound freeform shows its aggregate interpretation to the table', () => {
|
|
const game = pending(5, 'Do you have at least 5 spice or a Shield?');
|
|
const target = markup(game, 'b'), observer = markup(game, 'o');
|
|
for (const html of [target, observer]) {
|
|
assert.match(html, /Checked as:/);
|
|
assert.match(html, /you currently hold at least 5 spice/);
|
|
assert.match(html, /OR/);
|
|
assert.match(html, /Shield/);
|
|
}
|
|
assert.match(target, /<strong>Yes<\/strong>/);
|
|
assert.doesNotMatch(observer, /Your current game information establishes:/);
|
|
});
|
|
|
|
void test('a category freeform displays its primary-role meaning without exposing the target answer', () => {
|
|
const game = pending(5, 'Do you have a weapon?');
|
|
const target = markup(game, 'b'), observer = markup(game, 'o');
|
|
for (const html of [target, observer]) {
|
|
assert.match(html, /Checked as:/);
|
|
assert.match(html, /you currently hold at least 1 card whose primary role is a weapon/);
|
|
}
|
|
assert.match(target, /Your current game information establishes:/);
|
|
assert.doesNotMatch(observer, /Your current game information establishes:/);
|
|
});
|
|
|
|
void test('a negative freeform displays the checked zero-card meaning without exposing the target answer', () => {
|
|
const game = pending(5, 'Do you have no Shield?');
|
|
const target = markup(game, 'b'), observer = markup(game, 'o');
|
|
for (const html of [target, observer]) {
|
|
assert.match(html, /Checked as:/);
|
|
assert.match(html, /you currently hold exactly 0 cards named Shield/);
|
|
}
|
|
assert.match(target, /Your current game information establishes:/);
|
|
assert.doesNotMatch(observer, /Your current game information establishes:/);
|
|
});
|
|
|
|
void test('a category and negative-card compound displays its checked aggregate without revealing the answer', () => {
|
|
const game = pending(5, 'Do you have a weapon and no Shield?');
|
|
const target = markup(game, 'b'), observer = markup(game, 'o');
|
|
for (const html of [target, observer]) {
|
|
assert.match(html, /Checked as:/);
|
|
assert.match(html, /you currently hold at least 1 card whose primary role is a weapon/);
|
|
assert.match(html, /AND/);
|
|
assert.match(html, /you currently hold exactly 0 cards named Shield/);
|
|
}
|
|
assert.match(target, /Your current game information establishes:/);
|
|
assert.doesNotMatch(observer, /Your current game information establishes:/);
|
|
});
|
|
|
|
void test('unsupported mixed conjunctions keep their manual answer control', () => {
|
|
const game = pending(5, 'Do you have a weapon and a defense or a Shield?');
|
|
const target = markup(game, 'b');
|
|
assert.doesNotMatch(target, /Checked as:/);
|
|
assert.doesNotMatch(target, /Your current game information establishes:/);
|
|
assert.match(target, /Answer Yes/);
|
|
assert.match(target, /Answer No/);
|
|
});
|
|
|
|
void test('the question editor previews the v5 interpretation only for current facts', () => {
|
|
const props = { scope: 'fact' as const, text: 'Do you have a weapon and no Shield?', target: 'b',
|
|
leaderName: (id: string) => id, locationName: (id: string) => id, playerName: (id: string) => id };
|
|
const recognized = renderToStaticMarkup(createElement(FreeformFactPreview, props));
|
|
assert.match(recognized, /Recognized freeform question/);
|
|
assert.match(recognized, /primary role is a weapon/);
|
|
assert.match(recognized, /AND/);
|
|
assert.match(recognized, /exactly 0 cards named Shield/);
|
|
for (const other of [
|
|
{ ...props, scope: 'currentTurn' as const },
|
|
{ ...props, text: 'Do you have a weapon and a defense or a Shield?' },
|
|
]) {
|
|
const manual = renderToStaticMarkup(createElement(FreeformFactPreview, other));
|
|
assert.match(manual, /not automatically interpreted/);
|
|
assert.doesNotMatch(manual, /Recognized freeform question/);
|
|
}
|
|
});
|