Redesign Sentinel UI: test_frontend_contract.py
This commit is contained in:
parent
ff46387a43
commit
630f980906
1 changed files with 77 additions and 0 deletions
77
backup-monitor/tests/test_frontend_contract.py
Normal file
77
backup-monitor/tests/test_frontend_contract.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import re
|
||||
import subprocess
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
HTML = (ROOT / "templates" / "index.html").read_text(encoding="utf-8")
|
||||
JS = (ROOT / "static" / "js" / "app.js").read_text(encoding="utf-8")
|
||||
CSS = (ROOT / "static" / "css" / "style.css").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
class FrontendContractTests(unittest.TestCase):
|
||||
def test_stable_dom_ids_exist_once(self):
|
||||
required = {
|
||||
"nav-dashboard", "nav-alerts", "nav-hosts", "nav-config",
|
||||
"sysStatus", "lastScan", "mOk", "mSize", "mLatest",
|
||||
"mLatestHost", "mWarn", "mWarnCard", "clusterList",
|
||||
"liveStream", "chartSvg", "hostGrid", "alertList",
|
||||
"drawer", "drawerBg", "drawerTitle", "drawerBody",
|
||||
"modal", "modalBg", "hostForm", "formMode", "formName",
|
||||
"formKumaUrl", "formEnabled", "toasts",
|
||||
}
|
||||
for element_id in required:
|
||||
count = len(re.findall(rf'id=["\']{re.escape(element_id)}["\']', HTML))
|
||||
self.assertEqual(count, 1, f"#{element_id} must exist exactly once")
|
||||
|
||||
def test_uses_local_styles_without_runtime_css_framework(self):
|
||||
self.assertIn('/static/css/style.css', HTML)
|
||||
self.assertNotIn('cdn.tailwindcss.com', HTML)
|
||||
self.assertNotIn('Material+Symbols', HTML)
|
||||
self.assertNotIn('backdrop-blur', HTML)
|
||||
self.assertNotIn('pulse-', HTML)
|
||||
|
||||
def test_monitor_surface_has_semantic_landmarks_and_accessible_actions(self):
|
||||
self.assertRegex(HTML, r'<nav[^>]+aria-label="Hauptnavigation"')
|
||||
self.assertIn('<main', HTML)
|
||||
self.assertIn('aria-label="Daten aktualisieren"', HTML)
|
||||
self.assertIn('aria-label="Host hinzufügen"', HTML)
|
||||
self.assertIn('aria-live="polite"', HTML)
|
||||
|
||||
def test_copy_is_plain_german(self):
|
||||
expected = [
|
||||
'Backup-Übersicht', 'Letzte Aktualisierung', 'Heute gesichert',
|
||||
'Letzte Sicherung', 'Auffälligkeiten', 'Letzte Meldungen',
|
||||
'Backup-Hosts', 'Einstellungen',
|
||||
]
|
||||
for text in expected:
|
||||
self.assertIn(text, HTML)
|
||||
forbidden = ['Operational command', 'Real-time surveillance', 'LIVE', 'Vault Overview']
|
||||
for text in forbidden:
|
||||
self.assertNotIn(text, HTML)
|
||||
|
||||
def test_css_contains_responsive_and_motion_contracts(self):
|
||||
self.assertIn('@media (max-width: 720px)', CSS)
|
||||
self.assertIn('@media (prefers-reduced-motion: reduce)', CSS)
|
||||
self.assertIn(':focus-visible', CSS)
|
||||
self.assertIn('--status-ok', CSS)
|
||||
|
||||
def test_javascript_uses_semantic_status_classes_and_german_labels(self):
|
||||
self.assertIn('status--ok', JS)
|
||||
self.assertIn('Betriebsbereit', JS)
|
||||
self.assertIn('vor ', JS)
|
||||
self.assertNotIn('material-symbols-outlined', JS)
|
||||
self.assertNotIn('bg-${color}', JS)
|
||||
|
||||
def test_javascript_syntax(self):
|
||||
result = subprocess.run(
|
||||
["node", "--check", str(ROOT / "static" / "js" / "app.js")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue