729 lines
21 KiB
Python
729 lines
21 KiB
Python
"""
|
|
Extended unit tests for KworkClient to improve coverage.
|
|
|
|
These tests cover additional API endpoints and edge cases.
|
|
"""
|
|
|
|
import pytest
|
|
import respx
|
|
from httpx import Response
|
|
|
|
from kwork_api import KworkApiError, KworkClient
|
|
from kwork_api.models import (
|
|
Badge,
|
|
City,
|
|
Country,
|
|
Dialog,
|
|
Feature,
|
|
Kwork,
|
|
NotificationsResponse,
|
|
Project,
|
|
TimeZone,
|
|
)
|
|
|
|
BASE_URL = "https://api.kwork.ru"
|
|
|
|
|
|
class TestClientProperties:
|
|
"""Test client properties and initialization."""
|
|
|
|
def test_token_property(self):
|
|
"""Test token property getter."""
|
|
client = KworkClient(token="test_token_123")
|
|
assert client.token == "test_token_123"
|
|
|
|
def test_token_property_none(self):
|
|
"""Test token property when no token."""
|
|
client = KworkClient()
|
|
assert client.token is None
|
|
|
|
def test_cookies_property_empty(self):
|
|
"""Test cookies property with no cookies."""
|
|
client = KworkClient(token="test")
|
|
assert client.cookies == {}
|
|
|
|
def test_cookies_property_with_cookies(self):
|
|
"""Test cookies property returns copy."""
|
|
client = KworkClient(token="test", cookies={"userId": "123", "session": "abc"})
|
|
cookies = client.cookies
|
|
assert cookies == {"userId": "123", "session": "abc"}
|
|
cookies["modified"] = "value"
|
|
assert "modified" not in client.cookies
|
|
|
|
def test_credentials_property(self):
|
|
"""Test credentials property returns token and cookies."""
|
|
client = KworkClient(token="test_token", cookies={"userId": "123"})
|
|
creds = client.credentials
|
|
assert creds["token"] == "test_token"
|
|
assert creds["cookies"] == {"userId": "123"}
|
|
|
|
def test_credentials_property_no_cookies(self):
|
|
"""Test credentials with no cookies."""
|
|
client = KworkClient(token="test_token")
|
|
creds = client.credentials
|
|
assert creds["token"] == "test_token"
|
|
assert creds["cookies"] is None
|
|
|
|
|
|
class TestCatalogAPIExtended:
|
|
"""Extended tests for CatalogAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_details_extra(self):
|
|
"""Test get_details_extra endpoint."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"id": 456,
|
|
"title": "Extra Details Kwork",
|
|
"extra_field": "extra_value",
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getKworkDetailsExtra").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.catalog.get_details_extra(456)
|
|
|
|
assert result["id"] == 456
|
|
assert result["extra_field"] == "extra_value"
|
|
|
|
|
|
class TestProjectsAPIExtended:
|
|
"""Extended tests for ProjectsAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_payer_orders(self):
|
|
"""Test getting payer orders."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"orders": [
|
|
{"id": 101, "title": "Order 1", "amount": 5000.0, "status": "active"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/payerOrders").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.projects.get_payer_orders()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 1
|
|
assert isinstance(result[0], Project)
|
|
|
|
@respx.mock
|
|
async def test_get_worker_orders(self):
|
|
"""Test getting worker orders."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"orders": [
|
|
{"id": 202, "title": "Worker Order", "amount": 3000.0, "status": "completed"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/workerOrders").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.projects.get_worker_orders()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 1
|
|
|
|
|
|
class TestUserAPI:
|
|
"""Tests for UserAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_info(self):
|
|
"""Test getting user info."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"userId": 12345,
|
|
"username": "testuser",
|
|
"email": "test@example.com",
|
|
"balance": 50000.0,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/user").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.user.get_info()
|
|
|
|
assert result["userId"] == 12345
|
|
assert result["username"] == "testuser"
|
|
|
|
@respx.mock
|
|
async def test_get_reviews(self):
|
|
"""Test getting user reviews."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"reviews": [
|
|
{
|
|
"id": 1,
|
|
"rating": 5,
|
|
"comment": "Great work!",
|
|
"author": {"id": 999, "username": "client1"},
|
|
},
|
|
],
|
|
"pagination": {"current_page": 1, "total_pages": 5},
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/userReviews").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.user.get_reviews(user_id=12345, page=1)
|
|
|
|
assert len(result.reviews) == 1
|
|
assert result.reviews[0].rating == 5
|
|
|
|
@respx.mock
|
|
async def test_get_favorite_kworks(self):
|
|
"""Test getting favorite kworks."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"kworks": [
|
|
{"id": 100, "title": "Favorite Kwork 1", "price": 2000.0},
|
|
{"id": 101, "title": "Favorite Kwork 2", "price": 3000.0},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/favoriteKworks").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.user.get_favorite_kworks()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], Kwork)
|
|
|
|
|
|
class TestReferenceAPI:
|
|
"""Tests for ReferenceAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_cities(self):
|
|
"""Test getting cities list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"cities": [
|
|
{"id": 1, "name": "Москва", "country_id": 1},
|
|
{"id": 2, "name": "Санкт-Петербург", "country_id": 1},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/cities").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.reference.get_cities()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], City)
|
|
|
|
@respx.mock
|
|
async def test_get_countries(self):
|
|
"""Test getting countries list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"countries": [
|
|
{"id": 1, "name": "Россия", "code": "RU"},
|
|
{"id": 2, "name": "Беларусь", "code": "BY"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/countries").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.reference.get_countries()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], Country)
|
|
|
|
@respx.mock
|
|
async def test_get_timezones(self):
|
|
"""Test getting timezones list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"timezones": [
|
|
{"id": 1, "name": "Europe/Moscow", "offset": "+03:00"},
|
|
{"id": 2, "name": "Europe/Kaliningrad", "offset": "+02:00"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/timezones").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.reference.get_timezones()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], TimeZone)
|
|
|
|
@respx.mock
|
|
async def test_get_features(self):
|
|
"""Test getting features list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"features": [
|
|
{"id": 1, "name": "Feature 1", "category_id": 5, "price": 1000, "type": "extra"},
|
|
{"id": 2, "name": "Feature 2", "category_id": 5, "price": 2000, "type": "extra"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getAvailableFeatures").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.reference.get_features()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], Feature)
|
|
|
|
@respx.mock
|
|
async def test_get_public_features(self):
|
|
"""Test getting public features list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"features": [
|
|
{
|
|
"id": 10,
|
|
"name": "Public Feature",
|
|
"is_public": True,
|
|
"price": 500,
|
|
"type": "extra",
|
|
},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getPublicFeatures").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.reference.get_public_features()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 1
|
|
|
|
@respx.mock
|
|
async def test_get_badges_info(self):
|
|
"""Test getting badges info."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"badges": [
|
|
{"id": 1, "name": "Pro Seller", "icon_url": "https://example.com/badge1.png"},
|
|
{"id": 2, "name": "Verified", "icon_url": "https://example.com/badge2.png"},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getBadgesInfo").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.reference.get_badges_info()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], Badge)
|
|
|
|
|
|
class TestNotificationsAPI:
|
|
"""Tests for NotificationsAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_list(self):
|
|
"""Test getting notifications list."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"notifications": [
|
|
{
|
|
"id": 1,
|
|
"type": "order",
|
|
"title": "New Order",
|
|
"message": "New order received",
|
|
"is_read": False,
|
|
},
|
|
{
|
|
"id": 2,
|
|
"type": "message",
|
|
"title": "New Message",
|
|
"message": "You have a new message",
|
|
"is_read": True,
|
|
},
|
|
],
|
|
"unread_count": 5,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/notifications").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.notifications.get_list()
|
|
|
|
assert isinstance(result, NotificationsResponse)
|
|
assert result.unread_count == 5
|
|
|
|
@respx.mock
|
|
async def test_fetch(self):
|
|
"""Test fetching notifications."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"notifications": [
|
|
{
|
|
"id": 3,
|
|
"type": "system",
|
|
"title": "System Update",
|
|
"message": "System update available",
|
|
"is_read": False,
|
|
},
|
|
],
|
|
"unread_count": 1,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/notificationsFetch").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.notifications.fetch()
|
|
|
|
assert isinstance(result, NotificationsResponse)
|
|
assert len(result.notifications) == 1
|
|
|
|
@respx.mock
|
|
async def test_get_dialogs(self):
|
|
"""Test getting dialogs."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"dialogs": [
|
|
{"id": 1, "user_id": 100, "last_message": "Hello", "unread": 2},
|
|
{"id": 2, "user_id": 200, "last_message": "Hi", "unread": 0},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/dialogs").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.notifications.get_dialogs()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert isinstance(result[0], Dialog)
|
|
|
|
@respx.mock
|
|
async def test_get_blocked_dialogs(self):
|
|
"""Test getting blocked dialogs."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"dialogs": [
|
|
{"id": 99, "user_id": 999, "last_message": "Spam", "blocked": True},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/blockedDialogList").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.notifications.get_blocked_dialogs()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 1
|
|
|
|
|
|
class TestOtherAPI:
|
|
"""Tests for OtherAPI."""
|
|
|
|
@respx.mock
|
|
async def test_get_wants(self):
|
|
"""Test getting wants."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"wants": [{"id": 1, "title": "I need a logo"}],
|
|
"count": 1,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/myWants").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_wants()
|
|
|
|
assert "wants" in result
|
|
assert result["count"] == 1
|
|
|
|
@respx.mock
|
|
async def test_get_wants_status(self):
|
|
"""Test getting wants status."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"active_wants": 5,
|
|
"completed_wants": 10,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/wantsStatusList").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_wants_status()
|
|
|
|
assert result["active_wants"] == 5
|
|
|
|
@respx.mock
|
|
async def test_get_kworks_status(self):
|
|
"""Test getting kworks status."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"active_kworks": 3,
|
|
"total_sales": 50,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/kworksStatusList").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_kworks_status()
|
|
|
|
assert result["active_kworks"] == 3
|
|
|
|
@respx.mock
|
|
async def test_get_offers(self):
|
|
"""Test getting offers."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"offers": [{"id": 1, "title": "Special offer"}],
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/offers").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_offers()
|
|
|
|
assert "offers" in result
|
|
|
|
@respx.mock
|
|
async def test_get_exchange_info(self):
|
|
"""Test getting exchange info."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"usd_rate": 90.5,
|
|
"eur_rate": 98.2,
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/exchangeInfo").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_exchange_info()
|
|
|
|
assert result["usd_rate"] == 90.5
|
|
|
|
@respx.mock
|
|
async def test_get_channel(self):
|
|
"""Test getting channel info."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"channel_id": "main",
|
|
"name": "Main Channel",
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getChannel").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_channel()
|
|
|
|
assert result["channel_id"] == "main"
|
|
|
|
@respx.mock
|
|
async def test_get_in_app_notification(self):
|
|
"""Test getting in-app notifications."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"notifications": [{"id": 1, "message": "App update"}],
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getInAppNotification").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.other.get_in_app_notification()
|
|
|
|
assert "notifications" in result
|
|
|
|
@respx.mock
|
|
async def test_get_security_user_data(self):
|
|
"""Test getting security user data."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"two_factor_enabled": True,
|
|
"last_login": "2024-01-01T00:00:00Z",
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/getSecurityUserData").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.other.get_security_user_data()
|
|
|
|
assert result["two_factor_enabled"] is True
|
|
|
|
@respx.mock
|
|
async def test_is_dialog_allow_true(self):
|
|
"""Test is_dialog_allow returns True."""
|
|
client = KworkClient(token="test")
|
|
|
|
respx.post(f"{BASE_URL}/isDialogAllow").mock(
|
|
return_value=Response(200, json={"allowed": True})
|
|
)
|
|
|
|
result = await client.other.is_dialog_allow(12345)
|
|
|
|
assert result is True
|
|
|
|
@respx.mock
|
|
async def test_is_dialog_allow_false(self):
|
|
"""Test is_dialog_allow returns False."""
|
|
client = KworkClient(token="test")
|
|
|
|
respx.post(f"{BASE_URL}/isDialogAllow").mock(
|
|
return_value=Response(200, json={"allowed": False})
|
|
)
|
|
|
|
result = await client.other.is_dialog_allow(67890)
|
|
|
|
assert result is False
|
|
|
|
@respx.mock
|
|
async def test_get_viewed_kworks(self):
|
|
"""Test getting viewed kworks."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"kworks": [
|
|
{"id": 500, "title": "Viewed Kwork", "price": 1500.0},
|
|
]
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/viewedCatalogKworks").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.other.get_viewed_kworks()
|
|
|
|
assert isinstance(result, list)
|
|
assert len(result) == 1
|
|
assert isinstance(result[0], Kwork)
|
|
|
|
@respx.mock
|
|
async def test_get_favorite_categories(self):
|
|
"""Test getting favorite categories."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"categories": [1, 5, 10, 15],
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/favoriteCategories").mock(
|
|
return_value=Response(200, json=mock_data)
|
|
)
|
|
|
|
result = await client.other.get_favorite_categories()
|
|
|
|
assert isinstance(result, list)
|
|
assert 1 in result
|
|
assert 5 in result
|
|
|
|
@respx.mock
|
|
async def test_update_settings(self):
|
|
"""Test updating settings."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"success": True,
|
|
"updated": {"notifications_enabled": False},
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/updateSettings").mock(return_value=Response(200, json=mock_data))
|
|
|
|
settings = {"notifications_enabled": False, "theme": "dark"}
|
|
result = await client.other.update_settings(settings)
|
|
|
|
assert result["success"] is True
|
|
|
|
@respx.mock
|
|
async def test_go_offline(self):
|
|
"""Test going offline."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"success": True,
|
|
"status": "offline",
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/offline").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.go_offline()
|
|
|
|
assert result["success"] is True
|
|
assert result["status"] == "offline"
|
|
|
|
@respx.mock
|
|
async def test_get_actor(self):
|
|
"""Test getting actor info."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {
|
|
"actor_id": 123,
|
|
"name": "Test Actor",
|
|
}
|
|
|
|
respx.post(f"{BASE_URL}/actor").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client.other.get_actor()
|
|
|
|
assert result["actor_id"] == 123
|
|
|
|
|
|
class TestClientInternals:
|
|
"""Tests for internal client methods."""
|
|
|
|
def test_handle_response_success(self):
|
|
"""Test _handle_response with successful response."""
|
|
import httpx
|
|
|
|
client = KworkClient(token="test")
|
|
|
|
response = httpx.Response(200, json={"success": True, "data": "test"})
|
|
result = client._handle_response(response)
|
|
|
|
assert result["success"] is True
|
|
assert result["data"] == "test"
|
|
|
|
def test_handle_response_error(self):
|
|
"""Test _handle_response with error response."""
|
|
import httpx
|
|
|
|
client = KworkClient(token="test")
|
|
|
|
response = httpx.Response(400, json={"message": "Bad request"})
|
|
|
|
with pytest.raises(KworkApiError) as exc_info:
|
|
client._handle_response(response)
|
|
|
|
assert exc_info.value.status_code == 400
|
|
|
|
@respx.mock
|
|
async def test_request_method(self):
|
|
"""Test _request method directly."""
|
|
client = KworkClient(token="test")
|
|
|
|
mock_data = {"result": "success"}
|
|
|
|
respx.post(f"{BASE_URL}/test-endpoint").mock(return_value=Response(200, json=mock_data))
|
|
|
|
result = await client._request("POST", "/test-endpoint", json={"param": "value"})
|
|
|
|
assert result["result"] == "success"
|
|
|
|
async def test_context_manager_creates_client(self):
|
|
"""Test that context manager creates httpx client."""
|
|
async with KworkClient(token="test") as client:
|
|
assert client.token == "test"
|
|
|
|
assert client._client is None or client._client.is_closed
|