32272420cb
- test_peer_dashboard_services.py (63 tests): unit tests for all API fixes * peer_dashboard field names (name/transfer_rx/transfer_tx vs old stale names) * peer_dashboard service_urls dict with correct domain-keyed URLs * peer_services email structure (nested smtp/imap, address not username) * peer_services files key (not webdav), caldav URL (calendar.dev not radicale.dev:5232) * peer_services wireguard DNS (not 10.0.0.1), config text with DNS line * DNS zone records (api/webui → Caddy, VIPs for calendar/files/mail/webdav) * Caddyfile generation (all service blocks including webui.dev) * Access control (401 anon, 403 admin on peer-only routes, 404 missing peer) - e2e/api/test_peer_endpoints.py: fix stale field assertions, add structure checks - e2e/wg/test_wg_domain_access.py: E2E WG tests for DNS resolution via VPN tunnel * All *.dev domains resolve to correct IPs via CoreDNS * api.dev/webui.dev must resolve to Caddy, not container direct IPs * CoreDNS reachability through VPN tunnel * Peer config DNS field correctness - e2e/ui/test_peer_dashboard.py: UI checks for service icon links, CalDAV URL, email Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
215 lines
8.2 KiB
Python
215 lines
8.2 KiB
Python
"""
|
|
Peer dashboard and My Services page tests.
|
|
|
|
Scenarios:
|
|
12. Peer sees their own dashboard (PeerDashboard.jsx renders peer.name as <h1>)
|
|
13. Peer's My Services page loads and shows all service sections
|
|
14. Peer dashboard shows service icon links (calendar, files, mail, webdav)
|
|
15. My Services shows correct CalDAV URL (calendar.dev not radicale.dev:5232)
|
|
16. My Services shows email address field (not username)
|
|
|
|
Key selectors from PeerDashboard.jsx:
|
|
- h1 shows peer.name (peer.name from /api/peer/dashboard)
|
|
- "VPN Address" stat card label
|
|
- "Quick Access" section with service icon links from service_urls
|
|
- "My Services" link
|
|
|
|
Key selectors from MyServices.jsx:
|
|
- h2 "WireGuard VPN"
|
|
- h2 "Email", h2 "Calendar & Contacts", h2 "Files"
|
|
- "Address" label for email (not "Username")
|
|
- "CalDAV URL" label with calendar.dev value
|
|
"""
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.ui
|
|
|
|
|
|
# ── 12. Peer dashboard ───────────────────────────────────────────────────────
|
|
|
|
def test_peer_sees_peer_dashboard(peer_page, webui_base):
|
|
"""Peer lands on the root route which renders PeerDashboard, not the admin Dashboard."""
|
|
page, peer = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
assert '/login' not in page.url
|
|
|
|
|
|
def test_peer_dashboard_shows_peer_name(peer_page, webui_base):
|
|
"""PeerDashboard.jsx renders peer.name as the page <h1>."""
|
|
page, peer = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
# PeerDashboard line 61: <h1>{peer.name || 'My Dashboard'}</h1>
|
|
page.wait_for_selector(
|
|
f'h1:has-text("{peer["name"]}")',
|
|
timeout=6000,
|
|
)
|
|
except Exception:
|
|
pytest.xfail(
|
|
f"Peer name '{peer['name']}' not found as <h1> on PeerDashboard. "
|
|
"Check that the /api/peer/dashboard endpoint returns the peer name "
|
|
"and that PeerDashboard.jsx renders it."
|
|
)
|
|
|
|
|
|
def test_peer_dashboard_shows_vpn_address_label(peer_page, webui_base):
|
|
"""PeerDashboard.jsx shows a 'VPN Address' stat card."""
|
|
page, _ = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('text=VPN Address', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"VPN Address stat card not found — check PeerDashboard.jsx stat card labels"
|
|
)
|
|
|
|
|
|
def test_peer_dashboard_has_my_services_link(peer_page, webui_base):
|
|
"""PeerDashboard.jsx renders a 'My Services' quick-access link."""
|
|
page, _ = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('a:has-text("My Services"), button:has-text("My Services")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"'My Services' link not found on peer dashboard — check PeerDashboard.jsx Quick Access section"
|
|
)
|
|
|
|
|
|
# ── 13. My Services page ─────────────────────────────────────────────────────
|
|
|
|
def test_peer_my_services_page_loads(peer_page, webui_base):
|
|
"""Peer can navigate to /my-services without being redirected."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
assert '/login' not in page.url
|
|
|
|
|
|
def test_peer_my_services_shows_wireguard_section(peer_page, webui_base):
|
|
"""MyServices.jsx renders a 'WireGuard VPN' section heading."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('h2:has-text("WireGuard VPN")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"WireGuard VPN section heading not found on /my-services — "
|
|
"check MyServices.jsx and /api/peer/services endpoint"
|
|
)
|
|
|
|
|
|
def test_peer_my_services_shows_email_section(peer_page, webui_base):
|
|
"""MyServices.jsx renders an 'Email' section heading."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('h2:has-text("Email")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Email section heading not found on /my-services"
|
|
)
|
|
|
|
|
|
def test_peer_my_services_shows_calendar_section(peer_page, webui_base):
|
|
"""MyServices.jsx renders a 'Calendar & Contacts' section heading."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('h2:has-text("Calendar")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Calendar section heading not found on /my-services"
|
|
)
|
|
|
|
|
|
def test_peer_my_services_shows_files_section(peer_page, webui_base):
|
|
"""MyServices.jsx renders a 'Files' section heading."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('h2:has-text("Files")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Files section heading not found on /my-services"
|
|
)
|
|
|
|
|
|
# ── 14. Service icon links ────────────────────────────────────────────────────
|
|
|
|
def test_peer_dashboard_has_calendar_link(peer_page, webui_base):
|
|
"""PeerDashboard Quick Access section renders a Calendar icon link."""
|
|
page, _ = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('a:has-text("Calendar")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Calendar link not found on peer dashboard Quick Access — "
|
|
"check that service_urls.calendar is populated and PeerDashboard.jsx renders it"
|
|
)
|
|
|
|
|
|
def test_peer_dashboard_has_files_link(peer_page, webui_base):
|
|
"""PeerDashboard Quick Access section renders a Files icon link."""
|
|
page, _ = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('a:has-text("Files")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Files link not found on peer dashboard Quick Access"
|
|
)
|
|
|
|
|
|
def test_peer_dashboard_has_mail_link(peer_page, webui_base):
|
|
"""PeerDashboard Quick Access section renders a Mail icon link."""
|
|
page, _ = peer_page
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('a:has-text("Mail")', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"Mail link not found on peer dashboard Quick Access"
|
|
)
|
|
|
|
|
|
# ── 15. CalDAV URL correctness ────────────────────────────────────────────────
|
|
|
|
def test_peer_my_services_caldav_url_no_radicale(peer_page, webui_base):
|
|
"""CalDAV URL shown in My Services must not contain 'radicale' (no DNS record)."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
# If radicale.dev appears as CalDAV URL it means the bug is back
|
|
radicale_url = page.query_selector('text=radicale')
|
|
assert radicale_url is None, (
|
|
"Found 'radicale' text on My Services page — "
|
|
"CalDAV URL should be calendar.dev, not radicale.dev:5232"
|
|
)
|
|
except AssertionError:
|
|
raise
|
|
except Exception:
|
|
pass # page didn't load — other tests cover that
|
|
|
|
|
|
# ── 16. Email address display ─────────────────────────────────────────────────
|
|
|
|
def test_peer_my_services_shows_address_label(peer_page, webui_base):
|
|
"""MyServices.jsx renders 'Address' label for email (reads email.address)."""
|
|
page, _ = peer_page
|
|
page.goto(f"{webui_base}/my-services")
|
|
page.wait_for_load_state('networkidle')
|
|
try:
|
|
page.wait_for_selector('text=Address', timeout=5000)
|
|
except Exception:
|
|
pytest.xfail(
|
|
"'Address' label not found on My Services email section — "
|
|
"check that email.address is populated in /api/peer/services"
|
|
)
|