screens/flow/constants.py : TRIGGER_EVENTS += "clavier" (À l'appui sur une touche) et "minuteur" (Toutes les X millisecondes) — ni élément ni écran précis pour les deux, comme "evenement" déjà en place. FLOW_NODE_FIELDS += trigger_key/trigger_interval_ms. ensure_flow_schema.py : ALTER TABLE pour les 2 colonnes (patron trigger_custom_event_id). templates/screen_edit.html + static/js/screen_edit/flow-editor.js : - "clavier" : un champ "Touche à surveiller" qui capture lui-même la touche pressée (onkeydown sur l'input, captureFlowTriggerKey()) plutôt que de faire deviner la syntaxe attendue (ev.key du navigateur, ex. "ArrowUp", "a", " " pour Espace). - "minuteur" : un simple champ numérique (millisecondes). - nodeLabel() affiche "⌨️ Touche « X »"/"⏱️ Toutes les N ms" sur le nœud. static/js/play/triggers.js (moteur de jeu) : - bindKeyboardTriggers() : UN SEUL window.addEventListener('keydown', ...) posé une fois pour tout le jeu (voir l'amorçage en fin de templates/play.html) — même patron de scan global que dispatchGameEvent() pour "Sur un événement personnalisé". - runScreenTimerTriggers(screenId) : géré PAR ÉCRAN (appelé depuis showScreen(), static/js/play/screens.js) — démarre les setInterval des nœuds "minuteur" de l'écran affiché, arrête d'abord tous ceux de l'affichage précédent (même principe que runAnimationTimeline) pour ne jamais accumuler des minuteurs sur des écrans quittés. Vérifié : 255 tests passent (5 nouveaux, dont un qui verrouille que la touche Espace — très probablement utilisée en jeu — n'est pas filtrée comme une valeur "vide" par add_flow_node.py), 13 tests node:test toujours au vert, syntaxe JS validée sur tous les fichiers de static/js/play/ et static/js/screen_edit/. Comme le reste du graphe de logique côté client, le comportement RÉEL d'un keydown/setInterval n'est pas testable sans navigateur — test manuel recommandé (touche assignée à un saut, minuteur faisant avancer un compteur). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
75 lines
3.0 KiB
Python
75 lines
3.0 KiB
Python
"""Tests du déclencheur clavier ("clavier") et du minuteur récurrent
|
|
("minuteur") — Phase 3 du plan d'extension du moteur. Comme le reste du
|
|
graphe de logique côté client, le comportement RÉEL d'un vrai keydown/
|
|
setInterval n'est pas testable sans navigateur (voir play_js_bundle() —
|
|
on vérifie que la logique existe dans le JS livré, pas qu'elle s'exécute)."""
|
|
import json
|
|
import re
|
|
|
|
from conftest import play_js_bundle, screen_edit_js_bundle
|
|
|
|
import screens
|
|
|
|
|
|
def _create_screen(client, slug, name="Accueil"):
|
|
resp = client.post(f"/game/{slug}/screens/new", data={"name": name}, follow_redirects=False)
|
|
return int(re.search(r"/screens/(\d+)/edit", resp.headers["Location"]).group(1))
|
|
|
|
|
|
def _add_flow_node(client, slug, screen_id, **fields):
|
|
resp = client.post(
|
|
f"/game/{slug}/screens/{screen_id}/flow/nodes/add",
|
|
data=json.dumps(fields),
|
|
content_type="application/json",
|
|
)
|
|
assert resp.status_code == 200
|
|
return resp.get_json()["id"]
|
|
|
|
|
|
def test_keyboard_trigger_node_persists_key(client, game):
|
|
screen_id = _create_screen(client, game)
|
|
node_id = _add_flow_node(client, game, screen_id, node_type="trigger", trigger_event="clavier", trigger_key="ArrowUp")
|
|
node = screens.get_flow_node(game, node_id)
|
|
assert node["trigger_event"] == "clavier"
|
|
assert node["trigger_key"] == "ArrowUp"
|
|
assert node["trigger_element_id"] is None
|
|
|
|
|
|
def test_keyboard_trigger_persists_space_key(client, game):
|
|
"""La barre d'espace (ev.key === ' ', un seul caractère espace) ne doit
|
|
PAS être traitée comme une valeur "vide" par add_flow_node.py (qui
|
|
filtre None/"" — " " n'est ni l'un ni l'autre) : une touche très
|
|
probablement utilisée ("Espace pour sauter") doit bien se persister."""
|
|
screen_id = _create_screen(client, game)
|
|
node_id = _add_flow_node(client, game, screen_id, node_type="trigger", trigger_event="clavier", trigger_key=" ")
|
|
node = screens.get_flow_node(game, node_id)
|
|
assert node["trigger_key"] == " "
|
|
|
|
|
|
def test_timer_trigger_node_persists_interval(client, game):
|
|
screen_id = _create_screen(client, game)
|
|
node_id = _add_flow_node(
|
|
client, game, screen_id, node_type="trigger", trigger_event="minuteur", trigger_interval_ms=500,
|
|
)
|
|
node = screens.get_flow_node(game, node_id)
|
|
assert node["trigger_event"] == "minuteur"
|
|
assert node["trigger_interval_ms"] == 500
|
|
|
|
|
|
def test_play_page_exposes_keyboard_and_timer_trigger_runtime(client, game):
|
|
js = play_js_bundle()
|
|
assert "bindKeyboardTriggers" in js
|
|
assert "'clavier'" in js
|
|
assert "runScreenTimerTriggers" in js
|
|
assert "'minuteur'" in js
|
|
assert "trigger_interval_ms" in js
|
|
|
|
|
|
def test_screen_edit_exposes_keyboard_and_timer_trigger_editor(client, game):
|
|
html = client.get(f"/game/{game}/screens/{_create_screen(client, game)}/edit").get_data(as_text=True)
|
|
assert "nf-trigger-key-row" in html
|
|
assert "nf-trigger-interval-row" in html
|
|
js = screen_edit_js_bundle()
|
|
assert "captureFlowTriggerKey" in js
|
|
assert "trigger_interval_ms" in js
|