"""Integration tests for sidebar stats endpoint.""" import pytest from httpx import AsyncClient class TestSidebarStats: """Tests for GET /sessions/sidebar-stats.""" @pytest.mark.asyncio async def test_sidebar_stats_no_sessions( self, client: AsyncClient, auth_headers: dict ): """Empty stats when user has no sessions.""" response = await client.get( "/api/v1/sessions/sidebar-stats?tz_offset=0", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert data["resolved_today"] == 0 assert data["active_count"] == 0 assert data["total_session_minutes_today"] == 0 assert data["active_sessions"] == [] assert data["recent_completions"] == [] assert "tree_counts" in data @pytest.mark.asyncio async def test_sidebar_stats_with_active_session( self, client: AsyncClient, auth_headers: dict, test_tree: dict ): """Active session appears in activity feed.""" create_resp = await client.post( "/api/v1/sessions", json={"tree_id": test_tree["id"], "ticket_number": "TK-100"}, headers=auth_headers, ) assert create_resp.status_code == 201 response = await client.get( "/api/v1/sessions/sidebar-stats?tz_offset=0", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert data["active_count"] == 1 assert len(data["active_sessions"]) == 1 assert data["active_sessions"][0]["ticket_number"] == "TK-100" assert data["active_sessions"][0]["tree_id"] == test_tree["id"] @pytest.mark.asyncio async def test_sidebar_stats_resolved_today( self, client: AsyncClient, auth_headers: dict, test_tree: dict ): """Resolved session counts in resolved_today.""" create_resp = await client.post( "/api/v1/sessions", json={"tree_id": test_tree["id"]}, headers=auth_headers, ) session_id = create_resp.json()["id"] # Complete with resolved outcome await client.post( f"/api/v1/sessions/{session_id}/complete", json={"outcome": "resolved", "outcome_notes": "Fixed it"}, headers=auth_headers, ) response = await client.get( "/api/v1/sessions/sidebar-stats?tz_offset=0", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert data["resolved_today"] >= 1 assert data["active_count"] == 0 assert len(data["recent_completions"]) >= 1 @pytest.mark.asyncio async def test_sidebar_stats_max_active_sessions( self, client: AsyncClient, auth_headers: dict, test_tree: dict ): """Active sessions capped at 5.""" for i in range(7): await client.post( "/api/v1/sessions", json={"tree_id": test_tree["id"], "ticket_number": f"TK-{i}"}, headers=auth_headers, ) response = await client.get( "/api/v1/sessions/sidebar-stats?tz_offset=0", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert data["active_count"] == 7 assert len(data["active_sessions"]) == 5 @pytest.mark.asyncio async def test_sidebar_stats_recent_completions_max_3( self, client: AsyncClient, auth_headers: dict, test_tree: dict ): """Recent completions capped at 3.""" for i in range(5): create_resp = await client.post( "/api/v1/sessions", json={"tree_id": test_tree["id"]}, headers=auth_headers, ) session_id = create_resp.json()["id"] await client.post( f"/api/v1/sessions/{session_id}/complete", json={"outcome": "resolved", "outcome_notes": "Done"}, headers=auth_headers, ) response = await client.get( "/api/v1/sessions/sidebar-stats?tz_offset=0", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert len(data["recent_completions"]) == 3 @pytest.mark.asyncio async def test_sidebar_stats_requires_auth(self, client: AsyncClient): """Endpoint requires authentication.""" response = await client.get("/api/v1/sessions/sidebar-stats?tz_offset=0") assert response.status_code == 401 @pytest.mark.asyncio async def test_sidebar_stats_requires_tz_offset( self, client: AsyncClient, auth_headers: dict ): """tz_offset query param is required.""" response = await client.get( "/api/v1/sessions/sidebar-stats", headers=auth_headers, ) assert response.status_code == 422