"""GET /home — state-aware landing page. The boolean ``users.onboarded`` drives template selection. No auto-transition: the not-onboarded view stays put until the user reloads (the brainstorm called this out explicitly — quiet UI is preferable to a surprise redirect mid-setup). See origin: docs/brainstorms/home-page-requirements.md. """ from __future__ import annotations import tempfile import uuid import pytest @pytest.fixture def fresh_db(monkeypatch): with tempfile.TemporaryDirectory() as tmp: monkeypatch.setenv("DATA_DIR", tmp) monkeypatch.setenv("TESTING", "1") monkeypatch.setenv("JWT_SECRET_KEY", "test-jwt-secret-key-minimum-32-chars!!") yield tmp def _make_user_and_session(conn, email="u@example.com", onboarded=False): from src.repositories.users import UserRepository from app.auth.jwt import create_access_token uid = str(uuid.uuid4()) UserRepository(conn).create(id=uid, email=email, name=email.split("@")[0]) if onboarded: conn.execute("UPDATE users SET onboarded = TRUE WHERE id = ?", [uid]) return uid, create_access_token(user_id=uid, email=email) def _client(follow_redirects: bool = True): from fastapi.testclient import TestClient from app.main import app return TestClient(app, follow_redirects=follow_redirects) def test_home_unauth_redirects_to_login(fresh_db): """Non-API HTML routes redirect 401→/login per app.main's StarletteHTTPException handler. /home follows that contract.""" c = _client(follow_redirects=False) resp = c.get("/home") assert resp.status_code == 302 assert resp.headers["location"].startswith("/login") def test_home_not_onboarded_user_sees_setup_view(fresh_db): """A FALSE-onboarded user gets the install/setup template, identifiable by its 'Install Claude Code' heading and the self-mark button.""" from src.db import get_system_db, close_system_db conn = get_system_db() try: _, sess = _make_user_and_session(conn, onboarded=False) finally: conn.close() close_system_db() c = _client() resp = c.get("/home", cookies={"access_token": sess}) assert resp.status_code == 200 body = resp.text assert "install Claude Code" in body # step 1 label assert "install Agnes" in body # step 2 label assert "self-mark-btn" in body # self-acknowledged escape hatch assert "setupClaudeBtn" in body # primary one-click CTA from shared partial def test_home_onboarded_user_sees_nav_hub(fresh_db): """A TRUE-onboarded user gets the post-onboarding view: the blue install-hero is gone entirely (no welcome banner, no completion badge, no inline step commands), the offboard escape strip is the only setup-flow remnant rendered, and the rest of /home (connector tiles, news, etc.) stays. PR #289 collapsed the dual-state hero into a single not-onboarded-only render — pre-PR the onboarded branch reused the same `.install-hero` shell with welcome copy and a "Steps 1–4 done" badge.""" from src.db import get_system_db, close_system_db conn = get_system_db() try: _, sess = _make_user_and_session(conn, onboarded=True) finally: conn.close() close_system_db() c = _client() resp = c.get("/home", cookies={"access_token": sess}) assert resp.status_code == 200 body = resp.text # Install hero entirely absent for onboarded users. assert '