hermes-hub/tests/test_ui_mockup_redesign.py

147 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Acceptance tests for the approved three-theme mockup redesign."""
from __future__ import annotations
import ast
from pathlib import Path
import re
from types import SimpleNamespace
import pytest
pytest.importorskip("customtkinter")
import customtkinter as ctk
from antigravity_provider.router.ui.components import AccountCardWidget
from antigravity_provider.router.ui.theme import Theme
from antigravity_provider.router import hermes_hub_app as app_module
@pytest.fixture(scope="module")
def ui_root(tk_root):
root = ctk.CTkToplevel(tk_root)
root.withdraw()
yield root
root.destroy()
@pytest.mark.unit
def test_every_restored_account_handler_has_a_ui_trigger() -> None:
required = {"test", "set_main", "set_orchestrator", "assign_role"}
configured = {action for action, _label in AccountCardWidget.MANAGEMENT_ACTIONS}
assert configured == required
app_path = Path("src/antigravity_provider/router/hermes_hub_app.py")
tree = ast.parse(app_path.read_text(encoding="utf-8"))
handled = {
node.comparators[0].value
for node in ast.walk(tree)
if isinstance(node, ast.Compare)
and isinstance(node.left, ast.Name)
and node.left.id == "action"
and len(node.ops) == 1
and isinstance(node.ops[0], ast.Eq)
and len(node.comparators) == 1
and isinstance(node.comparators[0], ast.Constant)
and isinstance(node.comparators[0].value, str)
}
assert required <= handled
@pytest.mark.unit
def test_three_schemes_have_identical_token_coverage() -> None:
assert set(Theme.PALETTES) == {"dark", "hybrid", "light"}
token_sets = [set(palette) for palette in Theme.PALETTES.values()]
assert token_sets[0] == token_sets[1] == token_sets[2]
backgrounds = {palette["BG_WINDOW"] for palette in Theme.PALETTES.values()}
assert len(backgrounds) == 3
@pytest.mark.unit
def test_ui_colors_are_centralized_in_theme_tokens() -> None:
roots = [
Path("src/antigravity_provider/router/ui"),
Path("src/antigravity_provider/router/hermes_hub_app.py"),
]
offenders = []
for root in roots:
files = [root] if root.is_file() else list(root.rglob("*.py"))
for file in files:
if file.name == "theme.py":
continue
if re.search(r"#[0-9A-Fa-f]{3,8}", file.read_text(encoding="utf-8")):
offenders.append(str(file))
assert offenders == []
@pytest.mark.unit
def test_approved_mockup_numbers_are_not_shipped_as_placeholders() -> None:
source_files = list(Path("src/antigravity_provider/router/ui").rglob("*.py"))
source_files.append(Path("src/antigravity_provider/router/hermes_hub_app.py"))
source = "\n".join(file.read_text(encoding="utf-8") for file in source_files)
for fictional_value in ("78%", "09:0021:00", "842 rps", "99.98%", "42 Мбит/с"):
assert fictional_value not in source
@pytest.mark.unit
def test_approved_logo_and_consistent_sidebar_icon_system_are_wired() -> None:
assert Path("assets/branding/logo/logo_approved.png").is_file()
assets_source = Path("src/antigravity_provider/router/ui/assets.py").read_text(encoding="utf-8")
app_source = Path("src/antigravity_provider/router/hermes_hub_app.py").read_text(encoding="utf-8")
assert 'self.logo_dir / "logo_approved.png"' in assets_source
assert "def get_nav_icon" in assets_source
assert "get_nav_icon(icon, size=19)" in app_source
@pytest.mark.unit
def test_apply_scheme_updates_shared_semantic_aliases() -> None:
original = Theme.current_scheme
try:
for scheme in Theme.SCHEMES:
assert Theme.apply_scheme(scheme) == scheme
assert Theme.COLOR_POSITIVE == Theme.STATUS_HEALTHY
assert Theme.COLOR_CAUTION == Theme.STATUS_WARNING
assert Theme.COLOR_BRAND == Theme.ACCENT
finally:
Theme.apply_scheme(original)
@pytest.mark.ui
def test_restored_account_buttons_invoke_each_action(ui_root) -> None:
calls = []
card = AccountCardWidget(
ui_root,
"profile-1",
"user@example.test",
"OpenAI Codex",
on_action=lambda action, profile: calls.append((action, profile.profile_id)),
)
card.profile_model = SimpleNamespace(profile_id="profile-1")
try:
card.pack()
for action, _label in AccountCardWidget.MANAGEMENT_ACTIONS:
card.action_buttons[action].invoke()
assert calls == [(action, "profile-1") for action, _label in AccountCardWidget.MANAGEMENT_ACTIONS]
finally:
card.destroy()
@pytest.mark.ui
def test_assign_role_error_stays_visible_in_open_modal(ui_root, monkeypatch) -> None:
policy = SimpleNamespace(preferred_chain=[])
monkeypatch.setattr(app_module, "load_router_config", lambda: SimpleNamespace(roles={"orchestrator": policy}))
monkeypatch.setattr(
app_module.AutoAssigner,
"assign_profile_to_role",
lambda *_args, **_kwargs: (False, "Профиль не найден"),
)
ui_root._show_account_action_result = lambda *_args: None
modal = app_module.HermesHubApp._open_assign_role_modal(ui_root, "missing", "Claude")
try:
modal.save_button.invoke()
modal.update_idletasks()
assert modal.winfo_exists()
assert "Профиль не найден" in modal.result_label.cget("text")
finally:
modal.destroy()