From aecad2136e4115b2700a6faa37e123b66d83bb92 Mon Sep 17 00:00:00 2001 From: Churikova Tetiana Date: Wed, 16 Aug 2023 18:30:19 +0200 Subject: [PATCH] e2e: starting to-dos --- .../critical/test_public_chat_browsing.py | 72 +++++++++--------- .../tests/medium/test_activity_center.py | 5 +- test/appium/views/base_view.py | 25 ++++-- test/appium/views/chat_view.py | 13 +++- test/appium/views/dbs/waku_backup/user.py | 6 +- .../views/elements_templates/member3.png | Bin 8602 -> 7349 bytes test/appium/views/home_view.py | 1 - 7 files changed, 72 insertions(+), 50 deletions(-) diff --git a/test/appium/tests/critical/test_public_chat_browsing.py b/test/appium/tests/critical/test_public_chat_browsing.py index fc992f2be8..0f133a6fe7 100644 --- a/test/appium/tests/critical/test_public_chat_browsing.py +++ b/test/appium/tests/critical/test_public_chat_browsing.py @@ -437,9 +437,6 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): self.errors.verify_no_errors() @marks.testrail_id(703133) - @marks.xfail(reason="Restoring communities issue: 16787; " - "restoring contacts issue: 15500", - run=False) def test_restore_multiaccount_with_waku_backup_remove_switch(self): self.home.jump_to_communities_home() profile = self.home.profile_button.click() @@ -458,12 +455,16 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): "Incorrect contacts number restored: %s instead of %s" % (contacts_number, len(waku_user.contacts))) else: for i in range(contacts_number): - self.home.click_system_back_button_until_element_is_shown() - contact_row = self.home.contact_details_row(index=i + 1) - shown_name_text = contact_row.username_text.text - if shown_name_text in waku_user.contacts: - waku_user.contacts.remove(shown_name_text) - continue + key = waku_user.contacts[i] + if not self.home.element_by_text(key).is_element_displayed(30): + self.errors.append('%s was not restored as a contact from waku backup!' % key) + # Disabled for simple check as sometimes from waku-backup users restored with 3-random names + # self.home.click_system_back_button_until_element_is_shown() + # contact_row = self.home.contact_details_row(index=i + 1) + # shown_name_text = contact_row.username_text.text + # if shown_name_text in waku_user.contacts: + # waku_user.contacts.remove(shown_name_text) + # continue # else: # contact_row.click() # shown_name_text = profile.default_username_text.text @@ -477,9 +478,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase): # if chat.element_starts_with_text(name).is_element_displayed(sec=20): # waku_user.contacts.remove(name) # continue - if waku_user.contacts: - self.errors.append( - "Contact(s) was (were) not restored from backup: %s!" % ", ".join(waku_user.contacts)) + # if waku_user.contacts: + # self.errors.append( + # "Contact(s) was (were) not restored from backup: %s!" % ", ".join(waku_user.contacts)) self.home.just_fyi("Check restored communities") self.home.communities_tab.click() @@ -564,10 +565,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): self.channel_1.send_message(self.text_message) self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view() - self.community_1.send_invite_to_community(self.community_name, self.username_2) + self.community_1.share_community(self.community_name, self.username_2) self.home_1.get_to_community_channel_from_home(self.community_name) - # self.chat_2 = self.home_2.get_chat(self.username_1).click() self.home_2.just_fyi("Send message to contact (need for blocking contact) test") self.chat_2.send_message(self.text_message) self.chat_2.chat_element_by_text(self.community_name).view_community_button.click() @@ -978,9 +978,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): @marks.testrail_id(703086) def test_community_mark_all_messages_as_read(self): - self.home_1.jump_to_communities_home() - self.channel_2.click_system_back_button_until_element_is_shown() - self.home_2.communities_tab.click() + for home in self.home_1, self.home_2: + home.click_system_back_button_until_element_is_shown() + home.communities_tab.click() self.home_2.get_chat(self.community_name, community=True).click() self.community_2.get_channel(self.channel_name).click() self.channel_2.send_message(self.text_message) @@ -1144,8 +1144,6 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): self.errors.append('Community is still shown in the list after leave') self.errors.verify_no_errors() - @marks.xfail(reason="Can't invite user to closed community https://github.com/status-im/status-mobile/issues/16968", - run=False) @marks.testrail_id(702948) def test_community_hashtag_links_to_community_channels(self): for home in self.homes: @@ -1156,7 +1154,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): self.home_1.just_fyi("Device 1 creates a closed community") self.home_1.create_community(community_type="closed") community_name = "closed community" - self.community_1.send_invite_to_community(community_name, self.username_2) + self.community_1.share_community(community_name, self.username_2) self.home_2.just_fyi("Device 2 joins the community") self.home_2.get_chat(self.username_1).click() @@ -1165,31 +1163,40 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): self.chat_2.chat_element_by_text(community_name).view_community_button.click() self.community_2.join_community() + self.home_1.just_fyi("Device 1 accepts the community request") + self.home_1.jump_to_communities_home() + try: + self.home_1.notifications_unread_badge.wait_for_visibility_of_element(120) + except TimeoutException: + self.errors.append("Unread indicator is not shown in notifications on membership request") + self.home_1.open_activity_center_button.click() + reply_element = self.home_1.get_element_from_activity_center_view(self.username_2) + reply_element.swipe_right_on_element() + self.home_1.activity_notification_swipe_button.click() + self.home_1.close_activity_centre.click() + dogs_channel, cats_channel = "dogs", "cats" cats_message = "Where is a cat?" self.home_1.just_fyi("Device 1 sends a message in the cats channel") self.home_1.get_to_community_channel_from_home(community_name=community_name, channel_name=cats_channel) self.channel_1.send_message(cats_message) - self.channel_1.click_system_back_button_until_element_is_shown( - element=self.community_1.get_channel(dogs_channel)) + self.channel_1.jump_to_communities_home() + self.home_1.get_to_community_channel_from_home(community_name=community_name, channel_name=dogs_channel) self.home_1.just_fyi("Device 1 sends a message with hashtag in the dogs channel") - self.community_1.get_channel(dogs_channel).click_until_presence_of_element(self.channel_1.chat_message_input) message_with_hashtag = "#cats" self.channel_1.send_message(message_with_hashtag) self.home_2.just_fyi("Device 2 clicks on the message with hashtag in the community channel") - self.community_2.get_channel(dogs_channel).click_until_presence_of_element(self.channel_2.chat_message_input) - self.channel_2.chat_element_by_text(message_with_hashtag).message_body.wait_for_visibility_of_element(30) - self.channel_2.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate( - rel_x=0.2, rel_y=0.5) + self.home_2.jump_to_communities_home() + self.home_2.get_to_community_channel_from_home(community_name, dogs_channel) + self.channel_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body() if not self.channel_2.chat_element_by_text(cats_message).is_element_displayed(30): self.errors.append("Receiver was not navigated to the cats channel") self.home_1.just_fyi("Device 1 clicks on the message with hashtag in the community channel") - self.channel_1.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate( - rel_x=0.2, rel_y=0.5) + self.channel_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body() if not self.channel_1.chat_element_by_text(cats_message).is_element_displayed(30): self.errors.append("Sender was not navigated to the cats channel") @@ -1201,15 +1208,12 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase): self.home_1.just_fyi("Device 1 clicks on the message with hashtag in 1-1 chat") self.home_1.get_chat(self.username_2).click() - self.chat_1.chat_element_by_text(message_with_hashtag).message_body.wait_for_visibility_of_element(30) - self.chat_1.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate( - rel_x=0.2, rel_y=0.5) + self.chat_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body() if self.chat_1.chat_element_by_text(control_message_1_1_chat).is_element_disappeared(): self.errors.append("Receiver was navigated out of 1-1 chat") self.home_2.just_fyi("Device 2 clicks on the message with hashtag in 1-1 chat") - self.chat_2.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate( - rel_x=0.2, rel_y=0.5) + self.chat_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body() if self.chat_2.chat_element_by_text(control_message_1_1_chat).is_element_disappeared(): self.errors.append("Sender was navigated out of 1-1 chat") diff --git a/test/appium/tests/medium/test_activity_center.py b/test/appium/tests/medium/test_activity_center.py index a02df9e4d6..4f1a736b36 100644 --- a/test/appium/tests/medium/test_activity_center.py +++ b/test/appium/tests/medium/test_activity_center.py @@ -168,7 +168,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase): self.channel_1.send_message(self.text_message) self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view() - self.community_1.send_invite_to_community(self.community_name, self.username_2) + self.community_1.share_community(self.community_name, self.username_2) self.home_1.get_to_community_channel_from_home(self.community_name) self.chat_2 = self.home_2.get_chat(self.username_1).click() @@ -321,8 +321,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase): self.channel_name = "dogs" self.home_1.create_community(community_type="closed") self.home_1.reopen_app() - community_element = self.home_1.get_chat(community_name, community=True) - self.community_1.share_community(community_element, self.username_2) + self.community_1.share_community(community_name, self.username_2) self.home_2.just_fyi("Request access to community") self.home_2.jump_to_messages_home() diff --git a/test/appium/views/base_view.py b/test/appium/views/base_view.py index fb46ede8dd..167c22e5fa 100644 --- a/test/appium/views/base_view.py +++ b/test/appium/views/base_view.py @@ -604,19 +604,28 @@ class BaseView(object): sign_in_view = self.get_sign_in_view() sign_in_view.sign_in(password) - def jump_to_messages_home(self): + def click_on_floating_jump_to(self): self.hide_keyboard_if_shown() - self.jump_to_button.click() - self.chats_tab.click_until_presence_of_element(self.jump_to_button) + if self.chat_floating_screen.is_element_displayed(1): + Button(self.driver, xpath='//*[@content-desc="%s"]//*[@content-desc="%s"]' % + (self.chat_floating_screen.accessibility_id, self.jump_to_button.accessibility_id)).click() + elif self.community_floating_screen.is_element_displayed(1): + Button(self.driver, xpath='//*[@content-desc="%s"]//*[@content-desc="%s"]' % + (self.community_floating_screen.accessibility_id, + self.jump_to_button.accessibility_id)).click() + else: + self.jump_to_button.click() + + def jump_to_messages_home(self): + self.click_on_floating_jump_to() + self.chats_tab.click() def jump_to_communities_home(self): - self.hide_keyboard_if_shown() - self.jump_to_button.click() - self.communities_tab.click_until_presence_of_element(self.jump_to_button) + self.click_on_floating_jump_to() + self.communities_tab.click() def jump_to_card_by_text(self, text: str): - self.hide_keyboard_if_shown() - self.jump_to_button.click() + self.click_on_floating_jump_to() self.element_by_text(text).click() def reopen_app(self, password=common_password, sign_in=True): diff --git a/test/appium/views/chat_view.py b/test/appium/views/chat_view.py index 98292f0983..b674f1c68f 100644 --- a/test/appium/views/chat_view.py +++ b/test/appium/views/chat_view.py @@ -183,6 +183,10 @@ class ChatElementByText(Text): xpath="//%s//android.widget.TextView[contains(@text,'%s')]" % (self.chat_item_locator, self.message_text) ) + def click_on_link_inside_message_body(self): + self.message_body.wait_for_visibility_of_element(30) + self.message_body.click_inside_element_by_coordinate(rel_x=0.1, rel_y=0.9) + def wait_for_sent_state(self, wait_time=30): return BaseElement(self.driver, prefix=self.locator, xpath="//*[@content-desc='message-sent']").is_element_displayed(wait_time) @@ -458,6 +462,7 @@ class CommunityView(HomeView): Button(self.driver, xpath="//*[starts-with(@text,'%s')]%s" % (username, decline_suffix)).click() self.close_button.click() + # Should not be used anymore, outdated flow def send_invite_to_community(self, community_name, user_names_to_invite): if isinstance(user_names_to_invite, str): user_names_to_invite = [user_names_to_invite] @@ -474,11 +479,15 @@ class CommunityView(HomeView): self.share_invite_button.click_until_presence_of_element(self.invite_button) self.back_button.click_until_presence_of_element(self.plus_button) - def share_community(self, coummunity_element, user_names_to_share): + def share_community(self, community_name, user_names_to_share): if isinstance(user_names_to_share, str): user_names_to_share = [user_names_to_share] self.driver.info("Share to %s community" % ', '.join(map(str, user_names_to_share))) - coummunity_element.long_press_until_element_is_shown(self.share_community_button) + self.jump_to_communities_home() + home = self.get_home_view() + community_element = home.get_chat(community_name, community=True) + # community_element.long_press_until_element_is_shown(self.view_members_button) + community_element.long_press_until_element_is_shown(self.share_community_button) self.share_community_button.click() for user_name in user_names_to_share: user_contact = self.element_by_text_part(user_name) diff --git a/test/appium/views/dbs/waku_backup/user.py b/test/appium/views/dbs/waku_backup/user.py index ceca1929a1..a502f943e0 100644 --- a/test/appium/views/dbs/waku_backup/user.py +++ b/test/appium/views/dbs/waku_backup/user.py @@ -7,6 +7,8 @@ communities = { 'member_closed': 'test_comm_enc', 'member_pending': 'RC1 testing community' } -# contacts = ['Test_contact', 'MyCustomNickname'] # enable back when https://github.com/status-im/status-mobile/issues/15500 is fixed -contacts = ['Used Bulky Wirehair', 'Vengeful Healthy Arcticseal'] + +#contacts = ['Test_contact', 'MyCustomNickname'] # enable back when https://github.com/status-im/status-mobile/issues/15500 is fixed + +contacts = ['zQ3...rLSpUs', 'zQ3...mxAZUU'] blocked_user = 'Clear Flat Milkweedbug' diff --git a/test/appium/views/elements_templates/member3.png b/test/appium/views/elements_templates/member3.png index cd5ba2cd818383a347f851337a735e209842e757..5c996cc70f7cbf3e48db5c9d64740cdc39fa8bb9 100644 GIT binary patch literal 7349 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