diff --git a/templates/game_dashboard.html b/templates/game_dashboard.html index 1fce0814..b4b3842c 100644 --- a/templates/game_dashboard.html +++ b/templates/game_dashboard.html @@ -453,8 +453,8 @@ {% set rows = rows_by_definition[d.id] %} {% if rows %} {% for r in rows %} -
-
+
{% endfor %}
@@ -470,18 +470,18 @@ {% set col = f.name|colname %} {% if f.type == 'texte' %} - + {% elif f.type == 'texte_long' %} - + {% elif f.type in ('nombre_entier', 'nombre_decimal') %} - + {% elif f.type == 'booleen' %} - + {% elif f.type == 'date' %} - + {% elif f.type == 'relation' %}
- {% for opt in relation_options_by_definition[d.id].get(f.id, []) %} @@ -493,8 +493,8 @@ {% endfor %} - - + + {% endfor %} diff --git a/tests/test_data_form_id_collision.py b/tests/test_data_form_id_collision.py new file mode 100644 index 00000000..c799ae58 --- /dev/null +++ b/tests/test_data_form_id_collision.py @@ -0,0 +1,42 @@ +"""Régression : chaque objet a sa propre table SQLite, donc ses ids de +ligne repartent de 1 (db/rows/insert_row.py) — les
de l'onglet Données (game_dashboard.html) doivent donc être +scopés par objet (dataEditForm{{d.id}}-{{r.id}}), sinon deux objets ayant +chacun une ligne #1 partagent le même id de formulaire dans le DOM et le +navigateur soumet vers le premier objet trouvé, pas celui qu'on modifie +réellement.""" +import re + + +def _create_object(client, slug, name, field_name, field_type="texte"): + resp = client.post(f"/game/{slug}/objects/new", data={ + "object_name": name, "field_name[]": [field_name], "field_type[]": [field_type], + "field_relation[]": [""], "field_required[]": ["0"], "field_min[]": [""], "field_max[]": [""], + }, follow_redirects=False) + return int(resp.headers["Location"].rstrip("/").split("/")[-1]) + + +def test_data_edit_form_ids_are_scoped_per_object(client, game): + def_a = _create_object(client, game, "Jauge", "valeur", "nombre_entier") + def_b = _create_object(client, game, "Autre", "nom", "texte") + + # Chaque objet a sa PROPRE table -> sa première ligne a id=1 dans les + # deux cas, exactement le scénario qui provoquait la collision. + client.post(f"/game/{game}/objects/{def_a}/data/new", data={"valeur": "10"}) + client.post(f"/game/{game}/objects/{def_b}/data/new", data={"nom": "Bob"}) + + html = client.get(f"/game/{game}?tab=objects").get_data(as_text=True) + assert f'id="dataEditForm{def_a}-1"' in html + assert f'id="dataEditForm{def_b}-1"' in html + # Les deux formulaires doivent avoir des ids DISTINCTS malgré le même row id. + assert html.count('id="dataEditForm') == len(set(re.findall(r'id="(dataEditForm[^"]+)"', html))) + + # Modifier la donnée du DEUXIÈME objet doit bien mettre à jour def_b, + # sans toucher def_a. + client.post(f"/game/{game}/objects/{def_b}/data/1/edit", data={"nom": "Alice"}) + + import db + row_a = db.list_rows(game, db.get_definition(game, def_a))[0] + row_b = db.list_rows(game, db.get_definition(game, def_b))[0] + assert row_a["valeur"] == 10 + assert row_b["nom"] == "Alice"