fix(gui): clarifier aide et disponibilite moteurs
Passe theme clair, libelles utilisateur, aides conteneurs, recherche de mise a jour et indication honnete des moteurs optionnels non embarques. Tests GUI unitaires: 126 passed.
This commit is contained in:
@@ -46,6 +46,7 @@ def test_usage_tab_survives_theme_change(app):
|
||||
|
||||
def test_main_tab_renamed_to_administration():
|
||||
"""Retour Dom #2 : l'onglet principal Configuration devient Administration."""
|
||||
pytest.importorskip("customtkinter")
|
||||
from gui_v6.app import _TABS
|
||||
|
||||
labels = [label for _, label in _TABS]
|
||||
@@ -56,6 +57,7 @@ def test_main_tab_renamed_to_administration():
|
||||
def test_no_separate_rules_subtab():
|
||||
"""Retour Dom : les règles appartiennent au profil → plus de sous-onglet
|
||||
« Règles » séparé (et donc plus de « Règles 2 » incompréhensible)."""
|
||||
pytest.importorskip("customtkinter")
|
||||
from gui_v6.tabs.tab_config import _SUBTABS
|
||||
|
||||
keys = [key for key, _ in _SUBTABS]
|
||||
@@ -99,6 +101,25 @@ def test_beta_label_in_product_identity(app):
|
||||
assert any("bêta" in t or "beta" in t for t in texts)
|
||||
|
||||
|
||||
def test_default_theme_is_light():
|
||||
"""Retour Dom : le thème clair est le thème par défaut de la GUI."""
|
||||
from gui_v6 import theme as theme_mod
|
||||
|
||||
assert theme_mod.DEFAULT_THEME == "clair"
|
||||
|
||||
|
||||
def test_about_uses_user_facing_database_label(app):
|
||||
"""Retour Dom : éviter le terme technique anglais « Gazetteers » dans À propos."""
|
||||
app._show("about")
|
||||
app.update_idletasks()
|
||||
|
||||
texts = _all_texts(app._tab_frames["about"])
|
||||
joined = " | ".join(texts)
|
||||
assert "bases de données" in joined.lower()
|
||||
assert "Gazetteers" not in joined
|
||||
assert "Rechercher une mise à jour" in joined
|
||||
|
||||
|
||||
def _count_help_buttons(widget) -> int:
|
||||
from gui_v6.ui_kit import HelpButton
|
||||
|
||||
|
||||
@@ -2,7 +2,18 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from gui_v6.tabs.tab_config import CONFIG_INTERACTION_CONTRACT, CONFIG_MOCKUP_SECTIONS
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("customtkinter")
|
||||
|
||||
from gui_v6.tabs.tab_config import (
|
||||
CONFIG_INTERACTION_CONTRACT,
|
||||
CONFIG_MOCKUP_SECTIONS,
|
||||
MINI_TOGGLE_HEIGHT,
|
||||
MINI_TOGGLE_HINT_FONT_SIZE,
|
||||
MINI_TOGGLE_LABEL_FONT_SIZE,
|
||||
_DETECTION_OPTIONS,
|
||||
)
|
||||
|
||||
|
||||
def test_config_mockup_sections_cover_admin_surface():
|
||||
@@ -42,3 +53,12 @@ def test_config_interaction_contract_prebuilds_panels_and_mask_editor():
|
||||
"clear_page",
|
||||
"apply_template_selection",
|
||||
]
|
||||
|
||||
|
||||
def test_detection_rows_are_readable_in_light_theme():
|
||||
"""Retour Dom : les sous-labels de la colonne détection doivent rester lisibles."""
|
||||
assert ("Noms et prénoms", "Annuaire + IA") in _DETECTION_OPTIONS
|
||||
assert ("Noms et prénoms", "Bases de données + IA") not in _DETECTION_OPTIONS
|
||||
assert MINI_TOGGLE_HEIGHT >= 44
|
||||
assert MINI_TOGGLE_LABEL_FONT_SIZE >= 12
|
||||
assert MINI_TOGGLE_HINT_FONT_SIZE >= 11
|
||||
|
||||
@@ -57,7 +57,11 @@ def test_kwargs_defaults_v5_like():
|
||||
def test_kwargs_with_loaded_managers():
|
||||
settings = EngineSettings(enable_eds=True, enable_gliner=True)
|
||||
counter = {"camembert": 0, "eds": 0, "gliner": 0}
|
||||
managers = NerManagers(settings, factories=_counting_factories(counter))
|
||||
managers = NerManagers(
|
||||
settings,
|
||||
factories=_counting_factories(counter),
|
||||
caps_provider=_caps_provider(eds_ok=True, gliner_ok=True),
|
||||
)
|
||||
managers.ensure_loaded()
|
||||
kwargs = build_engine_kwargs(settings, managers)
|
||||
assert kwargs["use_hf"] is True
|
||||
@@ -89,7 +93,11 @@ def test_managers_not_loaded_on_init():
|
||||
def test_managers_load_once_and_state():
|
||||
settings = EngineSettings(enable_eds=True)
|
||||
counter = {"camembert": 0, "eds": 0, "gliner": 0}
|
||||
managers = NerManagers(settings, factories=_counting_factories(counter))
|
||||
managers = NerManagers(
|
||||
settings,
|
||||
factories=_counting_factories(counter),
|
||||
caps_provider=_caps_provider(eds_ok=True, gliner_ok=True),
|
||||
)
|
||||
assert managers.state == ManagerState.NOT_LOADED
|
||||
assert managers.ensure_loaded() == ManagerState.READY
|
||||
assert managers.ensure_loaded() == ManagerState.READY # idempotent
|
||||
@@ -121,7 +129,11 @@ def test_optional_manager_failure_is_tolerated():
|
||||
|
||||
return {"camembert": camembert, "eds": eds, "gliner": gliner}
|
||||
|
||||
managers = NerManagers(settings, factories=factories())
|
||||
managers = NerManagers(
|
||||
settings,
|
||||
factories=factories(),
|
||||
caps_provider=_caps_provider(eds_ok=True, gliner_ok=True),
|
||||
)
|
||||
assert managers.ensure_loaded() == ManagerState.READY # gliner ko ne bloque pas
|
||||
assert managers.use_hf is True
|
||||
|
||||
|
||||
@@ -28,9 +28,11 @@ class FakeResponse:
|
||||
class FakeSession:
|
||||
"""Session HTTP mockable : enregistre les appels, renvoie des réponses scriptées."""
|
||||
|
||||
def __init__(self, response=None, exc=None):
|
||||
def __init__(self, response=None, exc=None, get_response=None, get_exc=None):
|
||||
self._response = response
|
||||
self._exc = exc
|
||||
self._get_response = response if get_response is None else get_response
|
||||
self._get_exc = exc if get_exc is None else get_exc
|
||||
self.calls = []
|
||||
|
||||
def post(self, url, json, timeout):
|
||||
@@ -39,6 +41,12 @@ class FakeSession:
|
||||
raise self._exc
|
||||
return self._response
|
||||
|
||||
def get(self, url, timeout):
|
||||
self.calls.append({"url": url, "timeout": timeout})
|
||||
if self._get_exc is not None:
|
||||
raise self._get_exc
|
||||
return self._get_response
|
||||
|
||||
|
||||
def _client(tmp_path, session):
|
||||
store = LicenseStore(tmp_path / "license.json")
|
||||
@@ -173,6 +181,29 @@ def test_local_status_reads_store(tmp_path):
|
||||
assert status.license_ref == "LIC-7"
|
||||
|
||||
|
||||
def test_latest_version_reads_active_artifact(tmp_path):
|
||||
payload = {
|
||||
"version": "v11.0-beta",
|
||||
"channel": "beta",
|
||||
"filename": "Anonymisation-Setup.exe",
|
||||
}
|
||||
session = FakeSession(get_response=FakeResponse(200, payload))
|
||||
client, _ = _client(tmp_path, session)
|
||||
|
||||
version = client.latest_version()
|
||||
|
||||
assert version == payload
|
||||
assert session.calls[0]["url"] == "https://portail.example/api/v1/version"
|
||||
|
||||
|
||||
def test_latest_version_unavailable_on_404_or_network_error(tmp_path):
|
||||
client_404, _ = _client(tmp_path, FakeSession(get_response=FakeResponse(404, {"detail": "No active version"})))
|
||||
assert client_404.latest_version() is None
|
||||
|
||||
client_down, _ = _client(tmp_path, FakeSession(get_exc=TimeoutError("timeout")))
|
||||
assert client_down.latest_version() is None
|
||||
|
||||
|
||||
def test_status_never_exposes_token():
|
||||
# Le statut ne porte pas de token : la repr ne peut pas le fuiter.
|
||||
status = LicenseStatus.from_payload({"status": "active", "license_ref": "LIC-1"})
|
||||
|
||||
@@ -120,6 +120,7 @@ def test_attach_tooltip_does_not_break_widget(ctk_root):
|
||||
|
||||
def test_subtabs_include_editable_profils():
|
||||
"""Retour Dom : sous-onglet Profils réintroduit (éditeur)."""
|
||||
pytest.importorskip("customtkinter")
|
||||
from gui_v6.tabs.tab_config import _SUBTABS
|
||||
|
||||
keys = [k for k, _ in _SUBTABS]
|
||||
@@ -297,6 +298,21 @@ def test_regles_moved_into_profils(ctk_root, tmp_path, monkeypatch):
|
||||
tab.destroy()
|
||||
|
||||
|
||||
def test_profile_masking_does_not_expose_templates_folder_button(ctk_root, tmp_path, monkeypatch):
|
||||
"""Retour Dom : le bouton Dossier ouvrait un navigateur et n'aide pas l'utilisateur."""
|
||||
from gui_v6.tabs import tab_config
|
||||
|
||||
monkeypatch.setattr(tab_config, "_app_base_dir", lambda: tmp_path)
|
||||
tab = tab_config.ConfigTab(ctk_root)
|
||||
tab._show_sub("pro")
|
||||
tab.update_idletasks()
|
||||
|
||||
texts = _all_texts(tab._panels["pro"])
|
||||
assert "🖊 Ouvrir l'éditeur de masque" in texts
|
||||
assert "📁 Dossier" not in texts
|
||||
tab.destroy()
|
||||
|
||||
|
||||
def test_unavailable_engines_disabled_in_reglages(ctk_root, tmp_path, monkeypatch):
|
||||
"""Honnêteté moteurs : EDS-Pseudo / GLiNER non embarqués → switch désactivé
|
||||
et état forcé à False ; CamemBERT-bio reste actif."""
|
||||
|
||||
@@ -15,7 +15,7 @@ _REQUIRED_TOKENS = {
|
||||
|
||||
def test_four_themes_present():
|
||||
assert set(theme_mod.PALETTES) == {"sombre", "clair", "medical", "neutre"}
|
||||
assert theme_mod.DEFAULT_THEME == "sombre"
|
||||
assert theme_mod.DEFAULT_THEME == "clair"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", ["sombre", "clair", "medical", "neutre"])
|
||||
@@ -31,11 +31,11 @@ def test_palette_has_all_tokens(name):
|
||||
|
||||
|
||||
def test_default_palette_matches_mockup():
|
||||
p = theme_mod.get_palette("sombre")
|
||||
assert p["bg"] == "#1a1a2e"
|
||||
assert p["card"] == "#16213e"
|
||||
assert p["primary"] == "#e94560"
|
||||
assert p["accent"] == "#f5a623"
|
||||
p = theme_mod.get_palette(theme_mod.DEFAULT_THEME)
|
||||
assert p["bg"] == "#cdd2da"
|
||||
assert p["card"] == "#ffffff"
|
||||
assert p["primary"] == "#c93050"
|
||||
assert p["accent"] == "#b45309"
|
||||
|
||||
|
||||
def test_get_palette_fallback():
|
||||
|
||||
Reference in New Issue
Block a user