diff --git a/test/e2e/constants/group_chat.py b/test/e2e/constants/group_chat.py new file mode 100644 index 0000000000..6548d3c400 --- /dev/null +++ b/test/e2e/constants/group_chat.py @@ -0,0 +1,4 @@ +from enum import Enum + +class GroupChatMessages(Enum): + WELCOME_GROUP_MESSAGE = "Welcome to the beginning of the " diff --git a/test/e2e/constants/user.py b/test/e2e/constants/user.py index aa5ba62b7d..e49cd66085 100644 --- a/test/e2e/constants/user.py +++ b/test/e2e/constants/user.py @@ -9,7 +9,7 @@ user_account_one = UserAccount('squisher', '0000000000', [ user_account_two = UserAccount('athletic', '0000000000', [ 'measure', 'cube', 'cousin', 'debris', 'slam', 'ignore', 'seven', 'hat', 'satisfy', 'frown', 'casino', 'inflict' ]) -user_account_three = UserAccount('nervous', '000000000', []) +user_account_three = UserAccount('nervous', '0000000000', []) user_account_one_changed_password = UserAccount('squisher', 'NewPassword@12345', []) diff --git a/test/e2e/gui/components/messaging/edit_group_name_and_image_popup.py b/test/e2e/gui/components/messaging/edit_group_name_and_image_popup.py new file mode 100644 index 0000000000..04a6e5a7e9 --- /dev/null +++ b/test/e2e/gui/components/messaging/edit_group_name_and_image_popup.py @@ -0,0 +1,22 @@ +import allure + +from gui.components.base_popup import BasePopup +from gui.elements.qt.button import Button +from gui.elements.qt.text_edit import TextEdit + + +class EditGroupNameAndImagePopup(BasePopup): + + def __init__(self): + super(EditGroupNameAndImagePopup, self).__init__() + self._group_name_field = TextEdit('groupChatEdit_name_TextEdit') + self._save_changes_button = Button('save_changes_StatusButton') + + @allure.step('Change group name') + def change_group_name(self, name: str): + self._group_name_field.text = name + + @allure.step('Save changes') + def save_changes(self): + self._save_changes_button.click() + self.wait_until_hidden() diff --git a/test/e2e/gui/components/messaging/leave_group_popup.py b/test/e2e/gui/components/messaging/leave_group_popup.py new file mode 100644 index 0000000000..4df3142e04 --- /dev/null +++ b/test/e2e/gui/components/messaging/leave_group_popup.py @@ -0,0 +1,16 @@ +import allure + +from gui.components.base_popup import BasePopup +from gui.elements.qt.button import Button + + +class LeaveGroupPopup(BasePopup): + + def __init__(self): + super().__init__() + self._leave_button = Button('leave_StatusButton') + + @allure.step("Confirm leaving group") + def confirm_leaving(self): + self._leave_button.click() + self.wait_until_hidden() diff --git a/test/e2e/gui/objects_map/component_names.py b/test/e2e/gui/objects_map/component_names.py index 53a4d00ec9..273e1457c2 100644 --- a/test/e2e/gui/objects_map/component_names.py +++ b/test/e2e/gui/objects_map/component_names.py @@ -292,3 +292,10 @@ mainWindow_secureYourSeedPhraseBanner_ModuleWarning = {"container": statusDeskto copy_SyncCodeStatusButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "syncCodeCopyButton", "type": "StatusButton", "visible": True} done_SyncCodeStatusButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "syncAnewDeviceNextButton", "type": "StatusButton", "visible": True} syncCodeInput_StatusPasswordInput = {"container": statusDesktop_mainWindow_overlay, "id": "syncCodeInput", "type": "StatusPasswordInput", "unnamed": 1, "visible": True} + +# Edit group name and image popup +groupChatEdit_name_TextEdit = {"container": statusDesktop_mainWindow_overlay, "objectName": "groupChatEdit_name", "type": "TextEdit", "visible": True} +save_changes_StatusButton = {"checkable": False, "container": statusDesktop_mainWindow_overlay, "objectName": "groupChatEdit_save", "type": "StatusButton", "visible": True} + +# Leave group popup +leave_StatusButton = {"checkable": False, "container": statusDesktop_mainWindow_overlay, "objectName": "leaveGroupConfirmationDialogLeaveButton", "type": "StatusButton", "visible": True} diff --git a/test/e2e/gui/objects_map/messages_names.py b/test/e2e/gui/objects_map/messages_names.py index 166b2a2d26..3bdf78f3c6 100644 --- a/test/e2e/gui/objects_map/messages_names.py +++ b/test/e2e/gui/objects_map/messages_names.py @@ -1,4 +1,4 @@ -from .main_names import statusDesktop_mainWindow +from .main_names import statusDesktop_mainWindow, mainWindow_StatusWindow mainWindow_chatView_ChatView = {"container": statusDesktop_mainWindow, "id": "chatView", "type": "ChatView", "unnamed": 1, "visible": True} @@ -10,6 +10,7 @@ mainWindow_scrollView_StatusScrollView = {"container": mainWindow_contactColumnL scrollView_Flickable = {"container": mainWindow_scrollView_StatusScrollView, "type": "Flickable", "unnamed": 1, "visible": True} scrollView_ContactsColumnView_chatList_StatusChatList = {"container": mainWindow_scrollView_StatusScrollView, "objectName": "ContactsColumnView_chatList", "type": "StatusChatList", "visible": True} chatList_ListView = {"container": statusDesktop_mainWindow, "objectName": "chatListItems", "type": "StatusListView", "visible": True} + # Tool Bar mainWindow_statusToolBar_StatusToolBar = {"container": mainWindow_chatView_ChatView, "objectName": "statusToolBar", "type": "StatusToolBar", "visible": True} @@ -18,6 +19,34 @@ mainWindow_ChatColumnView = {"container": mainWindow_chatView_ChatView, "type": mainWindow_chatLogView_StatusListView = {"container": mainWindow_ChatColumnView, "objectName": "chatLogView", "type": "StatusListView", "visible": True} chatLogView_chatMessageViewDelegate_MessageView = {"container": mainWindow_chatLogView_StatusListView, "objectName": "chatMessageViewDelegate", "type": "MessageView", "visible": True, "enabled": True} +# Create Chat View +mainWindow_CreateChatView = {"container": statusDesktop_mainWindow, "type": "CreateChatView", "unnamed": 1, "visible": True} +createChatView_confirmBtn = {"container": statusDesktop_mainWindow, "objectName": "inlineSelectorConfirmButton", "type": "StatusButton"} +createChatView_contactsList = {"container": statusDesktop_mainWindow, "objectName": "createChatContactsList", "type": "StatusListView", "visible": True} +mainWindow_Cancel_StatusButton = {"checkable": False, "container": statusDesktop_mainWindow, "text": "Cancel", "type": "StatusButton", "unnamed": 1, "visible": True} + +# Chat Messages View +mainWindow_ChatMessagesView = {"container": statusDesktop_mainWindow, "type": "ChatMessagesView", "unnamed": 1, "visible": True} +chatView_log = {"container": statusDesktop_mainWindow, "objectName": "chatLogView", "type": "StatusListView", "visible": True} +groupchatLogView_chatMessageViewDelegate_MessageView = {"container": chatView_log, "objectName": "chatMessageViewDelegate", "type": "MessageView", "visible": True} +groupMessagesItem = {"container": groupchatLogView_chatMessageViewDelegate_MessageView, "type": "StatusBaseText", "unnamed": 1, "visible": True} +chatMessageViewDelegate_ChannelIdentifierView = {"container": chatLogView_chatMessageViewDelegate_MessageView, "type": "ChannelIdentifierView", "unnamed": 1, "visible": True} +chatLogView_Item = {"container": chatView_log, "type": "Item", "unnamed": 1, "visible": True} +statusChatInfoButton = {"container": mainWindow_statusToolBar_StatusToolBar, "objectName": "statusChatInfoButtonNameText", "type": "TruncatedTextWithTooltip", "visible": True} +moreOptionsButton_StatusFlatRoundButton = {"container": mainWindow_statusToolBar_StatusToolBar, "objectName": "chatToolbarMoreOptionsButton", "type": "StatusFlatRoundButton", "visible": True} +mainWindow_Overlay = {"container": statusDesktop_mainWindow, "type": "Overlay", "unnamed": 1, "visible": True} +edit_name_and_image_StatusMenuItem = {"checkable": False, "container": mainWindow_Overlay, "enabled": True, "objectName": "editNameAndImageMenuItem", "text": "Edit name and image", "type": "StatusMenuItem", "visible": True} +leave_group_StatusMenuItem = {"checkable": False, "container": mainWindow_Overlay, "enabled": True, "objectName": "deleteOrLeaveMenuItem", "text": "Leave group", "type": "StatusMenuItem", "visible": True} +mainWindow_inputScrollView_StatusScrollView = {"container": statusDesktop_mainWindow, "id": "inputScrollView", "type": "StatusScrollView", "unnamed": 1, "visible": True} +inputScrollView_Message_PlaceholderText = {"container": mainWindow_inputScrollView_StatusScrollView, "text": "Message", "type": "PlaceholderText", "unnamed": 1, "visible": True} +mainWindow_scrollView_StatusScrollView = {"container": mainWindow_StatusWindow, "id": "scrollView", "type": "StatusScrollView", "unnamed": 1, "visible": True} +scrollView_StatusChatListItem = {"container": mainWindow_scrollView_StatusScrollView, "type": "StatusChatListItem", "visible": True} + # User List Panel mainWindow_UserListPanel = {"container": mainWindow_chatView_ChatView, "type": "UserListPanel", "unnamed": 1, "visible": True} userListPanel_StatusMemberListItem = {"container": mainWindow_UserListPanel, "type": "StatusMemberListItem", "unnamed": 1, "visible": True} + +# Group chat users list panel +mainWindow_userListPanel_StatusListView = {"container": statusDesktop_mainWindow, "objectName": "userListPanel", "type": "StatusListView", "visible": True} +groupUserListPanel_StatusMemberListItem = {"container": mainWindow_userListPanel_StatusListView, "type": "StatusMemberListItem", "unnamed": 1, "visible": True} + diff --git a/test/e2e/gui/screens/messages.py b/test/e2e/gui/screens/messages.py index a4bfd2d1c6..c4a47d3d92 100644 --- a/test/e2e/gui/screens/messages.py +++ b/test/e2e/gui/screens/messages.py @@ -1,16 +1,21 @@ import time import typing +from typing import List import allure import configs import driver from driver.objects_access import walk_children +from gui.components.context_menu import ContextMenu +from gui.components.messaging.edit_group_name_and_image_popup import EditGroupNameAndImagePopup +from gui.components.messaging.leave_group_popup import LeaveGroupPopup from gui.elements.qt.button import Button from gui.elements.qt.list import List from gui.elements.qt.object import QObject from gui.elements.qt.scroll import Scroll from gui.elements.qt.text_edit import TextEdit +from gui.elements.qt.text_label import TextLabel from gui.screens.community import CommunityScreen from scripts.tools.image import Image @@ -23,6 +28,7 @@ class LeftPanel(QObject): self._search_text_edit = TextEdit('mainWindow_search_edit_TextEdit') self._scroll = Scroll('scrollView_Flickable') self._contacts_list = List('chatList_ListView') + self._contact_item = QObject('scrollView_StatusChatListItem') @property @allure.step('Get contacts') @@ -35,6 +41,28 @@ class LeftPanel(QObject): self._contacts_list.select(contact, 'objectName') return ChatView() + @allure.step('Click start chat button') + def start_chat(self): + self._start_chat_button.click(x=1, y=1) + return CreateChatView() + + @allure.step('Open context menu group chat') + def _open_context_menu_for_chat(self, chat_name: str) -> ContextMenu: + self._contact_item.real_name['objectName'] = chat_name + self._contact_item.open_context_menu() + return ContextMenu().wait_until_appears() + + @allure.step('Open leave popup') + def open_leave_group_popup(self, chat_name: str, attempt: int = 2) -> LeaveGroupPopup: + try: + self._open_context_menu_for_chat(chat_name).select('Leave group') + return LeaveGroupPopup().wait_until_appears() + except: + if attempt: + return self.open_leave_group_popup(chat_name, attempt - 1) + else: + raise + class ToolBar(QObject): @@ -115,6 +143,96 @@ class ChatView(QObject): return message.join_community() +class CreateChatView(QObject): + + def __init__(self): + super().__init__('mainWindow_CreateChatView') + self._confirm_button = Button('createChatView_confirmBtn') + self._cancel_button = Button('mainWindow_Cancel_StatusButton') + self._create_chat_contacts_list = List('createChatView_contactsList') + + @property + @allure.step('Get contacts') + def contacts(self) -> typing.List[str]: + return self._create_chat_contacts_list.get_values('title') + + @allure.step('Select contact in the list') + def select_contact(self, contact: str): + assert driver.waitFor(lambda: contact in self.contacts), f'Contact: {contact} not found in {self.contacts}' + self._create_chat_contacts_list.select(contact, 'title') + + @allure.step('Create chat by adding contacts from contact list') + def create_chat(self, members): + for member in members[0:]: + time.sleep(0.2) + self.select_contact(member) + self._confirm_button.click() + return ChatMessagesView().wait_until_appears() + + +class ChatMessagesView(QObject): + + def __init__(self): + super().__init__('mainWindow_ChatMessagesView') + self._group_chat_message_item = TextLabel('chatLogView_Item') + self._group_name_label = TextLabel('statusChatInfoButton') + self._more_button = Button('moreOptionsButton_StatusFlatRoundButton') + self._edit_menu_item = QObject('edit_name_and_image_StatusMenuItem') + self._leave_group_item = QObject('leave_group_StatusMenuItem') + self._message_field = TextEdit('inputScrollView_Message_PlaceholderText') + + @property + @allure.step('Get group name') + def group_name(self) -> str: + return self._group_name_label.text + + @property + @allure.step('Get group welcome message') + def group_welcome_message(self) -> str: + for delegate in walk_children(self._group_chat_message_item.object): + if getattr(delegate, 'id', '') == 'msgDelegate': + for item in walk_children(delegate): + if getattr(item, 'id', '') == 'descText': + return str(item.text) + + @allure.step('Click more options button') + def open_more_options(self): + self._more_button.click() + + @allure.step('Choose edit group name option') + def open_edit_group_name_form(self): + time.sleep(2) + self.open_more_options() + time.sleep(2) + self._edit_menu_item.click() + return EditGroupNameAndImagePopup().wait_until_appears() + + @allure.step('Choose leave group option') + def leave_group(self): + time.sleep(2) + self.open_more_options() + time.sleep(2) + self._leave_group_item.click() + return LeaveGroupPopup().wait_until_appears() + + @allure.step('Send message to group chat') + def send_message_to_group_chat(self, message: str): + self._message_field.type_text(message) + driver.nativeType('') + + +class Members(QObject): + + def __init__(self): + super().__init__('mainWindow_userListPanel_StatusListView') + self._member_item = QObject('groupUserListPanel_StatusMemberListItem') + + @property + @allure.step('Get group members') + def members(self) -> typing.List[str]: + return [str(member.title) for member in driver.findAllObjects(self._member_item.real_name)] + + class MessagesScreen(QObject): def __init__(self): @@ -122,3 +240,5 @@ class MessagesScreen(QObject): self.left_panel = LeftPanel() self.tool_bar = ToolBar() self.chat = ChatView() + self.right_panel = Members() + self.group_chat = ChatMessagesView() diff --git a/test/e2e/gui/screens/settings.py b/test/e2e/gui/screens/settings.py index e6281023f9..8264bb8427 100644 --- a/test/e2e/gui/screens/settings.py +++ b/test/e2e/gui/screens/settings.py @@ -247,6 +247,10 @@ class ContactsSettingsView(QObject): self._contact_request_button.click() return SendContactRequest().wait_until_appears() + @allure.step('Open contacts request form') + def send_contacts_request(self): + LeftPanel().open_messaging_settings().open_contacts_settings().open_contact_request_form() + @allure.step('Accept contact request') def accept_contact_request( self, contact: str, timeout_sec: int = configs.timeouts.MESSAGING_TIMEOUT_SEC) -> MessagesScreen: diff --git a/test/e2e/tests/test_messaging.py b/test/e2e/tests/test_messaging.py new file mode 100644 index 0000000000..d8cf84ccfe --- /dev/null +++ b/test/e2e/tests/test_messaging.py @@ -0,0 +1,180 @@ +import allure +import pytest +from allure_commons._allure import step + +import configs.testpath +import constants +from constants import UserAccount +from constants.group_chat import GroupChatMessages +from gui.main_window import MainWindow +from gui.screens.messages import MessagesScreen + +pytestmark = allure.suite("Messaging") + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703014', 'Create a group and send messages') +@pytest.mark.case(703014) +@pytest.mark.parametrize('user_data_one, user_data_two, user_data_three', [ + (configs.testpath.TEST_USER_DATA / 'user_account_one', configs.testpath.TEST_USER_DATA / 'user_account_two', + configs.testpath.TEST_USER_DATA / 'user_account_two') +]) +def test_group_chat(multiple_instance, user_data_one, user_data_two, user_data_three): + user_one: UserAccount = constants.user_account_one + user_two: UserAccount = constants.user_account_two + user_three: UserAccount = constants.user_account_three + members = [user_two.name, user_three.name] + main_window = MainWindow() + messages_screen = MessagesScreen() + + with multiple_instance() as aut_one, multiple_instance() as aut_two, multiple_instance() as aut_three: + with step(f'Launch multiple instances with authorized users {user_one.name} and {user_two.name}'): + for aut, account in zip([aut_one, aut_two, aut_three], [user_one, user_two, user_three]): + aut.attach() + main_window.wait_until_appears(configs.timeouts.APP_LOAD_TIMEOUT_MSEC).prepare() + main_window.authorize_user(account) + main_window.hide() + + with step(f'User {user_two.name}, get chat key'): + aut_two.attach() + main_window.prepare() + profile_popup = main_window.left_panel.open_user_canvas().open_profile_popup() + chat_key = profile_popup.chat_key + profile_popup.close() + main_window.hide() + + with step(f'User {user_one.name}, send contact request to {user_two.name}'): + aut_one.attach() + main_window.prepare() + settings = main_window.left_panel.open_settings() + messaging_settings = settings.left_panel.open_messaging_settings() + contacts_settings = messaging_settings.open_contacts_settings() + contact_request_popup = contacts_settings.open_contact_request_form() + contact_request_popup.send(chat_key, f'Hello {user_two.name}') + main_window.hide() + + with step(f'User {user_two.name}, accept contact request from {user_one.name}'): + aut_two.attach() + main_window.prepare() + settings = main_window.left_panel.open_settings() + messaging_settings = settings.left_panel.open_messaging_settings() + contacts_settings = messaging_settings.open_contacts_settings() + contacts_settings.accept_contact_request(user_one.name) + main_window.hide() + + with step(f'User {user_three.name}, get chat key'): + aut_three.attach() + main_window.prepare() + profile_popup = main_window.left_panel.open_user_canvas().open_profile_popup() + chat_key = profile_popup.chat_key + profile_popup.close() + main_window.hide() + + with step(f'User {user_one.name}, send contact request to {user_three.name}'): + aut_one.attach() + main_window.prepare() + settings = main_window.left_panel.open_settings() + messaging_settings = settings.left_panel.open_messaging_settings() + contacts_settings = messaging_settings.open_contacts_settings() + contact_request_popup = contacts_settings.open_contact_request_form() + contact_request_popup.send(chat_key, f'Hello {user_three.name}') + main_window.hide() + + with step(f'User {user_three.name}, accept contact request from {user_one.name}'): + aut_three.attach() + main_window.prepare() + settings = main_window.left_panel.open_settings() + messaging_settings = settings.left_panel.open_messaging_settings() + contacts_settings = messaging_settings.open_contacts_settings() + contacts_settings.accept_contact_request(user_one.name) + main_window.hide() + + with step(f'User {user_one.name}, start chat and add {user_two.name}'): + aut_one.attach() + main_window.prepare() + main_window.left_panel.open_messages_screen() + messages_screen.left_panel.start_chat().create_chat(members) + + with step('Verify group chat info'): + with step('Verify group chat name'): + group_chat_name = user_two.name + '&' + user_three.name + assert messages_screen.group_chat.group_name == group_chat_name, f'Group chat name is not correct' + with step('Welcome group message is correct'): + actual_welcome_message = messages_screen.group_chat.group_welcome_message + assert actual_welcome_message.startswith(GroupChatMessages.WELCOME_GROUP_MESSAGE.value) + assert actual_welcome_message.endswith(' group!') + assert group_chat_name in actual_welcome_message + with step('Verify there are three members in group members list'): + assert user_one.name in messages_screen.right_panel.members + assert user_two.name in messages_screen.right_panel.members + assert user_three.name in messages_screen.right_panel.members + assert len(messages_screen.right_panel.members) == 3 + + with step('Open edit group name and image form and change name'): + new_name = 'New_name' + edit_group_popup = messages_screen.group_chat.open_edit_group_name_form() + edit_group_popup.change_group_name(new_name) + edit_group_popup.save_changes() + + with step('Verify group chat name is changed'): + assert messages_screen.group_chat.group_name == new_name + + with step('Send message to group chat and verify it was sent'): + messages_screen.group_chat.send_message_to_group_chat('Hi') + message_objects = messages_screen.chat.messages + message_items = [message.text for message in message_objects] + for message_item in message_items: + assert 'Hi' in message_item + + with step('Leave group'): + messages_screen.group_chat.leave_group().confirm_leaving() + + with step('Check that group name is not displayed on left panel'): + assert new_name not in messages_screen.left_panel.contacts + main_window.hide() + + with step(f'Restart app for {user_two.name} and open group chat'): + aut_two.restart() + main_window.authorize_user(user_two) + messages_screen.left_panel.open_chat(new_name) + + with step('Verify there are two members in group members list'): + assert user_two.name in messages_screen.right_panel.members + assert user_three.name in messages_screen.right_panel.members + assert len(messages_screen.right_panel.members) == 2 + + with step('Send message to group chat and verify it was sent'): + messages_screen.group_chat.send_message_to_group_chat('Hi') + message_objects = messages_screen.chat.messages + message_items = [message.text for message in message_objects] + for message_item in message_items: + assert 'Hi' in message_item + + with step('Leave group'): + messages_screen.left_panel.open_leave_group_popup(new_name).confirm_leaving() + + with step('Check that group name is not displayed on left panel'): + assert new_name not in messages_screen.left_panel.contacts + main_window.hide() + + with step(f'Restart app for {user_three.name} and open group chat'): + aut_three.restart() + main_window.authorize_user(user_three) + messages_screen.left_panel.open_chat(new_name) + + with step('Verify there is one member in group members list'): + assert user_three.name in messages_screen.right_panel.members + assert len(messages_screen.right_panel.members) == 1 + + with step('Send message to group chat and verify it was sent'): + messages_screen.group_chat.send_message_to_group_chat('Hi') + message_objects = messages_screen.chat.messages + message_items = [message.text for message in message_objects] + for message_item in message_items: + assert 'Hi' in message_item + + with step('Leave group'): + messages_screen.left_panel.open_leave_group_popup(new_name).confirm_leaving() + + with step('Check that group name is not displayed on left panel'): + assert new_name not in messages_screen.left_panel.contacts + main_window.hide()