""" Sprint 8 Tests: Edit/regenerate, clear conversation, truncate, reconnect banner fix, syntax highlight. """ import json, pathlib, urllib.error, urllib.parse, urllib.request from tests._pytest_port import BASE def get(path): with urllib.request.urlopen(BASE + path, timeout=10) as r: return json.loads(r.read()) def post(path, body=None): data = json.dumps(body or {}).encode() req = urllib.request.Request(BASE + path, data=data, headers={"Content-Type": "application/json"}) try: with urllib.request.urlopen(req, timeout=10) as r: return json.loads(r.read()), r.status except urllib.error.HTTPError as e: return json.loads(e.read()), e.code def make_session_tracked(created_list): d, _ = post("/api/session/new", {}) sid = d["session"]["session_id"] created_list.append(sid) return sid # ── /api/session/clear ───────────────────────────────────────────── def test_session_clear_requires_session_id(cleanup_test_sessions): data, status = post("/api/session/clear", {}) assert status == 400 def test_session_clear_unknown_session_404(cleanup_test_sessions): data, status = post("/api/session/clear", {"session_id": "nonexistent_xyz"}) assert status == 404 def test_session_clear_wipes_messages(cleanup_test_sessions): created = [] sid = make_session_tracked(created) # Inject a fake message directly into the session via rename (to give it a title first) post("/api/session/rename", {"session_id": sid, "title": "clear-test"}) # Manually load and verify session exists sess = get(f"/api/session?session_id={urllib.parse.quote(sid)}") assert sess["session"]["session_id"] == sid # Clear it data, status = post("/api/session/clear", {"session_id": sid}) assert status == 200, f"Expected 200, got {status}: {data}" assert data.get("ok") is True assert data.get("session") is not None # Load again and verify messages empty sess2 = get(f"/api/session?session_id={urllib.parse.quote(sid)}") assert sess2["session"]["messages"] == [] assert sess2["session"]["title"] == "Untitled" # Cleanup post("/api/session/delete", {"session_id": sid}) def test_session_clear_returns_session_compact(cleanup_test_sessions): created = [] sid = make_session_tracked(created) data, status = post("/api/session/clear", {"session_id": sid}) assert status == 200 assert "session" in data assert data["session"]["session_id"] == sid post("/api/session/delete", {"session_id": sid}) # ── /api/session/truncate ────────────────────────────────────────── def test_session_truncate_requires_session_id(cleanup_test_sessions): data, status = post("/api/session/truncate", {"keep_count": 2}) assert status == 400 def test_session_truncate_requires_keep_count(cleanup_test_sessions): data, status = post("/api/session/truncate", {"session_id": "xyz"}) assert status == 400 def test_session_truncate_unknown_session_404(cleanup_test_sessions): data, status = post("/api/session/truncate", {"session_id": "nonexistent_xyz", "keep_count": 0}) assert status == 404 def test_session_truncate_returns_messages(cleanup_test_sessions): created = [] sid = make_session_tracked(created) data, status = post("/api/session/truncate", {"session_id": sid, "keep_count": 0}) assert status == 200 assert data.get("ok") is True assert "messages" in data["session"] assert data["session"]["messages"] == [] post("/api/session/delete", {"session_id": sid}) # ── Static files contain new features ───────────────────────────── def test_app_js_contains_edit_message(cleanup_test_sessions): """Verify editMessage function is present in ui.js (Sprint 9: module split).""" with urllib.request.urlopen(BASE + "/static/ui.js", timeout=10) as r: src = r.read().decode() assert "editMessage" in src assert "msg-edit-area" in src def test_app_js_contains_regenerate(cleanup_test_sessions): with urllib.request.urlopen(BASE + "/static/ui.js", timeout=10) as r: src = r.read().decode() assert "regenerateResponse" in src def test_app_js_contains_clear_conversation(cleanup_test_sessions): with urllib.request.urlopen(BASE + "/static/panels.js", timeout=10) as r: src = r.read().decode() assert "clearConversation" in src assert "api/session/clear" in src def test_app_js_contains_highlight_code(cleanup_test_sessions): with urllib.request.urlopen(BASE + "/static/ui.js", timeout=10) as r: src = r.read().decode() assert "highlightCode" in src assert "Prism" in src def test_index_html_contains_prism(cleanup_test_sessions): with urllib.request.urlopen(BASE + "/", timeout=10) as r: src = r.read().decode() assert "prismjs" in src.lower() def test_index_html_contains_clear_button(cleanup_test_sessions): with urllib.request.urlopen(BASE + "/", timeout=10) as r: src = r.read().decode() assert "btnClearConv" in src assert "clearConversation" in src