"""Tests for auth endpoints: login, refresh, me.""" import pytest from httpx import AsyncClient from app.models.user import User from app.utils.jwt import create_access_token, create_refresh_token @pytest.mark.asyncio async def test_login_valid_credentials(client: AsyncClient, admin_user: User): """POST /api/v1/auth/login with valid credentials returns 200 + JWT.""" response = await client.post("/api/v1/auth/login", json={ "email": "admin@test.com", "password": "Admin12345!", }) assert response.status_code == 200 data = response.json() assert "access_token" in data assert "refresh_token" in data assert data["token_type"] == "bearer" assert data["expires_in"] > 0 @pytest.mark.asyncio async def test_login_invalid_password(client: AsyncClient, admin_user: User): """POST /api/v1/auth/login with wrong password returns 401.""" response = await client.post("/api/v1/auth/login", json={ "email": "admin@test.com", "password": "WrongPassword!", }) assert response.status_code == 401 data = response.json() assert "error" in data["detail"] @pytest.mark.asyncio async def test_login_nonexistent_user(client: AsyncClient): """POST /api/v1/auth/login with unknown email returns 401.""" response = await client.post("/api/v1/auth/login", json={ "email": "nobody@test.com", "password": "SomePassword!", }) assert response.status_code == 401 @pytest.mark.asyncio async def test_login_inactive_user(client: AsyncClient, inactive_user: User): """POST /api/v1/auth/login with deactivated account returns 401.""" response = await client.post("/api/v1/auth/login", json={ "email": "inactive@test.com", "password": "Inactive123!", }) assert response.status_code == 401 @pytest.mark.asyncio async def test_login_invalid_email_format(client: AsyncClient): """POST /api/v1/auth/login with invalid email format returns 422.""" response = await client.post("/api/v1/auth/login", json={ "email": "not-an-email", "password": "SomePassword!", }) assert response.status_code == 422 @pytest.mark.asyncio async def test_refresh_valid_token(client: AsyncClient, admin_user: User): """POST /api/v1/auth/refresh with valid refresh token returns new tokens.""" refresh_token = create_refresh_token( user_id=str(admin_user.id), role="admin", email=admin_user.email, lang=admin_user.language, ) response = await client.post("/api/v1/auth/refresh", json={ "refresh_token": refresh_token, }) assert response.status_code == 200 data = response.json() assert "access_token" in data assert "refresh_token" in data assert data["token_type"] == "bearer" @pytest.mark.asyncio async def test_refresh_invalid_token(client: AsyncClient): """POST /api/v1/auth/refresh with invalid token returns 401.""" response = await client.post("/api/v1/auth/refresh", json={ "refresh_token": "invalid.token.here", }) assert response.status_code == 401 @pytest.mark.asyncio async def test_refresh_access_token_rejected(client: AsyncClient, admin_user: User): """POST /api/v1/auth/refresh with an access token (not refresh) returns 401.""" access_token = create_access_token( user_id=str(admin_user.id), role="admin", email=admin_user.email, lang=admin_user.language, ) response = await client.post("/api/v1/auth/refresh", json={ "refresh_token": access_token, }) assert response.status_code == 401 @pytest.mark.asyncio async def test_get_me_with_valid_token(client: AsyncClient, admin_user: User, admin_token: str): """GET /api/v1/auth/me with valid JWT returns 200 + user object.""" response = await client.get( "/api/v1/auth/me", headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 data = response.json() assert data["email"] == "admin@test.com" assert data["role"] == "admin" assert data["is_active"] is True assert "password_hash" not in data @pytest.mark.asyncio async def test_get_me_without_token(client: AsyncClient): """GET /api/v1/auth/me without token returns 401.""" response = await client.get("/api/v1/auth/me") assert response.status_code == 401 @pytest.mark.asyncio async def test_get_me_with_invalid_token(client: AsyncClient): """GET /api/v1/auth/me with invalid token returns 401.""" response = await client.get( "/api/v1/auth/me", headers={"Authorization": "Bearer invalid.token.here"}, ) assert response.status_code == 401 @pytest.mark.asyncio async def test_get_me_with_refresh_token(client: AsyncClient, admin_user: User): """GET /api/v1/auth/me with a refresh token (not access) returns 401.""" refresh_token = create_refresh_token( user_id=str(admin_user.id), role="admin", email=admin_user.email, lang=admin_user.language, ) response = await client.get( "/api/v1/auth/me", headers={"Authorization": f"Bearer {refresh_token}"}, ) assert response.status_code == 401