Suite des retours Dom sur la GUI V6 (par-dessus 6a0a581).
Addendum Profils / Réglages :
- Nouveau sous-onglet Administration « 👤 Profils » : le profil actif devient
un objet lisible (nom, description, masque requis, template, listes locales
avec compteurs) — données réelles lues depuis profile_defaults.
- Fenêtre « Tableau des termes » (terms_table_window.py) : table scrollable
avec recherche/filtre, colonnes Type/Terme/Source ; reste lisible à 50+
termes. Ajouter/éditer/supprimer désactivés « (à venir) » (écriture par
profil non câblée).
- Réglages : « Profil métier » → « Profil d'anonymisation », « Sortie… » →
« Dossier de sortie… » (+ infobulle), hints moteurs (standard/optionnel/
plus lent), bouton « Voir le profil », « Ouvrir le tableau des termes ».
- Aide « ? » + infobulles (ui_kit.attach_tooltip) près des éléments ambigus.
- profile_view.py : logique pure (résumé profil + lignes du tableau),
testable sans display.
Addendum bêta : en-tête « aivanonym » + badge « bêta », titre fenêtre
« … — bêta ». Détail version conservé dans À propos.
tests/unit/test_gui_v6_profiles.py + ajouts shell. 237 tests unit OK
(228 → 237, 0 régression), self-test GUI V6 OK, navigation des 5 sous-onglets
+ thème OK. V5/moteur/app_aivanov/profile_defaults non touchés, 0 dépendance.
Aucun build/push sans GO Dom — validation visuelle Dom attendue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
129 lines
3.9 KiB
Python
129 lines
3.9 KiB
Python
"""Shell GUI V6 : robustesse du changement de thème, libellés d'onglets, aide.
|
|
|
|
Smokes headless (Xvfb) — skip propre si pas de display.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def app():
|
|
pytest.importorskip("customtkinter")
|
|
try:
|
|
from gui_v6.app import AnonymisationApp
|
|
|
|
a = AnonymisationApp()
|
|
except Exception as exc: # pas de display
|
|
pytest.skip(f"display Tk indisponible: {exc}")
|
|
a.withdraw()
|
|
try:
|
|
yield a
|
|
finally:
|
|
try:
|
|
a.destroy()
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def test_usage_tab_survives_theme_change(app):
|
|
"""Retour Dom #1 : l'onglet Utilisation ne doit pas se vider au changement
|
|
de thème (le cache d'onglets ne doit pas conserver de widgets détruits)."""
|
|
app._show("use")
|
|
app.update_idletasks()
|
|
assert app._active == "use"
|
|
|
|
other = "clair" if app._theme_name != "clair" else "sombre"
|
|
app.set_theme(other)
|
|
app.update_idletasks()
|
|
|
|
assert app._active == "use"
|
|
assert "use" in app._tab_frames
|
|
frame = app._tab_frames["use"]
|
|
assert frame.winfo_exists() # onglet recréé et vivant, pas un widget mort
|
|
|
|
|
|
def test_main_tab_renamed_to_administration():
|
|
"""Retour Dom #2 : l'onglet principal Configuration devient Administration."""
|
|
from gui_v6.app import _TABS
|
|
|
|
labels = [label for _, label in _TABS]
|
|
assert any("Administration" in lbl for lbl in labels)
|
|
assert not any("Configuration" in lbl for lbl in labels)
|
|
|
|
|
|
def test_rules_subtab_has_no_unexplained_2():
|
|
"""Retour Dom #3 : « Règles 2 » incompréhensible → simple « Règles »."""
|
|
from gui_v6.tabs.tab_config import _SUBTABS
|
|
|
|
labels = [label for _, label in _SUBTABS]
|
|
assert any(lbl.strip() == "🛡️ Règles" for lbl in labels)
|
|
assert not any("Règles 2" in lbl or "Règles 2" in lbl for lbl in labels)
|
|
|
|
|
|
def test_help_button_opens_help_window(app):
|
|
"""Retours Dom #4/#5 : affordance d'aide « ? » réutilisable qui ouvre une
|
|
fenêtre d'aide en français."""
|
|
from gui_v6 import theme as theme_mod
|
|
from gui_v6 import ui_kit
|
|
|
|
p = theme_mod.get_palette(theme_mod.DEFAULT_THEME)
|
|
btn = ui_kit.help_button(app, p, "Cette section reste 100 % locale.", title="Aide test")
|
|
assert btn.cget("text") == "?"
|
|
win = btn.open_help()
|
|
app.update_idletasks()
|
|
assert win.winfo_exists()
|
|
win.destroy()
|
|
|
|
|
|
def _all_texts(widget) -> list:
|
|
out = []
|
|
try:
|
|
out.append(str(widget.cget("text")))
|
|
except Exception:
|
|
pass
|
|
for child in widget.winfo_children():
|
|
out += _all_texts(child)
|
|
return out
|
|
|
|
|
|
def test_beta_label_in_product_identity(app):
|
|
"""Addendum Dom : indiquer « bêta » à côté du nom produit (en-tête + titre)."""
|
|
app.update_idletasks()
|
|
assert "bêta" in app.title().lower() or "beta" in app.title().lower()
|
|
texts = [t.lower() for t in _all_texts(app)]
|
|
assert any("aivanonym" in t for t in texts)
|
|
assert any("bêta" in t or "beta" in t for t in texts)
|
|
|
|
|
|
def _count_help_buttons(widget) -> int:
|
|
from gui_v6.ui_kit import HelpButton
|
|
|
|
total = 1 if isinstance(widget, HelpButton) else 0
|
|
for child in widget.winfo_children():
|
|
total += _count_help_buttons(child)
|
|
return total
|
|
|
|
|
|
def test_each_tab_exposes_help(app):
|
|
"""Retour Dom #5 : une affordance d'aide « ? » est présente sur chaque onglet."""
|
|
for key in ("use", "cfg", "about"):
|
|
app._show(key)
|
|
app.update_idletasks()
|
|
assert _count_help_buttons(app._tab_frames[key]) >= 1, key
|
|
|
|
|
|
def test_navigation_and_theme_change_keep_tabs_alive(app):
|
|
"""Navigation + changement de thème : aucun onglet vide/mort."""
|
|
for key in ("use", "cfg", "about"):
|
|
app._show(key)
|
|
app.update_idletasks()
|
|
assert app._tab_frames[key].winfo_exists()
|
|
app.set_theme("medical")
|
|
app.update_idletasks()
|
|
for key in ("use", "cfg", "about"):
|
|
app._show(key)
|
|
app.update_idletasks()
|
|
assert app._tab_frames[key].winfo_exists()
|