"""Position/déplacement d'élément + condition de collision — Phase 5 du plan d'extension du moteur. Comme le reste du graphe de logique côté client, le comportement RÉEL (déplacement CSS effectif, chevauchement de rectangles via getBoundingClientRect) n'est pas testable sans navigateur (voir play_js_bundle() — on vérifie que la logique existe dans le JS livré et que les nœuds persistent leurs champs, pas qu'ils s'exécutent).""" import json import re from conftest import play_js_bundle, screen_edit_js_bundle import screens def _create_element(client, slug, widget="conteneur"): resp = client.post(f"/game/{slug}/screens/new", data={"name": "Accueil"}, follow_redirects=False) screen_id = int(re.search(r"/screens/(\d+)/edit", resp.headers["Location"]).group(1)) resp = client.post(f"/game/{slug}/screens/{screen_id}/elements/add", data={"widget": widget}, follow_redirects=False) element_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) return screen_id, element_id 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_position_action_node_persists_absolute_property(client, game): screen_id, element_id = _create_element(client, game) node_id = _add_flow_node( client, game, screen_id, node_type="action", action_type="modifier_element", target_element_id=element_id, element_property="pos_x", element_value="42", ) node = screens.get_flow_node(game, node_id) assert node["element_property"] == "pos_x" assert node["element_value"] == "42" def test_position_action_node_persists_relative_property(client, game): screen_id, element_id = _create_element(client, game) node_id = _add_flow_node( client, game, screen_id, node_type="action", action_type="modifier_element", target_element_id=element_id, element_property="pos_y_relatif", element_value="-5", ) node = screens.get_flow_node(game, node_id) assert node["element_property"] == "pos_y_relatif" assert node["element_value"] == "-5" def test_collision_condition_node_persists_both_elements(client, game): screen_id, element_a = _create_element(client, game) resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "conteneur"}, follow_redirects=False) element_b = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) node_id = _add_flow_node( client, game, screen_id, node_type="condition", cond_source="collision", cond_element_a=element_a, cond_element_b=element_b, ) node = screens.get_flow_node(game, node_id) assert node["cond_source"] == "collision" assert node["cond_element_a"] == element_a assert node["cond_element_b"] == element_b assert node["cond_field"] is None assert node["cond_operator"] is None def test_deleting_element_cleans_up_collision_condition_nodes(client, game): """Un nœud de collision qui référence un élément supprimé n'a plus de sens (voir delete_element.py) — même nettoyage que pour un déclencheur/ une action ciblant un élément supprimé.""" screen_id, element_a = _create_element(client, game) resp = client.post(f"/game/{game}/screens/{screen_id}/elements/add", data={"widget": "conteneur"}, follow_redirects=False) element_b = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) node_id = _add_flow_node( client, game, screen_id, node_type="condition", cond_source="collision", cond_element_a=element_a, cond_element_b=element_b, ) client.post(f"/game/{game}/elements/{element_a}/delete", follow_redirects=False) assert screens.get_flow_node(game, node_id) is None def test_play_page_exposes_position_and_collision_runtime(client, game): js = play_js_bundle() assert "pos_x" in js assert "pos_y" in js assert "elementsOverlap" in js assert "getBoundingClientRect" in js assert "'collision'" in js def test_screen_edit_exposes_collision_condition_editor(client, game): html = client.get(f"/game/{game}/screens/{_create_element(client, game)[0]}/edit").get_data(as_text=True) assert "nf-cond-collision-fields" in html assert "nf-cond-element-a" in html assert "nf-cond-element-b" in html js = screen_edit_js_bundle() assert "isCollision" in js assert "cond_element_a" in js