from __future__ import annotations from pathlib import Path import pytest from fastapi.testclient import TestClient from chat.app import app from chat.eventlog.log import append_event from chat.eventlog.projector import project @pytest.fixture def client(tmp_path, monkeypatch): config_path = tmp_path / "config.toml" config_path.write_text('featherless_api_key = "test"\n') monkeypatch.setenv("CHAT_CONFIG_PATH", str(config_path)) monkeypatch.setenv("CHAT_DB_PATH", str(tmp_path / "test.db")) with TestClient(app) as c: yield c def _author_bot_and_chat(db_path: Path, bot_id: str = "bot_a") -> None: """Insert a bot and a chat directly via the event log (skip kickoff route).""" from chat.db.connection import open_db with open_db(db_path) as conn: append_event( conn, kind="bot_authored", payload={ "id": bot_id, "name": "BotA", "persona": "thoughtful, observant", "voice_samples": [], "traits": ["shy"], "backstory": "", "initial_relationship_to_you": "coworker", "kickoff_prose": "you stay late at the office; she's there too", }, ) append_event( conn, kind="chat_created", payload={ "id": f"chat_{bot_id}", "host_bot_id": bot_id, "initial_time": "2026-04-26T20:00:00+00:00", "narrative_anchor": "Day 1", "weather": "", }, ) project(conn) def test_root_redirects_to_chats(client): response = client.get("/", follow_redirects=False) assert response.status_code == 303 assert response.headers["location"] == "/chats" def test_chats_list_empty_state(client): response = client.get("/chats") assert response.status_code == 200 body = response.text.lower() # Empty state should mention there are no chats yet. assert "no chats yet" in body def test_chats_list_renders_existing_chats(client, tmp_path): _author_bot_and_chat(tmp_path / "test.db", "bot_a") response = client.get("/chats") assert response.status_code == 200 body = response.text # The bot's display name should appear in the chat row. assert "BotA" in body # The chat's in-fiction time should appear in the meta. assert "2026-04-26T20:00:00+00:00" in body def test_existing_template_routes_still_work_with_new_layout(client): # Smoke test the layout reshuffle didn't break the existing pages. for path in ("/bots", "/bots/new", "/settings"): response = client.get(path) assert response.status_code == 200, f"{path} returned {response.status_code}" body = response.text # Each page should now show the persistent left-rail brand link. assert 'class="rail"' in body or "rail-brand" in body