The extension question was hidden behind the results screen (Gitea#11)
Jesse, playing v0.7.8: "Solitaire game ended. I did not have an option to extend the game by a day." The engine and the Frame were right — checked before changing anything. A solitaire game at the end of its timetable reaches awaitingExtension with extensionVotes [null], and renderEnding writes "play one more Day" into #actions. It then opens #resultsdlg, which is MODAL, so those buttons were directly underneath a dialog whose only control was Close. The results dialog now carries the question itself, hidden unless a vote is pending: Play One More Day / End the Game Here, casting the same game.extend intent. The #actions buttons stay as the fallback once it is closed. TODO.md #35 recorded extended play as verified on phoenix.local — over the HTTP API, which renders no dialog. What was proven was that the server supports it, not that a player can reach it. Noted there. Rides along in the unshipped v0.7.9. 870 tests pass, one new. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f2c87b6871
commit
e035dda5a3
@@ -3362,6 +3362,36 @@ describe('the end-of-game results screen (Gitea#16)', () => {
|
||||
return snapshot(s, [], null);
|
||||
};
|
||||
|
||||
it('asks the extension question ON the results dialog, not only behind it (Gitea#11)', () => {
|
||||
/**
|
||||
* REPORTED BY JESSE 2026-08-30: "Solitaire game ended. I did not have an option to extend the
|
||||
* game by a day."
|
||||
*
|
||||
* The engine and the Frame were right all along — a solitaire game at the end of its timetable
|
||||
* reaches `awaitingExtension` with an uncast vote, asserted below. What went wrong is that
|
||||
* `renderEnding` writes its two buttons into `#actions` and then opens `#resultsdlg`, which is
|
||||
* MODAL: the question was underneath a dialog whose only control was Close. Gitea#11 was
|
||||
* verified over the HTTP API, which renders no dialog, so the browser path never was.
|
||||
*/
|
||||
const f = finished();
|
||||
assert.equal(f.status, 'awaitingExtension', 'a solitaire game no longer pauses to ask');
|
||||
assert.equal(f.extensionVotes[f.viewer], null, 'the viewer has somehow already voted');
|
||||
|
||||
const html = readFileSync(join(dist, 'play.html'), 'utf8');
|
||||
for (const id of ['rs-extend-yes', 'rs-extend-no']) {
|
||||
assert.ok(html.includes(`id="${id}"`), `the results dialog cannot ask: no #${id}`);
|
||||
}
|
||||
|
||||
// And they are wired: shown only while a vote is pending, and casting the same intent the
|
||||
// `#actions` buttons do. Read from the source, since the dialog needs a DOM to drive.
|
||||
const src = readFileSync(join(root, 'src/web/main.ts'), 'utf8');
|
||||
const fn = /function showResults\(f: Frame\): void \{[\s\S]*?\n\}/.exec(src)?.[0] ?? '';
|
||||
assert.ok(fn !== '', 'showResults moved and this test cannot see it');
|
||||
assert.match(fn, /awaitingExtension/, 'the dialog does not know the game is asking');
|
||||
assert.match(fn, /'game\.extend'/, 'the dialog offers no way to answer');
|
||||
assert.match(fn, /yes\.hidden = !asking/, 'the buttons are not hidden on a game that is over');
|
||||
});
|
||||
|
||||
it('never prints a raw enum at the player', () => {
|
||||
// The bug the issue opens on: `GAME OVER — revenueFloor` is an internal identifier, shown at
|
||||
// the one moment the game has the player's whole attention.
|
||||
|
||||
Reference in New Issue
Block a user