"""Fusion ACC-1 — barre d'apps commune (carte kanbante#28). Le snippet figé de dracodev-commons est vendangé (CSS/JS statiques + partiel _draco_bar.html) et inclus par le cadre partagé _header.html : toutes les pages applicatives l'affichent avec Kanbante comme app courante ; l'écran de connexion, autonome, ne l'affiche pas. """ def test_barre_presente_sur_le_dashboard(client): r = client.get("/") assert r.status_code == 200 assert 'class="draco-bar"' in r.text assert 'data-current="kanbante"' in r.text assert "draco-barre.css" in r.text assert "draco-barre.js" in r.text assert 'window.DRACO_BAR_CONFIG' in r.text # Les quatre applications de la barre, aux URL publiques par # défaut (noms officiels/prod, issus de la configuration). for url in ("https://og.dracodev.net/", "https://flowdeck.dracodev.net/", "https://tiktak.dracodev.net/", "https://kanbante.dracodev.net/"): assert url in r.text # L'adresse du service d'agents est injectée au panneau. assert 'window.DRACO_PANNEAU_CONFIG = { api: "https://agent.dracodev.net" }' in r.text def test_barre_et_panneau_urls_par_configuration(monkeypatch, fake_gitea): # Dev/prod (0.32.0) : la dev déclare ses noms en -dev par # l'environnement ; aucun nom public n'est codé en dur. from fastapi.testclient import TestClient import app.main as main monkeypatch.setenv("DRACO_SSO_URL", "https://og-dev.dracodev.net") monkeypatch.setenv("DRACO_FLOWDECK_URL", "https://flowdeck-dev.dracodev.net") monkeypatch.setenv("DRACO_TIKTAK_URL", "https://tiktak-dev.dracodev.net") monkeypatch.setenv("KANBANTE_PUBLIC_URL", "https://kanbante-dev.dracodev.net") monkeypatch.setenv("AGENT_URL", "https://agent-dev.dracodev.net") with TestClient(main.app) as client: r = client.get("/") assert r.status_code == 200 for url in ("https://og-dev.dracodev.net/", "https://flowdeck-dev.dracodev.net/", "https://tiktak-dev.dracodev.net/", "https://kanbante-dev.dracodev.net/"): assert url in r.text assert 'api: "https://agent-dev.dracodev.net"' in r.text # Le JS statique du panneau ne contient aucun nom en dur : # il lit l'adresse injectée par l'hôte. js = client.get("/static/js/draco-panneau.js").text assert "DRACO_PANNEAU_CONFIG" in js assert "dracodev.net" not in js def test_config_agent_evenements_derive_de_agent_url(monkeypatch): from app.config import _env_settings monkeypatch.setenv("AGENT_URL", "https://agent-dev.dracodev.net") monkeypatch.delenv("AGENT_EVENEMENTS_URL", raising=False) s = _env_settings() assert s.agent_url == "https://agent-dev.dracodev.net" assert s.agent_evenements_url == ( "https://agent-dev.dracodev.net/api/v1/evenements" ) # L'URL d'événements explicite garde la priorité (override compose). monkeypatch.setenv( "AGENT_EVENEMENTS_URL", "https://exemple.invalid/journal" ) assert _env_settings().agent_evenements_url == ( "https://exemple.invalid/journal" ) # ── Dérivation d'environnement des URL sœurs (0.32.1) ── # Sur la dev, seul AGENT_EVENEMENTS_URL est posé : les URL sœurs # doivent suivre son suffixe (-dev) sans quatre variables de plus. _ENV_URLS_SOEURS = ( "DRACO_SSO_URL", # ObsiGate (émettrice SSO) "DRACO_FLOWDECK_URL", "DRACO_TIKTAK_URL", "KANBANTE_PUBLIC_URL", # Kanbante elle-même "AGENT_URL", ) _DEFAUTS_OFFICIELS = ( "https://og.dracodev.net", "https://flowdeck.dracodev.net", "https://tiktak.dracodev.net", "https://kanbante.dracodev.net", ) _URLS_DEV = ( "https://og-dev.dracodev.net", "https://flowdeck-dev.dracodev.net", "https://tiktak-dev.dracodev.net", "https://kanbante-dev.dracodev.net", ) def _nettoyer_env_soeurs(monkeypatch): for nom in _ENV_URLS_SOEURS: monkeypatch.delenv(nom, raising=False) def _urls_soeurs(settings): return ( settings.sso_url, settings.flowdeck_url, settings.tiktak_url, settings.public_url, ) def test_config_urls_soeurs_derivees_du_seul_agent_evenements(monkeypatch): from app.config import _env_settings _nettoyer_env_soeurs(monkeypatch) monkeypatch.setenv( "AGENT_EVENEMENTS_URL", "https://agent-dev.dracodev.net/api/v1/evenements", ) assert _urls_soeurs(_env_settings()) == _URLS_DEV def test_barre_urls_soeurs_derivees_du_seul_agent_evenements( monkeypatch, fake_gitea ): from fastapi.testclient import TestClient import app.main as main _nettoyer_env_soeurs(monkeypatch) monkeypatch.setenv( "AGENT_EVENEMENTS_URL", "https://agent-dev.dracodev.net/api/v1/evenements", ) with TestClient(main.app) as client: r = client.get("/") assert r.status_code == 200 for url in _URLS_DEV: assert f"{url}/" in r.text def test_config_url_soeur_explicite_gagne_sur_la_derivation(monkeypatch): from app.config import _env_settings _nettoyer_env_soeurs(monkeypatch) monkeypatch.setenv( "AGENT_EVENEMENTS_URL", "https://agent-dev.dracodev.net/api/v1/evenements", ) monkeypatch.setenv( "DRACO_FLOWDECK_URL", "https://flowdeck.example.test" ) s = _env_settings() assert s.flowdeck_url == "https://flowdeck.example.test" # Les autres sœurs restent dérivées de l'environnement. assert s.sso_url == "https://og-dev.dracodev.net" assert s.tiktak_url == "https://tiktak-dev.dracodev.net" assert s.public_url == "https://kanbante-dev.dracodev.net" def test_config_hote_agent_hors_motif_reste_aux_defauts(monkeypatch): from app.config import _env_settings _nettoyer_env_soeurs(monkeypatch) for url_agent in ( "https://agent.example.com/api/v1/evenements", "https://agent-dev.autre-domaine.net/api/v1/evenements", "http://192.168.30.101:8790/api/v1/evenements", "http://127.0.0.1:8790/api/v1/evenements", ): monkeypatch.setenv("AGENT_EVENEMENTS_URL", url_agent) assert _urls_soeurs(_env_settings()) == _DEFAUTS_OFFICIELS def test_config_aucun_env_reste_aux_defauts_officiels(monkeypatch): from app.config import _env_settings _nettoyer_env_soeurs(monkeypatch) monkeypatch.delenv("AGENT_EVENEMENTS_URL", raising=False) assert _urls_soeurs(_env_settings()) == _DEFAUTS_OFFICIELS def test_statiques_de_la_barre_servis(client): assert client.get("/static/css/draco-barre.css").status_code == 200 assert client.get("/static/js/draco-barre.js").status_code == 200 def test_menu_des_applications_par_la_marque(client): # v0.1.3 : la marque ✦ porte data-act="apps" et le JS commun # construit le menu (.draco-apps-menu) ; le logo passe à 24 px. accueil = client.get("/") assert 'data-act="apps"' in accueil.text # 0.23.3 : assets versionnés, sinon le cache garde l'ancien JS. assert "draco-barre.css?v=" in accueil.text assert "draco-barre.js?v=" in accueil.text js = client.get("/static/js/draco-barre.js").text assert "draco-apps-menu" in js css = client.get("/static/css/draco-barre.css").text assert "font-size: 24px" in css def test_barre_pleine_largeur_et_palier_mobile(client): # 0.23.1 : la barre est fixe pleine largeur (le padding du cadre # ne la repousse plus) et le palier mobile commons v0.1.2 ne # garde que l'onglet de l'app courante. style = client.get("/static/css/style.css").text assert "body.has-draco-bar .draco-bar" in style assert "position: fixed" in style barre = client.get("/static/css/draco-barre.css").text assert '.draco-bar[data-current="kanbante"] .draco-apptab[data-app="kanbante"]' in barre def test_pas_de_barre_sur_le_login(monkeypatch, fake_gitea): from fastapi.testclient import TestClient import app.main as main monkeypatch.setenv("KANBANTE_AUTH_USER", "bruno") monkeypatch.setenv("KANBANTE_AUTH_PASSWORD", "motdepasse") with TestClient(main.app) as client: r = client.get("/login") assert r.status_code == 200 assert "draco-bar" not in r.text