""" Conftest для E2E тестов Team Board API Содержит фикстуры для подключения к API и создания тестовых данных """ import pytest import pytest_asyncio import httpx import uuid from typing import Dict, Any, Optional @pytest.fixture(scope="session") def base_url(): """Базовый URL для API""" return "http://localhost:8100/api/v1" @pytest_asyncio.fixture async def admin_token(base_url: str) -> str: """Получает JWT токен администратора""" async with httpx.AsyncClient() as client: response = await client.post(f"{base_url}/auth/login", json={ "login": "admin", "password": "teamboard" }) assert response.status_code == 200 data = response.json() return data["token"] @pytest.fixture def agent_token(): """Bearer токен для агента из документации""" return "tb-coder-dev-token" @pytest.fixture def http_client(base_url: str, admin_token: str): """HTTP клиент с авторизацией для админа""" headers = {"Authorization": f"Bearer {admin_token}"} return httpx.AsyncClient(base_url=base_url, headers=headers, timeout=30.0) @pytest.fixture def agent_client(base_url: str, agent_token: str): """HTTP клиент с авторизацией для агента""" headers = {"Authorization": f"Bearer {agent_token}"} return httpx.AsyncClient(base_url=base_url, headers=headers, timeout=30.0) @pytest_asyncio.fixture async def test_project(http_client: httpx.AsyncClient) -> Dict[str, Any]: """Создаёт тестовый проект и удаляет его после теста""" project_slug = f"test-project-{uuid.uuid4().hex[:8]}" project_data = { "name": f"Test Project {project_slug}", "slug": project_slug, "description": "Test project for E2E tests", "repo_urls": ["https://github.com/test/repo"] } response = await http_client.post("/projects", json=project_data) assert response.status_code == 201 project = response.json() yield project # Cleanup - удаляем проект await http_client.delete(f"/projects/{project['id']}") @pytest_asyncio.fixture async def test_user(http_client: httpx.AsyncClient) -> Dict[str, Any]: """Создаёт тестового пользователя и удаляет его после теста""" user_slug = f"test-user-{uuid.uuid4().hex[:8]}" user_data = { "name": f"Test User {user_slug}", "slug": user_slug, "type": "human", "role": "member" } response = await http_client.post("/members", json=user_data) assert response.status_code == 201 user = response.json() yield user # Cleanup - помечаем пользователя неактивным await http_client.delete(f"/members/{user['id']}") @pytest_asyncio.fixture async def test_agent(http_client: httpx.AsyncClient) -> Dict[str, Any]: """Создаёт тестового агента и удаляет его после теста""" agent_slug = f"test-agent-{uuid.uuid4().hex[:8]}" agent_data = { "name": f"Test Agent {agent_slug}", "slug": agent_slug, "type": "agent", "role": "member", "agent_config": { "capabilities": ["coding", "testing"], "labels": ["backend", "python"], "chat_listen": "mentions", "task_listen": "assigned", "prompt": "Test agent for E2E tests" } } response = await http_client.post("/members", json=agent_data) assert response.status_code == 201 agent = response.json() yield agent # Cleanup await http_client.delete(f"/members/{agent['id']}") @pytest_asyncio.fixture async def test_task(http_client: httpx.AsyncClient, test_project: Dict[str, Any]) -> Dict[str, Any]: """Создаёт тестовую задачу в проекте""" task_data = { "title": "Test Task", "description": "Test task for E2E tests", "type": "task", "status": "backlog", "priority": "medium" } response = await http_client.post(f"/tasks?project_id={test_project['id']}", json=task_data) assert response.status_code == 201 task = response.json() yield task # Cleanup - задача удалится вместе с проектом @pytest_asyncio.fixture async def test_label(http_client: httpx.AsyncClient) -> Dict[str, Any]: """Создаёт тестовый лейбл""" label_slug = f"test-label-{uuid.uuid4().hex[:8]}" label_data = { "name": label_slug, "color": "#ff5733" } response = await http_client.post("/labels", json=label_data) assert response.status_code == 201 label = response.json() yield label # Cleanup await http_client.delete(f"/labels/{label['id']}") def assert_uuid(value: str): """Проверяет что строка является валидным UUID""" try: uuid.UUID(value) except (ValueError, TypeError): pytest.fail(f"'{value}' is not a valid UUID") def assert_timestamp(value: str): """Проверяет что строка является валидным ISO timestamp""" import datetime try: datetime.datetime.fromisoformat(value.replace('Z', '+00:00')) except ValueError: pytest.fail(f"'{value}' is not a valid ISO timestamp")