Batch of LLM-assisted fixes/feature updates

This commit is contained in:
Cam Spry committed 2026-10-30 23:02:45 -04:00
1 parent 7c6453160a
commit 05aaf394df
16 files changed
+5597 -912

No files matched your search

+116
View File
@@ -0,0 +1,116 @@
'use strict';
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { YarnGame } = require('../server');
/**
* Deterministic timer double so gameplay phases can be advanced in tests
* without real waiting.
*/
function createFakeTimers() {
let nextId = 1;
const intervals = new Map();
const timeouts = new Map();
return {
intervals,
timeouts,
setInterval(fn, ms) {
const id = nextId += 1;
intervals.set(id, { fn, ms });
return id;
},
clearInterval(id) {
intervals.delete(id);
},
setTimeout(fn, ms) {
const id = nextId += 1;
timeouts.set(id, { fn, ms });
return id;
},
clearTimeout(id) {
timeouts.delete(id);
},
/** Fire every live interval `times` times (snapshotting per pass). */
runIntervals(times = 1) {
for (let pass = 0; pass < times; pass += 1) {
for (const [id, { fn }] of [...intervals.entries()]) {
if (!intervals.has(id)) continue;
fn();
}
}
},
/** Fire every pending timeout once. */
runTimeouts() {
const pending = [...timeouts.values()];
timeouts.clear();
for (const { fn } of pending) fn();
}
};
}
function tempStoriesDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'yarn-test-'));
}
function makeGame(overrides = {}) {
const timers = overrides.timers || createFakeTimers();
const events = [];
const game = new YarnGame(overrides.roomName || 'test-room', {
timers,
broadcast: (event, payload) => events.push({ event, payload }),
botFactory: overrides.botFactory,
botType: overrides.botType || 'random',
storiesDir: overrides.storiesDir || tempStoriesDir()
});
const emitted = (name) => events.filter((entry) => entry.event === name);
return { game, timers, events, emitted };
}
function addPlayers(game, count) {
const ids = [];
for (let i = 0; i < count; i += 1) {
const id = `p${i + 1}`;
game.addPlayer(id, `Player ${i + 1}`, `socket-${i + 1}`);
ids.push(id);
}
return ids;
}
/** Start a game with `count` human players and no bots. */
async function startGame(game, count, settings = {}) {
const ids = addPlayers(game, count);
await game.startGame({ botCount: 0, timeLimit: 60, roundLimit: 15, ...settings });
return ids;
}
/** Submit one entry per player, in order. */
function submitAll(game, entries) {
entries.forEach(([playerId, text], index) => {
const result = game.submitEntry(playerId, text);
if (!result.ok) throw new Error(`submit failed for ${playerId}: ${result.error}`);
void index;
});
}
/** Cast the supplied votes and let the game close voting if complete. */
function voteAll(game, votes) {
for (const [playerId, entryIndex] of Object.entries(votes)) {
const result = game.submitVote(playerId, entryIndex);
if (!result.ok) throw new Error(`vote failed for ${playerId}: ${result.error}`);
}
game.checkVotesComplete();
}
module.exports = {
createFakeTimers,
tempStoriesDir,
makeGame,
addPlayers,
startGame,
submitAll,
voteAll
};