""" Pytest configuration and fixtures for webapp testing. Feature: 012-profile-contact-ui """ import os import sqlite3 import tempfile from typing import Generator import pytest from flask import Flask from flask.testing import FlaskClient # Set test environment variables before importing app os.environ["SECRET_KEY"] = "test-secret-key" os.environ["BACKEND_API_URL"] = "http://test-api:8080/v1" os.environ["HF_CLIENT_ID"] = "test-client-id" os.environ["HF_CLIENT_SECRET"] = "test-client-secret" os.environ["HF_REDIRECT_URI"] = "http://localhost:5000/callback" @pytest.fixture def app() -> Generator[Flask, None, None]: """Create and configure Flask app for testing.""" from webapp.src.app import create_app # Create temporary database file db_fd, db_path = tempfile.mkstemp(suffix=".db") os.environ["DATABASE_PATH"] = db_path # Create app app = create_app() app.config["TESTING"] = True app.config["WTF_CSRF_ENABLED"] = False # Initialize database schema with open("webapp/migrations/001_create_tables.sql", "r") as f: schema = f.read() conn = sqlite3.connect(db_path) conn.executescript(schema) conn.close() yield app # Cleanup os.close(db_fd) os.unlink(db_path) @pytest.fixture def client(app: Flask) -> FlaskClient: """Create test client for making requests.""" return app.test_client() @pytest.fixture def runner(app: Flask): """Create CLI test runner.""" return app.test_cli_runner() @pytest.fixture def authenticated_client(client: FlaskClient, monkeypatch) -> FlaskClient: """Create authenticated test client with mocked OAuth.""" # Mock OAuth flow def mock_authorize_redirect(*args, **kwargs): from flask import redirect return redirect("/callback?code=test-code") def mock_fetch_token(*args, **kwargs): return {"access_token": "test-token", "token_type": "Bearer"} def mock_fetch_userinfo(*args, **kwargs): return { "preferred_username": "testuser", "name": "Test User", "picture": "https://example.com/avatar.jpg", } # Import and patch auth service from webapp.src.services.auth_service import auth_service monkeypatch.setattr(auth_service.hf, "authorize_redirect", mock_authorize_redirect) monkeypatch.setattr(auth_service, "fetch_token", mock_fetch_token) monkeypatch.setattr(auth_service, "fetch_userinfo", mock_fetch_userinfo) # Mock backend API calls def mock_create_session(*args, **kwargs): return { "id": kwargs.get("session_id", "testuser_session"), "user_id": "testuser", "created_at": "2025-01-01T00:00:00Z", } from webapp.src.services import backend_client monkeypatch.setattr( backend_client.backend_client, "create_session", mock_create_session ) # Perform login flow with client.session_transaction() as sess: sess["user_id"] = "testuser" sess["display_name"] = "Test User" sess["profile_picture_url"] = "https://example.com/avatar.jpg" sess["session_id"] = "testuser_session" sess["access_token"] = "test-token" return client @pytest.fixture def test_user_profile(): """Create test user profile data.""" return { "user_id": "testuser", "display_name": "Test User", "profile_picture_url": "https://example.com/avatar.jpg", "session_id": "testuser_session", "created_at": "2025-01-01T00:00:00Z", } @pytest.fixture def test_contact_session(): """Create test contact session data.""" return { "session_id": "testuser_12345678-1234-1234-1234-123456789abc", "user_id": "testuser", "display_name": "Alice Smith", "last_interaction": "2025-01-01T12:00:00Z", "created_at": "2025-01-01T10:00:00Z", } @pytest.fixture def mock_backend_api(monkeypatch): """Mock all backend API calls for testing.""" from webapp.src.services import backend_client class MockBackendAPI: """Mock backend API client.""" def __init__(self): self.sessions = {} self.messages = {} def create_session(self, session_id: str, user_id: str, is_reference: bool = False): self.sessions[session_id] = { "id": session_id, "user_id": user_id, "is_reference": is_reference, "created_at": "2025-01-01T00:00:00Z", } self.messages[session_id] = [] return self.sessions[session_id] def get_session(self, session_id: str): if session_id not in self.sessions: raise backend_client.BackendAPIError(f"Session {session_id} not found") return { **self.sessions[session_id], "messages": self.messages.get(session_id, []), } def send_message(self, session_id: str, content: str, mode: str = "chat", sender: str = "user"): if session_id not in self.messages: self.messages[session_id] = [] message = { "message_id": f"msg_{len(self.messages[session_id])}", "session_id": session_id, "mode": mode, "content": content, "sender": sender if mode == "chat" else None, "created_at": "2025-01-01T12:00:00Z", } self.messages[session_id].append(message) return message def list_sessions(self, user_id: str): return [s for s in self.sessions.values() if s["user_id"] == user_id] def get_messages(self, session_id: str, mode: str = None): messages = self.messages.get(session_id, []) if mode: messages = [m for m in messages if m["mode"] == mode] return messages mock_api = MockBackendAPI() monkeypatch.setattr(backend_client, "backend_client", mock_api) return mock_api