from datetime import datetime, timedelta from calendar import day_name from allure import step from playwright.sync_api import Page from assertpy import assert_that from src.helpers.utils import calc_days_ago from src.pages.common_page import CommonPage from src.locators.artist_locators import ArtistLocators from src.ui_elements.base_ui_element import BaseUIElement from src.helpers import api_helper def return_number_only(value: str): if value[-1] == 'k': value = float(value[:-1]) * 1000 elif value[-1] == 'M': value = float(value[:-1]) * 1000000 elif value[-1] == 'B': value = float(value[:-1]) * 1000000000 else: value = float(value) return value def return_rounded_with_suffix(value: int): if value > 1000000000: value = "{}B".format(round(value/1000000000, 1)) elif value > 1000000: value = "{}M".format(round(value/1000000, 1)) elif value > 1000: value = "{}k".format(round(value/1000, 1)) else: return value if '.0' in value: value = ''.join([x for x in value.split('.0')]) return value class ArtistPage(CommonPage): def __init__(self, page: Page): super().__init__(page) self.page = page self.entity_type = 'artist' self.url = f'/{self.entity_type}' self.api_external_links = "**" + api_helper.api_external_links self.api_discovery_result = "**" + api_helper.api_discovery_result self.api_spotify_tracks = "**" + api_helper.api_spotify_tracks self.api_soundcloud_tracks = "**" + api_helper.api_soundcloud_tracks self.api_tiktok_videos = "**" + api_helper.api_tiktok_videos self.api_youtube_videos = "**" + api_helper.api_youtube_videos self.entity_name = BaseUIElement(self.page, ArtistLocators.ENTITY_NAME, 'Entity Name') self.entity_metadata = BaseUIElement(self.page, ArtistLocators.ENTITY_METADATA, 'Entity Metadata') self.error_failed_to_load_ext_link = BaseUIElement(self.page, ArtistLocators.EXT_LINKS_ERROR, "External link Error") self.btn_add_to_category = BaseUIElement(self.page, ArtistLocators.BTN_ADD_TO_CATEGORY, 'Add to Category button' ) self.entity_category = BaseUIElement(self.page, ArtistLocators.ENTITY_CATEGORY, "Entity's category") self.btn_remove_entity_category = BaseUIElement(self.page, ArtistLocators.BTN_REMOVE_ENTITY_CATEGORY, "Remove entity category button") self.ext_link = BaseUIElement(self.page, ArtistLocators.EXT_LINK, "External link") self.btn_rest_ext_link = BaseUIElement(self.page, ArtistLocators.BN_EXT_LINK_REST, "Rest external links button") self.ext_social_link = BaseUIElement(self.page, ArtistLocators.EXT_SOCIAL_LINK, "External Social Media link") self.ext_streaming_link = BaseUIElement(self.page, ArtistLocators.EXT_STREAMING_LINK, "External Streaming service link") self.btn_share = BaseUIElement(self.page, ArtistLocators.BTN_SHARE, "Share button") self.error_share = BaseUIElement(self.page, ArtistLocators.ERROR_SHARE, "Share Error to load") self.tab_performance = BaseUIElement(self.page, ArtistLocators.TAB_PERFORMANCE, "Entity Performance Tab") self.title_performance = BaseUIElement(self.page, ArtistLocators.TITLE_PERFORMANCE, "Entity Performance title") self.discovery_data_section = BaseUIElement(self.page, ArtistLocators.DISCOVERY_DATA, "Discovery Data section") self.chart_marker = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_MARKER, "Performance Chart's marker") self.chart_marker_tooltip_header = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_TOOLTIP_HEADER, "Performance Chart's tooltip header") self.chart_marker_tooltip_name = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_TOOLTIP_NAME, "Performance Chart's tooltip name") self.chart_x_labels = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_X_LABELS, "Performance Chart's X labels") self.chart_x_label = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_X_LABEL, "Performance Chart's X label") self.chart_y_labels = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_Y_LABELS, "Performance Chart's Y labels") self.chart_y_label = BaseUIElement(self.page, ArtistLocators.PERFORMANCE_CHART_Y_LABEL, "Performance Chart's Y label") self.not_enough_chart_data_message = BaseUIElement(self.page, ArtistLocators.NOT_ENOUGH_DATA_ERROR, "Not Enough Historical data message") self.discovery_stats_title = BaseUIElement(self.page, ArtistLocators.DISCOVERY_STATS_TITLE, "Discovery stats title") self.discovery_stats_last_date_value = BaseUIElement(self.page, ArtistLocators.DISCOVERY_STATS_LAST_DATE_VALUE, "Discovery stats Last Date value") self.discovery_stats_secondary = BaseUIElement(self.page, ArtistLocators.DISCOVERY_STATS_SECONDARY, "Discovery stats Secondary value") self.scope_bar = BaseUIElement(self.page, ArtistLocators.SCOPE_BAR, "Entity Scope Bar") self.tracks_error = BaseUIElement(self.page, ArtistLocators.TRACKS_ERROR, "Entity Tracks Error") self.videos_error = BaseUIElement(self.page, ArtistLocators.VIDEOS_ERROR, "Entity Videos Error") self.card_soundcloud_src = BaseUIElement(self.page, ArtistLocators.CARD_SOUNDCLOUD_SRC, "SoundCloud Card source") self.btn_card_soundcloud_details = BaseUIElement(self.page, ArtistLocators.BTN_CARD_SOUNDCLOUD_DETAILS, "SoundCloud Card Details button") self.card_soundcloud_release = BaseUIElement(self.page, ArtistLocators.CARD_SOUNDCLOUD_RELEASE, "SoundCloud Card Release Date") self.card_spotify_src = BaseUIElement(self.page, ArtistLocators.CARD_SPOTIFY_SRC, "Spotify Card source") self.btn_card_spotify_details = BaseUIElement(self.page, ArtistLocators.BTN_CARD_SPOTIFY_DETAILS, "Spotify Card Details button") self.card_spotify_release = BaseUIElement(self.page, ArtistLocators.CARD_SPOTIFY_RELEASE, "Spotify Card Release Date") self.card_tiktok_src = BaseUIElement(self.page, ArtistLocators.CARD_TIKTOK_SRC, "TikTok Card source") self.card_tiktok_name = BaseUIElement(self.page, ArtistLocators.CARD_TIKTOK_NAME, "TikTok Card name") self.card_tiktok_plays = BaseUIElement(self.page, ArtistLocators.CARD_TIKTOK_PLAYS, "TikTok Card plays") self.card_tiktok_likes = BaseUIElement(self.page, ArtistLocators.CARD_TIKTOK_LIKES, "TikTok Card likes") self.card_youtube_src = BaseUIElement(self.page, ArtistLocators.CARD_YOUTUBE_SRC, "YouTube Card source") self.card_youtube_title = BaseUIElement(self.page, ArtistLocators.CARD_YOUTUBE_TITLE, "YouTube Card title") self.card_youtube_plays = BaseUIElement(self.page, ArtistLocators.CARD_YOUTUBE_PLAYS, "YouTube Card plays") self.card_youtube_likes = BaseUIElement(self.page, ArtistLocators.CARD_YOUTUBE_LIKES, "YouTube Card likes") @step("Entity page is loaded") def is_page_loaded(self): self.entity_name.exists() @step("Check chart labels ordering by X axis") def check_chart_x_labels(self, chart_name): n = self.chart_x_labels.get_by(chart_name).get_count() latest_label = self.chart_x_label.get_by(chart_name, n).get_text() value_expected_1 = (datetime.today().date() - timedelta(days=1)).strftime('%-d %b') if latest_label == value_expected_1: delta = 1 else: delta = 2 for i in reversed(range(1, n+1)): label = self.chart_x_label.get_by(chart_name, i).get_text() date_grade = delta+2*(n-i) # totally depends on your screensize as chart is resizable print(f"Today is {datetime.today()}") value_expected = (datetime.today().date() - timedelta(days=date_grade)).strftime('%-d %b') print(f"Check chart X labels: actual: {label} vs expected: {value_expected}") assert_that(label).is_equal_to(value_expected) @step("Check chart labels ordering by Y axis and 1st date value") def check_chart_y_labels(self, chart_name): n = self.chart_y_labels.get_by(chart_name).get_count() for i in range(1, n): label_prev = return_number_only(self.chart_y_label.get_by(chart_name, i).get_text()) label_next = return_number_only(self.chart_y_label.get_by(chart_name, i + 1).get_text()) print(f"Check chart Y labels ordering: {label_prev} < {label_next}") assert_that(label_prev <= label_next).is_true() @step("Check chart tooltip when hovering over it") def check_chart_tooltip(self, chart_name, tooltip_number=1): """tooltip_number=2 if you click another chart""" self.chart_marker.get_by(chart_name).click() self.chart_marker.get_by(chart_name).hover() # Check chart name in tooltip tooltip_chart_name = self.chart_marker_tooltip_name.get_by(tooltip_number).get_text() print(f"Tooltip has chart name = {tooltip_chart_name}") assert_that(tooltip_chart_name).is_equal_to(chart_name) # Check date in tooltip tooltip_day = self.chart_marker_tooltip_header.get_by(tooltip_number).get_text() print(f"Tooltip has date = {tooltip_day}") tooltip_weekday = tooltip_day.split(', ')[0] assert_that(tooltip_weekday in list(day_name)).is_true() tooltip_date = tooltip_day.split(', ')[1] # expected = the middle date on the chart as we click ot the middle min_date = (datetime.today().date() - timedelta(days=27)).strftime('%m/%d/%Y') max_date = (datetime.today().date()).strftime('%m/%d/%Y') assert_that(min_date < tooltip_date < max_date).is_true() def check_stats_latest_release(self, latest_release_date): if not latest_release_date: self.discovery_stats_last_date_value.contain_text("N/A") return days_ago = calc_days_ago(latest_release_date, '%Y-%m-%d') + 1 print(f"Latest : {days_ago} days ago") if days_ago > 365: years_ago = round(days_ago/365) if years_ago == 1: self.discovery_stats_last_date_value.contain_text("1 Year Ago") else: self.discovery_stats_last_date_value.contain_text(f"{years_ago} Years Ago") elif days_ago > 30: month_ago = round(days_ago/30.5) self.discovery_stats_last_date_value.contain_text(f"{month_ago} Month Ago") elif days_ago <= 30: self.discovery_stats_last_date_value.contain_text(f"{days_ago} Days Ago") @step("Check TikTok discovery data stats for Artist") def check_discovery_data_stats_tiktok(self, network_response): discovery_result = network_response.value.json() creations_n = discovery_result['tiktok']['videos'] mentions_n = discovery_result['tiktok']['mentions'] avg_duration = discovery_result['tiktok']['avg_duration'].split('.')[0] latest_release_date = discovery_result['tiktok']['latest_release_date'] self.discovery_stats_title.contain_text(f"{return_rounded_with_suffix(creations_n)} Creations") self.check_stats_latest_release(latest_release_date) self.discovery_stats_secondary.get_by(1).contain_text(f"Mentions{mentions_n}") self.discovery_stats_secondary.get_by(2).contain_text(f"Avg. Duration{avg_duration}s") @step("Check YouTube discovery data stats") def check_discovery_data_stats_youtube(self, network_response): discovery_result = network_response.value.json() videos_n = discovery_result['youtube']['videos'] latest_release_date = discovery_result['youtube']['latest_release_date'] self.discovery_stats_title.contain_text(f"{return_rounded_with_suffix(videos_n)} Videos Released") self.check_stats_latest_release(latest_release_date) @step("Check Spotify discovery data stats") def check_discovery_data_stats_spotify(self, network_response): discovery_result = network_response.value.json() tracks_n = discovery_result['spotify']['tracks'] popularity_n = discovery_result['spotify']['popularity'] latest_release_date = discovery_result['spotify']['latest_release_date'] if tracks_n == 1: self.discovery_stats_title.contain_text("1 Track Released") else: self.discovery_stats_title.contain_text(f"{return_rounded_with_suffix(tracks_n)} Tracks Released") self.check_stats_latest_release(latest_release_date) self.discovery_stats_secondary.get_by(1).contain_text(f"Popularity{popularity_n}") @step("Check SoundCloud discovery data stats") def check_discovery_data_stats_soundcloud(self, network_response): discovery_result = network_response.value.json() tracks_n = discovery_result['soundcloud']['tracks'] likes_n = discovery_result['soundcloud']['likes'] latest_release_date = discovery_result['soundcloud']['latest_release_date'] if tracks_n == 1: self.discovery_stats_title.contain_text("1 Track Released") else: self.discovery_stats_title.contain_text(f"{return_rounded_with_suffix(tracks_n)} Tracks Released") self.check_stats_latest_release(latest_release_date) self.discovery_stats_secondary.get_by(1).contain_text(f"Likes{return_rounded_with_suffix(likes_n)}") @step("Check Spotify tracks on Artist/Track page") def check_spotify_tracks(self, network_response): spotify_tracks = network_response.value.json() for i in range(len(spotify_tracks)): print(i) # Check sorting by popularity_score if i+1 < len(spotify_tracks): current_score = spotify_tracks[i]['popularity_score'] next_score = spotify_tracks[i+1]['popularity_score'] assert_that(current_score >= next_score).is_true() # Check spotify track id page_track_src = self.card_spotify_src.get_by(i+1).get_attribute('src') assert_that(page_track_src).contains(spotify_tracks[i]['spotify_track_id']) # Check DNA track id page_track_link = self.btn_card_spotify_details.get_by(i+1).get_attribute('href') assert_that(page_track_link).contains(str(spotify_tracks[i]['cm_track_id'])) # Check Release date page_release_date = self.card_spotify_release.get_by(i + 1).get_text() response_release_date = spotify_tracks[i]['release_date'] if not response_release_date: assert_that(page_release_date).is_equal_to('N/A') else: page_release_date = datetime.strptime(page_release_date, '%m/%d/%Y') payload_release_date = datetime.strptime(response_release_date, '%Y-%m-%d') assert_that(page_release_date).is_equal_to(payload_release_date) assert_that(len(spotify_tracks)).is_less_than_or_equal_to(8) @step("Check SoundCloud tracks on Artist page") def check_soundcloud_tracks(self, network_response): soundcloud_tracks = network_response.value.json() for i in range(len(soundcloud_tracks)): # Check soundcloud track id page_track_src = self.card_soundcloud_src.get_by(i + 1).get_attribute('src') assert_that(page_track_src).contains(str(soundcloud_tracks[i]['soundcloud_id'])) # Check DNA track id page_track_link = self.btn_card_soundcloud_details.get_by(i + 1).get_attribute('href') assert_that(page_track_link).contains(str(soundcloud_tracks[i]['cm_track_id'])) # Check Release date page_release_date = self.card_soundcloud_release.get_by(i + 1).get_text() response_release_date = soundcloud_tracks[i]['release_date'] if not response_release_date: assert_that(page_release_date).is_equal_to('N/A') else: page_release_date = datetime.strptime(page_release_date, '%m/%d/%Y') payload_release_date = datetime.strptime(response_release_date, '%Y-%m-%d') assert_that(page_release_date).is_equal_to(payload_release_date) assert_that(len(soundcloud_tracks)).is_less_than_or_equal_to(8) @step("Check TikTok videos on Artist/Track page") def check_tiktok_videos(self, network_response): tiktok_videos = network_response.value.json() for i in range(len(tiktok_videos)): # Check video id and artist username page_tiktok_video_src = self.card_tiktok_src.get_by(i+1).get_attribute('href') assert_that(page_tiktok_video_src).contains(tiktok_videos[i]['video_id']) assert_that(page_tiktok_video_src).contains(tiktok_videos[i]['username']) # Check video name description page_card_name = self.card_tiktok_name.get_by(i+1).get_text() assert_that(page_card_name).contains(tiktok_videos[i]['description']) # Check Likes payload_likes = tiktok_videos[i]['likes'] page_likes = self.card_tiktok_likes.get_by(i + 1).get_text() if not payload_likes: assert_that(page_likes).is_equal_to('N/A') else: assert_that(page_likes).is_equal_to(return_rounded_with_suffix(payload_likes)) # Check Plays payload_views = tiktok_videos[i]['views'] page_views = self.card_tiktok_plays.get_by(i + 1).get_text() if not payload_views: assert_that(page_views).is_equal_to('N/A') else: assert_that(page_views).is_equal_to(return_rounded_with_suffix(payload_views)) assert_that(len(tiktok_videos)).is_less_than_or_equal_to(6) @step("Check YouTube videos on Artist/Track page") def check_youtube_videos(self, network_response): youtube_videos = network_response.value.json() for i in range(len(youtube_videos)): # Check youtube channel page_youtube_video_src = self.card_youtube_src.get_by(i+1).get_attribute('href') assert_that(page_youtube_video_src).contains(youtube_videos[i]['youtube_channel_id']) # Check video name description page_card_title = self.card_youtube_title.get_by(i+1).get_text() assert_that(page_card_title).contains(youtube_videos[i]['title']) # Check Likes payload_likes = youtube_videos[i]['likes'] page_likes = self.card_youtube_likes.get_by(i+1).get_text() if not payload_likes: assert_that(page_likes).is_equal_to('N/A') else: assert_that(page_likes).is_equal_to(return_rounded_with_suffix(payload_likes)) # Check Plays payload_views = youtube_videos[i]['views'] page_views = self.card_youtube_plays.get_by(i+1).get_text() if not payload_views: assert_that(page_views).is_equal_to('N/A') else: assert_that(page_views).is_equal_to(return_rounded_with_suffix(payload_views)) assert_that(len(youtube_videos)).is_less_than_or_equal_to(6) @step("Check Entity's name") def check_entity_name(self, network_response): entity_data = network_response.value.json() payload_data = entity_data['name'] self.entity_name.contain_text(payload_data) @step("Check Entity's label") def check_entity_label(self, network_response): entity_data = network_response.value.json() payload_data = entity_data['label'] self.entity_metadata.get_by('Label').contain_text(payload_data) @step("Check Entity's genre") def check_entity_genre(self, network_response): entity_data = network_response.value.json() payload_data = entity_data['genres'] for genre in payload_data: self.entity_metadata.get_by('Genre').contain_text(genre['name']) @step("Check Entity's country") def check_entity_country(self, network_response): entity_data = network_response.value.json() payload_data = entity_data['country']['name'] self.entity_metadata.get_by('Country').contain_text(payload_data)