feat: UI polish - dark default, version drift vs default release, humanized enums, failed-jobs layout, processing button hierarchy, PT-BR titles/CTAs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from pathlib import Path
|
||||
import re
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
@@ -85,7 +86,7 @@ def test_dashboard_renders_operational_queue_labels_and_human_dates():
|
||||
assert "Produtos com blockers abertos" in response.text
|
||||
assert "Blockers abertos" in response.text
|
||||
assert "Atenção necessária" in response.text
|
||||
assert "Ver todos" in response.text
|
||||
assert "Ver blockers" in response.text
|
||||
assert "Jobs com falha" in response.text
|
||||
assert "Agents desatualizados" in response.text
|
||||
assert not re.search(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}", response.text)
|
||||
@@ -188,9 +189,9 @@ def test_dashboard_lists_bounded_failed_job_rows_with_identity_error_age_and_emp
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
assert "Acme" in response.text and "Acme ERP" in response.text and "srv-01" in response.text
|
||||
assert "erro curto" in response.text and "Tipo / erro" in response.text and "Falhou" in response.text
|
||||
assert "erro curto" in response.text and "Falhas recentes" in response.text and "Falhou" in response.text
|
||||
assert 'href="/jobs?scope=active&status=FAILED&job_id=' in response.text
|
||||
assert response.text.count("erro curto") == 10
|
||||
assert response.text.count('class="error-text job-error-summary"') == 10 # bounded, one clamped summary per row
|
||||
assert 'title="2026-09-22T18:05:11+00:00"' in response.text
|
||||
assert ">22/09/2026 15:05<" in response.text
|
||||
with factory() as session:
|
||||
@@ -458,7 +459,8 @@ def test_agent_detail_reconciles_coverage_and_formats_missing_technical_fields()
|
||||
assert "Desconhecida · Desconhecida" not in response.text
|
||||
assert "ODS -" not in response.text
|
||||
context = response.text.split("<h2>Contexto da empresa</h2>", 1)[1].split("</article>", 1)[0]
|
||||
assert "Reprocessar tudo" in context
|
||||
assert "Reprocessar tudo" not in context # the only reprocess action lives in the Processamento panel
|
||||
assert response.text.count("Reprocessar tudo") == 1
|
||||
assert not re.search(r"<(?:a|button)\b[^>]*>\s*</(?:a|button)>", context)
|
||||
|
||||
|
||||
@@ -502,3 +504,35 @@ def test_agent_event_filters_lookahead_and_safe_event_reference_links_and_confir
|
||||
assert f'href="/agents/{agent_id}"' in confirmation.text
|
||||
assert client.post(f"/agents/{agent_id}/reprocess", data={"csrf_token": "wrong", "confirm": "yes"}).status_code == 403
|
||||
assert client.post(f"/agents/{agent_id}/reprocess", data={"csrf_token": csrf, "confirm": "yes"}, follow_redirects=False).status_code == 303
|
||||
|
||||
|
||||
def test_theme_defaults_to_dark_and_never_overrides_a_saved_choice():
|
||||
client, _, _ = _panel_client()
|
||||
base = client.get("/agents").text
|
||||
# no saved preference -> dark; an explicit "claro" is the only thing that yields light
|
||||
assert 'tema === "claro" ? "claro" : "escuro"' in base
|
||||
assert "prefers-color-scheme" not in (Path(__file__).parents[1] / "static" / "tema.js").read_text(encoding="utf-8")
|
||||
script = (Path(__file__).parents[1] / "static" / "tema.js").read_text(encoding="utf-8")
|
||||
assert 'return "escuro"' in script and 'localStorage.setItem("tema", novo)' in script
|
||||
for page in ("login.html", "logged_out.html", "sso_error.html"):
|
||||
assert 'data-tema="escuro"' in (Path(__file__).parents[1] / "templates" / page).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_operator_pages_use_portuguese_titles_and_consistent_ctas():
|
||||
client, agent_id, _ = _panel_client()
|
||||
assert "<title>Agents / Servidores | GTI Fiscal</title>" in client.get("/agents").text
|
||||
assert "<title>Blockers | GTI Fiscal</title>" in client.get("/blockers").text
|
||||
assert "<title>Jobs | GTI Fiscal</title>" in client.get("/jobs").text
|
||||
dashboard = client.get("/").text
|
||||
for old in ("Abrir fila", "Ver instalações", "Ver todos", "Ver job #"):
|
||||
assert old not in dashboard
|
||||
|
||||
|
||||
def test_agent_detail_processing_hierarchy_and_status_badges():
|
||||
client, agent_id, _ = _panel_client()
|
||||
page = client.get(f"/agents/{agent_id}").text
|
||||
assert page.count("Reprocessar tudo") == 1
|
||||
assert 'class="primary-action"' in page and 'class="botao secondary"' in page and 'class="caution"' in page
|
||||
assert "Mantém o heartbeat, mas não executa jobs" in page and "Recalcula todos os produtos" in page
|
||||
assert "Saúde técnica: " not in page and "Status fiscal: " not in page # context lives in the small label, not in the badge
|
||||
assert '<small class="status-label">Saúde técnica</small>' in page
|
||||
|
||||
Reference in New Issue
Block a user