fix: update tests for new login endpoint
This commit is contained in:
parent
7c392a822b
commit
e478807aa4
6
.ipynb_checkpoints/Untitled-checkpoint.ipynb
Normal file
6
.ipynb_checkpoints/Untitled-checkpoint.ipynb
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"cells": [],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
97
Untitled.ipynb
Normal file
97
Untitled.ipynb
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "f28552f1-618c-4853-92e2-566554a2de2c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import asyncio\n",
|
||||
"from kwork_api import KworkClient\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"load_dotenv('tests/e2e/.env')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "953d142e-a575-41b7-927d-8cd1546d2747",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"KworkAuthError: Login failed: 404\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" client = await KworkClient.login(\n",
|
||||
" username=os.getenv('KWORK_USERNAME'),\n",
|
||||
" password=os.getenv('KWORK_PASSWORD')\n",
|
||||
" )\n",
|
||||
" print(f\"✅ Logged in as: {client.token[:20]}...\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "655aa71e-5645-4c7a-aadd-5b044a0713c9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'8AQhyzQRcTJ6v81maCNa'"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"os.getenv('KWORK_PASSWORD')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -81,8 +81,6 @@ class KworkClient:
|
||||
"""
|
||||
|
||||
BASE_URL = "https://api.kwork.ru"
|
||||
LOGIN_URL = "https://kwork.ru/signIn"
|
||||
TOKEN_URL = "https://kwork.ru/getWebAuthToken"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -241,38 +239,41 @@ class KworkClient:
|
||||
|
||||
try:
|
||||
async with client._get_httpx_client() as http_client:
|
||||
# Step 1: Login to get session cookies
|
||||
# Step 1: Login to get session cookies and token
|
||||
# Kwork uses /api/user/login with JSON body
|
||||
login_data = {
|
||||
"login_or_email": username,
|
||||
"password": password,
|
||||
"l_username": username,
|
||||
"l_password": password,
|
||||
"jlog": 1,
|
||||
"recaptcha_pass_token": "",
|
||||
"track_client_id": False,
|
||||
"smart-token": "",
|
||||
"l_remember_me": "1",
|
||||
}
|
||||
|
||||
response = await http_client.post(
|
||||
cls.LOGIN_URL,
|
||||
data=login_data,
|
||||
headers={"Referer": "https://kwork.ru/"},
|
||||
"https://kwork.ru/api/user/login",
|
||||
json=login_data,
|
||||
headers={
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise KworkAuthError(f"Login failed: {response.status_code}")
|
||||
|
||||
# Extract cookies
|
||||
response_data = response.json()
|
||||
|
||||
# Extract userId from response or cookies
|
||||
cookies = dict(response.cookies)
|
||||
user_id = response_data.get("user_id") or cookies.get("userId")
|
||||
|
||||
if "userId" not in cookies:
|
||||
raise KworkAuthError("Login failed: no userId in cookies")
|
||||
if not user_id:
|
||||
raise KworkAuthError("Login failed: no userId in response")
|
||||
|
||||
# Step 2: Get web auth token
|
||||
token_response = await http_client.post(
|
||||
cls.TOKEN_URL,
|
||||
json={},
|
||||
)
|
||||
|
||||
if token_response.status_code != 200:
|
||||
raise KworkAuthError(f"Token request failed: {token_response.status_code}")
|
||||
|
||||
token_data = token_response.json()
|
||||
web_token = token_data.get("web_auth_token")
|
||||
# Extract web_auth_token from response
|
||||
web_token = response_data.get("web_auth_token") or cookies.get("web_auth_token")
|
||||
|
||||
if not web_token:
|
||||
raise KworkAuthError("No web_auth_token in response")
|
||||
@ -1174,9 +1175,7 @@ class KworkClient:
|
||||
"""
|
||||
return await self.client._request("POST", "/actor")
|
||||
|
||||
async def validate_text(
|
||||
self, text: str, context: str | None = None
|
||||
) -> ValidationResponse:
|
||||
async def validate_text(self, text: str, context: str | None = None) -> ValidationResponse:
|
||||
"""
|
||||
Проверить текст на соответствие требованиям Kwork.
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import pytest
|
||||
import respx
|
||||
from httpx import Response
|
||||
|
||||
from kwork_api import KworkApiError, KworkAuthError, KworkClient
|
||||
from kwork_api import KworkApiError, KworkAuthError, KworkClient, KworkNetworkError
|
||||
from kwork_api.models import CatalogResponse, ValidationResponse
|
||||
|
||||
|
||||
@ -18,22 +18,11 @@ class TestAuthentication:
|
||||
@respx.mock
|
||||
async def test_login_success(self):
|
||||
"""Test successful login."""
|
||||
import httpx
|
||||
|
||||
# Mock login endpoint
|
||||
login_route = respx.post("https://kwork.ru/signIn")
|
||||
login_route.mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
headers={"Set-Cookie": "userId=12345; slrememberme=token123"},
|
||||
)
|
||||
)
|
||||
|
||||
# Mock token endpoint
|
||||
token_route = respx.post("https://kwork.ru/getWebAuthToken").mock(
|
||||
login_route = respx.post("https://kwork.ru/api/user/login").mock(
|
||||
return_value=Response(
|
||||
200,
|
||||
json={"web_auth_token": "test_token_abc123"},
|
||||
json={"user_id": 12345, "web_auth_token": "test_token_abc123"},
|
||||
)
|
||||
)
|
||||
|
||||
@ -42,13 +31,12 @@ class TestAuthentication:
|
||||
|
||||
# Verify
|
||||
assert login_route.called
|
||||
assert token_route.called
|
||||
assert client._token == "test_token_abc123"
|
||||
|
||||
@respx.mock
|
||||
async def test_login_invalid_credentials(self):
|
||||
"""Test login with invalid credentials."""
|
||||
respx.post("https://kwork.ru/signIn").mock(
|
||||
respx.post("https://kwork.ru/api/user/login").mock(
|
||||
return_value=Response(401, json={"error": "Invalid credentials"})
|
||||
)
|
||||
|
||||
@ -57,11 +45,9 @@ class TestAuthentication:
|
||||
|
||||
@respx.mock
|
||||
async def test_login_no_userid(self):
|
||||
"""Test login without userId in cookies."""
|
||||
import httpx
|
||||
|
||||
respx.post("https://kwork.ru/signIn").mock(
|
||||
return_value=httpx.Response(200, headers={"Set-Cookie": "other=value"})
|
||||
"""Test login without userId in response."""
|
||||
respx.post("https://kwork.ru/api/user/login").mock(
|
||||
return_value=Response(200, json={"error": "No user_id"})
|
||||
)
|
||||
|
||||
with pytest.raises(KworkAuthError, match="no userId"):
|
||||
@ -70,14 +56,8 @@ class TestAuthentication:
|
||||
@respx.mock
|
||||
async def test_login_no_token(self):
|
||||
"""Test login without web_auth_token in response."""
|
||||
import httpx
|
||||
|
||||
respx.post("https://kwork.ru/signIn").mock(
|
||||
return_value=httpx.Response(200, headers={"Set-Cookie": "userId=123"})
|
||||
)
|
||||
|
||||
respx.post("https://kwork.ru/getWebAuthToken").mock(
|
||||
return_value=Response(200, json={"other": "data"})
|
||||
respx.post("https://kwork.ru/api/user/login").mock(
|
||||
return_value=Response(200, json={"user_id": 123})
|
||||
)
|
||||
|
||||
with pytest.raises(KworkAuthError, match="No web_auth_token"):
|
||||
@ -177,7 +157,9 @@ class TestProjectsAPI:
|
||||
"pagination": {"current_page": 1},
|
||||
}
|
||||
|
||||
respx.post(f"{client.base_url}/projects").mock(return_value=Response(200, json=mock_data))
|
||||
respx.post(f"{client.base_url}/projects").mock(
|
||||
return_value=Response(200, json=mock_data)
|
||||
)
|
||||
|
||||
result = await client.projects.get_list()
|
||||
|
||||
@ -193,7 +175,9 @@ class TestErrorHandling:
|
||||
"""Test 404 error handling."""
|
||||
client = KworkClient(token="test")
|
||||
|
||||
respx.post(f"{client.base_url}/getKworkDetails").mock(return_value=Response(404))
|
||||
respx.post(f"{client.base_url}/getKworkDetails").mock(
|
||||
return_value=Response(404)
|
||||
)
|
||||
|
||||
with pytest.raises(KworkApiError) as exc_info:
|
||||
await client.catalog.get_details(999)
|
||||
@ -205,7 +189,9 @@ class TestErrorHandling:
|
||||
"""Test 401 error handling."""
|
||||
client = KworkClient(token="invalid")
|
||||
|
||||
respx.post(f"{client.base_url}/catalogMainv2").mock(return_value=Response(401))
|
||||
respx.post(f"{client.base_url}/catalogMainv2").mock(
|
||||
return_value=Response(401)
|
||||
)
|
||||
|
||||
with pytest.raises(KworkAuthError):
|
||||
await client.catalog.get_list()
|
||||
@ -213,10 +199,12 @@ class TestErrorHandling:
|
||||
@respx.mock
|
||||
async def test_network_error(self):
|
||||
"""Test network error handling."""
|
||||
import httpx
|
||||
|
||||
client = KworkClient(token="test")
|
||||
|
||||
respx.post(f"{client.base_url}/catalogMainv2").mock(
|
||||
side_effect=Exception("Connection refused")
|
||||
side_effect=httpx.RequestError("Connection refused", request=None)
|
||||
)
|
||||
|
||||
with pytest.raises(KworkNetworkError):
|
||||
@ -231,9 +219,6 @@ class TestContextManager:
|
||||
async with KworkClient(token="test") as client:
|
||||
assert client._client is None # Not created yet
|
||||
|
||||
# Client should be created on first request
|
||||
# (but we don't make actual requests in this test)
|
||||
|
||||
# Client should be closed after context
|
||||
assert client._client is None or client._client.is_closed
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user