Dev #5

Merged
w-vandal merged 16 commits from dev into main 2026-08-30 09:29:41 +00:00
2 changed files with 112 additions and 1 deletions
Showing only changes of commit 6b9a491387 - Show all commits
+14 -1
View File
@@ -605,7 +605,20 @@
const found = [];
root.querySelectorAll('[data-element-id]').forEach(function(node) {
const sib = node.nextSibling;
if (sib && sib.nodeType === Node.COMMENT_NODE && COMMENT_MARKERS.indexOf(sib.data) !== -1) {
const hasCommentMarker = !!(sib && sib.nodeType === Node.COMMENT_NODE && COMMENT_MARKERS.indexOf(sib.data) !== -1);
// Un élément actuellement CACHÉ par une condition de
// visibilité (voir render_element_html.py) n'a pas de
// commentaire marqueur à sa suite — sa balise porte
// directement la classe "visibilityGated" à la place. Sans
// ce second cas, un élément qui passe de VISIBLE à CACHÉ
// n'était jamais retrouvé ici (seul le sens caché->visible
// l'était, via le commentaire) : son ancien nœud visible
// restait donc affiché indéfiniment à côté du nouveau,
// maintenant visible, qui le remplace normalement (ex. une
// icône "enveloppe fermée" jamais masquée en même temps que
// "enveloppe ouverte" qui apparaît après avoir cliqué).
const isHiddenPlaceholder = node.classList.contains('visibilityGated');
if (hasCommentMarker || isHiddenPlaceholder) {
found.push(node);
}
});
+98
View File
@@ -0,0 +1,98 @@
"""Régression : après une action "Modifier une donnée" qui fait BASCULER
une condition de visibilité (ex. une icône "enveloppe fermée" visible
quand is_opened=faux, une "enveloppe ouverte" visible quand is_opened=vrai),
templates/play.html::refreshRuntimeData() ne retrouvait, dans le HTML
fraîchement régénéré, que l'élément qui REDEVIENT visible (repéré via le
commentaire "<!--visibilityGated-->" posé après son contenu réel par
_mark(), voir render_element_html.py) — jamais celui qui REDEVIENT
CACHÉ, dont le placeholder ("<div class=\"visibilityGated\" ...
style=\"display:none;\"></div>") n'a pas de commentaire à sa suite, juste
une classe CSS sur lui-même. Résultat : l'ancien élément visible restait
affiché indéfiniment à côté du nouveau qui apparaît en plus (les deux
enveloppes en même temps).
Ces tests-ci ne peuvent pas simuler le DOM d'un navigateur (refreshRuntimeData
est du JS) — ils verrouillent seulement le CONTRAT côté serveur dont
dépend le correctif JS (findCommentMarkedDescendants, voir play.html) :
un élément CACHÉ par condition de visibilité doit porter la classe
"visibilityGated" directement sur sa balise, un élément VISIBLE sous
condition doit porter le commentaire juste après. Voir aussi
tests/test_data_binding_refresh_marker.py pour le marqueur "dataBound"."""
import re
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_icon_with_visibility(client, slug, screen_id, def_id, field_name, expected):
resp = client.post(f"/game/{slug}/screens/{screen_id}/elements/add", data={"widget": "icone"}, follow_redirects=False)
el_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1))
client.post(f"/game/{slug}/elements/{el_id}/save", data={
"ctrl_visibilite_cond_mode": "objet",
"ctrl_visibilite_cond_definition_id": str(def_id),
"ctrl_visibilite_cond_champ": field_name,
"ctrl_visibilite_cond_operateur": "egal",
"ctrl_visibilite_cond_valeur": expected,
})
return el_id
def test_hidden_element_carries_the_class_marker_not_a_comment(client, game):
resp = client.post(f"/game/{game}/objects/new", data={
"object_name": "Email", "field_name[]": ["is_opened"],
"field_type[]": ["booleen"], "field_relation[]": [""], "field_required[]": ["0"],
"field_min[]": [""], "field_max[]": [""],
}, follow_redirects=False)
def_id = int(resp.headers["Location"].rstrip("/").split("/")[-1])
client.post(f"/game/{game}/objects/{def_id}/data/new", data={"is_opened": "0"})
screen_id = _create_screen(client, game)
closed_id = _add_icon_with_visibility(client, game, screen_id, def_id, "is_opened", "Non")
open_id = _add_icon_with_visibility(client, game, screen_id, def_id, "is_opened", "Oui")
payload = client.get(f"/game/{game}/runtime-payload").get_json()
elements = {e["id"]: e for e in payload["screens"][0]["elements"]}
closed_html = elements[closed_id]["rendered_html"]
open_html = elements[open_id]["rendered_html"]
# is_opened=faux : l'enveloppe "fermée" est visible (marqueur en
# commentaire, après son vrai contenu) ; l'enveloppe "ouverte" est
# cachée (marqueur en CLASSE, directement sur le placeholder).
assert "<!--visibilityGated-->" in closed_html
assert f'data-element-id="{closed_id}"' in closed_html
assert "display:none" not in closed_html
assert 'class="visibilityGated"' in open_html
assert "display:none" in open_html
assert f'data-element-id="{open_id}"' in open_html
assert "<!--visibilityGated-->" not in open_html
def test_toggling_the_field_swaps_which_element_carries_which_marker(client, game):
resp = client.post(f"/game/{game}/objects/new", data={
"object_name": "Email2", "field_name[]": ["is_opened"],
"field_type[]": ["booleen"], "field_relation[]": [""], "field_required[]": ["0"],
"field_min[]": [""], "field_max[]": [""],
}, follow_redirects=False)
def_id = int(resp.headers["Location"].rstrip("/").split("/")[-1])
resp = client.post(f"/game/{game}/objects/{def_id}/data/new", data={"is_opened": "0"}, follow_redirects=False)
screen_id = _create_screen(client, game)
closed_id = _add_icon_with_visibility(client, game, screen_id, def_id, "is_opened", "Non")
open_id = _add_icon_with_visibility(client, game, screen_id, def_id, "is_opened", "Oui")
import db
rows = db.list_rows(game, db.get_definition(game, def_id))
row_id = rows[0]["id"]
db.update_row(game, db.get_definition(game, def_id), row_id, {"is_opened": "on"})
payload = client.get(f"/game/{game}/runtime-payload").get_json()
elements = {e["id"]: e for e in payload["screens"][0]["elements"]}
# is_opened=vrai maintenant : les rôles s'inversent complètement, aucun
# des deux ne doit garder son ancien marqueur.
assert 'class="visibilityGated"' in elements[closed_id]["rendered_html"]
assert "<!--visibilityGated-->" in elements[open_id]["rendered_html"]