E2E harness fixes to get all three modes (demo/cloud/local) passing:
- conftest.py: use ctx.add_cookies() for cloud auth instead of
ctx.route() or set_extra_http_headers(). Playwright's route() only
intercepts HTTP; set_extra_http_headers() explicitly excludes
WebSocket handshakes. Streamlit reads st.context.headers from the
WebSocket upgrade, so cookies are the only vehicle that reaches it
without a reverse proxy.
- cloud_session.py: fall back to Cookie header when X-CF-Session is
absent — supports direct access (E2E tests, dev without Caddy).
In production Caddy sets X-CF-Session; in tests the cf_session cookie
is set on the browser context and arrives in the Cookie header.
- modes/cloud.py: add /peregrine base URL path (STREAMLIT_SERVER_BASE_URL_PATH=peregrine)
- modes/local.py: correct port from 8502 → 8501 and add /peregrine path
All three modes now pass smoke + interaction tests clean.
- Add tests/e2e/test_smoke.py: page-load error check for all pages
- Add tests/e2e/test_interactions.py: click every interactable, diff
errors, XFAIL expected demo failures, flag regressions as XPASS
- Fix conftest get_page_errors() to use text_content() instead of
inner_text() so errors inside collapsed expanders are captured with
their actual message text (inner_text respects CSS display:none)
- Fix tests/e2e/modes/demo.py base_url to include /peregrine path prefix
(STREAMLIT_SERVER_BASE_URL_PATH=peregrine set in demo container)
App fixes surfaced by the harness:
- task_runner.py: add DEMO_MODE guard for discovery task — previously
crashed with FileNotFoundError on search_profiles.yaml before any
demo guard could fire; now returns friendly error immediately
- 6_Interview_Prep.py: stop auto-triggering LLM session on page load
in demo mode; show "AI features disabled" info instead, preventing
a silent st.error() inside the collapsed Practice Q&A expander
Both smoke and interaction tests now pass clean against demo mode.
BasePage provides navigation, error capture, and interactable discovery
with fnmatch-based expected_failure matching. SettingsPage extends it
with tab-aware discovery. All conftest imports are deferred to method
bodies so the module loads without a live browser fixture.
Add pytest-playwright and pytest-json-report to requirements.txt; create
tests/e2e/ skeleton (modes/, pages/, results/) with __init__.py files and
.gitkeep; add results subdirs to .gitignore.