"""Tests de la timeline d'animation : clips Animate.css ou personnalisés (images-clés), posés sur la piste d'un élément, avec un instant de départ et une durée sur l'axe du temps (secondes depuis l'affichage de l'écran).""" import json 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_element(client, slug, screen_id, widget): resp = client.post(f"/game/{slug}/screens/{screen_id}/elements/add", data={"widget": widget}, follow_redirects=False) return int(re.search(r"selected=(\d+)", resp.headers["Location"]).group(1)) def test_animate_css_clip_persists(client, game): screen_id = _create_screen(client, game) el_id = _add_element(client, game, screen_id, "titre") resp = client.post( f"/game/{game}/screens/{screen_id}/animations/clips/add", data=json.dumps({ "element_id": el_id, "kind": "animate_css", "animate_name": "bounce", "start_time": "1.5", "duration": "2", "delay": "0", "easing": "ease", "iteration_count": "1", }), content_type="application/json", ) assert resp.status_code == 200 clip = resp.get_json() assert clip["kind"] == "animate_css" assert clip["animate_name"] == "bounce" assert clip["start_time"] == 1.5 assert clip["duration"] == 2.0 assert clip["element_id"] == el_id def test_custom_keyframes_clip_persists(client, game): screen_id = _create_screen(client, game) el_id = _add_element(client, game, screen_id, "conteneur") keyframes = [{"percent": 0, "props": {"opacity": "0"}}, {"percent": 100, "props": {"opacity": "1"}}] resp = client.post( f"/game/{game}/screens/{screen_id}/animations/clips/add", data=json.dumps({ "element_id": el_id, "kind": "custom", "custom_keyframes": keyframes, "start_time": "0", "duration": "3", }), content_type="application/json", ) assert resp.status_code == 200 clip = resp.get_json() assert clip["kind"] == "custom" assert json.loads(clip["custom_keyframes"]) == keyframes def test_clip_update_changes_timing(client, game): screen_id = _create_screen(client, game) el_id = _add_element(client, game, screen_id, "bouton") clip = client.post( f"/game/{game}/screens/{screen_id}/animations/clips/add", data=json.dumps({"element_id": el_id, "kind": "animate_css", "animate_name": "fadeIn"}), content_type="application/json", ).get_json() resp = client.post( f"/game/{game}/animations/clips/{clip['id']}/update", data=json.dumps({"start_time": "4", "duration": "0.5"}), content_type="application/json", ) assert resp.status_code == 200 updated = resp.get_json() assert updated["start_time"] == 4.0 assert updated["duration"] == 0.5 def test_clip_delete_removes_it(client, game): screen_id = _create_screen(client, game) el_id = _add_element(client, game, screen_id, "bouton") clip = client.post( f"/game/{game}/screens/{screen_id}/animations/clips/add", data=json.dumps({"element_id": el_id, "kind": "animate_css", "animate_name": "tada"}), content_type="application/json", ).get_json() resp = client.post(f"/game/{game}/animations/clips/{clip['id']}/delete") assert resp.status_code == 200 html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert f'"id": {clip["id"]}' not in html def test_screen_edit_exposes_timeline_panel_and_animate_css_cdn(client, game): screen_id = _create_screen(client, game) html = client.get(f"/game/{game}/screens/{screen_id}/edit").data.decode() assert "animPanel" in html assert "Timeline d'animation" in html assert "animate.css" in html def test_play_page_exposes_animation_runtime_and_cdn(client, game): resp = client.get(f"/game/{game}/play") html = resp.data.decode() assert "animate.css" in html assert "runAnimationTimeline" in html assert "injectCustomKeyframes" in html def test_play_page_payload_includes_clip(client, game): screen_id = _create_screen(client, game) el_id = _add_element(client, game, screen_id, "titre") client.post( f"/game/{game}/screens/{screen_id}/animations/clips/add", data=json.dumps({"element_id": el_id, "kind": "animate_css", "animate_name": "pulse", "start_time": "2"}), content_type="application/json", ) html = client.get(f"/game/{game}/play").data.decode() assert '"animate_name": "pulse"' in html assert '"start_time": 2.0' in html