from time import sleep from appium.webdriver.common.appiumby import AppiumBy as By from helpers.platform.android.locators import ( resource_id_xpath, text_view_xpath) from ..base_screen import BaseScreen from page_objects.mixins.header_info_mixin import HeaderInfoMixin class ProductScreen(BaseScreen, HeaderInfoMixin): header = resource_id_xpath('swipeViewPage') all_time_streams = 'allTimeStreams' st_section = resource_id_xpath('streamingTrend') st_title = text_view_xpath('Streaming Trend') top_playlists = resource_id_xpath( 'accessibility.productRecordingScreenBody.productPlacementList') tracklist = resource_id_xpath('productTrackList') tracklist_title = text_view_xpath('Tracklist') tracklist_track = ('//android.view.ViewGroup' '[contains(@content-desc, "productTrack")]') tracklist_track_names = resource_id_xpath('trackName') tracklist_track_artists = resource_id_xpath('artistName') tracklist_track_stream_count = resource_id_xpath('streamCount') sources_btn = resource_id_xpath("sourcesLink") data_source_title = text_view_xpath('DATA SOURCES') data_source_close_btn = resource_id_xpath("closeButton") def assert_product_page_is_displayed(self, context): # TODO: Partial check of the product's name until GO-4060 will be fixed product_name_loc = ( f'//android.widget.TextView[@resource-id="productName" and ' f'starts-with(@text, "{context.product_name}")]' ) self.waiter(30, By.XPATH, product_name_loc) def verify_header_info(self, expected_info): self.scroll_header("left") header_info = self.header_info() for key, expected_value in expected_info.items(): actual_value = header_info.get(key) assert actual_value == expected_value, ( f"Header info mismatch for '{key}':\n" f"Expected: {expected_value}\n" f"Actual: {actual_value}\n" f"Full header info: {header_info}" ) self.scroll_header("right") def star_current_product(self, context): self.wait_for_element_invisibility(By.XPATH, self.active_item_path) self.waiter(20, By.XPATH, resource_id_xpath('starIcon')).click() self.waiter(5, By.XPATH, self.active_item_path) product_name = self.waiter( 5, By.XPATH, resource_id_xpath('productName')).text.strip() context.starred_product_names.append(product_name) context.search_starred_product_name = product_name # Workaround for an app issue: # the product may not appear in My Favorites # when navigating there immediately after starring it. sleep(5) def unstar_current_product(self, context): product_name = ( self.waiter(5, By.XPATH, resource_id_xpath('productName')).text.strip()) self.waiter(20, By.XPATH, resource_id_xpath('starIcon')).click() self.wait_for_element_invisibility(By.XPATH, self.active_item_path) self._remove_starred_product_name(context, product_name) def _remove_starred_product_name(self, context, product_name): starred_product_names = context.starred_product_names if product_name in starred_product_names: starred_product_names.remove(product_name) return matching_product_names = [ starred_product_name for starred_product_name in starred_product_names if product_name.startswith(starred_product_name) or starred_product_name.startswith(product_name) ] if len(matching_product_names) == 1: starred_product_names.remove(matching_product_names[0]) return raise AssertionError( "Could not match unstarred product to a stored favorite product.\n" f"Product screen name: {product_name}\n" f"Stored favorite products: {starred_product_names}" ) def assert_all_time_streams(self): self.assert_element(By.ACCESSIBILITY_ID, self.all_time_streams, 90) def assert_streaming_trends(self): self.assert_element(By.XPATH, self.st_section, 90) self.assert_element(By.XPATH, self.st_title, 5) def go_to_section(self, context, section_name): sections = { 'Streaming Trend': self.st_section, 'Top Playlists': self.top_playlists, 'Tracklist': self.tracklist } self.scroll_and_assert(By.XPATH, sections[section_name], 5) def tap_song_by_number(self, context, track_number): self.scroll_and_assert(By.XPATH, self.tracklist_title, max_scrolls=5) self.scroll_page() track_names = self.waiter(10, By.XPATH, self.tracklist_track_names, multiple=True) if track_number < 0 or track_number >= len(track_names): raise IndexError("Track number out of range") track_artists = self.waiter(1, By.XPATH, self.tracklist_track_artists, multiple=True) context.track_name_of_song = track_names[track_number].text context.track_artist_of_song = track_artists[track_number].text self.tap_after_overlap_check(track_names[track_number]) def verify_product_tracklist_displayed(self): self.scroll_and_assert(By.XPATH, self.tracklist_title, small_scroll=True, max_scrolls=20) self.scroll_and_assert(By.XPATH, self.tracklist_track) def verify_tracklist_cards_content(self): self.scroll_and_assert(By.XPATH, self.tracklist_track_names) self.waiter(5, By.XPATH, self.tracklist_track_artists) self.waiter(5, By.XPATH, self.tracklist_track_stream_count) def navigate_to_sources(self): self.scroll_and_assert(By.XPATH, self.sources_btn) self.waiter(3, By.XPATH, self.sources_btn).click() def verify_data_sources_opened(self, context): self.waiter(10, By.XPATH, self.data_source_title) popular_sources = ['AWA', 'Amazon Music', 'Apple Music'] for source in popular_sources: source_name = text_view_xpath(source) self.waiter(10, By.XPATH, source_name) self.waiter(3, By.XPATH, source_name + '/following-sibling::*[@resource-id="noErrorIcon"]') self.waiter(3, By.XPATH, source_name + "/following-sibling::*[1][@text='No issues']") def close_data_sources(self): self.waiter(3, By.XPATH, self.data_source_close_btn).click() self.scroll_and_assert(By.XPATH, self.tracklist_title, direction='up')