"""CLICKED_ROW_ID (-1, voir screens/flow/constants.py) : une action "Modifier une donnée" (ou un nœud Condition) peut viser "la ligne de Répéteur sur laquelle on vient de cliquer" plutôt qu'une ligne fixe - indispensable quand le déclencheur "Au clic" est posé sur un Répéteur, puisque chaque ligne exécute le même graphe et la ligne cliquée n'est jamais connue à l'avance dans l'éditeur.""" import json import re from typing import Any from flask.testing import FlaskClient import db from tests.conftest import not_none def _create_screen(client: FlaskClient, slug: str, name: str = "Accueil") -> Any: resp = client.post(f"/game/{slug}/screens/new", data={"name": name}, follow_redirects=False) return int(not_none(re.search(r"/screens/(\d+)/edit", resp.headers["Location"])).group(1)) def _create_email_object(client: FlaskClient, slug: str) -> Any: def_id = db.create_definition(slug, "Email", [{"name": "is_opened", "type": "booleen"}]) definition = not_none(db.get_definition(slug, def_id)) db.insert_row(slug, definition, {}) db.insert_row(slug, definition, {}) return def_id def test_modifier_donnee_targeting_clicked_row_updates_only_that_row(client: FlaskClient, game: str) -> None: def_id = _create_email_object(client, game) screen_id = _create_screen(client, game) resp = client.post( f"/game/{game}/screens/{screen_id}/flow/nodes/add", data=json.dumps( { "node_type": "action", "action_type": "modifier_donnee", "target_definition_id": def_id, "target_row_id": -1, "target_field": "is_opened", "data_operation": "definir_bool_vrai", "data_value": "", } ), content_type="application/json", ) node = resp.get_json() assert node["target_row_id"] == -1 resp = client.post( f"/game/{game}/flow/nodes/{node['id']}/run-data", data=json.dumps({"clicked_row_id": 2}), content_type="application/json", ) assert resp.get_json() == {"ok": True} definition = not_none(db.get_definition(game, def_id)) row1 = not_none(db.get_row(game, definition, 1)) row2 = not_none(db.get_row(game, definition, 2)) assert not row1["is_opened"] assert row2["is_opened"] def test_modifier_donnee_targeting_clicked_row_without_a_click_is_a_noop(client: FlaskClient, game: str) -> None: """Pas de ligne cliquée transmise (ex. déclenché autrement qu'un vrai clic sur une ligne de Répéteur) -> ne doit rien modifier, pas planter.""" def_id = _create_email_object(client, game) screen_id = _create_screen(client, game) resp = client.post( f"/game/{game}/screens/{screen_id}/flow/nodes/add", data=json.dumps( { "node_type": "action", "action_type": "modifier_donnee", "target_definition_id": def_id, "target_row_id": -1, "target_field": "is_opened", "data_operation": "definir_bool_vrai", "data_value": "", } ), content_type="application/json", ) node = resp.get_json() resp = client.post( f"/game/{game}/flow/nodes/{node['id']}/run-data", data=json.dumps({}), content_type="application/json" ) assert resp.get_json() == {"ok": False} definition = not_none(db.get_definition(game, def_id)) assert not not_none(db.get_row(game, definition, 1))["is_opened"] assert not not_none(db.get_row(game, definition, 2))["is_opened"] def test_ordinary_fixed_row_target_is_unaffected(client: FlaskClient, game: str) -> None: """Non-régression : une action visant une ligne FIXE (pas -1) continue d'ignorer tout clicked_row_id transmis.""" def_id = _create_email_object(client, game) screen_id = _create_screen(client, game) resp = client.post( f"/game/{game}/screens/{screen_id}/flow/nodes/add", data=json.dumps( { "node_type": "action", "action_type": "modifier_donnee", "target_definition_id": def_id, "target_row_id": 1, "target_field": "is_opened", "data_operation": "definir_bool_vrai", "data_value": "", } ), content_type="application/json", ) node = resp.get_json() client.post( f"/game/{game}/flow/nodes/{node['id']}/run-data", data=json.dumps({"clicked_row_id": 2}), content_type="application/json", ) definition = not_none(db.get_definition(game, def_id)) assert not_none(db.get_row(game, definition, 1))["is_opened"] assert not not_none(db.get_row(game, definition, 2))["is_opened"]