test: add E2E testing framework

- Add E2E test structure (tests/e2e/)
- Add conftest.py with fixtures and credentials loading
- Add test_auth.py with authentication tests
- Add .env.example template
- Add README.md with usage instructions
- Mark tests with @pytest.mark.e2e
- Add --slowmo option for rate limiting
This commit is contained in:
root 2026-03-29 01:35:57 +00:00
parent 0841be5153
commit 8cb0a59063
4 changed files with 252 additions and 0 deletions

5
tests/e2e/.env.example Normal file
View File

@ -0,0 +1,5 @@
# Kwork.ru credentials for E2E testing
# Copy this file to .env and fill in your test credentials
KWORK_USERNAME=your_test_username
KWORK_PASSWORD=your_test_password

136
tests/e2e/README.md Normal file
View File

@ -0,0 +1,136 @@
# End-to-End (E2E) Testing
E2E тесты требуют реальных credentials Kwork.ru и запускаются **только локально** (не в CI).
## ⚠️ Предупреждение
- **Не запускай в CI** — требуются реальные credentials
- **Используй тестовый аккаунт** — не основной аккаунт Kwork
- **Rate limiting** — добавляй задержки между запросами
---
## 🔧 Настройка
### 1. Создай файл окружения
```bash
cd /root/kwork-api
cp tests/e2e/.env.example tests/e2e/.env
```
### 2. Заполни credentials
```bash
# tests/e2e/.env
KWORK_USERNAME=your_test_username
KWORK_PASSWORD=your_test_password
```
### 3. Установи зависимости
```bash
uv sync --group dev
```
---
## 🚀 Запуск тестов
### Все E2E тесты
```bash
uv run pytest tests/e2e/ -v
```
### Конкретный тест
```bash
uv run pytest tests/e2e/test_auth.py -v
uv run pytest tests/e2e/test_catalog.py::test_get_catalog_list -v
```
### С задержками (rate limiting)
```bash
uv run pytest tests/e2e/ -v --slowmo=1
```
---
## 📁 Структура тестов
```
tests/e2e/
├── README.md # Этот файл
├── .env.example # Шаблон для credentials
├── conftest.py # Фикстуры и setup
├── test_auth.py # Аутентификация
├── test_catalog.py # Каталог кворков
├── test_projects.py # Биржа проектов
└── test_user.py # Пользовательские данные
```
---
## 🧪 Пример теста
```python
import pytest
from kwork_api import KworkClient
@pytest.mark.e2e
async def test_get_user_info():
"""E2E тест: получение информации о пользователе."""
async with await KworkClient.login(
username="test_user",
password="test_pass"
) as client:
user = await client.user.get_info()
assert user.username == "test_user"
assert user.balance >= 0
```
---
## 🏷️ Маркировка тестов
E2E тесты маркируются `@pytest.mark.e2e` для изоляции:
```bash
# Запустить только unit тесты (исключить e2e)
uv run pytest tests/ -v -m "not e2e"
# Запустить только e2e тесты
uv run pytest tests/ -v -m e2e
```
---
## 🔒 Безопасность
1. **Никогда не коммить `.env`** — добавлен в `.gitignore`
2. **Используй тестовый аккаунт** — не основной
3. **Не сохраняй токены в коде** — только через env vars
---
## 🐛 Troubleshooting
### Ошибка аутентификации
```
KworkAuthError: Invalid credentials
```
**Решение:** Проверь credentials в `.env`
### Rate limit
```
KworkApiError: Too many requests
```
**Решение:** Запусти с задержкой: `pytest --slowmo=2`
### Session expired
```
KworkAuthError: Session expired
```
**Решение:** Перезапусти тесты (session создаётся заново)

59
tests/e2e/conftest.py Normal file
View File

@ -0,0 +1,59 @@
"""
E2E тесты для Kwork API.
Требуют реальных credentials и запускаются только локально.
"""
import os
import pytest
from pathlib import Path
from dotenv import load_dotenv
# Загружаем .env
load_dotenv(Path(__file__).parent / ".env")
@pytest.fixture(scope="session")
def kwork_credentials():
"""Credentials для тестового аккаунта."""
return {
"username": os.getenv("KWORK_USERNAME"),
"password": os.getenv("KWORK_PASSWORD"),
}
@pytest.fixture(scope="session")
def require_credentials(kwork_credentials):
"""Пропускает тест если нет credentials."""
if not kwork_credentials["username"] or not kwork_credentials["password"]:
pytest.skip(
"E2E credentials not set. "
"Copy tests/e2e/.env.example to tests/e2e/.env and fill in credentials."
)
return kwork_credentials
@pytest.fixture(scope="function")
def slowmo(request):
"""Задержка между тестами для rate limiting."""
slowmo = request.config.getoption("--slowmo", default=0)
if slowmo > 0:
import time
time.sleep(slowmo)
def pytest_configure(config):
"""Регистрация маркера e2e."""
config.addinivalue_line(
"markers", "e2e: mark test as end-to-end (requires credentials)"
)
def pytest_addoption(parser):
"""Добавляет опцию --slowmo."""
parser.addoption(
"--slowmo",
type=float,
default=0,
help="Delay between tests in seconds (for rate limiting)"
)

52
tests/e2e/test_auth.py Normal file
View File

@ -0,0 +1,52 @@
"""
E2E тесты аутентификации.
"""
import pytest
from kwork_api import KworkClient
from kwork_api.errors import KworkAuthError
@pytest.mark.e2e
async def test_login_success(require_credentials):
"""E2E: Успешная аутентификация."""
client = await KworkClient.login(
username=require_credentials["username"],
password=require_credentials["password"]
)
try:
assert client.token is not None
assert len(client.token) > 0
finally:
await client.aclose()
@pytest.mark.e2e
async def test_login_invalid_credentials():
"""E2E: Неверные credentials."""
with pytest.raises(KworkAuthError):
await KworkClient.login(
username="invalid_user_12345",
password="invalid_pass_12345"
)
@pytest.mark.e2e
async def test_restore_session(require_credentials):
"""E2E: Восстановление сессии из токена."""
# First login
client1 = await KworkClient.login(
username=require_credentials["username"],
password=require_credentials["password"]
)
token = client1.token
await client1.aclose()
# Restore from token
client2 = KworkClient(token=token)
try:
user = await client2.user.get_info()
assert user.username == require_credentials["username"]
finally:
await client2.aclose()