2016-11-03 18:49:00 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import ujson
|
2017-10-08 09:34:59 +02:00
|
|
|
from django.http import HttpResponse
|
|
|
|
from typing import Any, Dict, List, Mapping, Text
|
2017-10-08 15:42:41 +02:00
|
|
|
from unittest import mock
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2017-05-01 07:29:56 +02:00
|
|
|
from zerver.lib.emoji import emoji_name_to_emoji_code
|
|
|
|
from zerver.lib.request import JsonableError
|
2017-03-13 05:45:50 +01:00
|
|
|
from zerver.lib.test_helpers import tornado_redirected_to_list, get_display_recipient, \
|
|
|
|
get_test_image_file
|
2016-11-03 18:49:00 +01:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2017-10-08 09:34:59 +02:00
|
|
|
from zerver.models import get_realm, Message, Reaction, RealmEmoji, Recipient, UserMessage
|
2016-11-03 18:49:00 +01:00
|
|
|
|
|
|
|
class ReactionEmojiTest(ZulipTestCase):
|
|
|
|
def test_missing_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Sending reaction without emoji fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2017-01-17 08:54:50 +01:00
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/',
|
2016-12-04 10:50:32 +01:00
|
|
|
**self.api_auth(sender))
|
2017-01-17 08:54:50 +01:00
|
|
|
self.assertEqual(result.status_code, 400)
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2016-12-04 10:50:32 +01:00
|
|
|
def test_add_invalid_emoji(self):
|
2016-11-03 18:49:00 +01:00
|
|
|
# type: () -> None
|
|
|
|
"""
|
2016-12-04 10:50:32 +01:00
|
|
|
Sending invalid emoji fails
|
2016-11-03 18:49:00 +01:00
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/foo',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_error(result, "Emoji 'foo' does not exist")
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2017-05-23 08:41:30 +02:00
|
|
|
def test_add_deactivated_realm_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Sending deactivated realm emoji fails.
|
|
|
|
"""
|
2017-07-22 21:05:13 +02:00
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
2017-05-23 08:41:30 +02:00
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
2017-07-22 21:05:13 +02:00
|
|
|
sender = self.example_email("hamlet")
|
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/green_tick',
|
2017-05-23 08:41:30 +02:00
|
|
|
**self.api_auth(sender))
|
2017-07-22 21:05:13 +02:00
|
|
|
self.assert_json_error(result, "Emoji 'green_tick' does not exist")
|
2017-05-23 08:41:30 +02:00
|
|
|
|
2016-11-03 18:49:00 +01:00
|
|
|
def test_valid_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting with valid emoji succeeds
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/smile',
|
|
|
|
**self.api_auth(sender))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(200, result.status_code)
|
|
|
|
|
2017-05-01 05:16:39 +02:00
|
|
|
def test_zulip_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting with zulip emoji succeeds
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2017-05-01 05:16:39 +02:00
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/zulip',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(200, result.status_code)
|
|
|
|
|
2017-03-23 04:15:32 +01:00
|
|
|
def test_valid_emoji_react_historical(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting with valid emoji on a historical message succeeds
|
|
|
|
"""
|
|
|
|
stream_name = "Saxony"
|
2017-08-25 06:01:29 +02:00
|
|
|
self.subscribe(self.example_user("cordelia"), stream_name)
|
2017-10-28 17:54:15 +02:00
|
|
|
message_id = self.send_stream_message(self.example_email("cordelia"), stream_name)
|
2017-03-23 04:15:32 +01:00
|
|
|
|
2017-05-07 21:25:59 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
|
|
|
sender = user_profile.email
|
2017-03-23 04:15:32 +01:00
|
|
|
|
|
|
|
# Verify that hamlet did not receive the message.
|
|
|
|
self.assertFalse(UserMessage.objects.filter(user_profile=user_profile,
|
|
|
|
message_id=message_id).exists())
|
|
|
|
|
|
|
|
# Have hamlet react to the message
|
|
|
|
result = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (message_id,),
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
# Fetch the now-created UserMessage object to confirm it exists and is historical
|
|
|
|
user_message = UserMessage.objects.get(user_profile=user_profile, message_id=message_id)
|
|
|
|
self.assertTrue(user_message.flags.historical)
|
|
|
|
self.assertTrue(user_message.flags.read)
|
|
|
|
self.assertFalse(user_message.flags.starred)
|
|
|
|
|
2016-11-03 18:49:00 +01:00
|
|
|
def test_valid_realm_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting with valid realm emoji succeeds
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2017-07-22 21:05:13 +02:00
|
|
|
emoji_name = 'green_tick'
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/%s' % (emoji_name,),
|
|
|
|
**self.api_auth(sender))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2017-05-01 07:29:56 +02:00
|
|
|
def test_emoji_name_to_emoji_code(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
An emoji name is mapped canonically to emoji code.
|
|
|
|
"""
|
|
|
|
realm = get_realm('zulip')
|
|
|
|
|
|
|
|
# Test active realm emoji.
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'green_tick')
|
|
|
|
self.assertEqual(emoji_code, 'green_tick')
|
|
|
|
self.assertEqual(reaction_type, 'realm_emoji')
|
|
|
|
|
|
|
|
# Test deactivated realm emoji.
|
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
|
|
|
with self.assertRaises(JsonableError) as exc:
|
|
|
|
emoji_name_to_emoji_code(realm, 'green_tick')
|
|
|
|
self.assertEqual(str(exc.exception), "Emoji 'green_tick' does not exist")
|
|
|
|
|
|
|
|
# Test ':zulip:' emoji.
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'zulip')
|
|
|
|
self.assertEqual(emoji_code, 'zulip')
|
|
|
|
self.assertEqual(reaction_type, 'zulip_extra_emoji')
|
|
|
|
|
|
|
|
# Test unicode emoji.
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'astonished')
|
|
|
|
self.assertEqual(emoji_code, '1f632')
|
|
|
|
self.assertEqual(reaction_type, 'unicode_emoji')
|
|
|
|
|
|
|
|
# Test override unicode emoji.
|
|
|
|
overriding_emoji = RealmEmoji.objects.create(
|
|
|
|
name='astonished', realm=realm, file_name='astonished')
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'astonished')
|
|
|
|
self.assertEqual(emoji_code, 'astonished')
|
|
|
|
self.assertEqual(reaction_type, 'realm_emoji')
|
|
|
|
|
|
|
|
# Test deactivate over-ridding realm emoji.
|
|
|
|
overriding_emoji.deactivated = True
|
|
|
|
overriding_emoji.save(update_fields=['deactivated'])
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'astonished')
|
|
|
|
self.assertEqual(emoji_code, '1f632')
|
|
|
|
self.assertEqual(reaction_type, 'unicode_emoji')
|
|
|
|
|
|
|
|
# Test override `:zulip:` emoji.
|
|
|
|
overriding_emoji = RealmEmoji.objects.create(
|
|
|
|
name='zulip', realm=realm, file_name='zulip')
|
|
|
|
emoji_code, reaction_type = emoji_name_to_emoji_code(realm, 'zulip')
|
|
|
|
self.assertEqual(emoji_code, 'zulip')
|
|
|
|
self.assertEqual(reaction_type, 'realm_emoji')
|
|
|
|
|
|
|
|
# Test non-existent emoji.
|
|
|
|
with self.assertRaises(JsonableError) as exc:
|
|
|
|
emoji_name_to_emoji_code(realm, 'invalid_emoji')
|
|
|
|
self.assertEqual(str(exc.exception), "Emoji 'invalid_emoji' does not exist")
|
|
|
|
|
2016-11-03 18:49:00 +01:00
|
|
|
class ReactionMessageIDTest(ZulipTestCase):
|
|
|
|
def test_missing_message_id(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting without a message_id fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages//emoji_reactions/smile',
|
|
|
|
**self.api_auth(sender))
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 404)
|
2016-11-03 18:49:00 +01:00
|
|
|
|
|
|
|
def test_invalid_message_id(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting to an invalid message id fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
sender = self.example_email("hamlet")
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/-1/emoji_reactions/smile',
|
|
|
|
**self.api_auth(sender))
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 404)
|
2016-11-03 18:49:00 +01:00
|
|
|
|
|
|
|
def test_inaccessible_message_id(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting to a inaccessible (for instance, private) message fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
pm_sender = self.example_email("hamlet")
|
2017-05-25 02:08:35 +02:00
|
|
|
pm_recipient = self.example_email("othello")
|
2017-05-25 01:44:04 +02:00
|
|
|
reaction_sender = self.example_email("iago")
|
2016-11-03 18:49:00 +01:00
|
|
|
|
|
|
|
result = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
|
|
|
"to": pm_recipient},
|
|
|
|
**self.api_auth(pm_sender))
|
|
|
|
self.assert_json_success(result)
|
2017-08-16 09:51:15 +02:00
|
|
|
pm_id = result.json()['id']
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
|
|
|
**self.api_auth(reaction_sender))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_error(result, "Invalid message(s)")
|
|
|
|
|
|
|
|
class ReactionTest(ZulipTestCase):
|
2016-11-30 08:14:46 +01:00
|
|
|
def test_add_existing_reaction(self):
|
2016-11-03 18:49:00 +01:00
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Creating the same reaction twice fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
pm_sender = self.example_email("hamlet")
|
2017-05-25 02:08:35 +02:00
|
|
|
pm_recipient = self.example_email("othello")
|
2016-11-03 18:49:00 +01:00
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
pm = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
|
|
|
"to": pm_recipient},
|
|
|
|
**self.api_auth(pm_sender))
|
|
|
|
self.assert_json_success(pm)
|
|
|
|
content = ujson.loads(pm.content)
|
2016-12-04 10:50:32 +01:00
|
|
|
|
2016-11-03 18:49:00 +01:00
|
|
|
pm_id = content['id']
|
2016-12-04 10:50:32 +01:00
|
|
|
first = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
|
|
|
**self.api_auth(reaction_sender))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_success(first)
|
2016-12-04 10:50:32 +01:00
|
|
|
second = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
|
|
|
**self.api_auth(reaction_sender))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_error(second, "Reaction already exists")
|
|
|
|
|
2016-11-30 08:14:46 +01:00
|
|
|
def test_remove_nonexisting_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Removing a reaction twice fails
|
|
|
|
"""
|
2017-05-25 01:40:26 +02:00
|
|
|
pm_sender = self.example_email("hamlet")
|
2017-05-25 02:08:35 +02:00
|
|
|
pm_recipient = self.example_email("othello")
|
2016-11-30 08:14:46 +01:00
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
pm = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
|
|
|
"to": pm_recipient},
|
|
|
|
**self.api_auth(pm_sender))
|
|
|
|
self.assert_json_success(pm)
|
|
|
|
content = ujson.loads(pm.content)
|
|
|
|
pm_id = content['id']
|
2016-12-04 10:50:32 +01:00
|
|
|
add = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
|
|
|
**self.api_auth(reaction_sender))
|
2016-11-30 08:14:46 +01:00
|
|
|
self.assert_json_success(add)
|
|
|
|
|
2016-12-04 10:50:32 +01:00
|
|
|
first = self.client_delete('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
2016-11-30 08:14:46 +01:00
|
|
|
**self.api_auth(reaction_sender))
|
|
|
|
self.assert_json_success(first)
|
|
|
|
|
2016-12-04 10:50:32 +01:00
|
|
|
second = self.client_delete('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
2016-11-30 08:14:46 +01:00
|
|
|
**self.api_auth(reaction_sender))
|
|
|
|
self.assert_json_error(second, "Reaction does not exist")
|
|
|
|
|
2017-10-08 15:42:41 +02:00
|
|
|
def test_remove_existing_reaction_with_renamed_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Removes an old existing reaction but the name of emoji got changed during
|
|
|
|
various emoji infra changes.
|
|
|
|
"""
|
|
|
|
sender = self.example_email("hamlet")
|
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/smile',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
with mock.patch('zerver.lib.emoji.name_to_codepoint', name_to_codepoint={}):
|
|
|
|
result = self.client_delete('/api/v1/messages/1/emoji_reactions/smile',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_remove_existing_reaction_with_deactivated_realm_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Removes an old existing reaction but the realm emoji used there has been deactivated.
|
|
|
|
"""
|
|
|
|
sender = self.example_email("hamlet")
|
|
|
|
result = self.client_put('/api/v1/messages/1/emoji_reactions/green_tick',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
# Deactivate realm emoji.
|
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
|
|
|
|
|
|
|
result = self.client_delete('/api/v1/messages/1/emoji_reactions/green_tick',
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
2016-11-30 08:14:46 +01:00
|
|
|
|
2016-11-03 18:49:00 +01:00
|
|
|
class ReactionEventTest(ZulipTestCase):
|
2016-11-30 08:14:46 +01:00
|
|
|
def test_add_event(self):
|
2016-11-03 18:49:00 +01:00
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Recipients of the message receive the reaction event
|
|
|
|
and event contains relevant data
|
|
|
|
"""
|
2017-05-24 02:42:31 +02:00
|
|
|
pm_sender = self.example_user('hamlet')
|
|
|
|
pm_recipient = self.example_user('othello')
|
2016-11-03 18:49:00 +01:00
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
result = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
2017-05-24 02:42:31 +02:00
|
|
|
"to": pm_recipient.email},
|
|
|
|
**self.api_auth(pm_sender.email))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_success(result)
|
2017-08-16 09:51:15 +02:00
|
|
|
pm_id = result.json()['id']
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
expected_recipient_ids = set([pm_sender.id, pm_recipient.id])
|
2016-11-03 18:49:00 +01:00
|
|
|
|
2017-08-04 02:25:38 +02:00
|
|
|
events = [] # type: List[Mapping[str, Any]]
|
2016-11-03 18:49:00 +01:00
|
|
|
with tornado_redirected_to_list(events):
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
2017-05-24 02:42:31 +02:00
|
|
|
**self.api_auth(reaction_sender.email))
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(len(events), 1)
|
|
|
|
|
|
|
|
event = events[0]['event']
|
|
|
|
event_user_ids = set(events[0]['users'])
|
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
2017-05-24 02:42:31 +02:00
|
|
|
self.assertEqual(event['user']['email'], reaction_sender.email)
|
2016-11-03 18:49:00 +01:00
|
|
|
self.assertEqual(event['type'], 'reaction')
|
|
|
|
self.assertEqual(event['op'], 'add')
|
|
|
|
self.assertEqual(event['emoji_name'], 'smile')
|
|
|
|
self.assertEqual(event['message_id'], pm_id)
|
2016-11-30 08:14:46 +01:00
|
|
|
|
|
|
|
def test_remove_event(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Recipients of the message receive the reaction event
|
|
|
|
and event contains relevant data
|
|
|
|
"""
|
2017-05-24 02:42:31 +02:00
|
|
|
pm_sender = self.example_user('hamlet')
|
|
|
|
pm_recipient = self.example_user('othello')
|
2016-11-30 08:14:46 +01:00
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
result = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
2017-05-24 02:42:31 +02:00
|
|
|
"to": pm_recipient.email},
|
|
|
|
**self.api_auth(pm_sender.email))
|
2016-11-30 08:14:46 +01:00
|
|
|
self.assert_json_success(result)
|
2017-08-17 08:42:19 +02:00
|
|
|
content = result.json()
|
2016-11-30 08:14:46 +01:00
|
|
|
pm_id = content['id']
|
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
expected_recipient_ids = set([pm_sender.id, pm_recipient.id])
|
2016-11-30 08:14:46 +01:00
|
|
|
|
2016-12-04 10:50:32 +01:00
|
|
|
add = self.client_put('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
2017-05-24 02:42:31 +02:00
|
|
|
**self.api_auth(reaction_sender.email))
|
2016-11-30 08:14:46 +01:00
|
|
|
self.assert_json_success(add)
|
|
|
|
|
2017-08-04 02:25:38 +02:00
|
|
|
events = [] # type: List[Mapping[str, Any]]
|
2016-11-30 08:14:46 +01:00
|
|
|
with tornado_redirected_to_list(events):
|
2016-12-04 10:50:32 +01:00
|
|
|
result = self.client_delete('/api/v1/messages/%s/emoji_reactions/smile' % (pm_id,),
|
2017-05-24 02:42:31 +02:00
|
|
|
**self.api_auth(reaction_sender.email))
|
2016-11-30 08:14:46 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(len(events), 1)
|
|
|
|
|
|
|
|
event = events[0]['event']
|
|
|
|
event_user_ids = set(events[0]['users'])
|
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
2017-05-24 02:42:31 +02:00
|
|
|
self.assertEqual(event['user']['email'], reaction_sender.email)
|
2016-11-30 08:14:46 +01:00
|
|
|
self.assertEqual(event['type'], 'reaction')
|
|
|
|
self.assertEqual(event['op'], 'remove')
|
|
|
|
self.assertEqual(event['emoji_name'], 'smile')
|
|
|
|
self.assertEqual(event['message_id'], pm_id)
|
2017-10-08 09:34:59 +02:00
|
|
|
|
|
|
|
class DefaultEmojiReactionTests(ZulipTestCase):
|
|
|
|
def post_reaction(self, reaction_info, message_id=1, sender='hamlet'):
|
|
|
|
# type: (Dict[str, str], int, str) -> HttpResponse
|
|
|
|
reaction_info['reaction_type'] = 'unicode_emoji'
|
|
|
|
sender = self.example_email(sender)
|
|
|
|
result = self.client_post('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def delete_reaction(self, reaction_info, message_id=1, sender='hamlet'):
|
|
|
|
# type: (Dict[str, str], int, str) -> HttpResponse
|
|
|
|
reaction_info['reaction_type'] = 'unicode_emoji'
|
|
|
|
sender = self.example_email(sender)
|
|
|
|
result = self.client_delete('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def get_message_reactions(self, message_id, emoji_code, reaction_type):
|
|
|
|
# type: (int, Text, Text) -> List[Reaction]
|
|
|
|
message = Message.objects.get(id=message_id)
|
|
|
|
reactions = Reaction.objects.filter(message=message,
|
|
|
|
emoji_code=emoji_code,
|
|
|
|
reaction_type=reaction_type)
|
|
|
|
return list(reactions)
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_add_default_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'thumbs_up',
|
|
|
|
'emoji_code': '1f44d',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_add_default_emoji_invalid_code(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': 'TBD',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, 'Emoji for this emoji code not found.')
|
|
|
|
|
|
|
|
def test_add_default_emoji_invalid_name(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'non-existent',
|
|
|
|
'emoji_code': '1f44d',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, 'Invalid emoji name.')
|
|
|
|
|
|
|
|
def test_add_to_existing_renamed_default_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
message = Message.objects.get(id=1)
|
|
|
|
reaction = Reaction.objects.create(user_profile=hamlet,
|
|
|
|
message=message,
|
|
|
|
emoji_name='old_name',
|
|
|
|
emoji_code='1f603',
|
|
|
|
reaction_type='unicode_emoji',
|
|
|
|
)
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'smiley',
|
|
|
|
'emoji_code': '1f603',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info, sender='AARON')
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
reactions = self.get_message_reactions(1, '1f603', 'unicode_emoji')
|
|
|
|
for reaction in reactions:
|
|
|
|
self.assertEqual(reaction.emoji_name, 'old_name')
|
|
|
|
|
|
|
|
def test_add_duplicate_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'non-existent',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, 'Reaction already exists.')
|
|
|
|
|
|
|
|
def test_preserve_non_canonical_name(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': '+1',
|
|
|
|
'emoji_code': '1f44d',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
reactions = self.get_message_reactions(1, '1f44d', 'unicode_emoji')
|
|
|
|
for reaction in reactions:
|
|
|
|
self.assertEqual(reaction.emoji_name, '+1')
|
|
|
|
|
|
|
|
def test_reaction_name_collapse(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': '+1',
|
|
|
|
'emoji_code': '1f44d',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
reaction_info['emoji_name'] = 'thumbs_up'
|
|
|
|
result = self.post_reaction(reaction_info, sender='AARON')
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
reactions = self.get_message_reactions(1, '1f44d', 'unicode_emoji')
|
|
|
|
for reaction in reactions:
|
|
|
|
self.assertEqual(reaction.emoji_name, '+1')
|
|
|
|
|
|
|
|
def test_delete_default_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
}
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_delete_non_existing_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'thumbs_up',
|
|
|
|
'emoji_code': '1f44d',
|
|
|
|
}
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, "Reaction doesn't exist.")
|
|
|
|
|
|
|
|
def test_delete_renamed_default_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
message = Message.objects.get(id=1)
|
|
|
|
Reaction.objects.create(user_profile=hamlet,
|
|
|
|
message=message,
|
|
|
|
emoji_name='old_name',
|
|
|
|
emoji_code='1f44f',
|
|
|
|
reaction_type='unicode_emoji',
|
|
|
|
)
|
|
|
|
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'new_name',
|
|
|
|
'emoji_code': '1f44f',
|
|
|
|
}
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_react_historical(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Reacting with valid emoji on a historical message succeeds.
|
|
|
|
"""
|
|
|
|
stream_name = "Saxony"
|
|
|
|
self.subscribe(self.example_user("cordelia"), stream_name)
|
|
|
|
message_id = self.send_stream_message(self.example_email("cordelia"), stream_name)
|
|
|
|
|
|
|
|
user_profile = self.example_user('hamlet')
|
|
|
|
|
|
|
|
# Verify that hamlet did not receive the message.
|
|
|
|
self.assertFalse(UserMessage.objects.filter(user_profile=user_profile,
|
|
|
|
message_id=message_id).exists())
|
|
|
|
|
|
|
|
# Have hamlet react to the message
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info, message_id=message_id)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
# Fetch the now-created UserMessage object to confirm it exists and is historical
|
|
|
|
user_message = UserMessage.objects.get(user_profile=user_profile, message_id=message_id)
|
|
|
|
self.assertTrue(user_message.flags.historical)
|
|
|
|
self.assertTrue(user_message.flags.read)
|
|
|
|
self.assertFalse(user_message.flags.starred)
|
|
|
|
|
|
|
|
class ZulipExtraEmojiReactionTest(ZulipTestCase):
|
|
|
|
def post_zulip_reaction(self, message_id=1, sender='hamlet'):
|
|
|
|
# type: (int, Text) -> HttpResponse
|
|
|
|
sender = self.example_email(sender)
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'zulip',
|
|
|
|
'emoji_code': 'zulip',
|
|
|
|
'reaction_type': 'zulip_extra_emoji',
|
|
|
|
}
|
|
|
|
result = self.client_post('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def test_add_zulip_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
result = self.post_zulip_reaction()
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_add_duplicate_zulip_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
result = self.post_zulip_reaction()
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
result = self.post_zulip_reaction()
|
|
|
|
self.assert_json_error(result, 'Reaction already exists.')
|
|
|
|
|
|
|
|
def test_delete_zulip_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
result = self.post_zulip_reaction()
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
sender = self.example_email('hamlet')
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'zulip',
|
|
|
|
'emoji_code': 'zulip',
|
|
|
|
'reaction_type': 'zulip_extra_emoji',
|
|
|
|
}
|
|
|
|
result = self.client_delete('/api/v1/messages/1/reactions',
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_delete_non_existent_zulip_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
sender = self.example_email('hamlet')
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'zulip',
|
|
|
|
'emoji_code': 'zulip',
|
|
|
|
'reaction_type': 'zulip_extra_emoji',
|
|
|
|
}
|
|
|
|
result = self.client_delete('/api/v1/messages/1/reactions',
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_error(result, "Reaction doesn't exist.")
|
|
|
|
|
|
|
|
class RealmEmojiReactionTests(ZulipTestCase):
|
|
|
|
def post_reaction(self, reaction_info, message_id=1, sender='hamlet'):
|
|
|
|
# type: (Dict[str, str], int, str) -> HttpResponse
|
|
|
|
reaction_info['reaction_type'] = 'realm_emoji'
|
|
|
|
sender = self.example_email(sender)
|
|
|
|
result = self.client_post('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def delete_reaction(self, reaction_info, message_id=1, sender='hamlet'):
|
|
|
|
# type: (Dict[str, str], int, str) -> HttpResponse
|
|
|
|
reaction_info['reaction_type'] = 'realm_emoji'
|
|
|
|
sender = self.example_email(sender)
|
|
|
|
result = self.client_delete('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def get_message_reactions(self, message_id, emoji_code, reaction_type):
|
|
|
|
# type: (int, Text, Text) -> List[Reaction]
|
|
|
|
message = Message.objects.get(id=message_id)
|
|
|
|
reactions = Reaction.objects.filter(message=message,
|
|
|
|
emoji_code=emoji_code,
|
|
|
|
reaction_type=reaction_type)
|
|
|
|
return list(reactions)
|
|
|
|
|
|
|
|
def test_add_realm_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'green_tick',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_add_realm_emoji_invalid_code(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'non_existent',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, 'Emoji for this emoji code not found.')
|
|
|
|
|
|
|
|
def test_add_deactivated_realm_emoji(self):
|
|
|
|
# type: () -> None
|
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
|
|
|
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'green_tick',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, 'Emoji for this emoji code not found.')
|
|
|
|
|
|
|
|
def test_add_to_existing_deactivated_realm_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'green_tick',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
|
|
|
|
|
|
|
result = self.post_reaction(reaction_info, sender='AARON')
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
reactions = self.get_message_reactions(1, 'green_tick', 'realm_emoji')
|
|
|
|
self.assertEqual(len(reactions), 2)
|
|
|
|
|
|
|
|
def test_remove_realm_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'green_tick',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_remove_deactivated_realm_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'green_tick',
|
|
|
|
'emoji_code': 'green_tick',
|
|
|
|
}
|
|
|
|
result = self.post_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
emoji = RealmEmoji.objects.get(name="green_tick")
|
|
|
|
emoji.deactivated = True
|
|
|
|
emoji.save(update_fields=['deactivated'])
|
|
|
|
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
def test_remove_non_existent_realm_emoji_reaction(self):
|
|
|
|
# type: () -> None
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'non_existent',
|
|
|
|
'emoji_code': 'TBD',
|
|
|
|
}
|
|
|
|
result = self.delete_reaction(reaction_info)
|
|
|
|
self.assert_json_error(result, "Reaction doesn't exist.")
|
|
|
|
|
|
|
|
def test_invalid_reaction_type(self) -> None:
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'zulip',
|
|
|
|
'emoji_code': 'zulip',
|
|
|
|
'reaction_type': 'nonexistent_emoji_type',
|
|
|
|
}
|
|
|
|
sender = self.example_email("hamlet")
|
|
|
|
message_id = 1
|
|
|
|
result = self.client_post('/api/v1/messages/%s/reactions' % (message_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(sender))
|
|
|
|
self.assert_json_error(result, "Emoji for this emoji code not found.")
|
|
|
|
|
|
|
|
class ReactionAPIEventTest(ZulipTestCase):
|
|
|
|
def test_add_event(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Recipients of the message receive the reaction event
|
|
|
|
and event contains relevant data
|
|
|
|
"""
|
|
|
|
pm_sender = self.example_user('hamlet')
|
|
|
|
pm_recipient = self.example_user('othello')
|
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
result = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
|
|
|
"to": pm_recipient.email},
|
|
|
|
**self.api_auth(pm_sender.email))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
pm_id = result.json()['id']
|
|
|
|
|
|
|
|
expected_recipient_ids = set([pm_sender.id, pm_recipient.id])
|
|
|
|
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
'reaction_type': 'unicode_emoji',
|
|
|
|
}
|
|
|
|
events = [] # type: List[Mapping[str, Any]]
|
|
|
|
with tornado_redirected_to_list(events):
|
|
|
|
result = self.client_post('/api/v1/messages/%s/reactions' % (pm_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(reaction_sender.email))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(len(events), 1)
|
|
|
|
|
|
|
|
event = events[0]['event']
|
|
|
|
event_user_ids = set(events[0]['users'])
|
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event['user']['user_id'], reaction_sender.id)
|
|
|
|
self.assertEqual(event['user']['email'], reaction_sender.email)
|
|
|
|
self.assertEqual(event['user']['full_name'], reaction_sender.full_name)
|
|
|
|
self.assertEqual(event['type'], 'reaction')
|
|
|
|
self.assertEqual(event['op'], 'add')
|
|
|
|
self.assertEqual(event['message_id'], pm_id)
|
|
|
|
self.assertEqual(event['emoji_name'], reaction_info['emoji_name'])
|
|
|
|
self.assertEqual(event['emoji_code'], reaction_info['emoji_code'])
|
|
|
|
self.assertEqual(event['reaction_type'], reaction_info['reaction_type'])
|
|
|
|
|
|
|
|
def test_remove_event(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Recipients of the message receive the reaction event
|
|
|
|
and event contains relevant data
|
|
|
|
"""
|
|
|
|
pm_sender = self.example_user('hamlet')
|
|
|
|
pm_recipient = self.example_user('othello')
|
|
|
|
reaction_sender = pm_recipient
|
|
|
|
|
|
|
|
result = self.client_post("/api/v1/messages", {"type": "private",
|
|
|
|
"content": "Test message",
|
|
|
|
"to": pm_recipient.email},
|
|
|
|
**self.api_auth(pm_sender.email))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
content = result.json()
|
|
|
|
pm_id = content['id']
|
|
|
|
|
|
|
|
expected_recipient_ids = set([pm_sender.id, pm_recipient.id])
|
|
|
|
|
|
|
|
reaction_info = {
|
|
|
|
'emoji_name': 'hamburger',
|
|
|
|
'emoji_code': '1f354',
|
|
|
|
'reaction_type': 'unicode_emoji',
|
|
|
|
}
|
|
|
|
add = self.client_post('/api/v1/messages/%s/reactions' % (pm_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(reaction_sender.email))
|
|
|
|
self.assert_json_success(add)
|
|
|
|
|
|
|
|
events = [] # type: List[Mapping[str, Any]]
|
|
|
|
with tornado_redirected_to_list(events):
|
|
|
|
result = self.client_delete('/api/v1/messages/%s/reactions' % (pm_id,),
|
|
|
|
reaction_info,
|
|
|
|
**self.api_auth(reaction_sender.email))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assertEqual(len(events), 1)
|
|
|
|
|
|
|
|
event = events[0]['event']
|
|
|
|
event_user_ids = set(events[0]['users'])
|
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event['user']['user_id'], reaction_sender.id)
|
|
|
|
self.assertEqual(event['user']['email'], reaction_sender.email)
|
|
|
|
self.assertEqual(event['user']['full_name'], reaction_sender.full_name)
|
|
|
|
self.assertEqual(event['type'], 'reaction')
|
|
|
|
self.assertEqual(event['op'], 'remove')
|
|
|
|
self.assertEqual(event['message_id'], pm_id)
|
|
|
|
self.assertEqual(event['emoji_name'], reaction_info['emoji_name'])
|
|
|
|
self.assertEqual(event['emoji_code'], reaction_info['emoji_code'])
|
|
|
|
self.assertEqual(event['reaction_type'], reaction_info['reaction_type'])
|