"""Notification tests — ACs 24-26: list, mark read, unread count.""" from __future__ import annotations from datetime import UTC, datetime import pytest from httpx import AsyncClient from app.core.notifications import create_notification from app.models.notification import Notification from tests.conftest import ORIGIN_HEADER, login_client, seed_tenant_and_users @pytest.mark.asyncio class TestNotifications: """ACs 24-26: Notification list, mark read, unread count.""" async def test_list_notifications_returns_200(self, client: AsyncClient, db_session): """AC 24: GET /api/v1/notifications -> 200 + unread first.""" seed = await seed_tenant_and_users(db_session) # Create some notifications for admin_a await create_notification( db_session, seed["tenant_a"].id, seed["admin_a"].id, "info", "Read Notif", "Already read", ) await db_session.flush() # Mark the first one as read from sqlalchemy import select q = select(Notification).where(Notification.title == "Read Notif") result = await db_session.execute(q) first_notif = result.scalar_one() first_notif.read_at = datetime.now(UTC) await db_session.flush() # Create an unread one await create_notification( db_session, seed["tenant_a"].id, seed["admin_a"].id, "info", "Unread Notif", "Not read yet", ) await db_session.commit() await login_client(client, "admin@tenanta.com") resp = await client.get("/api/v1/notifications") assert resp.status_code == 200 data = resp.json() assert "items" in data assert "total" in data # Unread should come first items = data["items"] if len(items) >= 2: # Find the unread and read ones unread = [i for i in items if i["read_at"] is None] read = [i for i in items if i["read_at"] is not None] if unread and read: # Unread should appear before read in the list unread_idx = items.index(unread[0]) read_idx = items.index(read[0]) assert unread_idx < read_idx async def test_mark_notification_read_returns_200(self, client: AsyncClient, db_session): """AC 25: PATCH /api/v1/notifications/{id}/read -> 200.""" seed = await seed_tenant_and_users(db_session) notif = await create_notification( db_session, seed["tenant_a"].id, seed["admin_a"].id, "info", "Test Notif", "Test body", ) await db_session.commit() await login_client(client, "admin@tenanta.com") resp = await client.patch( f"/api/v1/notifications/{notif.id}/read", headers=ORIGIN_HEADER, ) assert resp.status_code == 200 assert resp.json()["read_at"] is not None async def test_unread_count_returns_200_with_integer(self, client: AsyncClient, db_session): """AC 26: GET /api/v1/notifications/unread-count -> 200 + integer count.""" seed = await seed_tenant_and_users(db_session) await create_notification( db_session, seed["tenant_a"].id, seed["admin_a"].id, "info", "Unread 1", "Body 1", ) await create_notification( db_session, seed["tenant_a"].id, seed["admin_a"].id, "info", "Unread 2", "Body 2", ) await db_session.commit() await login_client(client, "admin@tenanta.com") resp = await client.get("/api/v1/notifications/unread-count") assert resp.status_code == 200 data = resp.json() assert "count" in data assert isinstance(data["count"], int) assert data["count"] >= 2