112 lines
4.4 KiB
Python
112 lines
4.4 KiB
Python
"""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"
|