73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { registerHooks } from 'node:module';
|
|
import { readFileSync } from 'node:fs';
|
|
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { applyAction, createGame, joinGame, newPlayer, viewGame, type Game, type GameView } from '../game/engine';
|
|
|
|
const aliases = registerHooks({
|
|
resolve(specifier, context, next) {
|
|
return next(specifier === 'next/image' ? 'vinext/shims/image' :
|
|
specifier === 'next/link' ? 'vinext/shims/link' : specifier, context);
|
|
},
|
|
load(url, context, next) {
|
|
if (!url.endsWith('.module.css')) return next(url, context);
|
|
const css = readFileSync(new URL(url), 'utf8');
|
|
const classes = Object.fromEntries([...css.matchAll(/\.([a-zA-Z_][\w-]*)/g)].map(match => [match[1], match[1]]));
|
|
return { format:'module', source:`export default ${JSON.stringify(classes)}`, shortCircuit:true };
|
|
},
|
|
});
|
|
const { GameTable } = await import('../components/game-table');
|
|
aliases.deregister();
|
|
|
|
function lobby(): Game {
|
|
const game = createGame('GROUPPREVIEWUI',newPlayer('at','Atreides','atreides'));
|
|
joinGame(game,newPlayer('em','Emperor','emperor'));
|
|
joinGame(game,newPlayer('gu','Guild','guild'));
|
|
return game;
|
|
}
|
|
const table = (game: GameView, busy = false) => renderToStaticMarkup(createElement(GameTable,
|
|
{game,busy,send:async () => {},onExit() {}}));
|
|
function groupLabel(html: string): string {
|
|
const label = html.match(/<label\b[^>]*>(?:(?!<\/label>)[\s\S])*Group alliances · unfinished preview(?:(?!<\/label>)[\s\S])*<\/label>/)?.[0];
|
|
assert.ok(label, 'The group-alliance preview selector is visible.');
|
|
return label;
|
|
}
|
|
|
|
void test('host sees each group variant and guests cannot change the selector', () => {
|
|
const game = lobby(), host = groupLabel(table(viewGame(game,'at')));
|
|
assert.match(host,/value="off"/);
|
|
assert.match(host,/value="three"/);
|
|
assert.match(host,/value="three-short"/);
|
|
assert.match(host,/value="unlimited"/);
|
|
assert.match(host,/Up to three members/);
|
|
assert.match(host,/Unlimited members/);
|
|
assert.doesNotMatch(host,/<select[^>]*disabled/);
|
|
assert.match(groupLabel(table(viewGame(game,'em'))),/<select[^>]*disabled/);
|
|
assert.match(groupLabel(table(viewGame(game,'at'),true)),/<select[^>]*disabled/);
|
|
});
|
|
|
|
void test('selected preview warns in the lobby and through real setup', () => {
|
|
let game = applyAction(lobby(),'at',{type:'coalitionPreview',variant:'three-short'});
|
|
const lobbyHtml = table(viewGame(game,'at'));
|
|
assert.match(lobbyHtml,/This incomplete preview needs three to six classic factions/);
|
|
assert.match(lobbyHtml,/Some powers and interactions remain unfinished/);
|
|
for (const seat of game.players) game = applyAction(game,seat.id,{type:'ready'});
|
|
game = applyAction(game,'at',{type:'start'});
|
|
for (const actor of ['at','em','gu']) {
|
|
const html = table(viewGame(game,actor));
|
|
assert.match(html,/Group alliances are an unfinished preview/);
|
|
assert.match(html,/Some faction powers and interactions are incomplete/);
|
|
}
|
|
});
|
|
|
|
void test('Advanced group preview keeps the explicit opt-in and incompatibility warning', () => {
|
|
let game = applyAction(lobby(),'at',{type:'coalitionPreview',variant:'three'});
|
|
game = applyAction(game,'at',{type:'rules',advanced:true});
|
|
const html = table(viewGame(game,'at'));
|
|
assert.match(html,/Advanced rules require their separate preview start/);
|
|
assert.match(html,/without expansion decks, other optional modules/);
|
|
assert.match(html,/Begin Advanced preview/);
|
|
});
|