Tegn og Gæt: forrige spils ord står ikke i ordfeltet
CI / test (push) Successful in 50s

Fejl (fundet af QA, også i drift siden 7367b72): telefonen huskede
kladderne under nøglen kode:trin:fase, fx "KLMT:0:word". Nøglen går igen i
næste spil i samme rum, og kladderne blev aldrig glemt, så ved "Spil igen"
(og ved skift til Tegn og Gæt igen) stod det ord, man sendte sidst, allerede
i feltet. Nu glemmes kladderne uden for opgaverne (lobby, tema, afsløring,
slut); inden for et trin overlever de stadig en ny render.

Test: tegn.js's afterPlay kørt i node med en lille falsk DOM (springes over
uden node); den fejler på den gamle tegn.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
agw
2026-10-20 21:58:27 +02:00
co-authored by Claude Opus 5.5
parent c26a0d52f9
commit 0149bf9bd3
2 changed files with 51 additions and 0 deletions
+4
View File
@@ -134,6 +134,7 @@
clearTimeout(root._tgBusy);
if (on) root._tgBusy = setTimeout(function () { root.classList.remove('busy'); }, 6000);
}
var TASKS = { word: 1, draw: 1, guess: 1 };
function stepKey(state) { return state.code + ':' + ((state.step || {}).index) + ':' + state.phase; }
var play = {};
@@ -216,6 +217,9 @@
function afterPlay(root, state, u) {
bindPlay(root);
var me = state.me || {}, t = me.task, s = tg(u);
/* kladderne hører til ét spil: nøglen (kode:trin:fase) går igen i næste spil i samme rum, så uden for
opgaverne (lobby, tema, afsløring, slut) glemmes de, ellers står forrige spils ord i feltet ved "Spil igen" */
if (!TASKS[state.phase]) s.drafts = {};
var key = stepKey(state);
if (s.key !== key) {
s.key = key; s.full = false;
+47
View File
@@ -0,0 +1,47 @@
"""Telefonens ordfelt i Tegn og Gæt (tegn.js afterPlay), kørt i node med en lille falsk DOM. Springes over uden node."""
import json
import shutil
import subprocess
import unittest
from pathlib import Path
TEGN_JS = Path(__file__).resolve().parents[1] / "static" / "party" / "tegn.js"
# Telefonen skriver et ord (input-hændelsen gemmer kladden), og så gennemløbes faserne. Hver render svarer til
# play.js: et nyt, tomt felt, når opgaven er ny, og afterPlay, der fylder kladden i.
SCRIPT = r"""
const fs = require('fs'), vm = require('vm');
const handlers = {};
const root = { _ui: {}, addEventListener: (t, f) => { handlers[t] = f; }, querySelectorAll: () => [], contains: () => true,
querySelector: (sel) => sel === '#tg-text' ? root.input : null };
const window = { WPP: { esc: (s) => String(s), now: () => 0, reducedMotion: () => true, cleanInput: (v) => v }, devicePixelRatio: 1,
addEventListener: () => {} };
vm.runInNewContext(fs.readFileSync(process.argv[1], 'utf8'), { window, document: { addEventListener() {} },
requestAnimationFrame: () => 0, setTimeout: () => 0, clearTimeout: () => {} });
const T = window.WPPTegn;
const state = (phase) => ({ code: 'KLMT', phase, step: { index: 0 }, me: { task: phase === 'word' ? { kind: 'word', done: false } : null } });
const render = (phase) => {
root.input = phase === 'word' ? { value: '', getAttribute: () => 'KLMT:0:word' } : null;
T.afterPlay(root, state(phase), root._ui);
return root.input && root.input.value;
};
const out = {};
render('word');
root.input.value = 'kat';
handlers.input && handlers.input({ target: Object.assign(root.input, { id: 'tg-text', matches: () => true, closest: () => root.input }) });
out.same_step = render('word'); // samme trin, ny render: kladden står der stadig
for (const p of ['draw', 'guess', 'reveal', 'final', 'theme']) render(p);
out.next_game = render('word'); // "Spil igen": samme nøgle KLMT:0:word i næste spil
console.log(JSON.stringify(out));
"""
@unittest.skipUnless(shutil.which("node"), "node findes ikke")
class WordDraftTests(unittest.TestCase):
def test_last_games_word_is_not_filled_in(self):
res = subprocess.run(["node", "-e", SCRIPT, str(TEGN_JS)], capture_output=True, text=True, timeout=30)
self.assertEqual(res.returncode, 0, res.stderr)
out = json.loads(res.stdout)
self.assertEqual(out["same_step"], "kat")
self.assertIn(out["next_game"], ("", None))