feat(lea): bulles 'Léa exécute' stylisées + templates par event
J3.4 — distinction visuelle entre : - Bulles chat normales (fond bleu clair, prefixe 💬, taille standard) - Bulles d'action Léa (fond gris clair, encadré subtil, icône sémantique en couleur, libellé court, métadonnées discrètes en pied) - Bulle paused supervisée (jaune, boutons interactifs — déjà en J3.5) Templates de libellés volontairement neutres : le contexte métier (UHCD, peakflow, J12.1, IPP 25003284…) provient des payloads émis par le pipeline côté serveur, pas de hardcoding dans le client. Mappage events → bulles : lea:action_started ▶ bleu "Démarrage : {workflow}" lea:action_progress ⋯ bleu "{step}" ou "Étape {current}/{total}" lea:done ✓ vert / ✗ rouge selon success lea:need_confirm ? bleu "{action.description}" lea:step_result ✓ / ✗ / · selon status lea:resumed → vert "Reprise" lea:resume_acked (silencieux côté UI) lea:abort_acked (silencieux côté UI) événement inconnu · gris fallback neutre 18 nouveaux tests pytest (templates + extract_meta). Total branche : 47/47 verts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
129
tests/integration/test_chat_window_templates.py
Normal file
129
tests/integration/test_chat_window_templates.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Tests des templates de bulles 'Léa exécute' (J3.4).
|
||||
|
||||
On teste les fonctions _tpl_* et _extract_meta de chat_window.py — elles sont
|
||||
purement fonctionnelles (input payload → output tuple), aucune UI tkinter
|
||||
nécessaire.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from agent_v0.agent_v1.ui import chat_window as cw
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Templates _tpl_*
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def test_tpl_action_started_uses_workflow_name():
|
||||
icon, color, title = cw._tpl_action_started({"workflow": "Demo Urgences UHCD"})
|
||||
assert icon == "▶"
|
||||
assert color == cw.ACTION_ICON_RUN
|
||||
assert "Demo Urgences UHCD" in title
|
||||
|
||||
|
||||
def test_tpl_action_started_fallback_when_no_workflow():
|
||||
_, _, title = cw._tpl_action_started({})
|
||||
assert "?" in title
|
||||
|
||||
|
||||
def test_tpl_action_progress_uses_step_when_provided():
|
||||
_, _, title = cw._tpl_action_progress({"step": "J'ouvre la fiche patient"})
|
||||
assert title == "J'ouvre la fiche patient"
|
||||
|
||||
|
||||
def test_tpl_action_progress_fallback_to_counter():
|
||||
_, _, title = cw._tpl_action_progress({"current": 4, "total": 7})
|
||||
assert "4/7" in title
|
||||
|
||||
|
||||
def test_tpl_done_success():
|
||||
icon, color, title = cw._tpl_done({"success": True, "message": "Codage terminé"})
|
||||
assert icon == "✓"
|
||||
assert color == cw.ACTION_ICON_OK
|
||||
assert title == "Codage terminé"
|
||||
|
||||
|
||||
def test_tpl_done_failure():
|
||||
icon, color, title = cw._tpl_done({"success": False, "message": "Action échouée"})
|
||||
assert icon == "✗"
|
||||
assert color == cw.ACTION_ICON_ERR
|
||||
assert title == "Action échouée"
|
||||
|
||||
|
||||
def test_tpl_done_default_success_when_unspecified():
|
||||
icon, _, _ = cw._tpl_done({})
|
||||
assert icon == "✓" # par défaut on suppose succès si non précisé
|
||||
|
||||
|
||||
def test_tpl_need_confirm_extracts_action_description():
|
||||
icon, _, title = cw._tpl_need_confirm({
|
||||
"action": {"description": "Cliquer sur l'IPP 25003284"}
|
||||
})
|
||||
assert icon == "?"
|
||||
assert "25003284" in title
|
||||
|
||||
|
||||
def test_tpl_need_confirm_fallback():
|
||||
_, _, title = cw._tpl_need_confirm({})
|
||||
assert "Validation" in title
|
||||
|
||||
|
||||
def test_tpl_step_result_ok():
|
||||
icon, color, _ = cw._tpl_step_result({"status": "ok", "message": "ok"})
|
||||
assert icon == "✓"
|
||||
assert color == cw.ACTION_ICON_OK
|
||||
|
||||
|
||||
def test_tpl_step_result_failed():
|
||||
icon, color, _ = cw._tpl_step_result({"status": "failed", "message": "boom"})
|
||||
assert icon == "✗"
|
||||
assert color == cw.ACTION_ICON_ERR
|
||||
|
||||
|
||||
def test_tpl_step_result_neutral_status():
|
||||
icon, color, _ = cw._tpl_step_result({"status": "skipped", "message": "passé"})
|
||||
assert icon == "·"
|
||||
assert color == cw.ACTION_ICON_INFO
|
||||
|
||||
|
||||
def test_tpl_resumed():
|
||||
icon, color, title = cw._tpl_resumed({})
|
||||
assert icon == "→"
|
||||
assert color == cw.ACTION_ICON_OK
|
||||
assert "Reprise" in title
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Dispatch — chaque event lea:* (hors paused/acks) doit avoir un template
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def test_all_relevant_events_have_a_template():
|
||||
expected = {
|
||||
"lea:action_started", "lea:action_progress", "lea:done",
|
||||
"lea:need_confirm", "lea:step_result", "lea:resumed",
|
||||
}
|
||||
assert set(cw._ACTION_TEMPLATES.keys()) == expected
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# _extract_meta
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
def test_extract_meta_with_workflow():
|
||||
meta = cw._extract_meta({"workflow": "Demo Urgences"})
|
||||
assert meta == "Demo Urgences"
|
||||
|
||||
|
||||
def test_extract_meta_with_progress():
|
||||
meta = cw._extract_meta({"workflow": "Demo Urgences", "current": 4, "total": 7})
|
||||
assert "Demo Urgences" in meta
|
||||
assert "étape 4/7" in meta
|
||||
|
||||
|
||||
def test_extract_meta_with_replay_id_truncated():
|
||||
meta = cw._extract_meta({"replay_id": "rep_abcdef0123456789"})
|
||||
assert "#789" in meta or "456789" in meta # 6 derniers caractères
|
||||
|
||||
|
||||
def test_extract_meta_empty_payload():
|
||||
assert cw._extract_meta({}) == ""
|
||||
Reference in New Issue
Block a user