Files
pic/tests/e2e/ui/test_peer_dashboard.py
T
roof 32272420cb test: add E2E coverage for peer dashboard/services, DNS records, and WG domain access
- 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>
2026-04-26 17:41:21 -04:00

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"
)