from __future__ import annotations from typing import Callable from fastapi import HTTPException from fastapi.testclient import TestClient from app import app from v1.auth.dependencies import get_auth_service from v1.auth.schemas import ( AuthTokenResponse, AuthUser, LoginRequest, RefreshRequest, SignupRequest, ) from v1.auth.service import AuthService class FakeAuthService(AuthService): def __init__(self, token_response: AuthTokenResponse) -> None: self._token_response = token_response async def signup(self, request: SignupRequest) -> AuthTokenResponse: return self._token_response async def login(self, request: LoginRequest) -> AuthTokenResponse: raise HTTPException(status_code=401, detail="Invalid credentials") async def refresh(self, request: RefreshRequest) -> AuthTokenResponse: raise HTTPException(status_code=401, detail="Invalid refresh token") async def logout(self, refresh_token: str | None) -> None: return None def _override_auth_service(service: AuthService) -> Callable[[], AuthService]: def _get_service() -> AuthService: return service return _get_service def test_signup_returns_token_response() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) app.dependency_overrides[get_auth_service] = _override_auth_service( FakeAuthService(token_response) ) client = TestClient(app) try: response = client.post( "/api/v1/auth/signup", json={"email": "user@example.com", "password": "secret123"}, ) assert response.status_code == 200 body = response.json() assert body["access_token"] == "access" assert body["refresh_token"] == "refresh" assert body["user"]["email"] == "user@example.com" finally: app.dependency_overrides = {} def test_login_invalid_returns_problem_details() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) app.dependency_overrides[get_auth_service] = _override_auth_service( FakeAuthService(token_response) ) client = TestClient(app) try: response = client.post( "/api/v1/auth/login", json={"email": "user@example.com", "password": "wrongpw"}, ) assert response.status_code == 401 assert response.headers["content-type"].startswith("application/problem+json") body = response.json() assert body["title"] == "Unauthorized" assert body["status"] == 401 assert body["detail"] == "Invalid credentials" finally: app.dependency_overrides = {} def test_refresh_invalid_returns_problem_details() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) app.dependency_overrides[get_auth_service] = _override_auth_service( FakeAuthService(token_response) ) client = TestClient(app) try: response = client.post( "/api/v1/auth/refresh", json={"refresh_token": "invalid"}, ) assert response.status_code == 401 assert response.headers["content-type"].startswith("application/problem+json") body = response.json() assert body["title"] == "Unauthorized" assert body["status"] == 401 assert body["detail"] == "Invalid refresh token" finally: app.dependency_overrides = {} def test_logout_returns_no_content() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) app.dependency_overrides[get_auth_service] = _override_auth_service( FakeAuthService(token_response) ) client = TestClient(app) try: response = client.post( "/api/v1/auth/logout", json={"refresh_token": "refresh"}, ) assert response.status_code == 204 assert response.content == b"" finally: app.dependency_overrides = {} def test_signup_validation_error_returns_problem_details() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) app.dependency_overrides[get_auth_service] = _override_auth_service( FakeAuthService(token_response) ) client = TestClient(app) try: response = client.post("/api/v1/auth/signup", json={}) assert response.status_code == 422 assert response.headers["content-type"].startswith("application/problem+json") body = response.json() assert body["title"] == "Unprocessable Content" assert body["status"] == 422 assert body["detail"] == "Invalid request" finally: app.dependency_overrides = {}