import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] HTML = ROOT / "frontend" / "index.html" DASHBOARD = ROOT / "frontend" / "dashboard.js" CSS = ROOT / "frontend" / "dashboard.css" WORKER = ROOT / "frontend" / "service-worker.js" def test_all_text_entry_flows_are_wired_to_keyboard_safe_panels(): html = HTML.read_text() dashboard = DASHBOARD.read_text() css = CSS.read_text() assert '' in html assert "createMobileComposerViewport({" in dashboard for panel, workspace, composer, submit, status in [ ("#issue-sheet .issue-sheet-panel", ".issue-comment-composer", "#issue-comment", "#send-issue-comment", "#issue-comment-status"), ("#pull-sheet .pull-sheet-panel", ".pull-comment-composer", "#pull-comment", "#send-pull-comment", "#pull-comment-status"), ("#update-sheet .update-sheet-panel", ".update-reply", "#update-reply", "#send-update-reply", "#update-reply-status"), ]: for selector in (panel, workspace, composer, submit, status): assert repr(selector) in dashboard assert "panel:qs('.create-issue-panel')" in dashboard assert "workspace:qs('#create-issue-form')" in dashboard assert "focusWithin:true" in dashboard assert "mobileComposerViewport.close(qs('.create-issue-panel'))" in dashboard assert "height:var(--composer-viewport-height,100dvh)" in css assert "top:var(--composer-viewport-top,0px)" in css assert ".composer-keyboard-active" in css assert ".create-issue-panel.composer-keyboard-active" in css assert ".composer-keyboard-active .create-issue-form :is(input,textarea,select,button) { scroll-margin-block:12px;" in css def test_offline_shell_contains_every_local_dashboard_runtime_asset(): html = HTML.read_text() worker = WORKER.read_text() local_assets = set(re.findall(r'(?:src|href)="((?:static/|manifest\.webmanifest)[^"?#]*)', html)) shell_assets = set(re.findall(r"BASE \+ '([^']+)'", worker.split("async function sessionCsrf", 1)[0])) assert local_assets <= shell_assets, f"Offline shell is missing: {sorted(local_assets - shell_assets)}" assert "stackchain-dashboard-shell-v94" in worker def test_all_conversation_composers_offer_accessible_mobile_mentions(): html = HTML.read_text() dashboard = DASHBOARD.read_text() css = CSS.read_text() assert '' in html for composer in ("issue-comment", "pull-comment", "update-reply"): assert f'id="{composer}-mentions"' in html assert f'id="{composer}-mention-status"' in html assert f"textarea:qs('#{composer}')" in dashboard assert f"listbox:qs('#{composer}-mentions')" in dashboard assert dashboard.count("createMentionComposer({") == 3 assert "mention-candidates?q=" in dashboard assert ".mention-options" in css assert "min-height:44px" in css assert "max-width:100%" in css