"""Tests du widget Onglets — ajouter/renommer/supprimer un onglet, contenu par onglet (un vrai conteneur enfant, voir screens/elements/add_tab.py). À ne pas confondre avec tests/test_onglets.py, qui teste l'action de flux existante "activer_onglet" (2.3, montrer un élément et masquer ses frères) — un mécanisme manuel plus bas niveau, toujours disponible séparément, que ce widget ne remplace pas.""" 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 _create_onglets(client, slug, screen_id): resp = client.post(f"/game/{slug}/screens/{screen_id}/elements/add", data={"widget": "onglets"}, follow_redirects=False) return int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) def _tab_rename_ids(html): """Ids des formulaires de renommage DANS le bloc "Onglets" du panneau de propriétés — pas le premier /elements//rename de la page, qui est le champ "Nommer" générique de l'élément actuellement sélectionné (pas forcément un onglet, ex. l'élément Onglets lui-même).""" block = html.split("Onglets (", 1)[-1] return [int(x) for x in re.findall(r"/elements/(\d+)/rename", block)] def test_new_tabs_widget_has_no_tabs_yet(client, game): screen_id = _create_screen(client, game) _create_onglets(client, game, screen_id) html = client.get(f"/game/{game}/play").data.decode() assert "forgeTabBtn" not in html assert "ajoute au moins un onglet" in html def test_add_tab_creates_a_named_child_container(client, game): screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) resp = client.post(f"/game/{game}/elements/{onglets_id}/tabs/add", follow_redirects=False) assert resp.status_code == 302 assert f"selected={onglets_id}" in resp.headers["Location"] # reste sur le widget Onglets, pas le nouvel onglet html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert ">Onglet 1<" in html # nom par défaut, affiché tel quel comme libellé de l'onglet def test_second_tab_is_named_onglet_2_and_starts_hidden(client, game): screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert ">Onglet 1<" in html assert ">Onglet 2<" in html # Seul le premier onglet est visible par défaut (le second est en display:none). assert 'style="display:none;"' in html def test_renaming_a_tab_changes_the_visible_label(client, game): screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") html = client.get(f"/game/{game}/screens/{screen_id}/edit?selected={onglets_id}").data.decode() tab_id = _tab_rename_ids(html)[0] client.post(f"/game/{game}/elements/{tab_id}/rename", data={"name": "Statistiques"}) html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert ">Statistiques<" in html assert ">Onglet 1<" not in html def test_deleting_a_tab_removes_it_and_reselects_the_tabs_widget(client, game): screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") client.post(f"/game/{game}/elements/{onglets_id}/tabs/add", follow_redirects=False) html = client.get(f"/game/{game}/screens/{screen_id}/edit?selected={onglets_id}").data.decode() tab_ids = _tab_rename_ids(html) assert len(tab_ids) == 2 resp = client.post(f"/game/{game}/elements/{tab_ids[1]}/delete", follow_redirects=False) assert resp.status_code == 302 assert f"selected={onglets_id}" in resp.headers["Location"] html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert html.count("forgeShowTab(this)") == 1 def test_tab_content_holds_a_real_container_children_can_be_added_to(client, game): """Régression : chaque onglet doit se comporter comme un vrai conteneur — on doit pouvoir y poser un Répéteur/Conteneur/etc. via "Ajouter DANS ce conteneur", exactement comme pour n'importe quel autre conteneur.""" screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") html = client.get(f"/game/{game}/screens/{screen_id}/edit?selected={onglets_id}").data.decode() tab_id = _tab_rename_ids(html)[0] resp = client.post(f"/game/{game}/elements/{tab_id}/children/add", data={"widget": "titre"}, follow_redirects=False) assert resp.status_code == 302 child_id = int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) client.post(f"/game/{game}/elements/{child_id}/save", data={"ctrl_content": "Bienvenue dans cet onglet"}) html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert "Bienvenue dans cet onglet" in html def test_deleting_the_tabs_widget_cascades_to_its_tabs(client, game): screen_id = _create_screen(client, game) onglets_id = _create_onglets(client, game, screen_id) client.post(f"/game/{game}/elements/{onglets_id}/tabs/add") client.post(f"/game/{game}/elements/{onglets_id}/delete") html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert "forgeTabBtn" not in html assert ">Onglet 1<" not in html