Upload tests/test_frontend_pages.py
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""Frontend-Smoke-Tests: verify all 13 HTML pages exist and contain the
|
||||
expected keywords/structure.
|
||||
|
||||
These tests read the HTML files directly from `app/webui/` (rather than
|
||||
hitting the FastAPI server) because the static-file mount is added in a
|
||||
later phase by the orchestrator. Once that mount is in place, the same
|
||||
checks could be re-implemented as `httpx.AsyncClient.get("/…")`.
|
||||
|
||||
Each test loads exactly one page and asserts:
|
||||
- file exists and is non-empty
|
||||
- contains the page's title text (so a typo / removal is caught)
|
||||
- has Tailwind-CDN, Alpine-CDN, and the app.css link
|
||||
- has no x-html attribute (R-5)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
WEBUI_DIR = Path(__file__).resolve().parent.parent / "app" / "webui"
|
||||
|
||||
|
||||
def _read(name: str) -> str:
|
||||
"""Read a file from the webui directory."""
|
||||
p = WEBUI_DIR / name
|
||||
assert p.exists(), f"Expected frontend file {p} to exist"
|
||||
return p.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Each page: (filename, [required substrings])
|
||||
# ---------------------------------------------------------------------------
|
||||
PAGES = [
|
||||
("index.html", ["Login", "Registrieren", "Anmelden", "Konto erstellen"]),
|
||||
("app.html", ["Dashboard", "Logout", "Pipeline"]),
|
||||
("accounts.html", ["Accounts", "Suche (Name)", "Branche", "+ New Account"]),
|
||||
("accounts-detail.html", ["Account-Detail", "Bearbeiten", "Löschen", "Info"]),
|
||||
("contacts.html", ["Contacts", "Vorname", "Nachname", "+ New Contact"]),
|
||||
("contacts-detail.html", ["Contact-Detail", "Bearbeiten", "Löschen"]),
|
||||
("pipeline.html", ["Pipeline", "Owner-ID (optional)", "+ New Deal", "Ziehe Karten"]),
|
||||
("activities.html", ["Activities", "+ New Activity", "Fällig"]),
|
||||
("settings-profile.html", ["Mein Profil", "Avatar-URL", "E-Mail-Benachrichtigungen"]),
|
||||
("settings-users.html", ["User-Verwaltung", "+ New User", "Rolle"]),
|
||||
("settings-org.html", ["Org-Einstellungen", "Aktuelle Organisation", "v1.1"]),
|
||||
("404.html", ["404", "Seite nicht gefunden", "Zum Dashboard"]),
|
||||
# Dashboard: ships inside app.html. We test the marker text directly there.
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("filename,required", PAGES)
|
||||
def test_frontend_page_loads(filename, required):
|
||||
"""Each HTML page must exist and contain its identifying substrings."""
|
||||
content = _read(filename)
|
||||
assert len(content) > 200, f"{filename} seems empty or too small"
|
||||
for needle in required:
|
||||
assert needle in content, f"{filename} missing required string {needle!r}"
|
||||
|
||||
|
||||
def test_index_html_contains_login_and_register():
|
||||
"""Index page (auth screen) must show both Login and Register tabs."""
|
||||
content = _read("index.html")
|
||||
assert "Login" in content
|
||||
assert "Registrieren" in content
|
||||
# Alpine-CDN required
|
||||
assert "alpinejs" in content
|
||||
|
||||
|
||||
def test_app_html_contains_dashboard_and_logout():
|
||||
"""app.html is the post-login shell — must show Dashboard + Logout."""
|
||||
content = _read("app.html")
|
||||
assert "Dashboard" in content
|
||||
assert "Logout" in content
|
||||
|
||||
|
||||
def test_13_pages_exist():
|
||||
"""Exactly 13 HTML pages must be present (index + app + 10 + 404)."""
|
||||
pages = sorted(p.name for p in WEBUI_DIR.glob("*.html"))
|
||||
assert len(pages) == 13, f"Expected 13 pages, found {len(pages)}: {pages}"
|
||||
|
||||
|
||||
def test_dashboard_section_inside_app_html():
|
||||
"""The dashboard content is rendered inside app.html (default landing)."""
|
||||
content = _read("app.html")
|
||||
# The 4 KPI labels from the dashboard section
|
||||
assert "Open Deals" in content
|
||||
assert "Pipeline Value" in content
|
||||
assert "Won this Month" in content
|
||||
assert "Conversion Rate" in content
|
||||
|
||||
|
||||
def test_each_page_links_app_css():
|
||||
"""Every page must reference /css/app.css."""
|
||||
for filename, _ in PAGES:
|
||||
content = _read(filename)
|
||||
assert "/css/app.css" in content, f"{filename} missing /css/app.css link"
|
||||
|
||||
|
||||
def test_each_page_includes_alpine_cdn():
|
||||
"""Every page must include the Alpine.js CDN script."""
|
||||
for filename, _ in PAGES:
|
||||
content = _read(filename)
|
||||
assert "alpinejs" in content, f"{filename} missing Alpine.js CDN"
|
||||
|
||||
|
||||
def test_each_page_includes_tailwind_cdn():
|
||||
"""Every page must include the Tailwind-CDN script (dev-mode)."""
|
||||
for filename, _ in PAGES:
|
||||
content = _read(filename)
|
||||
assert "cdn.tailwindcss.com" in content, f"{filename} missing Tailwind CDN"
|
||||
Reference in New Issue
Block a user