Added support for Bot API 7.0 (#1387)

* Added support for Bot API 7.0

* Fixed available tests

* Fixed text decorations

* Bot API 7.0 tests for ForwardMessages

* Bot API 7.0 tests for CopyMessages

* Bot API 7.0 tests for DeleteMessages

* Bot API 7.0 tests for GetUserChatBoosts

* Bot API 7.0 tests for SetMessageReaction

* Fixed custom_emoji attribute name

* Fixed tests

* Test parsing CallbackQuery message (inaccessible and accessible)

* Added changes description

* Bot API 7.0 tests for dispatcher handle update message_reaction

* Bot API 7.0 tests for dispatcher handle update message_reaction_count

* Bot API 7.0 tests for dispatcher handle update chat_boost

* Bot API 7.0 tests for dispatcher handle update removed_chat_boost

* fix tests: update ReactionTypeCustomEmoji custom_emoji -> custom_emoji_id

* micro fix Markdown V2 blockquote

* add tests for Markdown tools

* fix markdown test apply single entity

* add tests coverage for Message.react

* check that all messages and content types are covered for Message.content_type

* sort imports in tests (run `make reformat lint`)

* update Giveaway objects Unix time field to DateTime type

* Update Message.content_type property

* upgrade tests for message content_types and sent_copy

* Update Giveaway type generation config

* Update GiveawayWinners and PassportFile types generation configs

---------

Co-authored-by: Suren Khorenyan <surenkhorenyan@gmail.com>
This commit is contained in:
Alex Root Junior 2023-12-31 01:40:44 +02:00 committed by GitHub
parent 756cfeba0a
commit 6795b3de05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
244 changed files with 9401 additions and 1715 deletions

View file

@ -0,0 +1,29 @@
from random import randint
from aiogram.methods import CopyMessages
from aiogram.types import MessageId
from tests.mocked_bot import MockedBot
class TestCopyMessages:
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
CopyMessages,
ok=True,
result=[
MessageId(message_id=randint(100, 200)),
MessageId(message_id=randint(300, 400)),
],
)
response: list[MessageId] = await bot.copy_messages(
chat_id=randint(1000, 9999),
from_chat_id=randint(1000, 9999),
message_ids=[
randint(1000, 4999),
randint(5000, 9999),
],
)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -0,0 +1,19 @@
from aiogram.methods import DeleteMessages
from tests.mocked_bot import MockedBot
class TestDeleteMessages:
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
DeleteMessages,
ok=True,
result=True,
)
response: bool = await bot.delete_messages(
chat_id=42,
message_ids=[13, 77],
)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -20,4 +20,5 @@ class TestForwardMessage:
response: Message = await bot.forward_message(chat_id=42, from_chat_id=42, message_id=42)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -0,0 +1,29 @@
from random import randint
from aiogram.methods import ForwardMessages
from aiogram.types import MessageId
from tests.mocked_bot import MockedBot
class TestForwardMessages:
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
ForwardMessages,
ok=True,
result=[
MessageId(message_id=randint(100, 200)),
MessageId(message_id=randint(200, 300)),
],
)
response: list[MessageId] = await bot.forward_messages(
chat_id=randint(10, 50),
from_chat_id=randint(50, 99),
message_ids=[
randint(400, 500),
randint(600, 700),
],
)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -0,0 +1,52 @@
from datetime import datetime, timedelta
from random import randint
from aiogram.methods import GetUserChatBoosts
from aiogram.types import (
ChatBoost,
ChatBoostSourceGiveaway,
ChatBoostSourcePremium,
User,
UserChatBoosts,
)
from tests.mocked_bot import MockedBot
class TestGetUserChatBoosts:
async def test_bot_method(self, bot: MockedBot):
now = datetime.now()
user = User(
id=randint(200, 500),
is_bot=False,
first_name="name",
)
prepare_result = bot.add_result_for(
GetUserChatBoosts,
ok=True,
result=UserChatBoosts(
boosts=[
ChatBoost(
boost_id="eggs",
add_date=now - timedelta(days=7),
expiration_date=now + timedelta(days=14),
source=ChatBoostSourceGiveaway(
giveaway_message_id=randint(100, 300),
),
),
ChatBoost(
boost_id="spam",
add_date=now - timedelta(days=3),
expiration_date=now + timedelta(days=21),
source=ChatBoostSourcePremium(user=user),
),
]
),
)
response: UserChatBoosts = await bot.get_user_chat_boosts(
chat_id=randint(100, 200),
user_id=user.id,
)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -0,0 +1,25 @@
from random import randint
from aiogram.methods import SetMessageReaction
from aiogram.types import ReactionTypeCustomEmoji
from tests.mocked_bot import MockedBot
class TestSetMessageReaction:
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
SetMessageReaction,
ok=True,
result=True,
)
response: bool = await bot.set_message_reaction(
chat_id=randint(200, 300),
message_id=randint(100, 200),
reaction=[
ReactionTypeCustomEmoji(custom_emoji_id="qwerty"),
],
)
request = bot.get_request()
assert request
assert response == prepare_result.result

View file

@ -1,5 +1,5 @@
from aiogram.methods import AnswerCallbackQuery
from aiogram.types import CallbackQuery, User
from aiogram.types import CallbackQuery, InaccessibleMessage, Message, User
class TestCallbackQuery:
@ -17,3 +17,34 @@ class TestCallbackQuery:
for key, value in kwargs.items():
assert getattr(api_method, key) == value
def test_parse_message(self):
data = {
"id": "id",
"from": {"id": 42, "is_bot": False, "first_name": "name"},
"message": {
"message_id": 123,
"date": 1234567890,
"chat": {"id": 42, "type": "private"},
},
"chat_instance": "chat",
"data": "data",
}
callback_query = CallbackQuery.model_validate(data)
assert isinstance(callback_query.message, Message)
def test_parse_inaccessible_message(self):
data = {
"id": "id",
"from": {"id": 42, "is_bot": False, "first_name": "name"},
"message": {
"message_id": 123,
"date": 0,
"chat": {"id": 42, "type": "private"},
},
"chat_instance": "chat",
"data": "data",
}
callback_query = CallbackQuery.model_validate(data)
assert isinstance(callback_query.message, InaccessibleMessage)

View file

@ -31,6 +31,7 @@ from aiogram.methods import (
SendVideo,
SendVideoNote,
SendVoice,
SetMessageReaction,
StopMessageLiveLocation,
TelegramMethod,
UnpinChatMessage,
@ -50,6 +51,12 @@ from aiogram.types import (
ForumTopicEdited,
ForumTopicReopened,
Game,
GeneralForumTopicHidden,
GeneralForumTopicUnhidden,
Giveaway,
GiveawayCompleted,
GiveawayCreated,
GiveawayWinners,
InlineKeyboardButton,
InlineKeyboardMarkup,
InputMediaPhoto,
@ -62,11 +69,13 @@ from aiogram.types import (
Poll,
PollOption,
ProximityAlertTriggered,
ReactionTypeCustomEmoji,
Sticker,
Story,
SuccessfulPayment,
User,
UserShared,
UsersShared,
Venue,
Video,
VideoChatEnded,
@ -76,6 +85,7 @@ from aiogram.types import (
VideoNote,
Voice,
WebAppData,
WriteAccessAllowed,
)
from aiogram.types.message import ContentType, Message
@ -444,13 +454,23 @@ TEST_FORUM_TOPIC_REOPENED = Message(
from_user=User(id=42, is_bot=False, first_name="Test"),
forum_topic_reopened=ForumTopicReopened(),
)
TEST_USER_SHARED = Message(
TEST_MESSAGE_USER_SHARED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=User(id=42, is_bot=False, first_name="Test"),
user_shared=UserShared(request_id=42, user_id=42),
)
TEST_MESSAGE_USERS_SHARED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
users_shared=UsersShared(
request_id=0,
user_ids=[1, 2],
),
)
TEST_CHAT_SHARED = Message(
message_id=42,
date=datetime.datetime.now(),
@ -467,6 +487,73 @@ TEST_MESSAGE_STORY = Message(
forward_signature="Test",
forward_date=datetime.datetime.now(),
)
TEST_MESSAGE_GIVEAWAY = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
giveaway=Giveaway(
chats=[Chat(id=42, type="private")],
winners_selection_date=datetime.datetime.now() + datetime.timedelta(days=7),
winner_count=10,
),
)
TEST_MESSAGE_GIVEAWAY_CREATED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
giveaway_created=GiveawayCreated(),
)
TEST_MESSAGE_GIVEAWAY_WINNERS = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
giveaway_winners=GiveawayWinners(
chat=Chat(id=77, type="private"),
giveaway_message_id=123,
winners_selection_date=datetime.datetime.now(),
winner_count=1,
winners=[User(id=42, is_bot=False, first_name="Test")],
),
)
TEST_MESSAGE_GIVEAWAY_COMPLETED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
giveaway_completed=GiveawayCompleted(winner_count=10),
)
TEST_MESSAGE_HAS_MEDIA_SPOILER = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
has_media_spoiler=True,
)
TEST_MESSAGE_GENERAL_FORUM_TOPIC_HIDDEN = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
general_forum_topic_hidden=GeneralForumTopicHidden(),
)
TEST_MESSAGE_GENERAL_FORUM_TOPIC_UNHIDDEN = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
general_forum_topic_unhidden=GeneralForumTopicUnhidden(),
)
TEST_MESSAGE_WRITE_ACCESS_ALLOWED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=None,
write_access_allowed=WriteAccessAllowed(),
)
TEST_MESSAGE_UNKNOWN = Message(
message_id=42,
date=datetime.datetime.now(),
@ -474,63 +561,161 @@ TEST_MESSAGE_UNKNOWN = Message(
from_user=User(id=42, is_bot=False, first_name="Test"),
)
MESSAGES_AND_CONTENT_TYPES = [
[TEST_MESSAGE_TEXT, ContentType.TEXT],
[TEST_MESSAGE_AUDIO, ContentType.AUDIO],
[TEST_MESSAGE_ANIMATION, ContentType.ANIMATION],
[TEST_MESSAGE_DOCUMENT, ContentType.DOCUMENT],
[TEST_MESSAGE_GAME, ContentType.GAME],
[TEST_MESSAGE_PHOTO, ContentType.PHOTO],
[TEST_MESSAGE_STICKER, ContentType.STICKER],
[TEST_MESSAGE_VIDEO, ContentType.VIDEO],
[TEST_MESSAGE_VIDEO_NOTE, ContentType.VIDEO_NOTE],
[TEST_MESSAGE_VOICE, ContentType.VOICE],
[TEST_MESSAGE_CONTACT, ContentType.CONTACT],
[TEST_MESSAGE_VENUE, ContentType.VENUE],
[TEST_MESSAGE_LOCATION, ContentType.LOCATION],
[TEST_MESSAGE_NEW_CHAT_MEMBERS, ContentType.NEW_CHAT_MEMBERS],
[TEST_MESSAGE_LEFT_CHAT_MEMBER, ContentType.LEFT_CHAT_MEMBER],
[TEST_MESSAGE_INVOICE, ContentType.INVOICE],
[TEST_MESSAGE_SUCCESSFUL_PAYMENT, ContentType.SUCCESSFUL_PAYMENT],
[TEST_MESSAGE_CONNECTED_WEBSITE, ContentType.CONNECTED_WEBSITE],
[TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, ContentType.MIGRATE_FROM_CHAT_ID],
[TEST_MESSAGE_MIGRATE_TO_CHAT_ID, ContentType.MIGRATE_TO_CHAT_ID],
[TEST_MESSAGE_PINNED_MESSAGE, ContentType.PINNED_MESSAGE],
[TEST_MESSAGE_NEW_CHAT_TITLE, ContentType.NEW_CHAT_TITLE],
[TEST_MESSAGE_NEW_CHAT_PHOTO, ContentType.NEW_CHAT_PHOTO],
[TEST_MESSAGE_DELETE_CHAT_PHOTO, ContentType.DELETE_CHAT_PHOTO],
[TEST_MESSAGE_GROUP_CHAT_CREATED, ContentType.GROUP_CHAT_CREATED],
[TEST_MESSAGE_SUPERGROUP_CHAT_CREATED, ContentType.SUPERGROUP_CHAT_CREATED],
[TEST_MESSAGE_CHANNEL_CHAT_CREATED, ContentType.CHANNEL_CHAT_CREATED],
[TEST_MESSAGE_PASSPORT_DATA, ContentType.PASSPORT_DATA],
[TEST_MESSAGE_PROXIMITY_ALERT_TRIGGERED, ContentType.PROXIMITY_ALERT_TRIGGERED],
[TEST_MESSAGE_POLL, ContentType.POLL],
[
TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED,
ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED,
],
[TEST_MESSAGE_VIDEO_CHAT_SCHEDULED, ContentType.VIDEO_CHAT_SCHEDULED],
[TEST_MESSAGE_VIDEO_CHAT_STARTED, ContentType.VIDEO_CHAT_STARTED],
[TEST_MESSAGE_VIDEO_CHAT_ENDED, ContentType.VIDEO_CHAT_ENDED],
[
TEST_MESSAGE_VIDEO_CHAT_PARTICIPANTS_INVITED,
ContentType.VIDEO_CHAT_PARTICIPANTS_INVITED,
],
[TEST_MESSAGE_DICE, ContentType.DICE],
[TEST_MESSAGE_WEB_APP_DATA, ContentType.WEB_APP_DATA],
[TEST_FORUM_TOPIC_CREATED, ContentType.FORUM_TOPIC_CREATED],
[TEST_FORUM_TOPIC_EDITED, ContentType.FORUM_TOPIC_EDITED],
[TEST_FORUM_TOPIC_CLOSED, ContentType.FORUM_TOPIC_CLOSED],
[TEST_FORUM_TOPIC_REOPENED, ContentType.FORUM_TOPIC_REOPENED],
[TEST_MESSAGE_USER_SHARED, ContentType.USER_SHARED],
[TEST_MESSAGE_USERS_SHARED, ContentType.USERS_SHARED],
[TEST_CHAT_SHARED, ContentType.CHAT_SHARED],
[TEST_MESSAGE_STORY, ContentType.STORY],
[TEST_MESSAGE_GIVEAWAY, ContentType.GIVEAWAY],
[TEST_MESSAGE_GIVEAWAY_CREATED, ContentType.GIVEAWAY_CREATED],
[TEST_MESSAGE_GIVEAWAY_WINNERS, ContentType.GIVEAWAY_WINNERS],
[TEST_MESSAGE_GIVEAWAY_COMPLETED, ContentType.GIVEAWAY_COMPLETED],
[TEST_MESSAGE_HAS_MEDIA_SPOILER, ContentType.HAS_MEDIA_SPOILER],
[TEST_MESSAGE_GENERAL_FORUM_TOPIC_HIDDEN, ContentType.GENERAL_FORUM_TOPIC_HIDDEN],
[TEST_MESSAGE_GENERAL_FORUM_TOPIC_UNHIDDEN, ContentType.GENERAL_FORUM_TOPIC_UNHIDDEN],
[TEST_MESSAGE_WRITE_ACCESS_ALLOWED, ContentType.WRITE_ACCESS_ALLOWED],
[TEST_MESSAGE_UNKNOWN, ContentType.UNKNOWN],
]
MESSAGES_AND_COPY_METHODS = [
[TEST_MESSAGE_TEXT, SendMessage],
[TEST_MESSAGE_AUDIO, SendAudio],
[TEST_MESSAGE_ANIMATION, SendAnimation],
[TEST_MESSAGE_DOCUMENT, SendDocument],
[TEST_MESSAGE_GAME, None],
[TEST_MESSAGE_PHOTO, SendPhoto],
[TEST_MESSAGE_STICKER, SendSticker],
[TEST_MESSAGE_VIDEO, SendVideo],
[TEST_MESSAGE_VIDEO_NOTE, SendVideoNote],
[TEST_MESSAGE_VOICE, SendVoice],
[TEST_MESSAGE_CONTACT, SendContact],
[TEST_MESSAGE_VENUE, SendVenue],
[TEST_MESSAGE_LOCATION, SendLocation],
[TEST_MESSAGE_STORY, ForwardMessage],
[TEST_MESSAGE_NEW_CHAT_MEMBERS, None],
[TEST_MESSAGE_LEFT_CHAT_MEMBER, None],
[TEST_MESSAGE_INVOICE, None],
[TEST_MESSAGE_SUCCESSFUL_PAYMENT, None],
[TEST_MESSAGE_CONNECTED_WEBSITE, None],
[TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, None],
[TEST_MESSAGE_MIGRATE_TO_CHAT_ID, None],
[TEST_MESSAGE_PINNED_MESSAGE, None],
[TEST_MESSAGE_NEW_CHAT_TITLE, None],
[TEST_MESSAGE_NEW_CHAT_PHOTO, None],
[TEST_MESSAGE_DELETE_CHAT_PHOTO, None],
[TEST_MESSAGE_GROUP_CHAT_CREATED, None],
[TEST_MESSAGE_SUPERGROUP_CHAT_CREATED, None],
[TEST_MESSAGE_CHANNEL_CHAT_CREATED, None],
[TEST_MESSAGE_PASSPORT_DATA, None],
[TEST_MESSAGE_PROXIMITY_ALERT_TRIGGERED, None],
[TEST_MESSAGE_POLL, SendPoll],
[TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED, None],
[TEST_MESSAGE_VIDEO_CHAT_STARTED, None],
[TEST_MESSAGE_VIDEO_CHAT_ENDED, None],
[TEST_MESSAGE_VIDEO_CHAT_PARTICIPANTS_INVITED, None],
[TEST_MESSAGE_DICE, SendDice],
[TEST_MESSAGE_USER_SHARED, None],
[TEST_CHAT_SHARED, None],
[TEST_MESSAGE_GIVEAWAY_COMPLETED, None],
[TEST_MESSAGE_HAS_MEDIA_SPOILER, None],
[TEST_MESSAGE_WEB_APP_DATA, None],
[TEST_FORUM_TOPIC_CREATED, None],
[TEST_FORUM_TOPIC_EDITED, None],
[TEST_FORUM_TOPIC_CLOSED, None],
[TEST_FORUM_TOPIC_REOPENED, None],
[TEST_MESSAGE_GENERAL_FORUM_TOPIC_HIDDEN, None],
[TEST_MESSAGE_GENERAL_FORUM_TOPIC_UNHIDDEN, None],
[TEST_MESSAGE_GIVEAWAY_CREATED, None],
[TEST_MESSAGE_USERS_SHARED, None],
[TEST_MESSAGE_VIDEO_CHAT_SCHEDULED, None],
[TEST_MESSAGE_WRITE_ACCESS_ALLOWED, None],
[TEST_MESSAGE_GIVEAWAY, None],
[TEST_MESSAGE_GIVEAWAY_WINNERS, None],
[TEST_MESSAGE_UNKNOWN, None],
]
class TestAllMessageTypesTested:
@pytest.fixture(scope="function")
def known_content_types(self):
content_types = {t for t in ContentType}
content_types.remove(ContentType.ANY)
return content_types
def test_for_content_type_tests(self, known_content_types):
"""
Test if all ContentType options have example messages.
On new Bot API updates new ContentType entries are created.
TestMessage.test_content_type checks what content type is returned.
Make sure MESSAGES_AND_CONTENT_TYPES has examples
for all the ContentType entries, fail otherwise.
"""
content_types_w_example_messages = {t[1] for t in MESSAGES_AND_CONTENT_TYPES}
assert content_types_w_example_messages == known_content_types
def test_for_copy_methods(self, known_content_types):
"""
Test if all known message types are checked for copy_message.
Also relies on the previous test (both should be green)
"""
checked_content_types = {m[0].content_type for m in MESSAGES_AND_COPY_METHODS}
assert checked_content_types == known_content_types
class TestMessage:
@pytest.mark.parametrize(
"message,content_type",
[
[TEST_MESSAGE_TEXT, ContentType.TEXT],
[TEST_MESSAGE_AUDIO, ContentType.AUDIO],
[TEST_MESSAGE_ANIMATION, ContentType.ANIMATION],
[TEST_MESSAGE_DOCUMENT, ContentType.DOCUMENT],
[TEST_MESSAGE_GAME, ContentType.GAME],
[TEST_MESSAGE_PHOTO, ContentType.PHOTO],
[TEST_MESSAGE_STICKER, ContentType.STICKER],
[TEST_MESSAGE_VIDEO, ContentType.VIDEO],
[TEST_MESSAGE_VIDEO_NOTE, ContentType.VIDEO_NOTE],
[TEST_MESSAGE_VOICE, ContentType.VOICE],
[TEST_MESSAGE_CONTACT, ContentType.CONTACT],
[TEST_MESSAGE_VENUE, ContentType.VENUE],
[TEST_MESSAGE_LOCATION, ContentType.LOCATION],
[TEST_MESSAGE_NEW_CHAT_MEMBERS, ContentType.NEW_CHAT_MEMBERS],
[TEST_MESSAGE_LEFT_CHAT_MEMBER, ContentType.LEFT_CHAT_MEMBER],
[TEST_MESSAGE_INVOICE, ContentType.INVOICE],
[TEST_MESSAGE_SUCCESSFUL_PAYMENT, ContentType.SUCCESSFUL_PAYMENT],
[TEST_MESSAGE_CONNECTED_WEBSITE, ContentType.CONNECTED_WEBSITE],
[TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, ContentType.MIGRATE_FROM_CHAT_ID],
[TEST_MESSAGE_MIGRATE_TO_CHAT_ID, ContentType.MIGRATE_TO_CHAT_ID],
[TEST_MESSAGE_PINNED_MESSAGE, ContentType.PINNED_MESSAGE],
[TEST_MESSAGE_NEW_CHAT_TITLE, ContentType.NEW_CHAT_TITLE],
[TEST_MESSAGE_NEW_CHAT_PHOTO, ContentType.NEW_CHAT_PHOTO],
[TEST_MESSAGE_DELETE_CHAT_PHOTO, ContentType.DELETE_CHAT_PHOTO],
[TEST_MESSAGE_GROUP_CHAT_CREATED, ContentType.GROUP_CHAT_CREATED],
[TEST_MESSAGE_SUPERGROUP_CHAT_CREATED, ContentType.SUPERGROUP_CHAT_CREATED],
[TEST_MESSAGE_CHANNEL_CHAT_CREATED, ContentType.CHANNEL_CHAT_CREATED],
[TEST_MESSAGE_PASSPORT_DATA, ContentType.PASSPORT_DATA],
[TEST_MESSAGE_PROXIMITY_ALERT_TRIGGERED, ContentType.PROXIMITY_ALERT_TRIGGERED],
[TEST_MESSAGE_POLL, ContentType.POLL],
[
TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED,
ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED,
],
[TEST_MESSAGE_VIDEO_CHAT_SCHEDULED, ContentType.VIDEO_CHAT_SCHEDULED],
[TEST_MESSAGE_VIDEO_CHAT_STARTED, ContentType.VIDEO_CHAT_STARTED],
[TEST_MESSAGE_VIDEO_CHAT_ENDED, ContentType.VIDEO_CHAT_ENDED],
[
TEST_MESSAGE_VIDEO_CHAT_PARTICIPANTS_INVITED,
ContentType.VIDEO_CHAT_PARTICIPANTS_INVITED,
],
[TEST_MESSAGE_DICE, ContentType.DICE],
[TEST_MESSAGE_WEB_APP_DATA, ContentType.WEB_APP_DATA],
[TEST_FORUM_TOPIC_CREATED, ContentType.FORUM_TOPIC_CREATED],
[TEST_FORUM_TOPIC_EDITED, ContentType.FORUM_TOPIC_EDITED],
[TEST_FORUM_TOPIC_CLOSED, ContentType.FORUM_TOPIC_CLOSED],
[TEST_FORUM_TOPIC_REOPENED, ContentType.FORUM_TOPIC_REOPENED],
[TEST_USER_SHARED, ContentType.USER_SHARED],
[TEST_CHAT_SHARED, ContentType.CHAT_SHARED],
[TEST_MESSAGE_STORY, ContentType.STORY],
[TEST_MESSAGE_UNKNOWN, ContentType.UNKNOWN],
],
MESSAGES_AND_CONTENT_TYPES,
)
def test_content_type(self, message: Message, content_type: str):
assert message.content_type == content_type
@ -637,47 +822,7 @@ class TestMessage:
@pytest.mark.parametrize(
"message,expected_method",
[
[TEST_MESSAGE_TEXT, SendMessage],
[TEST_MESSAGE_AUDIO, SendAudio],
[TEST_MESSAGE_ANIMATION, SendAnimation],
[TEST_MESSAGE_DOCUMENT, SendDocument],
[TEST_MESSAGE_GAME, None],
[TEST_MESSAGE_PHOTO, SendPhoto],
[TEST_MESSAGE_STICKER, SendSticker],
[TEST_MESSAGE_VIDEO, SendVideo],
[TEST_MESSAGE_VIDEO_NOTE, SendVideoNote],
[TEST_MESSAGE_VOICE, SendVoice],
[TEST_MESSAGE_CONTACT, SendContact],
[TEST_MESSAGE_VENUE, SendVenue],
[TEST_MESSAGE_LOCATION, SendLocation],
[TEST_MESSAGE_STORY, ForwardMessage],
[TEST_MESSAGE_NEW_CHAT_MEMBERS, None],
[TEST_MESSAGE_LEFT_CHAT_MEMBER, None],
[TEST_MESSAGE_INVOICE, None],
[TEST_MESSAGE_SUCCESSFUL_PAYMENT, None],
[TEST_MESSAGE_CONNECTED_WEBSITE, None],
[TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, None],
[TEST_MESSAGE_MIGRATE_TO_CHAT_ID, None],
[TEST_MESSAGE_PINNED_MESSAGE, None],
[TEST_MESSAGE_NEW_CHAT_TITLE, None],
[TEST_MESSAGE_NEW_CHAT_PHOTO, None],
[TEST_MESSAGE_DELETE_CHAT_PHOTO, None],
[TEST_MESSAGE_GROUP_CHAT_CREATED, None],
[TEST_MESSAGE_SUPERGROUP_CHAT_CREATED, None],
[TEST_MESSAGE_CHANNEL_CHAT_CREATED, None],
[TEST_MESSAGE_PASSPORT_DATA, None],
[TEST_MESSAGE_PROXIMITY_ALERT_TRIGGERED, None],
[TEST_MESSAGE_POLL, SendPoll],
[TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED, None],
[TEST_MESSAGE_VIDEO_CHAT_STARTED, None],
[TEST_MESSAGE_VIDEO_CHAT_ENDED, None],
[TEST_MESSAGE_VIDEO_CHAT_PARTICIPANTS_INVITED, None],
[TEST_MESSAGE_DICE, SendDice],
[TEST_USER_SHARED, None],
[TEST_CHAT_SHARED, None],
[TEST_MESSAGE_UNKNOWN, None],
],
MESSAGES_AND_COPY_METHODS,
)
def test_send_copy(
self,
@ -861,6 +1006,20 @@ class TestMessage:
assert isinstance(method, UnpinChatMessage)
assert method.chat_id == message.chat.id
def test_react(self):
message = Message(
message_id=777,
chat=Chat(id=-42, type="channel"),
date=datetime.datetime.now(),
)
emoji_reaction = ReactionTypeCustomEmoji(custom_emoji_id="qwerty")
method = message.react(
reaction=[emoji_reaction],
)
assert isinstance(method, SetMessageReaction)
assert method.chat_id == message.chat.id
assert method.reaction == [emoji_reaction]
@pytest.mark.parametrize(
"text,entities,mode,expected_value",
[

View file

@ -18,16 +18,24 @@ from aiogram.methods import GetMe, GetUpdates, SendMessage, TelegramMethod
from aiogram.types import (
CallbackQuery,
Chat,
ChatBoost,
ChatBoostRemoved,
ChatBoostSourceGiveaway,
ChatBoostUpdated,
ChatJoinRequest,
ChatMemberMember,
ChatMemberUpdated,
ChosenInlineResult,
InlineQuery,
Message,
MessageReactionCountUpdated,
MessageReactionUpdated,
Poll,
PollAnswer,
PollOption,
PreCheckoutQuery,
ReactionCount,
ReactionTypeCustomEmoji,
ShippingAddress,
ShippingQuery,
Update,
@ -447,6 +455,76 @@ class TestDispatcher:
True,
True,
),
pytest.param(
"message_reaction",
Update(
update_id=42,
message_reaction=MessageReactionUpdated(
chat=Chat(id=-42, type="channel"),
message_id=12345,
user=User(id=42, is_bot=False, first_name="Test"),
date=datetime.datetime.now(),
old_reaction=[],
new_reaction=[ReactionTypeCustomEmoji(custom_emoji_id="qwerty")],
),
),
True,
True,
),
pytest.param(
"message_reaction_count",
Update(
update_id=42,
message_reaction_count=MessageReactionCountUpdated(
chat=Chat(id=-42, type="channel"),
message_id=12345,
date=datetime.datetime.now(),
reactions=[
ReactionCount(
type=ReactionTypeCustomEmoji(custom_emoji_id="qwerty"),
total_count=123,
),
],
),
),
True,
False,
),
pytest.param(
"chat_boost",
Update(
update_id=42,
chat_boost=ChatBoostUpdated(
chat=Chat(id=-42, type="channel"),
boost=ChatBoost(
boost_id="qwerty",
add_date=datetime.datetime.now(),
expiration_date=datetime.datetime.now(),
source=ChatBoostSourceGiveaway(
giveaway_message_id=77,
),
),
),
),
True,
False,
),
pytest.param(
"removed_chat_boost",
Update(
update_id=42,
removed_chat_boost=ChatBoostRemoved(
chat=Chat(id=-42, type="channel"),
boost_id="qwerty",
remove_date=datetime.datetime.now(),
source=ChatBoostSourceGiveaway(
giveaway_message_id=77,
),
),
),
True,
False,
),
],
)
async def test_listen_update(

View file

@ -268,7 +268,7 @@ class TestNode:
assert (
node.as_pretty_string(indent=True)
== """Strikethrough(
Text(
CustomEmoji(
'X',
custom_emoji_id='42'
)

View file

@ -3,8 +3,10 @@ from typing import Any, Callable, Optional, Tuple
import pytest
from aiogram.utils.markdown import (
blockquote,
bold,
code,
hblockquote,
hbold,
hcode,
hide_link,
@ -54,6 +56,22 @@ class TestMarkdown:
None,
'<a href="https://aiogram.dev">&#8203;</a>',
],
[blockquote, ("spam", "eggs"), " ", ">spam eggs"],
pytest.param(
blockquote,
("spam", "eggs"),
"\n",
">spam\n>eggs",
id="Markdown V2 blockquote multiline",
),
[hblockquote, ("spam", "eggs"), " ", "<blockquote>spam eggs</blockquote>"],
pytest.param(
hblockquote,
("spam", "eggs"),
"\n",
"<blockquote>spam\neggs</blockquote>",
id="HTML blockquote multiline",
),
],
)
def test_formatter(

View file

@ -66,6 +66,11 @@ class TestTextDecoration:
MessageEntity(type="text_link", offset=0, length=5, url="https://aiogram.dev"),
'<a href="https://aiogram.dev">test</a>',
],
[
html_decoration,
MessageEntity(type="blockquote", offset=0, length=5),
"<blockquote>test</blockquote>",
],
[markdown_decoration, MessageEntity(type="bold", offset=0, length=5), "*test*"],
[markdown_decoration, MessageEntity(type="italic", offset=0, length=5), "_\rtest_\r"],
[markdown_decoration, MessageEntity(type="code", offset=0, length=5), "`test`"],
@ -106,6 +111,11 @@ class TestTextDecoration:
),
"[test](tg://user?id=42)",
],
[
markdown_decoration,
MessageEntity(type="blockquote", offset=0, length=5),
">test",
],
],
)
def test_apply_single_entity(