from __future__ import annotations import pytest import v1.auth.gateway as auth_gateway_module from v1.auth.schemas import ( AuthUser, SessionCreateRequest, SessionRefreshRequest, SessionResponse, UserByEmailResponse, VerificationCreateRequest, VerificationCreateResponse, VerificationResendRequest, VerificationVerifyRequest, ) from v1.auth.service import AuthService, AuthServiceGateway class FakeGateway(AuthServiceGateway): def __init__(self, response: SessionResponse) -> None: self._response = response async def create_verification( self, request: VerificationCreateRequest ) -> VerificationCreateResponse: return VerificationCreateResponse(email=request.email) async def verify_verification( self, request: VerificationVerifyRequest ) -> SessionResponse: return self._response async def resend_verification(self, request: VerificationResendRequest) -> None: return None async def create_session(self, request: SessionCreateRequest) -> SessionResponse: return self._response async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse: return self._response async def delete_session(self, refresh_token: str | None) -> None: return None async def get_user_by_email(self, email: str) -> UserByEmailResponse: return UserByEmailResponse( id="user-1", email=email, created_at="2026-02-24T00:00:00Z", email_confirmed_at=None, ) @pytest.mark.asyncio async def test_signup_maps_response() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = SessionResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) service = AuthService(gateway=FakeGateway(token_response)) start_result = await service.create_verification( VerificationCreateRequest( username="demo", email="user@example.com", password="secret123" ) ) assert start_result.email == "user@example.com" result = await service.verify_verification( VerificationVerifyRequest(email="user@example.com", token="123456") ) assert result.access_token == "access" assert result.refresh_token == "refresh" assert result.user.id == "user-1" class LogoutAssertingGateway(AuthServiceGateway): def __init__(self, expected_refresh_token: str) -> None: self._expected_refresh_token = expected_refresh_token async def create_verification( self, request: VerificationCreateRequest ) -> VerificationCreateResponse: raise NotImplementedError async def verify_verification( self, request: VerificationVerifyRequest ) -> SessionResponse: raise NotImplementedError async def resend_verification(self, request: VerificationResendRequest) -> None: raise NotImplementedError async def create_session(self, request: SessionCreateRequest) -> SessionResponse: raise NotImplementedError async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse: raise NotImplementedError async def delete_session(self, refresh_token: str | None) -> None: assert refresh_token == self._expected_refresh_token async def get_user_by_email(self, email: str) -> UserByEmailResponse: raise NotImplementedError @pytest.mark.asyncio async def test_logout_forwards_refresh_token() -> None: service = AuthService(gateway=LogoutAssertingGateway("refresh-token")) await service.delete_session("refresh-token") @pytest.mark.asyncio async def test_get_user_by_email_forwards_to_gateway() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = SessionResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) service = AuthService(gateway=FakeGateway(token_response)) result = await service.get_user_by_email("user@example.com") assert result.email == "user@example.com" @pytest.mark.asyncio async def test_signup_resend_returns_none() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = SessionResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) service = AuthService(gateway=FakeGateway(token_response)) result = await service.resend_verification( VerificationResendRequest(email="user@example.com") ) assert result is None @pytest.mark.asyncio async def test_supabase_signup_passes_username_in_metadata( monkeypatch: pytest.MonkeyPatch, ) -> None: captured_payload: dict[str, object] = {} class FakeSupabaseAuth: def sign_up(self, payload: dict[str, object]) -> object: captured_payload.update(payload) class _User: id = "user-1" email = "user@example.com" class _Session: access_token = "access" refresh_token = "refresh" expires_in = 3600 token_type = "bearer" class _Response: user = _User() session = None return _Response() class FakeClient: auth = FakeSupabaseAuth() monkeypatch.setattr(auth_gateway_module, "create_client", lambda *_: FakeClient()) gateway = auth_gateway_module.SupabaseAuthGateway() await gateway.create_verification( VerificationCreateRequest( username="demo", email="user@example.com", password="secret123", ) ) assert captured_payload["data"] == {"username": "demo"}