Implement plans
This commit is contained in:
227
core/tests/test_compose_react.py
Normal file
227
core/tests/test_compose_react.py
Normal file
@@ -0,0 +1,227 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from core.models import ChatSession, Message, Person, PersonIdentifier, User
|
||||
|
||||
|
||||
class ComposeReactTests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user("compose-react", "react@example.com", "pw")
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def _build_message(self, *, service: str, identifier: str, source_message_id: str = ""):
|
||||
person = Person.objects.create(user=self.user, name=f"{service} person")
|
||||
person_identifier = PersonIdentifier.objects.create(
|
||||
user=self.user,
|
||||
person=person,
|
||||
service=service,
|
||||
identifier=identifier,
|
||||
)
|
||||
session = ChatSession.objects.create(
|
||||
user=self.user,
|
||||
identifier=person_identifier,
|
||||
)
|
||||
message = Message.objects.create(
|
||||
user=self.user,
|
||||
session=session,
|
||||
ts=1770000000123,
|
||||
sender_uuid="sender-1",
|
||||
text="hello",
|
||||
source_service=service,
|
||||
source_message_id=source_message_id or "",
|
||||
source_chat_id=identifier,
|
||||
receipt_payload={},
|
||||
)
|
||||
return person, person_identifier, message
|
||||
|
||||
@patch("core.views.compose.history.apply_reaction", new_callable=AsyncMock)
|
||||
@patch("core.views.compose.transport.send_reaction", new_callable=AsyncMock)
|
||||
def test_signal_react_uses_numeric_source_message_id_timestamp(
|
||||
self, mocked_send_reaction, mocked_apply_reaction
|
||||
):
|
||||
person, _, message = self._build_message(
|
||||
service="signal",
|
||||
identifier="+15551230000",
|
||||
source_message_id="1771234567000",
|
||||
)
|
||||
mocked_send_reaction.return_value = True
|
||||
mocked_apply_reaction.return_value = message
|
||||
|
||||
response = self.client.post(
|
||||
reverse("compose_react"),
|
||||
{
|
||||
"service": "signal",
|
||||
"identifier": "+15551230000",
|
||||
"person": str(person.id),
|
||||
"message_id": str(message.id),
|
||||
"emoji": "👍",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["ok"])
|
||||
self.assertEqual("👍", payload["emoji"])
|
||||
self.assertFalse(payload["remove"])
|
||||
mocked_send_reaction.assert_awaited_once()
|
||||
_, kwargs = mocked_send_reaction.await_args
|
||||
self.assertEqual("signal", mocked_send_reaction.await_args.args[0])
|
||||
self.assertEqual("+15551230000", mocked_send_reaction.await_args.args[1])
|
||||
self.assertEqual(1771234567000, kwargs["target_timestamp"])
|
||||
self.assertEqual("sender-1", kwargs["target_author"])
|
||||
self.assertEqual("", kwargs["target_message_id"])
|
||||
|
||||
@patch("core.views.compose.history.apply_reaction", new_callable=AsyncMock)
|
||||
@patch("core.views.compose.transport.send_reaction", new_callable=AsyncMock)
|
||||
def test_whatsapp_react_uses_upstream_message_id(
|
||||
self, mocked_send_reaction, mocked_apply_reaction
|
||||
):
|
||||
person, _, message = self._build_message(
|
||||
service="whatsapp",
|
||||
identifier="12345@s.whatsapp.net",
|
||||
source_message_id="wamid.ABC123",
|
||||
)
|
||||
mocked_send_reaction.return_value = True
|
||||
mocked_apply_reaction.return_value = message
|
||||
|
||||
response = self.client.post(
|
||||
reverse("compose_react"),
|
||||
{
|
||||
"service": "whatsapp",
|
||||
"identifier": "12345@s.whatsapp.net",
|
||||
"person": str(person.id),
|
||||
"message_id": str(message.id),
|
||||
"emoji": "❤️",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["ok"])
|
||||
self.assertEqual("wamid.ABC123", payload["target_upstream_id"])
|
||||
mocked_send_reaction.assert_awaited_once()
|
||||
_, kwargs = mocked_send_reaction.await_args
|
||||
self.assertEqual("wamid.ABC123", kwargs["target_message_id"])
|
||||
|
||||
@patch("core.views.compose.transport.send_reaction", new_callable=AsyncMock)
|
||||
def test_toggle_removes_existing_actor_reaction(self, mocked_send_reaction):
|
||||
person, _, message = self._build_message(
|
||||
service="signal",
|
||||
identifier="+15551230000",
|
||||
source_message_id="1771234567000",
|
||||
)
|
||||
message.receipt_payload = {
|
||||
"reactions": [
|
||||
{
|
||||
"emoji": "👍",
|
||||
"actor": f"web:{self.user.id}:signal",
|
||||
"source_service": "signal",
|
||||
"removed": False,
|
||||
}
|
||||
]
|
||||
}
|
||||
message.save(update_fields=["receipt_payload"])
|
||||
mocked_send_reaction.return_value = True
|
||||
|
||||
with patch(
|
||||
"core.views.compose.history.apply_reaction",
|
||||
new=AsyncMock(return_value=message),
|
||||
):
|
||||
response = self.client.post(
|
||||
reverse("compose_react"),
|
||||
{
|
||||
"service": "signal",
|
||||
"identifier": "+15551230000",
|
||||
"person": str(person.id),
|
||||
"message_id": str(message.id),
|
||||
"emoji": "👍",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["ok"])
|
||||
self.assertTrue(payload["remove"])
|
||||
_, kwargs = mocked_send_reaction.await_args
|
||||
self.assertTrue(kwargs["remove"])
|
||||
|
||||
def test_unsupported_service_returns_error(self):
|
||||
response = self.client.post(
|
||||
reverse("compose_react"),
|
||||
{
|
||||
"service": "xmpp",
|
||||
"identifier": "someone@example.com",
|
||||
"message_id": "does-not-matter",
|
||||
"emoji": "👍",
|
||||
},
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertEqual(
|
||||
{"ok": False, "error": "service_not_supported"},
|
||||
response.json(),
|
||||
)
|
||||
|
||||
def test_missing_whatsapp_target_returns_error(self):
|
||||
person, _, message = self._build_message(
|
||||
service="whatsapp",
|
||||
identifier="12345@s.whatsapp.net",
|
||||
source_message_id="",
|
||||
)
|
||||
response = self.client.post(
|
||||
reverse("compose_react"),
|
||||
{
|
||||
"service": "whatsapp",
|
||||
"identifier": "12345@s.whatsapp.net",
|
||||
"person": str(person.id),
|
||||
"message_id": str(message.id),
|
||||
"emoji": "😂",
|
||||
},
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertEqual(
|
||||
{"ok": False, "error": "whatsapp_target_unresolvable"},
|
||||
response.json(),
|
||||
)
|
||||
|
||||
def test_compose_page_renders_reaction_actions_for_signal(self):
|
||||
person, _, _ = self._build_message(
|
||||
service="signal",
|
||||
identifier="+15551230000",
|
||||
source_message_id="1771234567000",
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("compose_page"),
|
||||
{
|
||||
"service": "signal",
|
||||
"identifier": "+15551230000",
|
||||
"person": str(person.id),
|
||||
},
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
content = response.content.decode("utf-8")
|
||||
self.assertIn("data-react-url=", content)
|
||||
self.assertIn("compose-reaction-actions", content)
|
||||
|
||||
def test_compose_page_hides_reaction_actions_for_unsupported_service(self):
|
||||
person, _, _ = self._build_message(
|
||||
service="xmpp",
|
||||
identifier="person@example.com",
|
||||
source_message_id="msg-1",
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("compose_page"),
|
||||
{
|
||||
"service": "xmpp",
|
||||
"identifier": "person@example.com",
|
||||
"person": str(person.id),
|
||||
},
|
||||
)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertNotIn(
|
||||
'class="compose-reaction-actions"',
|
||||
response.content.decode("utf-8"),
|
||||
)
|
||||
Reference in New Issue
Block a user