""" E2E tests for DESIGN.md migration (Commit 0.5). Tests: dark toggle, FOUC prevention, bottom nav, active tab amber, dark contrast. """ import pytest pytestmark = [pytest.mark.e2e] def test_dark_mode_toggle(page, app_url): """Dark toggle switches theme and persists in localStorage.""" page.goto(f"{app_url}/settings") page.wait_for_load_state("networkidle") # Settings page has the dark mode toggle toggle = page.locator("#settDarkMode") assert toggle.is_visible() # Start in light mode theme = page.evaluate("document.documentElement.getAttribute('data-theme')") if theme == "dark": toggle.click() page.wait_for_timeout(200) # Toggle to dark toggle.click() page.wait_for_timeout(200) assert page.evaluate("document.documentElement.getAttribute('data-theme')") == "dark" assert page.evaluate("localStorage.getItem('theme')") == "dark" # Toggle back to light toggle.click() page.wait_for_timeout(200) assert page.evaluate("document.documentElement.getAttribute('data-theme')") != "dark" assert page.evaluate("localStorage.getItem('theme')") == "light" def test_fouc_prevention(page, app_url): """Theme is applied before CSS loads (inline script in ).""" # Set dark theme in localStorage before navigation page.goto(f"{app_url}/") page.evaluate("localStorage.setItem('theme', 'dark')") # Navigate fresh — the inline script should apply dark before paint page.goto(f"{app_url}/") # Check immediately (before networkidle) that data-theme is set theme = page.evaluate("document.documentElement.getAttribute('data-theme')") assert theme == "dark", "FOUC: dark theme not applied before first paint" # Cleanup page.evaluate("localStorage.removeItem('theme')") def test_bottom_nav_visible_on_mobile(page, app_url): """Bottom nav is visible on mobile viewport, top navbar is hidden.""" page.set_viewport_size({"width": 375, "height": 812}) page.goto(f"{app_url}/") page.wait_for_load_state("networkidle") bottom_nav = page.locator(".bottom-nav") top_navbar = page.locator(".top-navbar") assert bottom_nav.is_visible(), "Bottom nav should be visible on mobile" assert not top_navbar.is_visible(), "Top navbar should be hidden on mobile" # Check 5 tabs exist tabs = page.locator(".bottom-nav-item") assert tabs.count() == 5 def test_active_tab_amber_accent(page, app_url): """Active nav tab uses amber accent color, not blue.""" page.goto(f"{app_url}/") page.wait_for_load_state("networkidle") active_tab = page.locator(".nav-tab.active") assert active_tab.count() >= 1 # Get computed color of active tab color = page.evaluate(""" () => getComputedStyle(document.querySelector('.nav-tab.active')).color """) # Amber #D97706 = rgb(217, 119, 6) assert "217" in color and "119" in color, f"Active tab color should be amber, got: {color}" def test_dark_mode_contrast(page, app_url): """Dark mode has proper contrast — bg is dark, text is light.""" page.goto(f"{app_url}/") page.wait_for_load_state("networkidle") # Enable dark mode page.evaluate("document.documentElement.setAttribute('data-theme', 'dark')") page.wait_for_timeout(100) bg = page.evaluate("getComputedStyle(document.body).backgroundColor") color = page.evaluate("getComputedStyle(document.body).color") # bg should be dark (#121212 = rgb(18, 18, 18)) assert "18" in bg, f"Dark mode bg should be dark, got: {bg}" # text should be light (#E8E4DD = rgb(232, 228, 221)) assert "232" in color or "228" in color, f"Dark mode text should be light, got: {color}" # Cleanup page.evaluate("document.documentElement.removeAttribute('data-theme')")