""" Tests fuer das Design-System (Light/Dark Mode, CSS-Variablen). Testet: - CSS-Variablen-Definitionen - Theme-Switching (Light/Dark Mode) - Footer-Struktur mit Legal-Links - Design-Konsistenz """ import pytest import re from pathlib import Path class TestCSSVariables: """Tests fuer CSS-Variablen im Design-System.""" @pytest.fixture def studio_css(self): """Laedt CSS-Variablen fuer Tests. Nach dem Refactoring sind die Variablen in modules/base/variables.css. Fallback auf studio.css fuer Abwaertskompatibilitaet. """ # Primaer: Modularisierte Variablen-Datei variables_path = Path(__file__).parent.parent / "frontend" / "static" / "css" / "modules" / "base" / "variables.css" if variables_path.exists(): return variables_path.read_text() # Fallback: Legacy studio.css css_path = Path(__file__).parent.parent / "frontend" / "static" / "css" / "studio.css" if css_path.exists(): return css_path.read_text() return None @pytest.fixture def base_py(self): """Laedt base.py fuer Tests.""" base_path = Path(__file__).parent.parent / "frontend" / "components" / "base.py" if base_path.exists(): return base_path.read_text() return None def test_dark_mode_primary_color_is_teal(self, studio_css): """Test: Dark Mode Primary ist Teal (#0f766e).""" if studio_css is None: pytest.skip("studio.css nicht gefunden") # Suche nach --bp-primary in :root (Dark Mode) root_match = re.search(r':root\s*\{([^}]+)\}', studio_css, re.DOTALL) assert root_match is not None, ":root Block nicht gefunden" root_content = root_match.group(1) assert "--bp-primary: #0f766e" in root_content, "Dark Mode Primary sollte Teal (#0f766e) sein" def test_dark_mode_accent_color_is_lime_green(self, studio_css): """Test: Dark Mode Accent ist Lime Green (#22c55e).""" if studio_css is None: pytest.skip("studio.css nicht gefunden") root_match = re.search(r':root\s*\{([^}]+)\}', studio_css, re.DOTALL) assert root_match is not None, ":root Block nicht gefunden" root_content = root_match.group(1) assert "--bp-accent: #22c55e" in root_content, "Dark Mode Accent sollte Lime Green (#22c55e) sein" def test_light_mode_primary_color_is_sky_blue(self, studio_css): """Test: Light Mode Primary ist Sky Blue (#0ea5e9).""" if studio_css is None: pytest.skip("studio.css nicht gefunden") # Suche nach [data-theme="light"] Block light_match = re.search(r'\[data-theme="light"\]\s*\{([^}]+)\}', studio_css, re.DOTALL) assert light_match is not None, "[data-theme='light'] Block nicht gefunden" light_content = light_match.group(1) assert "--bp-primary: #0ea5e9" in light_content, "Light Mode Primary sollte Sky Blue (#0ea5e9) sein" def test_light_mode_accent_color_is_fuchsia(self, studio_css): """Test: Light Mode Accent ist Fuchsia (#d946ef).""" if studio_css is None: pytest.skip("studio.css nicht gefunden") light_match = re.search(r'\[data-theme="light"\]\s*\{([^}]+)\}', studio_css, re.DOTALL) assert light_match is not None, "[data-theme='light'] Block nicht gefunden" light_content = light_match.group(1) assert "--bp-accent: #d946ef" in light_content, "Light Mode Accent sollte Fuchsia (#d946ef) sein" def test_no_hardcoded_material_design_grays(self): """Test: Keine hardcodierten Material Design Grays (#E0E0E0, #F5F5F5, #F8F8F8).""" # Pruefe alle CSS-Dateien im modules-Verzeichnis css_base = Path(__file__).parent.parent / "frontend" / "static" / "css" modules_dir = css_base / "modules" if not modules_dir.exists(): # Fallback: Pruefe nur studio.css css_path = css_base / "studio.css" if not css_path.exists(): pytest.skip("Keine CSS-Dateien gefunden") css_files = [css_path] else: css_files = list(modules_dir.rglob("*.css")) # Diese sollten durch CSS-Variablen ersetzt sein # Ausnahme: In Kommentaren oder Variable-Definitionen problem_colors = ['#E0E0E0', '#F5F5F5', '#F8F8F8'] for css_file in css_files: lines = css_file.read_text().split('\n') for line_num, line in enumerate(lines, 1): # Ueberspringe Kommentare if line.strip().startswith('/*') or line.strip().startswith('*') or line.strip().startswith('//'): continue # Ueberspringe Variable-Definitionen im Light-Mode Block if '--bp-' in line: continue for color in problem_colors: if color in line.upper(): pytest.fail(f"Hardcodierte Farbe {color} gefunden in {css_file.name}:{line_num}: {line.strip()}") def test_light_mode_uses_slate_colors(self, studio_css): """Test: Light Mode verwendet Slate-Farbpalette.""" if studio_css is None: pytest.skip("studio.css nicht gefunden") light_match = re.search(r'\[data-theme="light"\]\s*\{([^}]+)\}', studio_css, re.DOTALL) assert light_match is not None, "[data-theme='light'] Block nicht gefunden" light_content = light_match.group(1) # Slate-50 fuer Background assert "#f8fafc" in light_content.lower(), "Light Mode sollte Slate-50 (#f8fafc) verwenden" # Slate-200 fuer Border assert "#e2e8f0" in light_content.lower(), "Light Mode sollte Slate-200 (#e2e8f0) fuer Border verwenden" def test_base_py_has_website_design_light_mode(self, base_py): """Test: base.py verwendet Website Design fuer Light Mode.""" if base_py is None: pytest.skip("base.py nicht gefunden") # Pruefe auf Website Design Kommentar assert "Website Design" in base_py, "base.py sollte Website Design verwenden" assert "Sky Blue" in base_py or "#0ea5e9" in base_py, "base.py sollte Sky Blue fuer Light Mode verwenden" assert "Fuchsia" in base_py or "#d946ef" in base_py, "base.py sollte Fuchsia fuer Light Mode verwenden" class TestFooterStructure: """Tests fuer Footer-Struktur mit Legal-Links.""" @pytest.fixture def studio_html(self): """Laedt studio.html fuer Tests.""" html_path = Path(__file__).parent.parent / "frontend" / "templates" / "studio.html" if html_path.exists(): return html_path.read_text() return None @pytest.fixture def base_py(self): """Laedt base.py fuer Tests.""" base_path = Path(__file__).parent.parent / "frontend" / "components" / "base.py" if base_path.exists(): return base_path.read_text() return None def test_footer_has_impressum_link(self, studio_html): """Test: Footer enthaelt Impressum-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "Impressum" in studio_html, "Footer sollte Impressum-Link enthalten" def test_footer_has_agb_link(self, studio_html): """Test: Footer enthaelt AGB-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "AGB" in studio_html, "Footer sollte AGB-Link enthalten" def test_footer_has_datenschutz_link(self, studio_html): """Test: Footer enthaelt Datenschutz-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "Datenschutz" in studio_html, "Footer sollte Datenschutz-Link enthalten" def test_footer_has_cookies_link(self, studio_html): """Test: Footer enthaelt Cookies-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "Cookies" in studio_html, "Footer sollte Cookies-Link enthalten" def test_footer_has_deine_rechte_link(self, studio_html): """Test: Footer enthaelt Deine Rechte (GDPR)-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "Deine Rechte" in studio_html, "Footer sollte 'Deine Rechte' (GDPR)-Link enthalten" def test_footer_has_einstellungen_link(self, studio_html): """Test: Footer enthaelt Einstellungen-Link.""" if studio_html is None: pytest.skip("studio.html nicht gefunden") assert "Einstellungen" in studio_html, "Footer sollte Einstellungen-Link enthalten" def test_base_py_footer_has_all_links(self, base_py): """Test: base.py Footer enthaelt alle erforderlichen Links.""" if base_py is None: pytest.skip("base.py nicht gefunden") required_links = ["Impressum", "AGB", "Datenschutz", "Cookies", "Deine Rechte", "Einstellungen"] for link in required_links: assert link in base_py, f"base.py Footer sollte '{link}'-Link enthalten" class TestThemeSwitching: """Tests fuer Theme-Switching Funktionalitaet.""" @pytest.fixture def studio_js(self): """Laedt studio.js fuer Tests.""" js_path = Path(__file__).parent.parent / "frontend" / "static" / "js" / "studio.js" if js_path.exists(): return js_path.read_text() return None def test_theme_toggle_function_exists(self, studio_js): """Test: Theme-Toggle Funktion existiert.""" if studio_js is None: pytest.skip("studio.js nicht gefunden") assert "initThemeToggle" in studio_js or "theme-toggle" in studio_js, \ "Theme-Toggle Funktionalitaet sollte existieren" def test_theme_saved_to_localstorage(self, studio_js): """Test: Theme wird in localStorage gespeichert.""" if studio_js is None: pytest.skip("studio.js nicht gefunden") assert "localStorage" in studio_js, "Theme sollte in localStorage gespeichert werden" assert "bp-theme" in studio_js or "bp_theme" in studio_js, \ "Theme-Key sollte 'bp-theme' oder 'bp_theme' sein" def test_data_theme_attribute_used(self, studio_js): """Test: data-theme Attribut wird verwendet.""" if studio_js is None: pytest.skip("studio.js nicht gefunden") assert "data-theme" in studio_js, "data-theme Attribut sollte fuer Theme-Switching verwendet werden"