diff --git a/test/appium/tests/activity_center/test_activity_center.py b/test/appium/tests/activity_center/test_activity_center.py index 499edce461..681755ee09 100644 --- a/test/appium/tests/activity_center/test_activity_center.py +++ b/test/appium/tests/activity_center/test_activity_center.py @@ -170,7 +170,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC self.home_2.just_fyi("Device 2 sign in, user name is " + self.username_2) self.home_2.reopen_app(sign_in=False) self.device_2.show_profiles_button.wait_and_click() - self.device_2.get_user(username=self.username_2).click() + self.device_2.get_user_profile_by_name(username=self.username_2).click() self.device_2.sign_in() self.loop.run_until_complete(run_in_parallel(((_device_1_creates_user, {}), diff --git a/test/appium/tests/critical/chats/test_group_chat.py b/test/appium/tests/critical/chats/test_group_chat.py index 319a09986c..840c08a5c4 100644 --- a/test/appium/tests/critical/chats/test_group_chat.py +++ b/test/appium/tests/critical/chats/test_group_chat.py @@ -115,12 +115,18 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase): self.chats[2].add_remove_same_reaction(message=message, emoji="thumbs-up") self.chats[2].set_reaction(message=message, emoji="laugh") - for i in range(3): - self.chats[i].just_fyi("Checking reactions count for each group member and admin") - message_element = self.chats[i].chat_element_by_text(message) - message_element.emojis_below_message(emoji="thumbs-up").wait_for_element_text(2) - message_element.emojis_below_message(emoji="love").wait_for_element_text(1) - message_element.emojis_below_message(emoji="laugh").wait_for_element_text(1) + def _check_reactions_count(chat_view_index): + self.chats[chat_view_index].just_fyi("Checking reactions count for each group member and admin") + chat_element = self.chats[chat_view_index].chat_element_by_text(message) + chat_element.emojis_below_message(emoji="thumbs-up").wait_for_element_text(2) + chat_element.emojis_below_message(emoji="love").wait_for_element_text(1) + chat_element.emojis_below_message(emoji="laugh").wait_for_element_text(1) + + self.loop.run_until_complete(run_in_parallel(( + (_check_reactions_count, {'chat_view_index': 0}), + (_check_reactions_count, {'chat_view_index': 1}), + (_check_reactions_count, {'chat_view_index': 2}) + ))) self.chats[0].just_fyi("Admin checks info about voted users") self.chats[0].chat_element_by_text(message).emojis_below_message( @@ -163,15 +169,23 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase): self.chats[2].add_remove_same_reaction(message=message, emoji="laugh") self.chats[2].add_remove_same_reaction(message=message, emoji="sad") - for i in range(3): - self.chats[i].just_fyi("Checking reactions count for each group member and admin after they were changed") - message_element = self.chats[i].chat_element_by_text(message) + def _check_reactions_count_after_change(chat_view_index): + self.chats[chat_view_index].just_fyi( + "Checking reactions count for each group member and admin after they were changed") + chat_element = self.chats[chat_view_index].chat_element_by_text(message) try: - message_element.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1) - message_element.emojis_below_message(emoji="love").wait_for_element_text(1) - message_element.emojis_below_message(emoji="sad").wait_for_element_text(2) + chat_element.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1) + chat_element.emojis_below_message(emoji="love").wait_for_element_text(1) + chat_element.emojis_below_message(emoji="sad").wait_for_element_text(2) except (Failed, NoSuchElementException): - self.errors.append("Incorrect reactions count for %s after changing the reactions" % self.usernames[i]) + self.errors.append( + "Incorrect reactions count for %s after changing the reactions" % self.usernames[chat_view_index]) + + self.loop.run_until_complete(run_in_parallel(( + (_check_reactions_count_after_change, {'chat_view_index': 0}), + (_check_reactions_count_after_change, {'chat_view_index': 1}), + (_check_reactions_count_after_change, {'chat_view_index': 2}) + ))) self.chats[0].just_fyi("Admin relogins") self.chats[0].reopen_app() @@ -286,11 +300,16 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase): @marks.testrail_id(702808) def test_group_chat_offline_pn(self): - for i in range(1, 3): - self.homes[i].navigate_back_to_home_view() - self.homes[i].chats_tab.click() - self.homes[i].groups_tab.click() - self.homes[i].get_chat(self.chat_name).click() + def _proceed_to_chat(index): + self.homes[index].navigate_back_to_home_view() + self.homes[index].chats_tab.click() + self.homes[index].groups_tab.click() + self.homes[index].get_chat(self.chat_name).click() + + self.loop.run_until_complete(run_in_parallel(( + (_proceed_to_chat, {'index': 1}), + (_proceed_to_chat, {'index': 2}) + ))) message_1, message_2 = 'message from old member', 'message from new member' @@ -318,11 +337,18 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase): self.homes[0].chats_tab.click() self.homes[0].get_chat(self.chat_name).click() - self.homes[0].just_fyi("check that messages are shown for every member") - for i in range(3): - for message in (message_1, message_2): - if not self.chats[i].chat_element_by_text(message).is_element_displayed(30): - self.errors.append('%s if not shown for device %s' % (message, str(i))) + def _check_messages(index): + self.chats[index].just_fyi("Check that messages are shown for user %s" % self.usernames[index]) + for message_text in (message_1, message_2): + if not self.chats[index].chat_element_by_text(message_text).is_element_displayed(30): + self.errors.append('%s if not shown for device %s' % (message_text, index)) + + self.loop.run_until_complete(run_in_parallel(( + (_check_messages, {'index': 0}), + (_check_messages, {'index': 1}), + (_check_messages, {'index': 2}) + ))) + self.errors.verify_no_errors() @marks.testrail_id(702732) @@ -381,28 +407,33 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase): self.chats[1].chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30)): self.errors.append("Message 4 is not pinned in group chat after unpinning previous one") - self.chats[0].just_fyi("Check pinned messages count and content") - for chat_number, group_chat in enumerate([self.chats[0], self.chats[1]]): - count = group_chat.pinned_messages_count.text + def _check_pinned_messages(index): + self.chats[index].just_fyi("Check pinned messages count and content for user %s" % self.usernames[index]) + count = self.chats[index].pinned_messages_count.text if count != '3': self.errors.append( - "Pinned messages count %s doesn't match expected 3 for user %s" % (count, chat_number + 1)) - group_chat.pinned_messages_count.click() - for message in self.message_1, self.message_3, self.message_4: - pinned_by = group_chat.pinned_messages_list.get_message_pinned_by_text(message) + "Pinned messages count %s doesn't match expected 3 for user %s" % (count, self.usernames[index])) + self.chats[index].pinned_messages_count.click() + for message_text in self.message_1, self.message_3, self.message_4: + pinned_by = self.chats[index].pinned_messages_list.get_message_pinned_by_text(message_text) if pinned_by.is_element_displayed(): text = pinned_by.text.strip() - expected_text = "You" if chat_number == 0 else self.usernames[0] + expected_text = "You" if index == 0 else self.usernames[0] if text != expected_text: self.errors.append( "Pinned by '%s' doesn't match expected '%s' for user %s" % ( - text, expected_text, chat_number + 1) + text, expected_text, self.usernames[index]) ) else: self.errors.append( - "Message '%s' is missed on Pinned messages list for user %s" % (message, chat_number + 1) + "Message '%s' is missed on Pinned messages list for user %s" % (message, self.usernames[index]) ) + self.loop.run_until_complete(run_in_parallel(( + (_check_pinned_messages, {'index': 0}), + (_check_pinned_messages, {'index': 1}) + ))) + self.errors.verify_no_errors() @marks.testrail_id(703495) diff --git a/test/appium/tests/critical/chats/test_public_chat_browsing.py b/test/appium/tests/critical/chats/test_public_chat_browsing.py index 4ec7ae8b7c..52adbb0084 100644 --- a/test/appium/tests/critical/chats/test_public_chat_browsing.py +++ b/test/appium/tests/critical/chats/test_public_chat_browsing.py @@ -33,43 +33,6 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): self.community_view = self.home.get_community_view() self.channel = self.community_view.get_channel(self.channel_name).click() - @marks.testrail_id(703503) - @marks.xfail(reason="Curated communities not loading, https://github.com/status-im/status-mobile/issues/17852", - run=False) - def test_community_discovery(self): - self.home.navigate_back_to_home_view() - self.home.communities_tab.click() - self.home.discover_communities_button.click() - self.home.community_card_item.wait_for_visibility_of_element(30) - - if len(self.home.community_card_item.find_elements()) > 1: - contributors_test_community_attributes = "Test Community", 'Open for anyone', 'Web3', 'Software dev' - for text in contributors_test_community_attributes: - if not self.home.element_by_text(text).is_element_displayed(10): - self.errors.append("'%s' text is not in Discovery!" % text) - self.home.element_by_text(contributors_test_community_attributes[0]).click() - element_templates = { - self.community_view.join_button: 'discovery_join_button.png', - self.community_view.get_channel_avatar(): 'discovery_general_channel.png', - } - for element, template in element_templates.items(): - if element.is_element_differs_from_template(template): - element.save_new_screenshot_of_element('%s_different.png' % template.split('.')[0]) - self.errors.append( - "Element %s is different from expected template %s!" % (element.locator, template)) - self.community_view.navigate_back_to_home_view() - self.home.communities_tab.click() - self.home.discover_communities_button.click() - self.home.community_card_item.wait_for_visibility_of_element(30) - self.home.swipe_up() - - status_ccs_community_attributes = '(old) Status CCs', 'Community for Status CCs', 'Ethereum', \ - 'Software dev', 'Web3' - for text in status_ccs_community_attributes: - if not self.community_view.element_by_text(text).is_element_displayed(10): - self.errors.append("'%s' text is not shown for (old) Status CCs!" % text) - self.errors.verify_no_errors() - @marks.testrail_id(702846) def test_community_navigate_to_channel_when_relaunch(self): text_message = 'some_text' @@ -261,7 +224,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): self.home.just_fyi("Check that can remove user from logged out state") self.home.reopen_app(sign_in=False) self.sign_in.show_profiles_button.wait_and_click() - user_card = self.sign_in.get_user(username=self.username) + user_card = self.sign_in.get_user_profile_by_name(username=self.username) user_card.open_user_options() self.sign_in.remove_profile_button.click() if not self.sign_in.element_by_translation_id("remove-profile-confirm-message").is_element_displayed(30): @@ -276,6 +239,67 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): self.errors.verify_no_errors() + @marks.testrail_id(703503) + def test_community_discovery(self): + try: + # workaround for case if a user is logged out in the previous test + self.sign_in.get_user_profile_by_index(index=1).click() + self.sign_in.sign_in() + except NoSuchElementException: + pass + self.home.navigate_back_to_home_view() + self.home.just_fyi("Turn off testnet in the profile settings") + profile = self.home.profile_button.click() + profile.advanced_button.scroll_and_click() + profile.testnet_mode_toggle.click() + profile.ok_button.click() + self.sign_in.sign_in() + + self.home.just_fyi("Check Discover Communities content") + self.home.communities_tab.click() + self.home.discover_communities_button.click() + self.home.community_card_item.wait_for_elements(seconds=120) + + expected_communities = { + ' 0xUX': ['Design', 'Ethereum', 'Collaboration'], + 'Status': ['Web3', 'Blockchain', 'Ethereum'], + 'Status Inu': ['News', 'Social', 'Web3'], + } + for community_name, tags in expected_communities.items(): + self.home.just_fyi("Check %s community tags in the Discover communities screen" % community_name) + card = self.home.get_discover_community_card_by_name(community_name=community_name) + try: + card.wait_for_visibility_of_element(30) + if community_name == 'Status': + card.swipe_to_web_element() + missing_tags = list() + for text in tags: + try: + card.get_child_element_by_text(text=text).wait_for_element() + except TimeoutException: + missing_tags.append(text) + if missing_tags: + self.errors.append("Community '%s' is missing tag(s) %s." % (community_name, ','.join(tags))) + + if community_name == 'Status': + self.home.just_fyi("Check Status community screen") + card.click() + if self.community_view.join_button.is_element_differs_from_template( + 'status_community_join_button.png'): + self.errors.append("Status community Join button is different from expected template.") + if self.community_view.community_logo.is_element_differs_from_template('status_community_logo.png'): + self.errors.append("Status community logo is different from expected template.") + + self.community_view.close_community_view_button.click() + self.home.discover_communities_button.click() + self.home.swipe_up() + + except TimeoutException: + self.errors.append("Community '%s' is not in the Discover Communities list." % community_name) + + self.errors.verify_no_errors() + # Note: this test should always be the LAST ONE in the group because it turns on mainnet in the app! + @pytest.mark.xdist_group(name="new_three_2") @marks.new_ui_critical @@ -998,6 +1022,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase): self.errors.verify_no_errors() @marks.testrail_id(702948) + @marks.xfail(reason="Can't enter channel after community is fetched for the first time, " \ + "https://github.com/status-im/status-mobile/issues/20395") def test_community_hashtag_links_to_community_channels(self): for home in self.homes: home.navigate_back_to_home_view() @@ -1098,6 +1124,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase): self.errors.verify_no_errors() @marks.testrail_id(703629) + @marks.xfail(reason="Can't enter channel after community is fetched for the first time, " \ + "https://github.com/status-im/status-mobile/issues/20395") def test_community_join_when_node_owner_offline(self): for home in self.homes: home.navigate_back_to_home_view() @@ -1143,8 +1171,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase): general_channel.click() if not self.channel_2.chat_element_by_text(control_message_general_chat).is_element_displayed(30): self.errors.append( - "Message in community channel is not visible for user before join, it was indicated as" \ - "%s sent for the sender before he went offline" % "" if message_sent else "not") + "Message in community channel is not visible for user before join, it was indicated as " \ + "%s sent for the sender before he went offline" % ("" if message_sent else "not")) else: self.errors.append("Community channel is not displayed for user before join") self.community_2.toast_content_element.wait_for_invisibility_of_element(30) diff --git a/test/appium/views/base_element.py b/test/appium/views/base_element.py index 126fa8ae8c..f4e976ca51 100644 --- a/test/appium/views/base_element.py +++ b/test/appium/views/base_element.py @@ -367,6 +367,9 @@ class BaseElement(object): def exclude_emoji(value): return 'emoji' if value in emoji.UNICODE_EMOJI else value + def get_child_element_by_text(self, text: str): + return BaseElement(self.driver, prefix=self.locator, xpath="//*[@text='%s']" % text) + class EditBox(BaseElement): diff --git a/test/appium/views/chat_view.py b/test/appium/views/chat_view.py index a79d3130f9..5676fbd71f 100644 --- a/test/appium/views/chat_view.py +++ b/test/appium/views/chat_view.py @@ -406,10 +406,10 @@ class CommunityView(HomeView): #### NEW UI # Communities initial page - self.close_community_view_button = Button( - self.driver, - xpath="//*[@content-desc='community-options-for-community']/../*[1]//android.widget.ImageView") + self.close_community_view_button = Button(self.driver, accessibility_id="back-button") self.community_title = Text(self.driver, accessibility_id="community-title") + self.community_logo = BaseElement( + self.driver, xpath="//*[@content-desc='community-title']/preceding-sibling::*/android.widget.ImageView") self.community_description_text = Text(self.driver, accessibility_id="community-description-text") self.community_status_joined = Text(self.driver, accessibility_id="status-tag-positive") self.community_status_pending = Text(self.driver, accessibility_id="status-tag-pending") diff --git a/test/appium/views/elements_templates/status_community_join_button.png b/test/appium/views/elements_templates/status_community_join_button.png new file mode 100644 index 0000000000..9622b5e98d Binary files /dev/null and b/test/appium/views/elements_templates/status_community_join_button.png differ diff --git a/test/appium/views/elements_templates/status_community_logo.png b/test/appium/views/elements_templates/status_community_logo.png new file mode 100644 index 0000000000..3f61a0ff8c Binary files /dev/null and b/test/appium/views/elements_templates/status_community_logo.png differ diff --git a/test/appium/views/home_view.py b/test/appium/views/home_view.py index 109532d8de..07f17bdb40 100644 --- a/test/appium/views/home_view.py +++ b/test/appium/views/home_view.py @@ -603,3 +603,10 @@ class HomeView(BaseView): address = self.copy_wallet_address() self.click_system_back_button() return address + + def get_discover_community_card_by_name(self, community_name: str): + return BaseElement( + self.driver, + xpath="//*[@content-desc='%s'][descendant::*[@content-desc='chat-name-text'][@text='%s']]" % ( + self.community_card_item.accessibility_id, community_name) + ) diff --git a/test/appium/views/profile_view.py b/test/appium/views/profile_view.py index 14fead27dc..f41aa077fe 100644 --- a/test/appium/views/profile_view.py +++ b/test/appium/views/profile_view.py @@ -61,7 +61,7 @@ class ENSusernames(Button): class AdvancedButton(Button): def __init__(self, driver): - super().__init__(driver, accessibility_id="advanced-button") + super().__init__(driver, accessibility_id="icon, Advanced, label-component, icon") def click(self): self.scroll_to_element().click() @@ -363,6 +363,8 @@ class ProfileView(BaseView): self.profile_blocked_users_button = Button(self.driver, accessibility_id="Blocked users, label-component, icon") self.profile_legacy_button = Button(self.driver, accessibility_id="icon, Legacy settings, label-component, icon") + self.testnet_mode_toggle = Button(self.driver, + xpath="//*[@content-desc='test-networks-enabled']/android.widget.Switch") def switch_network(self, network='Mainnet with upstream RPC'): self.driver.info("## Switch network to '%s'" % network, device=False) diff --git a/test/appium/views/sign_in_view.py b/test/appium/views/sign_in_view.py index 7a3e46c18c..ec2ad9b7fd 100644 --- a/test/appium/views/sign_in_view.py +++ b/test/appium/views/sign_in_view.py @@ -12,8 +12,9 @@ from views.base_view import BaseView class MultiAccountButton(Button): class Username(Text): def __init__(self, driver, locator_value): - super(MultiAccountButton.Username, self).__init__(driver, - xpath="%s//android.widget.TextView[@content-desc='username']" % locator_value) + super(MultiAccountButton.Username, self).__init__( + driver, + xpath="%s//android.widget.TextView[@content-desc='username']" % locator_value) def __init__(self, driver, position=1): super(MultiAccountButton, self).__init__(driver, @@ -123,10 +124,17 @@ class TermsOfUseLink(Button): class UserProfileElement(Button): - def __init__(self, driver, username): + def __init__(self, driver, username: str = None, index: int = None): self.username = username - super().__init__(driver, - xpath="//*[@text='%s']//ancestor::android.view.ViewGroup[@content-desc='profile-card']" % username) + self.index = index + if username: + super().__init__( + driver, + xpath="//*[@text='%s']//ancestor::android.view.ViewGroup[@content-desc='profile-card']" % self.username) + elif index: + super().__init__(driver, xpath="(//*[@content-desc='profile-card'])[%s]" % self.index) + else: + raise AttributeError("Either username or profile index should be defined") def open_user_options(self): Button(self.driver, xpath='%s//*[@content-desc="profile-card-options"]' % self.locator).click() @@ -154,8 +162,9 @@ class SignInView(BaseView): self.privacy_policy_link = PrivacyPolicyLink(self.driver) self.terms_of_use_link = TermsOfUseLink(self.driver) self.keycard_storage_button = KeycardKeyStorageButton(self.driver) - self.first_username_on_choose_chat_name = Text(self.driver, - xpath="//*[@content-desc='select-account-button-0']//android.widget.TextView[1]") + self.first_username_on_choose_chat_name = Text( + self.driver, + xpath="//*[@content-desc='select-account-button-0']//android.widget.TextView[1]") self.get_keycard_banner = Button(self.driver, translation_id="get-a-keycard") self.accept_tos_checkbox = self.checkbox_button @@ -348,7 +357,12 @@ class SignInView(BaseView): print(str(e)) self.driver.info('## Exporting database is finished!', device=False) - def get_user(self, username): + def get_user_profile_by_name(self, username: str): self.driver.info("Getting username card by '%s'" % username) - expected_element = UserProfileElement(self.driver, username) - return expected_element if expected_element.is_element_displayed(10) else self.driver.fail("User is not found!") + expected_element = UserProfileElement(self.driver, username=username) + return expected_element if expected_element.is_element_displayed(10) else self.driver.fail( + "User %s is not found!" % username) + + def get_user_profile_by_index(self, index: int): + self.driver.info("Getting username card by index %s" % index) + return UserProfileElement(self.driver, index=index)