mantimon-tcg/backend/tests/api/conftest.py
Cal Corum ca3aca2b38 Add has_starter_deck to user profile API response
The frontend routing guard checks has_starter_deck to decide whether to
redirect users to starter selection. The field was missing from the API
response, causing authenticated users with a starter deck to be
incorrectly redirected to /starter on page refresh.

- Add has_starter_deck computed property to User model
- Add has_starter_deck field to UserResponse schema
- Add unit tests for User model properties
- Add API tests for has_starter_deck in profile response

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:14:04 -06:00

135 lines
3.7 KiB
Python

"""Test fixtures for API endpoint tests.
Provides fixtures for testing FastAPI endpoints with mocked dependencies.
"""
from contextlib import asynccontextmanager
from datetime import UTC, datetime
from unittest.mock import MagicMock, patch
from uuid import uuid4
import fakeredis.aioredis
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy.ext.asyncio import AsyncSession
from app.api import deps as api_deps
from app.api.auth import router as auth_router
from app.api.users import router as users_router
from app.db.models import User
from app.services.jwt_service import create_access_token, create_refresh_token
@pytest.fixture
def fake_redis():
"""Provide a fake Redis instance for testing."""
return fakeredis.aioredis.FakeRedis(decode_responses=True)
@pytest.fixture
def mock_get_redis(fake_redis):
"""Mock the get_redis context manager to use fake Redis."""
@asynccontextmanager
async def _mock_get_redis():
yield fake_redis
return _mock_get_redis
@pytest.fixture
def test_user():
"""Create a test user object.
Returns a User model instance that can be used in tests.
The user is not persisted to database.
"""
user = User(
email="test@example.com",
display_name="Test User",
avatar_url="https://example.com/avatar.jpg",
oauth_provider="google",
oauth_id="google-123",
is_premium=False,
premium_until=None,
)
# Manually set the ID since we're not using database
user.id = str(uuid4())
user.created_at = datetime.now(UTC)
user.updated_at = datetime.now(UTC)
user.last_login = None
user.linked_accounts = []
user.decks = [] # No decks by default (no starter selected)
return user
@pytest.fixture
def premium_user(test_user):
"""Create a premium test user."""
from datetime import timedelta
test_user.is_premium = True
test_user.premium_until = datetime.now(UTC) + timedelta(days=30)
return test_user
@pytest.fixture
def access_token(test_user):
"""Create a valid access token for the test user."""
from uuid import UUID
user_id = UUID(test_user.id) if isinstance(test_user.id, str) else test_user.id
return create_access_token(user_id)
@pytest.fixture
def refresh_token_data(test_user):
"""Create a valid refresh token and JTI for the test user."""
from uuid import UUID
user_id = UUID(test_user.id) if isinstance(test_user.id, str) else test_user.id
token, jti = create_refresh_token(user_id)
return {"token": token, "jti": jti, "user_id": user_id}
@pytest.fixture
def mock_db_session():
"""Create a mock database session."""
return MagicMock(spec=AsyncSession)
@pytest.fixture
def app(mock_get_redis, mock_db_session):
"""Create a test FastAPI app with mocked Redis and DB.
This creates a minimal app with just the auth and users routers,
with Redis and database mocked.
"""
# Create test app (no lifespan since we're mocking everything)
test_app = FastAPI()
test_app.include_router(auth_router, prefix="/api")
test_app.include_router(users_router, prefix="/api")
# Override get_db dependency to return mock session
async def override_get_db():
yield mock_db_session
test_app.dependency_overrides[api_deps.get_db] = override_get_db
# Patch get_redis globally for this app
with (
patch("app.api.auth.get_redis", mock_get_redis),
patch("app.services.token_store.get_redis", mock_get_redis),
):
yield test_app
# Clean up overrides
test_app.dependency_overrides.clear()
@pytest.fixture
def client(app):
"""Create a test client for the app."""
return TestClient(app)