"""Tests for notifications API endpoints.""" from datetime import datetime import pytest from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.models.notification import Notification from app.models.user import User @pytest.fixture def test_notification(db: Session, test_user: User) -> Notification: """Create test notification.""" notification = Notification( user_id=test_user.id, type="booking_created", title="Test Notification", message="This is a test notification", is_read=False, created_at=datetime.utcnow(), ) db.add(notification) db.commit() db.refresh(notification) return notification @pytest.fixture def test_read_notification(db: Session, test_user: User) -> Notification: """Create read test notification.""" notification = Notification( user_id=test_user.id, type="booking_approved", title="Read Notification", message="This notification has been read", is_read=True, created_at=datetime.utcnow(), ) db.add(notification) db.commit() db.refresh(notification) return notification @pytest.fixture def other_user_notification(db: Session, test_admin: User) -> Notification: """Create notification for another user.""" notification = Notification( user_id=test_admin.id, type="booking_created", title="Admin Notification", message="This belongs to admin", is_read=False, created_at=datetime.utcnow(), ) db.add(notification) db.commit() db.refresh(notification) return notification def test_get_notifications_for_user( client: TestClient, auth_headers: dict[str, str], test_notification: Notification, test_read_notification: Notification, other_user_notification: Notification, ) -> None: """Test getting all notifications for current user.""" response = client.get("/api/notifications", headers=auth_headers) assert response.status_code == 200 data = response.json() # Should only return notifications for current user assert len(data) == 2 # Should be ordered by created_at DESC (most recent first) notification_ids = [n["id"] for n in data] assert test_notification.id in notification_ids assert test_read_notification.id in notification_ids assert other_user_notification.id not in notification_ids def test_filter_unread_notifications( client: TestClient, auth_headers: dict[str, str], test_notification: Notification, test_read_notification: Notification, ) -> None: """Test filtering notifications by is_read status.""" # Get only unread notifications response = client.get( "/api/notifications", headers=auth_headers, params={"is_read": False}, ) assert response.status_code == 200 data = response.json() assert len(data) == 1 assert data[0]["id"] == test_notification.id assert data[0]["is_read"] is False # Get only read notifications response = client.get( "/api/notifications", headers=auth_headers, params={"is_read": True}, ) assert response.status_code == 200 data = response.json() assert len(data) == 1 assert data[0]["id"] == test_read_notification.id assert data[0]["is_read"] is True def test_mark_notification_as_read( client: TestClient, auth_headers: dict[str, str], test_notification: Notification, ) -> None: """Test marking a notification as read.""" response = client.put( f"/api/notifications/{test_notification.id}/read", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert data["id"] == test_notification.id assert data["is_read"] is True assert data["title"] == "Test Notification" assert data["message"] == "This is a test notification" def test_cannot_mark_others_notification( client: TestClient, auth_headers: dict[str, str], other_user_notification: Notification, ) -> None: """Test that users cannot mark other users' notifications as read.""" response = client.put( f"/api/notifications/{other_user_notification.id}/read", headers=auth_headers, ) assert response.status_code == 403 data = response.json() assert "own notifications" in data["detail"].lower() def test_mark_nonexistent_notification( client: TestClient, auth_headers: dict[str, str], ) -> None: """Test marking a non-existent notification as read.""" response = client.put( "/api/notifications/99999/read", headers=auth_headers, ) assert response.status_code == 404 data = response.json() assert "not found" in data["detail"].lower() def test_get_notifications_without_auth(client: TestClient) -> None: """Test that authentication is required for notifications endpoints.""" response = client.get("/api/notifications") assert response.status_code == 403 response = client.put("/api/notifications/1/read") assert response.status_code == 403