diff --git a/test/e2e/constants/community_settings.py b/test/e2e/constants/community_settings.py index b65e0ed109..18c1e077d1 100644 --- a/test/e2e/constants/community_settings.py +++ b/test/e2e/constants/community_settings.py @@ -58,6 +58,8 @@ class ToastMessages(Enum): BLOCKED_USER_TOAST = ' blocked' UNBLOCKED_USER_TOAST = ' unblocked' REMOVED_CONTACT_TOAST = 'Contact removed' + BANNED_USER_TOAST = ' was banned from ' + UNBANNED_USER_TOAST = ' unbanned from ' class LimitWarnings(Enum): diff --git a/test/e2e/gui/components/community/ban_member_popup.py b/test/e2e/gui/components/community/ban_member_popup.py new file mode 100644 index 0000000000..7a8f8269a5 --- /dev/null +++ b/test/e2e/gui/components/community/ban_member_popup.py @@ -0,0 +1,23 @@ +import allure + +import configs +from gui.components.base_popup import BasePopup +from gui.elements.button import Button +from gui.objects_map import names + + +class BanMemberPopup(BasePopup): + + def __init__(self): + super().__init__() + self._ban_confirm_button = Button(names.ban_StatusButton) + + @allure.step('Wait until appears {0}') + def wait_until_appears(self, timeout_msec: int = configs.timeouts.UI_LOAD_TIMEOUT_MSEC): + self._ban_confirm_button.wait_until_appears(timeout_msec) + return self + + @allure.step('Confirm banning member') + def confirm_banning(self): + self._ban_confirm_button.click() + \ No newline at end of file diff --git a/test/e2e/gui/objects_map/communities_names.py b/test/e2e/gui/objects_map/communities_names.py index da241c2f5c..8cc4a883fb 100644 --- a/test/e2e/gui/objects_map/communities_names.py +++ b/test/e2e/gui/objects_map/communities_names.py @@ -77,6 +77,8 @@ mainWindow_MembersSettingsPanel = {"container": mainWindow_communityLoader_Loade membersListViews_ListView = {"container": mainWindow_MembersSettingsPanel, "objectName": "CommunityMembersTabPanel_MembersListViews", "type": "ListView", "visible": True} memberItem_StatusMemberListItem = {"container": membersListViews_ListView, "id": "memberItem", "type": "StatusMemberListItem", "unnamed": 1, "visible": True} communitySettings_MembersTab_Member_Kick_Button = {"container": membersListViews_ListView, "objectName": "MemberListItem_KickButton", "type": "StatusButton", "visible": True} +memberItem_Ban_StatusButton = {"checkable": False, "container": membersListViews_ListView, "objectName": "MemberListItem_BanButton", "type": "StatusButton", "visible": True} +memberItem_Unban_StatusButton = {"checkable": False, "container": membersListViews_ListView, "objectName": "MemberListItem_UnbanButton", "type": "StatusButton", "visible": True} # Tokens View mainWindow_mintPanel_MintTokensSettingsPanel = {"container": mainWindow_StatusWindow, "id": "mintPanel", "type": "MintTokensSettingsPanel", "unnamed": 1, "visible": True} @@ -225,3 +227,6 @@ croppedImageEditBanner = {"container": mainWindow_communityEditPanelScrollView_E mainWindow_userListPanel_StatusListView = {"container": statusDesktop_mainWindow, "objectName": "userListPanel", "type": "StatusListView", "visible": True} userListPanel_StatusMemberListItem = {"container": mainWindow_userListPanel_StatusListView, "type": "StatusMemberListItem", "unnamed": 1, "visible": True} statusBadge_StatusBadge = {"container": userListPanel_StatusMemberListItem, "id": "statusBadge", "type": "StatusBadge", "unnamed": 1, "visible": True} +mainWindow_membersTabBar_StatusTabBar = {"container": statusDesktop_mainWindow, "id": "membersTabBar", "type": "StatusTabBar", "unnamed": 1, "visible": True} +membersTabBar_Banned_StatusTabButton = {"checkable": True, "container": mainWindow_membersTabBar_StatusTabBar, "objectName": "bannedButton", "type": "StatusTabButton", "visible": True} +membersTabBar_All_Members_StatusTabButton = {"checkable": True, "container": mainWindow_membersTabBar_StatusTabBar, "objectName": "allMembersButton", "type": "StatusTabButton", "visible": True} diff --git a/test/e2e/gui/objects_map/messaging_names.py b/test/e2e/gui/objects_map/messaging_names.py index 9ef40bcbf9..f3d7f1c008 100644 --- a/test/e2e/gui/objects_map/messaging_names.py +++ b/test/e2e/gui/objects_map/messaging_names.py @@ -84,6 +84,7 @@ edit_inputScrollView_messageInputField_TextArea = {"container": chatMessageViewD chatMessageViewDelegate_Save_StatusButton = {"checkable": False, "container": chatLogView_chatMessageViewDelegate_MessageView, "id": "saveBtn", "type": "StatusButton", "unnamed": 1, "visible": True} chatMessageViewDelegate_reply_icon_StatusIcon = {"container": chatLogView_chatMessageViewDelegate_MessageView, "objectName": "reply-icon", "type": "StatusIcon", "visible": True} mainWindow_replyArea_StatusChatInputReplyArea = {"container": statusDesktop_mainWindow, "id": "replyArea", "type": "StatusChatInputReplyArea", "unnamed": 1, "visible": True} +layout_recentMessagesButton_AnchorButton = {"checkable": False, "container": mainWindow_chatLogView_StatusListView, "id": "recentMessagesButton", "type": "AnchorButton", "unnamed": 1, "visible": True} # Message link preview mainWindow_optionsComboBox_ComboBox = {"container": statusDesktop_mainWindow, "id": "optionsComboBox", "type": "ComboBox", "unnamed": 1, "visible": True} diff --git a/test/e2e/gui/objects_map/names.py b/test/e2e/gui/objects_map/names.py index 348f4cc913..e9d21e260f 100644 --- a/test/e2e/gui/objects_map/names.py +++ b/test/e2e/gui/objects_map/names.py @@ -194,6 +194,12 @@ join_StatusButton = { "container": statusDesktop_mainWindow_overlay, "type": "St welcome_authenticate_StatusButton = {"container": statusDesktop_mainWindow_overlay, "type": "StatusButton", "unnamed": 1, "visible": True} share_your_addresses_to_join_StatusButton = {"container": statusDesktop_mainWindow_overlay, "type": "StatusButton", "unnamed": 1, "visible": True} +# Kick member popup +confirm_kick_StatusButton = {"checkable": False, "container": statusDesktop_mainWindow_overlay, "objectName": "CommunityMembers_KickModal_KickButton", "type": "StatusButton", "visible": True} + +# Ban member popup +ban_StatusButton = {"checkable": False, "container": statusDesktop_mainWindow_overlay, "objectName": "CommunityMembers_BanModal_BanButton", "type": "StatusButton", "visible": True} + # Pinned messages unpinButton_StatusFlatRoundButton = {"container": statusDesktop_mainWindow_overlay, "id": "unpinButton", "type": "StatusFlatRoundButton", "unnamed": 1, "visible": True} headerActionsCloseButton_StatusFlatRoundButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "headerActionsCloseButton", "type": "StatusFlatRoundButton", "visible": True} diff --git a/test/e2e/gui/screens/community.py b/test/e2e/gui/screens/community.py index 59cf24f02c..2881146f04 100644 --- a/test/e2e/gui/screens/community.py +++ b/test/e2e/gui/screens/community.py @@ -438,12 +438,22 @@ class Members(QObject): super().__init__(communities_names.mainWindow_userListPanel_StatusListView) self._member_item = QObject(communities_names.userListPanel_StatusMemberListItem) self._user_badge_color = QObject(communities_names.statusBadge_StatusBadge) + self._banned_tab_button = Button(communities_names.membersTabBar_Banned_StatusTabButton) + self._all_members_tab_button = Button(communities_names.membersTabBar_All_Members_StatusTabButton) @property @allure.step('Get all members') def members(self) -> typing.List[str]: return [str(member.statusListItemTitle.text) for member in driver.findAllObjects(self._member_item.real_name)] + @allure.step('Open banned tab') + def click_banned_button(self): + self._banned_tab_button.click() + + @allure.step('Open all members tab') + def click_all_members_button(self): + self._all_members_tab_button.click() + @allure.step('Click member by name') def click_member(self, member_name: str): for member in driver.findAllObjects(self._member_item.real_name): diff --git a/test/e2e/gui/screens/community_settings.py b/test/e2e/gui/screens/community_settings.py index 1b5add759b..c3bb933297 100644 --- a/test/e2e/gui/screens/community_settings.py +++ b/test/e2e/gui/screens/community_settings.py @@ -7,6 +7,7 @@ import allure import configs import driver from driver.objects_access import walk_children +from gui.components.community.ban_member_popup import BanMemberPopup from gui.components.community.color_select_popup import ColorSelectPopup from gui.components.community.tags_select_popup import TagsSelectPopup from gui.components.kick_member_popup import KickMemberPopup @@ -267,6 +268,8 @@ class MembersView(QObject): super().__init__(communities_names.mainWindow_MembersSettingsPanel) self._member_list_item = QObject(communities_names.memberItem_StatusMemberListItem) self._kick_member_button = Button(communities_names.communitySettings_MembersTab_Member_Kick_Button) + self._ban_member_button = Button(communities_names.memberItem_Ban_StatusButton) + self._unban_member_button = Button(communities_names.memberItem_Unban_StatusButton) @property @allure.step('Get community members') @@ -302,6 +305,25 @@ class MembersView(QObject): assert kick_member_popup.exists kick_member_popup.confirm_kicking() + @allure.step('Ban community member') + def ban_member(self, member_name: str): + member = self.get_member_object(member_name) + QObject(real_name=driver.objectMap.realName(member)).hover() + self._ban_member_button.click() + return BanMemberPopup().wait_until_appears() + + @allure.step('Unban community member') + def unban_member(self, member_name: str, attempt: int = 2): + member = self.get_member_object(member_name) + QObject(real_name=driver.objectMap.realName(member)).hover() + try: + self._unban_member_button.wait_until_appears().click() + except AssertionError as er: + if attempt: + self.unban_member(member_name, attempt-1) + else: + raise er + class AirdropsView(QObject): def __init__(self): diff --git a/test/e2e/gui/screens/messages.py b/test/e2e/gui/screens/messages.py index 795ae79fc7..48389e9dd2 100644 --- a/test/e2e/gui/screens/messages.py +++ b/test/e2e/gui/screens/messages.py @@ -231,6 +231,7 @@ class ChatView(QObject): super().__init__(messaging_names.mainWindow_ChatColumnView) self._message_list_item = QObject(messaging_names.chatLogView_chatMessageViewDelegate_MessageView) self._deleted_message = QObject(messaging_names.chatMessageViewDelegate_deletedMessage_RowLayout) + self._recent_messages_button = QObject(messaging_names.layout_recentMessagesButton_AnchorButton) @allure.step('Get messages') def messages(self, index: int) -> typing.List[Message]: @@ -239,6 +240,8 @@ class ChatView(QObject): # message_list_item has different indexes if we run multiple instances, so we pass index if index is not None: self._message_list_item.real_name['index'] = index + if self._recent_messages_button.is_visible: + self._recent_messages_button.click() for item in driver.findAllObjects(self._message_list_item.real_name): if getattr(item, 'isMessage', False): _messages.append(Message(item)) diff --git a/test/e2e/tests/communities/test_communities.py b/test/e2e/tests/communities/test_communities.py index 82e624183e..47aaddd950 100644 --- a/test/e2e/tests/communities/test_communities.py +++ b/test/e2e/tests/communities/test_communities.py @@ -1,3 +1,4 @@ +import time from copy import deepcopy from datetime import datetime @@ -8,6 +9,7 @@ from allure_commons._allure import step import driver from constants import ColorCodes, UserAccount from constants.community_settings import ToastMessages +from gui.screens.community import Members from gui.screens.messages import MessagesScreen from . import marks @@ -129,15 +131,20 @@ def test_edit_community(main_screen: MainWindow, params): @allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703252', 'Kick user') @allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703254', 'Edit chat - Delete any message') -@pytest.mark.case(703252, 703252) -def test_community_admin_kick_member_and_delete_message(multiple_instances): - user_one: UserAccount = constants.user_account_one - user_two: UserAccount = constants.user_account_two +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/736991', 'Owner can ban member') +@pytest.mark.case(703252, 703252, 736991) +@pytest.mark.parametrize('user_data_one, user_data_two', [ + (configs.testpath.TEST_USER_DATA / 'group_chat_user_2', configs.testpath.TEST_USER_DATA / 'group_chat_user_1') +]) +def test_community_admin_ban_kick_member_and_delete_message(multiple_instances, user_data_one, user_data_two): + user_one: UserAccount = constants.group_chat_user_2 + user_two: UserAccount = constants.group_chat_user_1 + timeout = configs.timeouts.UI_LOAD_TIMEOUT_MSEC community_params = deepcopy(constants.community_params) community_params['name'] = f'{datetime.now():%d%m%Y_%H%M%S}' main_screen = MainWindow() - with multiple_instances() as aut_one, multiple_instances() as aut_two: + with multiple_instances(user_data=user_data_one) as aut_one, multiple_instances(user_data=user_data_two) as aut_two: 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], [user_one, user_two]): aut.attach() @@ -145,36 +152,11 @@ def test_community_admin_kick_member_and_delete_message(multiple_instances): main_screen.authorize_user(account) main_screen.hide() - with step(f'User {user_two.name}, get chat key'): - aut_two.attach() - main_screen.prepare() - profile_popup = main_screen.left_panel.open_online_identifier().open_profile_popup_from_online_identifier() - chat_key = profile_popup.copy_chat_key - profile_popup.close() - main_screen.hide() - - with step(f'User {user_one.name}, send contact request to {user_two.name}'): - aut_one.attach() - main_screen.prepare() - settings = main_screen.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_screen.hide() - - with step(f'User {user_two.name}, accept contact request from {user_one.name}'): - aut_two.attach() - main_screen.prepare() - settings = main_screen.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) - with step(f'User {user_two.name}, create community and invite {user_one.name}'): - with step('Enable creation of community option'): - settings = main_screen.left_panel.open_settings() - settings.left_panel.open_advanced_settings().enable_creation_of_communities() + aut_two.attach() + main_screen.prepare() + settings = main_screen.left_panel.open_settings() + settings.left_panel.open_advanced_settings().enable_creation_of_communities() community = main_screen.create_community(community_params['name'], community_params['description'], community_params['intro'], community_params['outro'], @@ -187,9 +169,9 @@ def test_community_admin_kick_member_and_delete_message(multiple_instances): main_screen.prepare() messages_view = main_screen.left_panel.open_messages_screen() assert driver.waitFor(lambda: user_two.name in messages_view.left_panel.get_chats_names, - configs.timeouts.UI_LOAD_TIMEOUT_MSEC) + 10000) chat = messages_view.left_panel.click_chat_by_name(user_two.name) - community_screen = chat.accept_community_invite(community_params['name'], '0') + community_screen = chat.accept_community_invite(community_params['name'], 0) with step(f'User {user_one.name}, verify welcome community popup'): welcome_popup = community_screen.left_panel.open_welcome_community_popup() @@ -197,7 +179,7 @@ def test_community_admin_kick_member_and_delete_message(multiple_instances): assert community_params['intro'] == welcome_popup.intro welcome_popup.join().authenticate(user_one.password) assert driver.waitFor(lambda: not community_screen.left_panel.is_join_community_visible, - 8000), 'Join community button not hidden' + 10000), 'Join community button not hidden' messages_screen = MessagesScreen() message_text = "Hi" messages_screen.group_chat.send_message_to_group_chat(message_text) @@ -216,15 +198,59 @@ def test_community_admin_kick_member_and_delete_message(multiple_instances): with step(f'User {user_one.name} verify that message was deleted by {user_two.name}'): aut_one.attach() main_screen.prepare() - assert driver.waitFor(lambda: messages_screen.chat.get_deleted_message_state, - configs.timeouts.UI_LOAD_TIMEOUT_MSEC) + assert driver.waitFor(lambda: messages_screen.chat.get_deleted_message_state, timeout) main_screen.hide() + with step(f'User {user_two.name}, ban {user_one.name} from the community'): + aut_two.attach() + main_screen.prepare() + community_setting = community_screen.left_panel.open_community_settings() + members = community_setting.left_panel.open_members() + members.ban_member(user_one.name).confirm_banning() + + with step('Check toast message about banned member'): + toast_messages = main_screen.wait_for_notification() + assert len(toast_messages) == 1, \ + f"Multiple toast messages appeared" + message = toast_messages[0] + assert message == user_one.name + ToastMessages.BANNED_USER_TOAST.value + community_params['name'], \ + f"Toast message is incorrect, current message is {message}" + + with step(f'User {user_two.name}, does not see {user_one.name} in members list'): + members_list = community_screen.right_panel.members + assert driver.waitFor(lambda: user_one.name not in members_list, timeout) + + with step(f'User {user_two.name}, see {user_one.name} in banned members list'): + community_screen.right_panel.click_banned_button() + assert driver.waitFor(lambda: user_one.name not in members_list, timeout) + + with step(f'User {user_two.name}, unban {user_one.name} in banned members list'): + members.unban_member(user_one.name) + time.sleep(2) + + with step('Check toast message about unbanned member'): + toast_messages = main_screen.wait_for_notification() + toast_message = user_one.name + ToastMessages.UNBANNED_USER_TOAST.value + community_params['name'] + assert driver.waitFor(lambda: toast_message in toast_messages, timeout), \ + f"Toast message is incorrect, current message {toast_message} is not in {toast_messages}" + main_screen.hide() + + with step(f'User {user_one.name} join community again {user_two.name}'): + aut_one.attach() + main_screen.prepare() + community_screen = chat.accept_community_invite(community_params['name'], 0) + welcome_popup = community_screen.left_panel.open_welcome_community_popup() + welcome_popup.join().authenticate(user_one.password) + assert driver.waitFor(lambda: not community_screen.left_panel.is_join_community_visible, + 10000), 'Join community button not hidden' + main_screen.hide() + + with step(f'User {user_two.name}, kick {user_one.name} from the community'): aut_two.attach() main_screen.prepare() - community_setting = community_screen.left_panel.open_community_settings() - community_setting.left_panel.open_members().kick_member(user_one.name) + Members().click_all_members_button() + members.kick_member(user_one.name) with step('Check toast message about kicked member'): toast_messages = main_screen.wait_for_notification() @@ -235,11 +261,10 @@ def test_community_admin_kick_member_and_delete_message(multiple_instances): f"Toast message is incorrect, current message is {message}" with step(f'User {user_two.name}, does not see {user_one.name} in members list'): - assert driver.waitFor(lambda: user_one.name not in community_screen.right_panel.members) + assert driver.waitFor(lambda: user_one.name not in community_screen.right_panel.members, timeout) main_screen.hide() with step(f'User {user_one.name} is not in the community anymore'): aut_one.attach() main_screen.prepare() - assert driver.waitFor(lambda: len(main_screen.left_panel.communities) == 0, - configs.timeouts.UI_LOAD_TIMEOUT_MSEC) + assert driver.waitFor(lambda: community_params['name'] not in main_screen.left_panel.communities, timeout) diff --git a/ui/app/AppLayouts/Communities/panels/MembersSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/MembersSettingsPanel.qml index aeb931521c..5c2d72ff81 100644 --- a/ui/app/AppLayouts/Communities/panels/MembersSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MembersSettingsPanel.qml @@ -68,12 +68,14 @@ SettingsPage { StatusTabButton { id: allMembersBtn + objectName: "allMembersButton" width: implicitWidth text: qsTr("All Members") } StatusTabButton { id: pendingRequestsBtn + objectName: "pendingRequestsButton" width: implicitWidth text: qsTr("Pending Requests") enabled: pendingMemberRequestsModel.count > 0 @@ -81,6 +83,7 @@ SettingsPage { StatusTabButton { id: declinedRequestsBtn + objectName: "declinedRequestsButton" width: implicitWidth text: qsTr("Rejected") enabled: declinedMemberRequestsModel.count > 0 @@ -88,6 +91,7 @@ SettingsPage { StatusTabButton { id: bannedBtn + objectName: "bannedButton" width: implicitWidth enabled: bannedMembersModel.count > 0 text: qsTr("Banned") diff --git a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml index a462b63f9d..4ab6982d48 100644 --- a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml @@ -243,6 +243,7 @@ Item { StatusButton { id: banButton + objectName: "MemberListItem_BanButton" anchors.verticalCenter: parent.verticalCenter visible: banButtonVisible text: qsTr("Ban") @@ -252,6 +253,7 @@ Item { }, StatusButton { + objectName: "MemberListItem_UnbanButton" anchors.verticalCenter: parent.verticalCenter visible: unbanButtonVisible text: qsTr("Unban")