diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py index e4d1af2..0a80b33 100644 --- a/tests/e2e/conftest.py +++ b/tests/e2e/conftest.py @@ -17,6 +17,21 @@ from kwork_api import KworkClient load_dotenv(Path(__file__).parent / ".env") +class E2EClient: + """Wrapper for KworkClient that manages event loop lifecycle.""" + + def __init__(self, client: KworkClient): + self.client = client + self.loop = asyncio.new_event_loop() + + def __getattr__(self, name): + return getattr(self.client, name) + + def close(self): + self.loop.run_until_complete(self.client.close()) + self.loop.close() + + @pytest.fixture(scope="session") def kwork_credentials(): """Credentials для тестового аккаунта.""" @@ -44,7 +59,7 @@ def e2e_client(require_credentials): Используется во всех тестах кроме test_auth.py (там тестируем сам логин). """ - import asyncio + loop = asyncio.new_event_loop() async def create(): return await KworkClient.login( @@ -52,9 +67,11 @@ def e2e_client(require_credentials): password=require_credentials["password"], ) - client = asyncio.new_event_loop().run_until_complete(create()) - yield client - asyncio.new_event_loop().run_until_complete(client.close()) + client = loop.run_until_complete(create()) + wrapper = E2EClient(client) + yield wrapper + wrapper.close() + loop.close() @pytest.fixture(scope="module") @@ -64,15 +81,13 @@ def catalog_kwork_id(e2e_client): Выполняется ОДИН РАЗ в начале модуля и переиспользуется. """ - import asyncio - async def get(): catalog = await e2e_client.catalog.get_list(page=1) if len(catalog.kworks) > 0: return catalog.kworks[0].id return None - return asyncio.new_event_loop().run_until_complete(get()) + return e2e_client.loop.run_until_complete(get()) @pytest.fixture(scope="function") diff --git a/tests/e2e/test_catalog.py b/tests/e2e/test_catalog.py index 1709e0d..e0af9a5 100644 --- a/tests/e2e/test_catalog.py +++ b/tests/e2e/test_catalog.py @@ -1,15 +1,13 @@ """ E2E тесты для каталога и проектов. -Используют session-scoped e2e_client fixture - логин ОДИН РАЗ для всех тестов. +Используют module-scoped e2e_client fixture - логин ОДИН РАЗ для всех тестов модуля. Все тесты read-only - ничего не изменяют на сервере. Endpoints основаны на HAR анализе (mitmproxy + har-analyzer skill). """ import pytest -from kwork_api import KworkClient - @pytest.mark.e2e async def test_get_catalog_list(e2e_client): @@ -18,7 +16,7 @@ async def test_get_catalog_list(e2e_client): HAR: POST https://api.kwork.ru/catalogMainv2 """ # Первая страница каталога - catalog = await e2e_client.catalog.get_list(page=1) + catalog = await e2e_client.client.client.catalog.get_list(page=1) assert catalog is not None # API может вернуть пустой список (это нормально) @@ -41,7 +39,7 @@ async def test_get_kwork_details(e2e_client, catalog_kwork_id): pytest.skip("Catalog is empty") # Получаем детали - details = await e2e_client.catalog.get_details(catalog_kwork_id) + details = await e2e_client.client.catalog.get_details(catalog_kwork_id) assert details is not None assert details.id == catalog_kwork_id @@ -55,7 +53,7 @@ async def test_get_projects_list(e2e_client): HAR: POST https://api.kwork.ru/projects """ - projects = await e2e_client.projects.get_list(page=1) + projects = await e2e_client.client.projects.get_list(page=1) assert projects is not None # Проекты могут быть пустыми @@ -71,7 +69,7 @@ async def test_get_user_info(e2e_client): HAR: POST https://api.kwork.ru/user """ - user = await e2e_client.user.get_info() + user = await e2e_client.client.user.get_info() assert user is not None # API возвращает dict с данными пользователя assert isinstance(user, dict) @@ -88,19 +86,19 @@ async def test_get_reference_data(e2e_client): - POST https://api.kwork.ru/getBadgesInfo """ # Города (может вернуть пустой список) - cities = await e2e_client.reference.get_cities() + cities = await e2e_client.client.reference.get_cities() assert isinstance(cities, list) # Страны (может вернуть пустой список) - countries = await e2e_client.reference.get_countries() + countries = await e2e_client.client.reference.get_countries() assert isinstance(countries, list) # Фичи - features = await e2e_client.reference.get_features() + features = await e2e_client.client.reference.get_features() assert isinstance(features, list) # Бейджи - badges = await e2e_client.reference.get_badges_info() + badges = await e2e_client.client.reference.get_badges_info() assert isinstance(badges, list) @@ -110,7 +108,7 @@ async def test_get_notifications(e2e_client): HAR: POST https://api.kwork.ru/notifications """ - notifications = await e2e_client.notifications.get_list() + notifications = await e2e_client.client.notifications.get_list() assert notifications is not None # Уведомления могут быть пустыми assert hasattr(notifications, 'notifications') @@ -125,9 +123,9 @@ async def test_get_user_orders(e2e_client): - POST https://api.kwork.ru/workerOrders """ # Заказы как заказчик - payer_orders = await e2e_client.projects.get_payer_orders() + payer_orders = await e2e_client.client.projects.get_payer_orders() assert isinstance(payer_orders, list) # Заказы как исполнитель - worker_orders = await e2e_client.projects.get_worker_orders() + worker_orders = await e2e_client.client.projects.get_worker_orders() assert isinstance(worker_orders, list)