annator-command-center / tests /mobile_api /test_mobile_auth.py
techprotrade's picture
Deploy ATOM FastAPI command center runtime (part 8)
aef804e verified
Raw
History Blame Contribute Delete
7.16 kB
"""
Mobile API Authentication Tests
Tests for mobile API authentication endpoints:
- Login success and failure
- Token refresh
- Token validation (/api/auth/me)
- Logout
All tests use API-first approach with TestClient (no browser).
Response structure matches web API for consistency.
"""
import pytest
from fastapi.testclient import TestClient
class TestMobileLogin:
"""Test mobile login endpoint"""
def test_mobile_login_success(self, mobile_api_client: TestClient, mobile_test_user):
"""Test successful login with valid credentials"""
# Login with valid credentials
response = mobile_api_client.post("/api/auth/login", json={
"username": mobile_test_user.email,
"password": "MobileTest123!"
})
# Verify response
assert response.status_code == 200
data = response.json()
# Verify token structure
assert "access_token" in data
assert isinstance(data["access_token"], str)
assert len(data["access_token"]) > 0
# Verify token type
assert data.get("token_type") == "bearer"
# Verify expires_in field (if present)
if "expires_in" in data:
assert isinstance(data["expires_in"], int)
assert data["expires_in"] > 0
def test_mobile_login_invalid_credentials(self, mobile_api_client: TestClient):
"""Test login with invalid credentials returns 401"""
response = mobile_api_client.post("/api/auth/login", json={
"username": "nonexistent@example.com",
"password": "WrongPassword123!"
})
# Verify error response
assert response.status_code == 401
data = response.json()
# Verify error message
assert "detail" in data
# Verify access_token NOT in response
assert "access_token" not in data
def test_mobile_login_wrong_password(self, mobile_api_client: TestClient, mobile_test_user):
"""Test login with correct email but wrong password"""
response = mobile_api_client.post("/api/auth/login", json={
"username": mobile_test_user.email,
"password": "WrongPassword123!"
})
# Verify error response
assert response.status_code == 401
assert "access_token" not in response.json()
class TestMobileTokenRefresh:
"""Test mobile token refresh endpoint"""
def test_mobile_token_refresh(self, mobile_api_client: TestClient, mobile_auth_headers: dict):
"""Test token refresh returns new access token"""
# Get old token from headers
old_token = mobile_auth_headers["Authorization"].replace("Bearer ", "")
# Refresh token
response = mobile_api_client.post("/api/auth/refresh", headers=mobile_auth_headers)
# Verify response
assert response.status_code == 200
data = response.json()
# Verify new token returned
assert "access_token" in data
assert isinstance(data["access_token"], str)
assert len(data["access_token"]) > 0
# Verify new token differs from old token
new_token = data["access_token"]
assert new_token != old_token
# Verify token type
assert data.get("token_type") == "bearer"
class TestMobileTokenValidation:
"""Test mobile token validation via /api/auth/me"""
def test_mobile_token_validation(self, mobile_api_client: TestClient, mobile_auth_headers: dict, mobile_test_user):
"""Test token validation returns user data"""
# Get current user info
response = mobile_api_client.get("/api/auth/me", headers=mobile_auth_headers)
# Verify response
assert response.status_code == 200
data = response.json()
# Verify user data fields
assert "id" in data
assert "email" in data
assert data["email"] == mobile_test_user.email
# Verify role or status field (if present)
if "role" in data:
assert data["role"] is not None
if "status" in data:
assert data["status"] is not None
def test_mobile_token_validation_without_auth(self, mobile_api_client: TestClient):
"""Test token validation fails without auth header"""
response = mobile_api_client.get("/api/auth/me")
# Verify unauthorized response
assert response.status_code == 401
def test_mobile_token_validation_invalid_token(self, mobile_api_client: TestClient):
"""Test token validation fails with invalid token"""
response = mobile_api_client.get("/api/auth/me", headers={
"Authorization": "Bearer invalid_token_12345"
})
# Verify unauthorized response
assert response.status_code == 401
class TestMobileLogout:
"""Test mobile logout endpoint"""
def test_mobile_logout(self, mobile_api_client: TestClient, mobile_auth_headers: dict):
"""Test logout invalidates token"""
# Logout
response = mobile_api_client.post("/api/auth/logout", headers=mobile_auth_headers)
# Verify logout response
assert response.status_code == 200
data = response.json()
# Verify success message
assert "success" in data or "message" in data
# Note: JWT tokens are stateless, so logout is client-side
# The server logs the logout event but doesn't invalidate the token
# Subsequent requests will still work until token expires
def test_mobile_logout_without_auth(self, mobile_api_client: TestClient):
"""Test logout requires authentication"""
response = mobile_api_client.post("/api/auth/logout")
# Verify unauthorized response
assert response.status_code == 401
class TestMobileAuthResponseStructure:
"""Test mobile auth responses match web API structure"""
def test_mobile_login_response_structure(self, mobile_api_client: TestClient, mobile_test_user):
"""Test login response structure matches web API"""
response = mobile_api_client.post("/api/auth/login", json={
"username": mobile_test_user.email,
"password": "MobileTest123!"
})
data = response.json()
# Verify expected fields present
expected_fields = ["access_token", "token_type"]
for field in expected_fields:
assert field in data, f"Missing field: {field}"
# Verify field types
assert isinstance(data["access_token"], str)
assert isinstance(data["token_type"], str)
def test_mobile_me_response_structure(self, mobile_api_client: TestClient, mobile_auth_headers: dict):
"""Test /api/auth/me response structure matches web API"""
response = mobile_api_client.get("/api/auth/me", headers=mobile_auth_headers)
data = response.json()
# Verify expected fields present
expected_fields = ["id", "email"]
for field in expected_fields:
assert field in data, f"Missing field: {field}"
# Verify field types
assert isinstance(data["id"], str)
assert isinstance(data["email"], str)