1
0
This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/tests/functional/test_fast_e2e.py
Alexander Whitestone 9d78eb31d1 ruff (#169)
* polish: streamline nav, extract inline styles, improve tablet UX

- Restructure desktop nav from 8+ flat links + overflow dropdown into
  5 grouped dropdowns (Core, Agents, Intel, System, More) matching
  the mobile menu structure to reduce decision fatigue
- Extract all inline styles from mission_control.html and base.html
  notification elements into mission-control.css with semantic classes
- Replace JS-built innerHTML with secure DOM construction in
  notification loader and chat history
- Add CONNECTING state to connection indicator (amber) instead of
  showing OFFLINE before WebSocket connects
- Add tablet breakpoint (1024px) with larger touch targets for
  Apple Pencil / stylus use and safe-area padding for iPad toolbar
- Add active-link highlighting in desktop dropdown menus
- Rename "Mission Control" page title to "System Overview" to
  disambiguate from the chat home page
- Add "Home — Timmy Time" page title to index.html

https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h

* fix(security): move auth-gate credentials to environment variables

Hardcoded username, password, and HMAC secret in auth-gate.py replaced
with os.environ lookups. Startup now refuses to run if any variable is
unset. Added AUTH_GATE_SECRET/USER/PASS to .env.example.

https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h

* refactor(tooling): migrate from black+isort+bandit to ruff

Replace three separate linting/formatting tools with a single ruff
invocation. Updates tox.ini (lint, format, pre-push, pre-commit envs),
.pre-commit-config.yaml, and CI workflow. Fixes all ruff errors
including unused imports, missing raise-from, and undefined names.
Ruff config maps existing bandit skips to equivalent S-rules.

https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-11 12:23:35 -04:00

254 lines
8.8 KiB
Python

"""Fast E2E tests - all checks in one browser session, under 20 seconds.
RUN: SELENIUM_UI=1 pytest tests/functional/test_fast_e2e.py -v
"""
import os
import httpx
import pytest
try:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
HAS_SELENIUM = True
except ImportError:
HAS_SELENIUM = False
pytestmark = pytest.mark.skipif(
not HAS_SELENIUM or os.environ.get("SELENIUM_UI") != "1",
reason="Selenium not installed or SELENIUM_UI not set to 1",
)
DASHBOARD_URL = os.environ.get("DASHBOARD_URL", "http://localhost:8000")
@pytest.fixture(scope="module")
def driver():
"""Single browser instance for all tests (module-scoped for reuse)."""
opts = Options()
opts.add_argument("--headless=new") # Headless for speed
opts.add_argument("--no-sandbox")
opts.add_argument("--disable-dev-shm-usage")
opts.add_argument("--disable-gpu")
opts.add_argument("--window-size=1280,900")
d = webdriver.Chrome(options=opts)
d.implicitly_wait(2) # Reduced from 5s
yield d
d.quit()
@pytest.fixture(scope="module")
def dashboard_url():
"""Verify server is running."""
try:
r = httpx.get(f"{DASHBOARD_URL}/health", timeout=3)
if r.status_code != 200:
pytest.skip("Dashboard not healthy")
except Exception:
pytest.skip(f"Dashboard not reachable at {DASHBOARD_URL}")
return DASHBOARD_URL
class TestAllPagesLoad:
"""Single test that checks all pages load - much faster than separate tests."""
def test_all_dashboard_pages_exist(self, driver, dashboard_url):
"""Verify all new feature pages load successfully in one browser session."""
pages = [
("/swarm/events", "Event"),
("/lightning/ledger", "Lightning Ledger"),
("/memory", "Memory"),
("/router/status", "Router Status"),
("/self-modify/queue", "Upgrade"),
("/swarm/live", "Swarm"), # Live page has "Swarm" not "Live"
]
failures = []
for path, expected_text in pages:
try:
driver.get(f"{dashboard_url}{path}")
# Quick check - wait max 5s for any content
WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Give a small extra buffer for animations (fadeUp in style.css)
import time
time.sleep(0.5)
# Verify page has expected content
body_text = driver.find_element(By.TAG_NAME, "body").text
if expected_text.lower() not in body_text.lower():
failures.append(f"{path}: missing '{expected_text}'")
except Exception as exc:
failures.append(f"{path}: {type(exc).__name__}")
if failures:
pytest.fail(f"Pages failed to load: {', '.join(failures)}")
class TestAllFeaturesWork:
"""Combined functional tests - single browser session."""
def test_event_log_and_memory_and_ledger_functional(self, driver, dashboard_url):
"""Test Event Log, Memory, and Ledger functionality in one go."""
# 1. Event Log - verify events display
driver.get(f"{dashboard_url}/swarm/events")
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
import time
time.sleep(0.5)
# Should have header and either events or empty state
body = driver.find_element(By.TAG_NAME, "body").text
assert "event log" in body.lower(), "Event log page missing header"
# Create a task via API to generate an event
try:
httpx.post(
f"{dashboard_url}/swarm/tasks",
data={"description": "E2E test task"},
timeout=2,
)
except Exception:
pass # Ignore, just checking page exists
# 2. Memory - verify search works
driver.get(f"{dashboard_url}/memory?query=test")
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
# Should have search input
search = driver.find_elements(By.CSS_SELECTOR, "input[type='search'], input[name='query']")
assert search, "Memory page missing search input"
# 3. Ledger - verify balance display
driver.get(f"{dashboard_url}/lightning/ledger")
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
time.sleep(0.5)
body = driver.find_element(By.TAG_NAME, "body").text
# Should show balance-related text
has_balance = any(x in body.lower() for x in ["balance", "sats", "transaction", "ledger"])
assert has_balance, "Ledger page missing balance info"
class TestCascadeRouter:
"""Cascade Router - combined checks."""
def test_router_status_and_navigation(self, driver, dashboard_url):
"""Verify router status page and nav link in one test."""
# Check router status page
driver.get(f"{dashboard_url}/router/status")
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
import time
time.sleep(0.5)
body = driver.find_element(By.TAG_NAME, "body").text
# Should show providers or config message
has_content = any(
x in body.lower()
for x in ["provider", "router", "ollama", "config", "status", "registry"]
)
assert has_content, "Router status page missing content"
# Check nav has router link
driver.get(dashboard_url)
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
nav_links = driver.find_elements(By.XPATH, "//a[contains(@href, '/router')]")
assert nav_links, "Navigation missing router link"
class TestUpgradeQueue:
"""Upgrade Queue - combined checks."""
def test_upgrade_queue_page_and_elements(self, driver, dashboard_url):
"""Verify upgrade queue page loads with expected elements."""
driver.get(f"{dashboard_url}/self-modify/queue")
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
import time
time.sleep(0.5)
body = driver.find_element(By.TAG_NAME, "body").text
# Should have queue header
assert "upgrade" in body.lower() or "queue" in body.lower(), "Missing queue header"
# Should have pending section or empty state
has_pending = "pending" in body.lower() or "no pending" in body.lower()
assert has_pending, "Missing pending upgrades section"
# Check for approve/reject buttons if upgrades exist
driver.find_elements(By.XPATH, "//button[contains(text(), 'Approve')]")
driver.find_elements(By.XPATH, "//button[contains(text(), 'Reject')]")
# Either no upgrades (no buttons) or buttons exist
# This is a soft check - page structure is valid either way
class TestActivityFeed:
"""Activity Feed - combined checks."""
def test_swarm_live_page_and_activity_feed(self, driver, dashboard_url):
"""Verify swarm live page has activity feed elements."""
driver.get(f"{dashboard_url}/swarm/live")
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, "body")))
import time
time.sleep(0.5)
body = driver.find_element(By.TAG_NAME, "body").text
# Should have live indicator or activity section
has_live = any(x in body.lower() for x in ["live", "activity", "swarm", "agents", "tasks"])
assert has_live, "Swarm live page missing content"
# Check for WebSocket connection indicator (if implemented)
# or just basic structure
panels = driver.find_elements(By.CSS_SELECTOR, ".card, .panel, .mc-panel")
assert panels, "Swarm live page missing panels"
class TestFastSmoke:
"""Ultra-fast smoke tests using HTTP where possible."""
def test_all_routes_respond_200(self, dashboard_url):
"""HTTP-only test - no browser, very fast."""
routes = [
"/swarm/events",
"/lightning/ledger",
"/memory",
"/router/status",
"/self-modify/queue",
"/swarm/live",
]
failures = []
for route in routes:
try:
r = httpx.get(f"{dashboard_url}{route}", timeout=3, follow_redirects=True)
if r.status_code != 200:
failures.append(f"{route}: {r.status_code}")
except Exception as exc:
failures.append(f"{route}: {type(exc).__name__}")
if failures:
pytest.fail(f"Routes failed: {', '.join(failures)}")