| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- """Tests for ChattoClient using respx to mock HTTP."""
- import pytest
- import respx
- import httpx
- from chattolib.client import ChattoClient
- from chattolib.exceptions import ChattoGraphQLError, ChattoAuthError
- from chattolib.types import PresenceStatus
- @pytest.fixture
- def mock_api():
- with respx.mock(base_url="https://chat.chatto.run") as api:
- yield api
- @pytest.fixture
- def client():
- return ChattoClient(token="test-token")
- def _gql_response(data: dict) -> httpx.Response:
- return httpx.Response(200, json={"data": data})
- async def test_me(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "me": {
- "id": "u1",
- "login": "alice",
- "displayName": "Alice",
- "createdAt": "2025-01-01T00:00:00Z",
- "avatarUrl": None,
- "presenceStatus": "ONLINE",
- }
- }
- )
- )
- async with client:
- user = await client.me()
- assert user.id == "u1"
- assert user.login == "alice"
- assert user.display_name == "Alice"
- async def test_rooms(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "instance": {
- "rooms": [
- {
- "id": "r1",
- "type": "CHANNEL",
- "name": "general",
- "description": None,
- "archived": False,
- "autoJoin": True,
- "hasUnread": False,
- "hasMention": False,
- }
- ]
- }
- }
- )
- )
- async with client:
- rooms = await client.rooms()
- assert len(rooms) == 1
- assert rooms[0].name == "general"
- assert rooms[0].type.value == "CHANNEL"
- async def test_graphql_error(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=httpx.Response(
- 200,
- json={"errors": [{"message": "Not authorized"}]},
- )
- )
- async with client:
- with pytest.raises(ChattoGraphQLError, match="Not authorized"):
- await client.me()
- async def test_auth_error(mock_api, client):
- mock_api.post("/api/graphql").mock(return_value=httpx.Response(401))
- async with client:
- with pytest.raises(ChattoAuthError):
- await client.me()
- async def test_post_message(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {"postMessage": {"id": "e1", "createdAt": "2025-01-01T00:00:00Z"}}
- )
- )
- async with client:
- result = await client.post_message("r1", "Hello!")
- assert result["id"] == "e1"
- async def test_room_events(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "roomEvents": {
- "events": [
- {
- "id": "e1",
- "createdAt": "2025-01-01T00:00:00Z",
- "actorId": "u1",
- "actor": {
- "id": "u1",
- "login": "alice",
- "displayName": "Alice",
- "avatarUrl": None,
- },
- "event": {
- "roomId": "r1",
- "body": "Hello",
- "attachments": [],
- "reactions": [],
- "inReplyTo": None,
- "inThread": None,
- "replyCount": 0,
- "lastReplyAt": None,
- "linkPreview": None,
- },
- }
- ],
- "hasOlder": False,
- "hasNewer": False,
- "startCursor": None,
- "endCursor": None,
- }
- }
- )
- )
- async with client:
- page = await client.room_events("r1", limit=10)
- assert len(page.events) == 1
- assert page.events[0].body == "Hello"
- assert page.events[0].actor.login == "alice"
- async def test_login():
- with respx.mock(base_url="https://chat.chatto.run") as api:
- api.post("/auth/login").mock(
- return_value=httpx.Response(
- 200,
- json={"success": True, "token": "cht_abc123", "user": {"id": "u1", "login": "alice"}},
- headers={"set-cookie": "chatto_session=xyz; Path=/; HttpOnly"},
- )
- )
- client = await ChattoClient.login("alice", "password123")
- assert client._token == "cht_abc123"
- assert client._session_cookie == "xyz"
- await client.close()
- async def test_login_invalid():
- with respx.mock(base_url="https://chat.chatto.run") as api:
- api.post("/auth/login").mock(return_value=httpx.Response(401, json={"error": "Invalid credentials"}))
- with pytest.raises(ChattoAuthError, match="Invalid credentials"):
- await ChattoClient.login("bad", "creds")
- async def test_edit_message(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"editMessage": {"id": "e1"}})
- )
- async with client:
- result = await client.edit_message("r1", "e1", "edited body")
- assert result["id"] == "e1"
- async def test_delete_message(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"deleteMessage": True})
- )
- async with client:
- result = await client.delete_message("r1", "e1")
- assert result is True
- async def test_add_reaction(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"addReaction": True})
- )
- async with client:
- result = await client.add_reaction("r1", "e1", "thumbsup")
- assert result is True
- async def test_remove_reaction(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"removeReaction": True})
- )
- async with client:
- result = await client.remove_reaction("r1", "e1", "thumbsup")
- assert result is True
- async def test_create_room(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {"createRoom": {"id": "r1", "type": "CHANNEL", "name": "general", "description": None}}
- )
- )
- async with client:
- room = await client.create_room("general")
- assert room.id == "r1"
- assert room.name == "general"
- async def test_update_my_profile(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "updateMyProfile": {
- "id": "u1",
- "login": "newname",
- "displayName": "New Name",
- }
- }
- )
- )
- async with client:
- user = await client.update_my_profile(login="newname", display_name="New Name")
- assert user.login == "newname"
- assert user.display_name == "New Name"
- async def test_update_presence(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"updateMyPresence": True})
- )
- async with client:
- result = await client.update_presence(PresenceStatus.ONLINE)
- assert result is True
- async def test_upload_my_avatar(mock_api, client, tmp_path):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {"uploadMyAvatar": {"id": "u1", "avatarUrl": "https://example.com/avatar.jpg"}}
- )
- )
- avatar = tmp_path / "avatar.jpg"
- avatar.write_bytes(b"\xff\xd8\xff\xe0fake-jpeg")
- async with client:
- result = await client.upload_my_avatar(str(avatar))
- assert result["avatarUrl"] == "https://example.com/avatar.jpg"
- async def test_user(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "user": {
- "id": "u1",
- "login": "alice",
- "displayName": "Alice",
- "createdAt": "2025-01-01T00:00:00Z",
- "avatarUrl": None,
- "presenceStatus": "ONLINE",
- }
- }
- )
- )
- async with client:
- user = await client.user("u1")
- assert user.id == "u1"
- assert user.login == "alice"
- async def test_user_by_login(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response(
- {
- "userByLogin": {
- "id": "u1",
- "login": "alice",
- "displayName": "Alice",
- "createdAt": None,
- "avatarUrl": None,
- "presenceStatus": None,
- }
- }
- )
- )
- async with client:
- user = await client.user_by_login("alice")
- assert user.login == "alice"
- async def test_start_dm(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"startDM": {"id": "r1", "name": "DM"}})
- )
- async with client:
- result = await client.start_dm(["u1", "u2"])
- assert result["id"] == "r1"
- async def test_dismiss_notification(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"dismissNotification": True})
- )
- async with client:
- result = await client.dismiss_notification("n1")
- assert result is True
- async def test_dismiss_all_notifications(mock_api, client):
- mock_api.post("/api/graphql").mock(
- return_value=_gql_response({"dismissAllNotifications": True})
- )
- async with client:
- result = await client.dismiss_all_notifications()
- assert result is True
|