import datetime import json import locale import logging import math import operator import random import time from urllib import parse import allure import numpy import pandas as pd from assertpy import assert_that from dateutil import rrule from genson.schema import builder from jsonschema import ValidationError, validate from natsort import natsorted from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException from selenium.webdriver import ActionChains from ui_automation_framework.core import BasePage, TestStatus from ui_automation_framework.utils import AppConfig, CoreConfig from ui_automation_framework.utils import logger as cl from app.api_client import ApiClient from app.mysql_db_client_custom import MySqlClient from app.src.pages.third_party.applecharts_page import AppleCharts class TrackPage(BasePage): log = cl.Logger(logging.DEBUG) MARKETS_TOP = {"tab": "top-markets-", "url": 1} MARKETS_ALL = {"tab": "all-markets", "url": 2} TOP_6_COUNTRIES = ["us", "ca", "gb", "de", "au", "fr"] TOP_6_COUNTRIES_VALUES = ["United States", "Canada", "United Kingdom", "Germany", "Australia", "France"] APPLE = "apple" AMAZON = "amazon" TD_PREVIOUS_PLAYLIST_TAB = "previous_playlists_tab" TD_CURRENT_PLAYLIST_TAB = "first_playlist" TD_COLUMN_COUNTRY_CODE = "country-code" TD_COLUMN_ENTITY = "Entity" TD_COLUMN_TRACK_POSITION = "track-position" TD_COLUMN_POSITION_TREND = "track-position-change" TD_COLUMN_ADDED_DAYS = "track-days-in-playlist" TD_COLUMN_LATEST_DAY = "track-streams-latest-day" TD_COLUMN_STREAMS_7_DAYS_TRACK = "selected-track-streams-7-days" TD_COLUMN_STREAMS_7_DAYS_ENTITY = "selected-playlist-streams-7-days" TD_COLUMN_PLAYLIST_FOLLOWERS = "followers" TD_PP_COLUMN_ADDED_DATE = "track-added-date" TD_PP_COLUMN_REMOVED_DATE = "track-removed-date" REGION_NORTH_AMERICA = "North America" GRAPH_TAB_STREAMS = "track-performance-streams" GRAPH_TAB_COUNTRIES = "track-performance-countries" REGION_EX_US = "Ex–US Only" REGION_MIDDLE_EAST = "Middle East" REGION_CIS = "CIS" REGION_AFRICA = "Africa" REGION_ASIA = "Asia" REGION_EUROPE = "Europe" REGION_LATIN_IBERIA = "Latin-Iberia" REGION_OCEANIA = "Oceania" REGION_UK = "UK" REGIONS = [REGION_EX_US, REGION_AFRICA, REGION_ASIA, REGION_CIS, REGION_EUROPE, REGION_LATIN_IBERIA, REGION_MIDDLE_EAST, REGION_NORTH_AMERICA, REGION_OCEANIA, REGION_UK] europe_region_countries = AppConfig.get("regions")["europe"]["api"] top_markets_api = ["us", "in", "th", "id", "ph", "br", "mx", "fr", "vn", "my", "gb", "pe", "co", "de", "ca"] current_playlists_sort = "current_playlists_sort" sorting = "sorting" tr_det_top_markets = "tr_det_top_markets" tr_det_tab = "tr_det_tab" tr_det_owner_market = "tr_det_owner_market" tr_det_owner_market_prev = "tr_det_owner_market_prev" tr_det_playlist_type = "tr_det_playlist_type" tr_det_playlist_type_prev = "tr_det_playlist_type_prev" tr_det_owner_ctg_prev = "tr_det_owner_ctg_prev" tr_det_owner_ctg = "tr_det_owner_ctg" tr_det_filter = "tr_det_filter" tr_det_st_filter = "tr_det_st_filter" tr_det_charts = "tr_det_charts" tr_det_charts_dsp = "tr_det_charts_dsp" tr_det_chart_beta_dsp = "tr_det_chart_beta_dsp" tr_det_st_apple_markets = "tr_det_st_apple_markets" tr_det_st_market = "tr_det_st_market" tr_det_view = "tr_det_view" tr_det_video = "tr_det_video" tr_det_source = "tr_det_source" tr_det_country = "tr_det_country" tr_det_yt_filter = "tr_det_yt_filter" tr_det_region = "tr_det_region" tr_det_market_str = "tr_det_market_str" tr_det_tc = "tr_det_tc" tr_det_dsp = "tr_det_dsp" tr_det_dsp_prev = "tr_det_dsp_prev" tr_det_current_entity = "tr_det_current_entity" trending_date = "trending_date" str_gr_type = "str_gr_type" str_gr_view = "str_gr_view" str_gr_country = "str_gr_country" str_gr_region = "str_gr_region" str_gr_tab = "str_gr_tab" str_gr_dsp = "str_gr_dsp" str_gr_video = "str_gr_video" str_gr_source = "str_gr_source" str_gr_start_date = "str_gr_start_date" str_gr_end_date = "str_gr_end_date" str_gr_country_list = "str_gr_country_list" str_gr_tt = "str_gr_tt" str_gr_tc = "str_gr_tc" str_gr_tier = "str_gr_tier" graph_line_graph = "single" graph_area_graph = "multi" graph_percentage = "percentage" graph_by_source = "bySource" graph_by_engagement = "byEngagement" graph_amazon = "amazon" graph_by_voice = "byVoice" graph_by_tier = "byTier" graph_all_streams = "allStreams" dd_by_voice = "By Voice" dd_lean_back_forward = "Lean Fwd / Back" dd_by_tier = "By Tier" dd_all_streams = "All Streams" dd_by_source = "By Source" market = "market" previous_playlists_sort = "previous_playlists_sort" url_sorting = "sorting" desc = "desc" asc = "asc" stations_sort = "stations_sort" sum_value = "sum" all_markets = "All Markets" sony_offices = "Sony Offices" top_markets = "Top Markets" all_tiers = "All Tiers" lf_locator = "lean-forward" lb_locator = "lean-back" dt_locator = "device-type" os_locator = "operating-system" CHARTS_SPOTIFY_WEEKLY = "Spotify Weekly" CHARTS_APPLE_MUSIC_DAILY = "Apple Music Daily" CHARTS_COMBINED_DAILY = "Combined Daily" CHARTS_SPOTIFY_DAILY = "Spotify Daily" lf_legend = ["User Playlist", "Songs", "Album", "Artist", "Search"] lb_legend = ["Playlists", "Station"] dt_legend = ["Voice-Controlled", "Mobile", "Desktop", "Other"] os_legend = ["Alexa", "Android", "iOS", "Mac", "Windows", "Other"] tier_options = ["All Tiers", "Ad-Supported", "Prime", "Unlimited"] apply_button_loc = "//button[.='Apply']" hint_locator = "(//iframe/following-sibling::div/*)[last()]" dp_predefined_periods = ["2-weeks", "4-weeks", "8-weeks", "12-weeks", "26-weeks", "1-year"] td_stations_columns = ["country-code", "Entity", "track-streams-latest-day", "track-streams-7-days", "selected-playlist-streams-7-days"] stations_non_sortable_columns = ["position", "cover", "actions"] dp_predefined_count_days = [2 * 7, 4 * 7, 8 * 7, 12 * 7, 26 * 7, 365] playlists = "playlists" suggested_videos = "suggested_videos" vevo = "Vevo" manual = "Manual" premium_ugc = "Premium UGC" nvp_youtube_selected_videos = "youtube-videos-control" vp_youtube_selected_videos = "track-videos-control" youtube_key_sources = [ "browse_features", "external", "notifications", "playlist_pages", playlists, suggested_videos, "video_cards_and_annotations", "youtube_advertising", "youtube_search", ] youtube_all_sources = youtube_key_sources + [ "programming_from_claimed_content", "youtube_channels", "direct_or_unknown", "interactive_video_endscreen", "other_youtube_features", "shorts", "stories", ] column_video_title = "video-title" column_avg_view_duration = "avg-views-duration-percent" columns_vp_yt_kpi = [ column_video_title, "views-7-days", "trend-views-7-days", "views-in-period", "avg-views-per-day", # column_avg_view_duration, ] columns_previous = [ ["C", "country"], ["Name", "name"], ["Owner", "owner"], ["Added", "track_added"], ["Removed", "track_removed"], ["Days in Playlist", "day_in_playlist"], ["Followers", "followers"], ] CSV_AMAZON_BY_SOURCE_COLUMNS = [ "All Streams", "User Playlist Streams", "Songs Streams", "Album Streams", "Artist Streams", "Search Streams", "Playlist Streams", "Station Streams", ] TIKTOK_BY_VIEWS = "By Views" TIKTOK_BY_CREATIONS = "By Creations" TIKTOK_PREMIUM_GENERATED = "Premium Generated" TIKTOK_USER_GENERATED = "User Generated" TIKTOK_ALL_CONTENTS = "All Contents" TIKTOK_By_UGC_PGC = "By UGC/PGC" ugc = "ugc" pgc = "pgc" AMAZON_BY_SOURCE = ["All Sources", "Album", "Artist", "Playlists", "Search", "Songs", "Station", "User Playlist"] UNSTARRED_TRACK_BUTTON_COLOR = "rgba(255, 60, 129, 1)" UNSTARRED_TRACK_BUTTON_COLOR_HOVERED = "rgba(217, 43, 105, 1)" STARRED_TRACK_BUTTON_COLOR_HOVERED = "rgba(218, 218, 230, 1)" STARRED_TRACK_BUTTON_COLOR = "rgba(255, 255, 255, 1)" BY_MARKETS_TAB_NAME = "BY MARKETS" YT_TRENDING_TITLE = "Trending Music Videos" YT_TRENDING_DETAILS_TAB = "details" YT_TRENDING_OVERVIEW_TAB = "overview" YT_TRENDING_OVERVIEW_BY_REGIONS = "by-regions" YT_TRENDING_OVERVIEW_BY_MARKETS = "by-markets" YT_TRENDING_SORT_BY_ALPHABETICAL = "Alphabetical" YT_TRENDING_SORT_BY_VIDEO_POSITION = "Video Position" not_featured = "not-featured" featured = "featured" yt_trending_sort_by_alf = "name-text" yt_trending_sort_by_video = "position-text" YT_TRENDING_DATEPICKER_COLLAPSED_BG_COLOR = "rgba(255, 255, 255, 1)" CALENDAR_GRID_FIRST_WEEKDAY = "MO" TRENDING_REGIONS = ["NORTH AMERICA", "Europe", "Latin-Iberia", "UK", "Oceania", "ASIA", "AFRICA", "CIS", "Other"] YT_TRENDING_FILTERING_ICON_COLOR = "rgba(14, 16, 26, 1)" YT_TRENDING_HOME_MARKET_CARD_BORDER = "1px solid rgb(173, 177, 204)" def __init__(self, driver): super().__init__(driver) self.driver = driver self.track_locators = self.get_page_locators("TrackPage", "track_page_elements.json") self.track_comparison_page = self.get_page_locators("TrackComparisonPage", "comparison_elements.json") self.album_page = self.get_page_locators("AlbumPage", "album_elements.json") self.apple_charts = AppleCharts(self.driver) self.ts = TestStatus(self.driver) self.sql_client = MySqlClient() self.api_client = ApiClient() @allure.step("Navigating to the specified track page") def open_track_page_with_market(self, track_with_market): self.driver.get(CoreConfig.ENV_BASE_URL + track_with_market) self.page_has_loaded() @allure.step("Navigating to the track page with market name") def open_track_page(self, apple_spotify, track_id, market): self.driver.get(f"{CoreConfig.ENV_BASE_URL}/{apple_spotify}/track/{track_id}?market={market}") self.page_has_loaded() @allure.step("Navigating to the specified Spotify track page") def open_spotify_track_page(self, track_id): self.driver.get(CoreConfig.ENV_BASE_URL + "/spotify/track/" + track_id) self.page_has_loaded() @allure.step("Navigating to the specified Spotify track page spotify with market id") def open_spotify_track_page_with_market_id(self, track_id, market_id): self.driver.get(CoreConfig.ENV_BASE_URL + "/spotify/track/" + track_id + "?market=" + str(market_id)) self.page_has_loaded() @allure.step("Navigating to the specified Apple track page ") def open_apple_track_page(self, track_id): self.driver.get(CoreConfig.ENV_BASE_URL + "/apple/track/" + track_id) self.page_has_loaded() @allure.step("Navigating to the specified Apple track page with market id") def open_apple_track_page_with_market_id(self, track_id, market_id): self.driver.get(f"{CoreConfig.ENV_BASE_URL}/apple/track/{track_id}?market={market_id}") self.page_has_loaded() @allure.step("Getting track page title") def get_track_page_title(self): return self.get_title() @allure.step("Is track page title present") def is_track_page_title_present(self, track): track_title = "track-title" self.wait_for_element_visible(track_title, "id") displayed_track_title = self.get_text(track_title, "id").lower().split(" ")[0][:10] self.log.info("track title is displayed:" + displayed_track_title) assert_that(displayed_track_title).is_equal_to(track.lower().split(" ")[0][:10]) return displayed_track_title == track.lower().split(" ")[0][:10] @allure.step("Is track title present") def is_track_title_present(self): track_title = "track-title" self.wait_for_element_visible(track_title, "id") title = self.is_element_displayed(track_title, "id") assert_that(title).is_true() @allure.step("Selecting market") def select_market(self, market): self.wait_for_element_visible(*self.locator(self.track_locators, "market_picker")) market_el = self.get_element(*self.locator(self.track_locators, "market_picker")) self.click_element(element=market_el) market_item = "//*[contains(@id, 'header-market-switcher-item-')][contains(@id, '-label')][text()='{}']".format(market) market_item = self.get_element(market_item, "xpath") self.click_on_element_js(market_item) @allure.step("Get displayed market") def is_market_in_header_correct(self, market): market_item = "header-market-switcher" self.wait_for_element_visible(market_item, "id") displayed_market = self.get_text(market_item, "id") self.log.info("market is displayed:" + displayed_market) self.ts.markFinal(displayed_market == market, "market is: {}".format(displayed_market)) return displayed_market == market @allure.step("Selecting data provider") def select_dsp(self, dsp): current_dsp = self.get_current_dsp() if current_dsp != dsp: dsp_picker = self.wait_for_element_clickable(*self.locator(self.track_locators, "dsp_picker")) dsp_item = f"//*[contains(@id,'dsp-dd')]/..//*[text()='{dsp}']" self.click_on_element_js(element=dsp_picker) dsp_item_el = self.wait_for_element_clickable(locator=dsp_item, locator_type="xpath") self.click_on_element_js(element=dsp_item_el) self.is_graph_period_displayed() self.page_has_loaded() time.sleep(2) self.log.info("DSP selected: " + dsp) @allure.step("Selecting 1 year quick filter for the graph") def select_graph_one_year_period(self): self.select_predefined_period(self.dp_predefined_periods[-1]) @allure.step("TP - select previous playlist tab") def td_switch_to_past_playlists_tab(self): self.scroll_to_track_details() previous_tab = self.wait_for_element_visible(*self.locator(self.track_locators, "previous_playlists_tab")) self.click_on_element_js(element=previous_tab) self.wait_for_element_visible(*self.locator(self.track_locators, "td_previous_export")) self.is_tab_selected(*self.locator(self.track_locators, "previous_playlists_tab")) @allure.step("Getting graph period value") def get_graph_period_displayed(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "graph_period_string")) days = str(self.get_text(*self.locator(self.track_locators, "graph_period_string"))) return int(days.split(" ")[1]) def is_graph_period_displayed(self): self.wait_for_element_visible(*self.locator(self.track_locators, "graph_period_string")) self.log.info("Graph period is displayed") # TODO add parametrisation for dates @allure.step("selecting custom period in previous month") def select_previous_mounth_period(self): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) # assert_that(self.is_element_displayed("//*[contains(@id, '-2-weeks')]", "xpath")).is_true() previous_month_picker = "DayPicker-NavButton--prev" self.driver.execute_script("document.getElementsByClassName('" + previous_month_picker + "')[0].click();") first = self.wait_for_element_visible(*self.locator(self.track_locators, "firstDayOfPreviousMonth")) last = self.wait_for_element_visible(*self.locator(self.track_locators, "lastDayOfPreviousMonth")) self.click_on_element_js(element=first) self.click_on_element_js(element=last) self.is_graph_period_displayed() time.sleep(2) @allure.step("Selecting one day period for previous month") def select_one_day_period_in_previous_month(self): calendar_icon = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar_icon) self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_window")) one_day = self.wait_for_element_visible(*self.locator(self.track_locators, "firstDayOfPreviousMonth")) self.click_on_element_js(element=one_day) time.sleep(2) self.click_on_element_js(element=one_day) time.sleep(2) @allure.step("Calculating lean back values") def get_lean_back_values(self): back_total = 0 column_locator = "//span[text()='Lean Back']/../div//span[contains(., '%')]" self.wait_for_element_visible(*self.locator(self.track_locators, "graph_total")) self.wait_for_element_visible(column_locator, "xpath") for element in self.get_elements(column_locator, "xpath"): text = element.text value = text.replace("%", "") back_total = back_total + int(value) self.log.info("Lean back total is: " + str(back_total)) return back_total @allure.step("Calculating lean forward values") def get_lean_forward_values(self): forward_total = 0 column_locator = "//span[text()='Lean Forward']/../div//span[contains(., '%')]" self.wait_for_element_visible(*self.locator(self.track_locators, "graph_total")) self.wait_for_element_visible(column_locator, "xpath") for element in self.get_elements(column_locator, "xpath"): text = element.text value = text.replace("%", "") forward_total = forward_total + int(value) self.log.info("Lean forward total is: " + str(forward_total)) return forward_total @allure.step("Retrieving start date from calendar") def get_calendar_start_date(self): self.wait_for_element_visible(*self.locator(self.track_locators, "date_field_from")) date_raw = str(self.get_text(*self.locator(self.track_locators, "date_field_from"))).split("–")[0] print(date_raw) return datetime.datetime.strptime(date_raw, self.get_date_format_from_locale()).strftime("%Y-%m-%d") @allure.step("Retrieving deeplink start date from the url") def get_url_start_date(self): return self.parameter_from_url("str_gr_start_date") @allure.step("Verify deeplink start date from the url") def verify_url_start_date(self, correct_date): return self.get_url_start_date == correct_date @allure.step("Verify deeplink end date from the url") def verify_url_end_date(self, correct_date): return self.get_url_end_date == correct_date @allure.step("Retrieving deeplink end date from the url") def get_url_end_date(self): url = self.get_url() params = dict(parse.parse_qsl(parse.urlsplit(url).query)) return params["str_gr_end_date"] @allure.step("Retrieving end date from calendar") def get_calendar_end_date(self): self.wait_for_element_visible(*self.locator(self.track_locators, "date_field_to")) date_raw = str(self.get_text(*self.locator(self.track_locators, "date_field_to"))).split("–")[1] print(date_raw) return datetime.datetime.strptime(date_raw, self.get_date_format_from_locale()).strftime("%Y-%m-%d") @allure.step("Retrieving total streams value for the graph tooltip") def get_tooltip_total(self): self.wait_for_element_visible(*self.locator(self.track_locators, "graph")) markers = "//*[(@class='highcharts-series-group')]/*[(name()='g') and contains(@class," " 'highcharts-areaspline-series')]/*[contains(@class, 'highcharts-tracker-line')" " and @visibility='visible']" self.wait_for_element_visible(markers, "xpath") total = "" for element in self.get_elements(markers, "xpath"): ActionChains(self.driver).move_to_element(element).click().perform() tooltip_locator = "//div[contains(@class, 'highcharts-tooltip')]//div/div[2]/span[2]/b" self.wait_for_element_visible(tooltip_locator, "xpath") try: total = self.get_element(tooltip_locator, "xpath") total = self.get_text(element=total) self.log.info("The total value of streams on the tooltip is: " + total) break except NoSuchElementException or StaleElementReferenceException: self.log.info("Element doesn't contain tooltip") continue return total def millify(self, n): n = float(n) millidx = max(0, min(4, int(math.floor(0 if n == 0 else math.log10(abs(n)) / 3)))) return int("{:.0f}".format(n / 10 ** (3 * millidx))) @allure.step("Getting global streams count form the api") def get_api_global_streams_count(self, market, track_isrc): resp = self.api_client.get_streams_count(market, track_isrc)["global_value"] self.log.info(resp) return self.millify(resp) @allure.step("Getting market streams count form the api") def get_api_market_streams_count(self, market, track_isrc): resp = self.api_client.get_streams_count(market, track_isrc)["market_value"] self.log.info(resp) return self.millify(resp) @allure.step("Getting global streams count for the track on GUI") def get_ui_global_streams_count(self): count = self.wait_for_element_visible(*self.locator(self.track_locators, "global_value")) return self.millify(float(self.get_text(element=count).upper().replace("K", "").replace("M", "").replace("B", "").replace("T", ""))) @allure.step("Getting market streams count for the track on GUI") def get_ui_market_streams_count(self): count = self.wait_for_element_visible(*self.locator(self.track_locators, "market_value")) return self.millify(float(self.get_text(element=count).upper().replace("K", "").replace("M", "").replace("B", "").replace("T", ""))) @allure.step("Getting data for demographics data from API") def get_api_demographics(self, start_date, end_date): resp = self.api_client.get_heavy_spotify_demographics(start_date, end_date) self.log.info(resp) return resp @allure.step("Getting total streams count for selected period") def get_streams_in_period_total(self): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, "graph_total")) total = self.get_text(*self.locator(self.track_locators, "graph_total")) self.log.info("streams in period total graph is: " + total) return total def get_playlist_id(self, position): playlists_locator = "(//a[contains(@href, '/playlist/')])[{}]".format(position) self.scroll_to_element(playlists_locator, "xpath") id = self.get_attribute_value(playlists_locator, "xpath", None, "href").split("/")[-1].split("?")[0] self.log.info(f"playlist id: {id}") return id def td_get_playlist_ids(self, full=False): self.scroll_to_track_details() self.page_has_loaded() loc = "//*[contains(@id, '-table-cell-Entity-')]/..//*[contains(@href, '/playlist/')]" attrs = [] self.wait_for_element_visible(locator=loc, locator_type="xpath") elms = self.get_elements(locator=loc, locator_type="xpath") for e in elms: if full: attrs.append(str(self.get_attribute_value(element=e, attribute="href")).replace(CoreConfig.ENV_BASE_URL, "")) else: attrs.append(str(self.get_attribute_value(element=e, attribute="href")).split("/")[-1].split("?")[0]) self.log.info(f"href from playlist name in track details: {attrs}") return attrs @allure.step("Scroll to Track Details") def scroll_to_track_details(self): selector = "first_playlist" if "/spotify/playlist/" in self.get_url(): selector = "spotify-playlist-details-tab-tracks" self.wait_for_element_visible(*self.locator(self.track_locators, selector)) self.driver.execute_script("arguments[0].scrollIntoView(true);", self.get_element(*self.locator(self.track_locators, selector))) self.page_has_loaded() @allure.step("Getting IDs of displayed playlists") def get_playlists_ids(self, number_of_lists): self.scroll_to_track_details() playlist_ids = [] for i in range(1, number_of_lists + 1): if self.get_playlist_id(i).startswith("pl."): pass else: playlist_ids.append(self.get_playlist_id(i)) self.log.info("List of palylists IDs: " + "" + str(playlist_ids)) return playlist_ids @allure.step("Getting IDs, Days and Streams data of displayed playlists") def get_playlists_ids_days(self, number_of_lists): self.wait_for_element_visible(*self.locator(self.track_locators, "first_playlist")) self.driver.execute_script( "arguments[0].scrollIntoView(false);", self.get_element(*self.locator(self.track_locators, "first_playlist")), ) playlist_ids = [] playlist_days_ui = [] playlist_streams = [] for i in range(1, number_of_lists + 1): if self.get_playlist_id(i).startswith("pl."): pass else: playlist_ids.append(self.get_playlist_id(i)) playlist_days_ui.append(self.get_days_in_playslist(self.get_playlist_id(i))) playlist_streams.append(self.get_streams_7_days_in_playslist(self.get_playlist_id(i))) self.log.info("List of playlists IDs: " + str(playlist_ids)) self.log.info("List of playlists days: " + str(playlist_days_ui)) self.log.info("List of playlists streams: " + str(playlist_streams)) return playlist_ids, playlist_days_ui, playlist_streams def find_date_added(self, isrc, playlist_id): return self.sql_client.find_date_added(isrc, playlist_id) def find_streams_7_days(self, playlist_id, market): return self.sql_client.get_sum_of_streams_for_7_days(playlist_id, market) def get_days_in_playslist_db(self, isrc, playlist_id): date_db = self.find_date_added(isrc, playlist_id)[0].date() today = datetime.datetime.today().date() delta = (today - date_db).total_seconds() * 1000 return int(delta / 86400000 + 1) def get_days_in_playslists_db(self, playlists, isrc): playlists_days = [] for playlist in playlists: playlists_days.append(self.get_days_in_playslist_db(isrc, playlist)) self.log.info("Playlist days: " + str(playlists_days)) return playlists_days def get_removed_dates_db(self, isrc, playlists): dates_removed = [] for playlist in playlists: dates_removed.append(self.get_playlist_track_removed_date(isrc, playlist)) self.log.info("Playlist removed dates: " + str(dates_removed)) return dates_removed def get_playlist_track_removed_date(self, isrc, playlist): return self.sql_client.get_date_removed(isrc, playlist) def get_streams_in_playlists_db(self, playlists, market): playlists_streams = [] for playlist in playlists: playlists_streams.append(int(self.find_streams_7_days(playlist, market))) self.log.info("Playlist streams for 7 days: " + str(playlists_streams)) return playlists_streams def get_days_in_playslists(self, playlists): playlists_days = [] for playlist in playlists: playlist_locator = "//a[contains (@href, '{}')]/../../..//div[7]/div/div/span".format(playlist) playlists_days.append(self.get_text(playlist_locator, "xpath", None)) self.log.info(playlists_days) return playlists_days def get_days_in_playslist(self, playlist): playlist_locator = "//a[contains (@href, '{}')]/../../..//div[7]/div/div/span".format(playlist) playlists_days = self.get_text(playlist_locator, "xpath", None) self.log.info(playlists_days) return playlists_days def get_streams_7_days_in_playslist(self, playlist): playlist_streams_locator = "//a[contains (@href, '{}')]/../../..//div[9]/div/span".format(playlist) playlists_streams = self.get_text(playlist_streams_locator, "xpath", None) self.log.info(playlists_streams) return playlists_streams.replace(",", "").replace(".", "") def are_lists_equal(self, db_values, ui_values): passed = True for i in range(len(db_values)): self.log.info("DB value: " + str(db_values[i]) + " UI Value: " + str(ui_values[i])) if int(ui_values[i]) != int(db_values[i]): passed = False else: continue return passed def are_same_values_in_lists(self, list_1, list_2): passed = True for value_1 in list_1: for value_2 in list_2: if value_1 == value_2: self.log.info("value 1: " + value_1 + " value_2: " + value_2) passed = False else: continue return passed def are_start_dates_match(self): self.log.info("Retrieved start date from calendar: " + self.get_calendar_start_date()) self.log.info("Retrieved start date from url: " + self.get_url_start_date()) return self.get_calendar_start_date() == self.get_url_start_date() def are_end_dates_match(self): self.log.info("Retrieved end date from calendar: " + self.get_calendar_end_date()) self.log.info("Retrieved end date from url: " + self.get_url_end_date()) return self.get_calendar_end_date() == self.get_url_end_date() def are_graph_total_and_tooltip_match(self, tooltip_total, graph_total): self.log.info("Retrieved tooltip total: " + tooltip_total) self.log.info("Retrieved Streams in period’ in legend: " + graph_total) return tooltip_total == graph_total def is_graph_period_correct(self, period_from_graph, period): self.log.info(f"Retrieved period for graph is: {period_from_graph}") if (period - 10) < int(period_from_graph) <= period: return True def are_lean_froward_and_back_100(self, lean_back, lean_forward): self.log.info("Retrieved lean back total: " + str(lean_back)) self.log.info("Retrieved lean forward total: " + str(lean_forward)) if 97 < int(lean_back + lean_forward) < 103: return True def are_market_values_equal(self, api, ui): self.log.info("Retrieved api value: " + str(api)) self.log.info("Retrieved ui value: " + str(ui)) return api == ui @allure.step("Get local storage home market ID") def get_local_storage_home_market_id(self): from_storage = self.driver.execute_script("return window.localStorage.getItem(arguments[0]);", "authData") home_id = json.loads(str(from_storage)).get("profile").get("homeMarketID") self.log.info("local storage home market id is: " + str(home_id)) return home_id @allure.step("Get local storage active market ID") def get_local_storage_active_market_id(self): self.refresh() self.page_has_loaded() active_id = self.driver.execute_script("return window.localStorage.getItem('activeMarketID');") self.log.info("local storage active market id is: " + str(active_id)) return int(active_id) def wait_for_local_storage_active_market_id(self, value): script = "return window.localStorage.getItem('activeMarketID');" from_js = self.wait_for_value_from_js(script, value) self.log.info("local storage active market id is: " + str(from_js)) return value @allure.step("Set local storage active market ID") def set_local_storage_active_market_id(self, market_id): active_id = self.driver.execute_script("window.localStorage.setItem('activeMarketID', " + str(market_id) + ");") self.log.info("set local storage active market id to: " + str(active_id)) @allure.step("Verify market from url") def get_market_from_url(self): self.page_has_loaded() self.wait_for_url_contains("?market=") url = self.get_url() params = dict(parse.parse_qsl(parse.urlsplit(url).query)) url_id = params["market"] self.log.info("market id from url is: " + str(url_id)) return int(url_id) @allure.step("Clear local storage") def clear_local_storage(self): self.driver.execute_script("window.localStorage.clear();") self.log.info("local storage is cleared") @allure.step("Check market id in history") def go_back_and_verify_local_storage_and_url_market_id(self, param): self.page_has_loaded() self.is_graph_period_displayed() self.go_back() self.page_has_loaded() self.is_graph_period_displayed() url_market = self.get_market_from_url() storage_market = self.wait_for_local_storage_active_market_id(param) return url_market == storage_market == param @allure.step("Get Selected market name") def get_selected_market_name(self, market_name): market_current = self.get_text(*self.locator(self.track_locators, "market_picker")) self.ts.markFinal(market_current == market_name, f"current market: {market_current}\nexpected: {market_name}") return market_current == market_name def track_details_select_view(self, view): self.page_has_loaded() self.wait_for_element_visible(*self.locator(self.track_locators, view)) self.wait_for_element_clickable(*self.locator(self.track_locators, view)) self.click_element(*self.locator(self.track_locators, view)) self.log.info("Select graph view - " + view) self.is_graph_period_displayed() self.page_has_loaded() time.sleep(1) self.is_tab_selected(*self.locator(self.track_locators, view)) def select_graph_view(self, view): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) tp_header = self.wait_for_element_visible(*self.locator(self.track_locators, "tp_header")) self.click_element(element=tp_header) dd = "//*[contains(@id, 'graph-type-dd')]" self.wait_for_element_visible(locator=f"{dd}/span", locator_type="xpath") self.wait_for_element_clickable(locator=f"{dd}/span", locator_type="xpath") current_view = self.get_text(locator=f"{dd}/span", locator_type="xpath") if current_view != view and view == "Line Graph": if self.is_tab_selected_no_assert(locator="track-performance-streams", locator_type="id"): self.change_source_type(AppConfig.get("source")["all_streams"]) else: dd_el = self.wait_for_element_visible(locator=dd, locator_type="xpath") self.click_element(element=dd_el) item = self.wait_for_element_visible(locator=f"{dd}/..//*[text()='{view}']", locator_type="xpath") self.click_element(element=item) else: dd_el = self.wait_for_element_visible(locator=dd, locator_type="xpath") self.click_on_element_js(element=dd_el) item = self.wait_for_element_visible(locator=f"{dd}/..//*[text()='{view}']", locator_type="xpath") self.click_on_element_js(element=item) self.log.info("Select graph view - " + view) current_view = self.get_text(locator=f"{dd}/span", locator_type="xpath") self.ts.markFinal(current_view == view, f"view is: {current_view}, expected: {view}") self.is_graph_period_displayed() self.page_has_loaded() @allure.step("Select graph view - single line") def choose_graph_view_line_graph(self): self.select_graph_view("Line Graph") @allure.step("Select line graph without any conditions") def choose_graph_view_line_graph_direct(self): dd = self.wait_for_element_clickable( locator="[dd = //*[contains(@id, 'graph-type-dd')]", locator_type="xpath", ) self.click_element(element=dd) item = self.get_element(locator="//*[text()='Line Graph']", locator_type="xpath") self.click_on_element_js(element=item) self.is_graph_period_displayed() self.page_has_loaded() @allure.step("Select graph view - multiple line") def choose_graph_view_area_graph(self): self.select_graph_view("Area Graph") @allure.step("Select graph view - percentage") def choose_graph_view_area_graph_percentage(self): self.select_graph_view("Area Graph, %") @allure.step("Select graph view - bar chart") def choose_graph_view_bar_chart(self): self.select_graph_view("Bar Chart") @allure.step("Select track details - table view") def td_switch_to_table_view(self): self.scroll_to_track_details() self.track_details_select_view("track_details_table_view") @allure.step("Select track details - graph view") def track_details_choose_graph_view(self): self.scroll_to_track_details() self.track_details_select_view("track_details_graph_view") self.page_has_loaded() @allure.step("Get parameter from url") def parameter_from_url(self, parameter): self.page_has_loaded() self.wait_for_url_contains(parameter) url = self.get_url() params = dict(parse.parse_qsl(parse.urlsplit(url).query)) url_param = params[parameter] self.log.info(parameter + " from url is: " + str(url_param)) return url_param @allure.step("Stream and source - get chosen Country") def graph_verify_chosen_country(self, market_name): country = self.wait_for_element_visible(*self.locator(self.track_locators, "streams_and_graphs_country")) current_country = self.get_text(element=country) assert_that(current_country).is_equal_to(market_name) @allure.step("Stream and source - choose Country") def stream_and_source_choose_country(self, market_name): self.is_graph_period_displayed() dd = self.wait_for_element_visible(*self.locator(self.track_locators, "streams_and_graphs_country")) current_country = self.get_text(element=dd) self.click_on_element_js(element=dd) country_dd = "//*[contains(text(), '{market}')]" country_choose = f"{country_dd}/preceding-sibling::input" if current_country != market_name: loc = country_choose.format(market=self.all_markets) c_dd = self.get_element(locator=loc, locator_type="xpath") self.click_on_element_js(element=c_dd) if self.is_checked(locator=country_choose.format(market=self.all_markets), locator_type="xpath"): self.click_on_element_js(element=c_dd) country = country_choose.format(market=market_name) cc_dd = self.get_element(locator=country, locator_type="xpath") self.click_on_element_js(element=cc_dd) self.dd_click_apply() self.is_graph_period_displayed() self.log.info(f"Stream and source - choose country: {market_name}") @allure.step("Stream and source - choose Source") def change_source_value(self, source_name): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) if self.is_tab_selected_no_assert(locator="track-performance-streams", locator_type="id"): self.change_source_type(AppConfig.get("source")["by_source"]) self.uncheck_all_sources() source = f"""//*[contains(text(), '{source_name}')]/preceding-sibling::input""" self.click_on_element_js(self.get_element(source, "xpath")) apply = self.wait_for_element_visible(locator=self.apply_button_loc, locator_type="xpath") self.click_on_element_js(element=apply) self.is_graph_period_displayed() self.log.info("Stream and source - choose source: " + source_name) @allure.step("Stream and source - choose Source") def change_source_values(self, source_names): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) if self.is_tab_selected_no_assert(locator="track-performance-streams", locator_type="id"): self.change_source_type(AppConfig.get("source")["by_source"]) self.uncheck_all_sources() for source_name in source_names: source = f"""//*[contains(text(), '{source_name}')]/preceding-sibling::input""" self.click_on_element_js(self.get_element(source, "xpath")) apply = self.wait_for_element_visible(locator=self.apply_button_loc, locator_type="xpath") self.click_on_element_js(element=apply) self.is_graph_period_displayed() self.log.info(f"Stream and source - choose source: {source_names}") @allure.step("Stream and source - choose Source") def uncheck_all_sources(self): dd = self.wait_for_element_visible(*self.locator(self.track_locators, "streams_and_graphs_sources_dd")) self.click_on_element_js(element=dd) source_all = f"""//*[contains(text(), '{AppConfig.get("source")["all"]}')]/preceding-sibling::input""" self.click_on_element_js(self.get_element(source_all, "xpath")) checked = self.get_attribute_value(locator=source_all, locator_type="xpath", attribute="data-checked") self.log.info(f"checked: {checked}") if checked == "checked": self.click_on_element_js(self.get_element(source_all, "xpath")) @allure.step("Selecting period from date picker quick filter for the graph") def change_period_in_date_picker(self, param): quick_filter = f"//b[text()='{param}']" calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) item = self.wait_for_element_visible(quick_filter, "xpath") self.click_on_element_js(element=item) self.is_graph_period_displayed() self.log.info("Change date using quick filter to: " + param) @allure.step("Get selected dsp") def get_current_dsp(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) dsp_el = self.wait_for_element_visible(*self.locator(self.track_locators, "current_dsp")) dsp = self.get_text(element=dsp_el) self.log.info("Current dsp is: " + dsp) return dsp @allure.step("Get selected source") def get_current_source(self, param="streams_and_graphs"): self.wait_for_element_visible(*self.locator(self.track_locators, f"{param}_sources_dd")) source = self.get_text(*self.locator(self.track_locators, f"{param}_sources_dd")) self.log.info("Current source is: " + source) return source @allure.step("Get selected country") def graph_get_selected_market(self, dd="streams_and_graphs"): url = self.get_url() if "/youtube/video/" in url: if self.is_tab_selected_no_assert(locator="youtube-markets"): dd = "youtube_vbm" else: dd = "youtube_nvp" elif "/spotify/track/" in url and self.is_tab_selected_no_assert("track-performance-streams"): dd = "streams_and_graphs" elif "/spotify/track/" in url and self.is_tab_selected_no_assert("track-performance-countries"): dd = "tp_sbm" elif "/spotify/track/" in url and self.is_tab_selected_no_assert("track-performance-youtube"): dd = "youtube_vp" elif "/spotify/track/" in url and self.is_tab_selected_no_assert("performance_tiktok_tab"): dd = "tiktok" self.wait_for_element_clickable(*self.locator(self.track_locators, f"{dd}_country")) self.wait_for_element_visible(*self.locator(self.track_locators, f"{dd}_country")) self.is_graph_period_displayed() country = self.get_text(*self.locator(self.track_locators, f"{dd}_country")) self.log.info("Selected country in graph is: " + country) return country def is_source_list_active(self): is_active = self.is_enabled(*self.locator(self.track_locators, "streams_and_graphs_sources_dd")) self.log.info("is button inactive: " + str(is_active)) return is_active @allure.step("TP - switch to tab") def switch_to_tab(self, tab): self.page_has_loaded() self.click_element(*self.locator(self.track_locators, tab)) self.page_has_loaded() self.is_graph_period_displayed() self.is_tab_selected(*self.locator(self.track_locators, tab)) self.log.info("switch to tab: " + tab) self.log.info("is " + tab + " active: " + str(self.is_element_selected(*self.locator(self.track_locators, tab)))) @allure.step("Switch to By Markets tab") def switch_to_streams_by_markets_tab(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.switch_to_tab("countries_tab") time.sleep(2) @allure.step("Switch to Streams and Sources tab") def switch_to_streams_and_sources_tab(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.switch_to_tab("streams_and_sources_tab") def is_source_list_visible(self): return self.is_element_displayed(*self.locator(self.track_locators, "streams_and_graphs_sources_dd")) @allure.step("Track details - change owner category") def td_change_owner_category_to(self, category): all_categories_loc = "All Owner Categories " self.scroll_to_track_details() current_category = self.td_get_owner_category() if current_category != category: self.wait_for_element_clickable(self.wait_for_element_clickable(*self.locator(self.track_locators, "owner_category"))) self.click_element(*self.locator(self.track_locators, "owner_category")) self.click_on_element_js(self.get_element(all_categories_loc)) if self.is_checked(all_categories_loc, "id"): self.click_on_element_js(self.get_element(all_categories_loc)) if isinstance(category, str): category_el = f"{category} " el = self.get_element(category_el) self.click_on_element_js(element=el) else: for c in category: category_loc = f"{c} " el = self.get_element(category_loc) self.click_on_element_js(element=el) self.click_element(locator="(//button[.='Apply'])[last()]", locator_type="xpath") self.page_has_loaded() self.log.info(f"Track details - change owner category: {category}") @allure.step("Get current owner category") def td_get_owner_category(self): self.scroll_to_track_details() self.wait_for_element_visible(*self.locator(self.track_locators, "owner_category")) self.wait_for_element_clickable(*self.locator(self.track_locators, "owner_category")) category = self.get_text(*self.locator(self.track_locators, "owner_category")) self.log.info("Get current owner category: " + category) return category @allure.step("Get current owner market") def td_get_owner_market(self): self.wait_for_element_visible(*self.locator(self.track_locators, "owner_market")) market = self.get_text(*self.locator(self.track_locators, "owner_market")) self.log.info("Get current owner market: " + market) return market @allure.step("Track details - change owner market name") def td_change_owner_market_to(self, markets): self.page_has_loaded() self.scroll_to_track_details() dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "owner_market")) self.click_element(element=dd) all_markets = self.get_element("All Owner Markets ") self.click_on_element_js(element=all_markets) if self.get_attribute_value(element=all_markets, attribute="data-checked") == "checked": self.click_on_element_js(element=all_markets) if isinstance(markets, str): markets = [markets] for m in markets: market = self.get_element(locator=m + " ") self.click_on_element_js(market) apply_btn_locator = "//*[contains(@id, '-owner-markets-dd')]/following::button[.='Apply']" self.click_on_element_js(self.get_element(locator=apply_btn_locator, locator_type="xpath")) @allure.step("Track details - change type") def td_change_type(self, types): self.scroll_to_track_details() self.wait_for_element_clickable(*self.locator(self.track_locators, "track_details_type")) self.click_element(*self.locator(self.track_locators, "track_details_type")) checkbox1_loc = "//input[contains(@id, 'type-filter-dd-checkbox-1')]" checkbox2_loc = "//input[contains(@id, 'type-filter-dd-checkbox-2')]" for checkbox in [checkbox1_loc, checkbox2_loc]: if self.is_checked(checkbox, "xpath"): self.click_element(checkbox, "xpath") if isinstance(types, str): types = [types] for type in types: if type == AppConfig.get("type")["editorial"]: loc = checkbox2_loc elif type == AppConfig.get("type")["personalized"]: loc = checkbox1_loc type_el = self.get_element(locator=loc, locator_type="xpath") self.click_element(element=type_el) self.click_element("(//button[contains(@id, 'apply-btn')])[last()]", "xpath") def is_tab_selected(self, locator, locator_type="id"): attr_value = self.get_attribute_value(locator, locator_type, attribute="data-selected") self.ts.markFinal(attr_value == "selected", "{} tab is selected".format(locator)) return attr_value == "selected" def is_tab_selected_no_assert(self, locator, locator_type="id"): attr_value = self.get_attribute_value(locator, locator_type, attribute="data-selected") return attr_value == "selected" def is_checked(self, locator, locator_type): attr_value = self.get_attribute_value(locator, locator_type, attribute="data-checked") return attr_value == "checked" @allure.step("Switch to playlist") def td_switch_to_playlist(self, playlist): self.scroll_to_track_details() tab = self.get_element(*self.locator(self.track_locators, playlist)) self.click_on_element_js(element=tab) self.wait_for_element_clickable(*self.locator(self.track_locators, "td_previous_export")) self.is_tab_selected(*self.locator(self.track_locators, playlist)) self.log.info("switch to playlist: " + playlist) @allure.step("Switch to streams") def track_details_switch_to_streams(self, name): self.scroll_to_track_details() streams = "//div[contains(@id, 'streams-scope-bar')]/span[text()='{} Streams']".format(name) self.click_element(streams, "xpath") self.page_has_loaded() self.log.info("switch to streams: " + name) @allure.step("Switch to streams") def td_switch_to_worldwide_streams(self, ww=True): self.scroll_to_track_details() if ww: tab = "worldwide-" else: tab = "current-market" loc = f"track-page-current-playlists-and-stations-controls-{tab}-scope-bar" tab = self.get_element(locator=loc, locator_type="id") self.click_element(element=tab) self.is_tab_selected(locator=loc, locator_type="id") self.page_has_loaded() self.wait_track_details_table_displayed() self.log.info(f"switch to streams: {tab}") @allure.step("track details - sort by column") def td_sort_table_by_column(self, column): sort_by = "//span[text()='{}']".format(column) self.scroll_to_track_details() column_header = self.get_element(sort_by, "xpath") self.click_on_element_js(element=column_header) self.page_has_loaded() @allure.step("track details - charts combined sort by column") def track_details_charts_combined_sort_table_by_column(self, column): sort_column_locator = "" if column == "Country": sort_column_locator = "//span[text()='Country']/following-sibling::div/span[contains(@class, 'icon')]" elif column == "Spotify Change": sort_column_locator = "(//span[text()='Change']/following-sibling::div/span[contains(@class, 'icon')])[1]" elif column == "Spotify Current Position": sort_column_locator = "(//span[text()='Current Position']/following-sibling::div/span[contains(@class, 'icon')])[1]" elif column == "Apple Music Change": sort_column_locator = "(//span[text()='Change']/following-sibling::div/span[contains(@class, 'icon')])[2]" elif column == "Apple Music Current Position": sort_column_locator = "(//span[text()='Current Position']/following-sibling::div/span[contains(@class, 'icon')])[2]" else: self.log.info("no such column: {}".format(column)) self.wait_for_element_visible(sort_column_locator, "xpath") self.click_element(sort_column_locator, "xpath") self.page_has_loaded() @allure.step("get followers from table") def td_get_playlist_followers_values(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-followers-')]/div/span", "xpath") values = [] for element in elements: if len(element.text) > 0: values.append(int(str(element.text).replace(",", ""))) self.log.info("followers values: " + str(values)) return values @allure.step("get positions from table") def get_positions_from_table(self): self.scroll_to_track_details() elements = self.get_elements("//div[contains(@id, '-track-position-chart')]/span", "xpath") values = [] for element in elements: values.append(int(str(element.text))) self.log.info("positions values: " + str(values)) return values @allure.step("Get track stream latest day from table") def td_get_track_streams_latest_day_values(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-streams-latest-day-')]", "xpath") values = [] for element in elements: streams_value = self.get_text(element=element) values.append(streams_value) values_formatted = [int(str(value).replace(",", "")) for value in values if value != ""] self.log.info("track stream latest day values: " + str(values_formatted)) return values_formatted @allure.step("get track stream days 7 from table") def td_get_track_streams_7_days_values(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-track-streams-7-days-') and not(contains(@id, 'tooltip'))]//../*[string-length(text()) > 0]", "xpath") values = [] for element in elements: values.append(int(str(element.text).replace(",", ""))) self.log.info("track stream days 7 values: " + str(values)) return values @allure.step("Get in playlist streams 7 days from table") def td_get_in_playlist_streams_7_days_values(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-playlist-streams-7-days-') and not(contains(@id, 'tooltip'))]//../*[string-length(text()) > 0]", "xpath") values = [] for element in elements: values.append(int(str(element.text).replace(",", ""))) self.log.info("in playlist streams 7 days values: " + str(values)) return values @allure.step("get playlist stream days 7 from table") def get_playlist_stream_days_from_table(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, 'playlist-streams-7-days-')]/div/span", "xpath") values = [self.get_text(element=element) for element in elements] values_formatted = [int(str(value).replace(",", "")) for value in values if value != ""] self.log.info("playlist stream days 7 values: " + str(values_formatted)) return values_formatted @allure.step("Get chart names from table") def td_cps_get_playlist_names(self, stations=False): self.scroll_to_track_details() locator = "//div[contains(@id, 'cell-Entity')]//../a[contains(@href, '/playlist/')]" if stations: locator = "//div[contains(@id, 'cell-Entity')]/div/div/span" self.page_has_loaded() time.sleep(1) self.wait_for_element_visible(locator, "xpath") self.wait_for_element_clickable(locator, "xpath") elements = self.get_elements(locator, "xpath") values = [] for element in elements: if len(element.text) > 0: values.append(element.text) self.log.info("chart names values: " + str(values)) return values @allure.step("track details - search be filter") def td_search_filter(self, text): self.wait_for_element_clickable(*self.locator(self.track_locators, "track_details_filter_field")) self.clear_text(*self.locator(self.track_locators, "track_details_filter_field")) self.send_text(text, *self.locator(self.track_locators, "track_details_filter_field")) self.click_element(*self.locator(self.track_locators, "track_details_filter_icon")) self.page_has_loaded() @allure.step("verify track details - each name contains filtered query") def verify_each_name_contains(self, text): list = self.td_cps_get_playlist_names() return all(text.lower() in string.lower() for string in list) @allure.step("track details - is previous playlist tab active") def td_is_past_tab_active(self): is_active = self.is_enabled(*self.locator(self.track_locators, "previous_playlists_tab")) self.log.info("is previous playlist tab active: " + str(is_active)) return is_active @allure.step("track details - is current playlist tab active") def td_is_current_playlist_tab_active(self): is_active = self.is_enabled(*self.locator(self.track_locators, "first_playlist")) self.log.info("is current playlist tab active: " + str(is_active)) return is_active @allure.step("track details - is owner market dropdown active") def is_owner_market_tab_active(self): is_active = self.is_enabled(*self.locator(self.track_locators, "owner_market")) self.log.info("is owner market dropdown active: " + str(is_active)) return is_active @allure.step("track details - is owner category dropdown active") def is_owner_category_tab_active(self): is_active = self.is_enabled(*self.locator(self.track_locators, "owner_category")) self.log.info("is owner category dropdown active: " + str(is_active)) return is_active @allure.step("track details - is table displayed") def wait_track_details_table_displayed(self, scroll=True): if scroll: self.scroll_to_track_details() self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_table")) self.log.info("track details table displayed") @allure.step("track details - switch to bar chart") def td_switch_to_bar_chart(self): self.click_on_element_js(self.get_element(*self.locator(self.track_locators, "track_details_graph_view"))) self.page_has_loaded() @allure.step("track details - scroll to markets graph") def scroll_to_markets_graph(self): self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_markets_graph")) self.scroll_to_element(*self.locator(self.track_locators, "track_details_markets_graph")) self.page_has_loaded() @allure.step("track details - click on market") def track_details_markets_click_on(self, market): market = "//span[@tag='smallText'][text()='{}']".format(market) self.scroll_to_element(market, "xpath") self.wait_for_element_clickable(market, "xpath") self.click_element(market, "xpath") self.page_has_loaded() @allure.step("track details - filter click clear icon") def td_filter_click_clear_icon(self, wait_not_visible=True): self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_clear_icon")) self.click_element(*self.locator(self.track_locators, "track_details_filter_clear_icon")) if wait_not_visible: time.sleep(2) @allure.step("track details - filter clear icon displayed") def td_filter_is_clear_icon_displayed(self): icon = self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_clear_icon")) assert_that(self.is_element_displayed(element=icon)).is_true() @allure.step("track details - is barchart inactive") def track_details_is_bar_chart_inactive(self, market): market_color = "//span[@tag='smallText'][text()='{}']//preceding-sibling::div".format(market) color = self.get_element(market_color, "xpath").value_of_css_property("background-color") self.log.info("is {} inactive: {}".format(market, color)) return color @allure.step("track details - get chart countries from table") def td_get_countries_from_table(self, no_sum=False): self.scroll_to_track_details() selector = "//*[contains(@id, 'country-code-')]/..//img[contains(@src, 'svg')]" self.page_has_loaded() if no_sum: selector = "//*[contains(@id, 'country-code-')]/*/*/img[contains(@src, 'svg')]" self.wait_for_element_visible(selector, "xpath") elements = self.get_elements(selector, "xpath") values = [] for element in elements: values.append(str(element.get_attribute("src")).split(".")[-2].split("/")[-1]) self.log.info(f"countries values: {values}") return values @allure.step("track details - get chart positions from table") def get_chart_positions_from_table(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-track-position-')]/div/span/span[1]", "xpath") values = [] for e in elements: self.log.info("position before extraction: {}".format(self.get_text(element=e))) values.append(int(str(self.get_text(element=e)))) self.log.info("positions values: " + str(values)) return values @allure.step("track details - get chart trends from table") def td_get_position_trends(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, '-change-')]/div", "xpath") values = [] for e in elements: if self.get_text(element=e) == "": values.append(0) else: values.append(int(str(self.get_text(element=e)))) self.log.info("trends values: " + str(values[:15])) return values[:15] @allure.step("track details - get chart days from table") def get_chart_days_from_table(self): self.scroll_to_track_details() elements = self.get_elements("//*[contains(@id, 'track-days-in-playlist-')]/div/div/span", "xpath") values = [] for e in elements: values.append(int(str(self.get_text(element=e)))) self.log.info("days values: " + str(values)) return values @allure.step("track details - sort track details by track stream 7 days") def track_details_sort_table_by_track_stream_7_days(self): sort_by = "(//*[contains(@id, '-track-streams-7-days')])[1]" self.wait_for_element_visible(sort_by, "xpath") self.click_element(sort_by, "xpath") self.page_has_loaded() @allure.step("track details - sort track details by playlist stream 7 days") def track_details_sort_table_by_playlist_stream_7_days(self): sort_by = "(//*[contains(@id, '-playlist-streams-7-days')])[1]" self.scroll_to_track_details() self.wait_for_element_visible(sort_by, "xpath") self.click_element(sort_by, "xpath") self.page_has_loaded() @allure.step("track details - switch to chart tab") def td_switch_to_charts_tab(self): self.scroll_to_element("//*[text()='Date']", "xpath") charts = self.wait_for_element_clickable(*self.locator(self.track_locators, "track_details_charts")) self.click_element(element=charts) self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_charts_overview")) self.log.info("switch to charts tab") self.is_tab_selected(*self.locator(self.track_locators, "track_details_charts")) @allure.step("track details - switch to chart sub-tab") def track_details_switch_to_charts_sub_tab(self): self.scroll_to_track_details() charts_sub_tab = self.wait_for_element_clickable(*self.locator(self.track_locators, "track_details_charts_sub_tab")) self.click_element(element=charts_sub_tab) self.log.info("switch to charts sub-tab") @allure.step("track details - charts is spotify daily selected") def track_details_charts_is_spotify_daily_selected(self): self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_charts_spotify_daily")) return self.is_enabled(*self.locator(self.track_locators, "track_details_charts_spotify_daily")) @allure.step("track details - charts is tab selected selected") def track_details_charts_is_tab_selected(self, tab_name): tab_locator = f"//button/span[contains(text(), '{tab_name}')]" tab = self.wait_for_element_visible(tab_locator, "xpath") self.log.info(f"tab {tab_name} is chosen: {self.is_element_displayed(element=tab)}") return self.is_element_displayed(element=tab) @allure.step("track details - charts is tab selected selected") def td_charts_select_dsp(self, tab_name): charts_dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "charts_dd_weekly_daily")) self.click_element(element=charts_dd) e = self.wait_for_element_clickable(f"//*[contains(text(), '{tab_name}')]", "xpath") self.click_element(element=e) self.log.info(f"click on charts dd item {tab_name}") @allure.step("track details - charts spotify get values from column") def td_charts_spotify_get_column_values(self): self.scroll_to_track_details() self.wait_for_element_visible(locator="//div[contains(@id, 'market-rank-')]/div/span", locator_type="xpath") column_locator = "" values = {} columns = ["Size", "Country", "Change", "Current", "Peak", "Entry", "Peak Date", "Entry Date"] for column in columns: if column == "Size": column_locator = "//div[contains(@id, 'market-rank-')]/div/span" elif column == "Country": column_locator = "//div[contains(@id, 'region-name-')]/div/span" elif column == "Change": column_locator = "//div[contains(@id, 'position-change-')]/div/div/div/div" elif column == "Current": column_locator = "//div[contains(@id, 'current-position-')]/div/span" elif column == "Peak": column_locator = "//div[contains(@id, 'peak-position-')]/div/span" elif column == "Entry": column_locator = "//div[contains(@id, 'entry-position-')]/div/span" elif column == "Peak Date": column_locator = "//div[contains(@id, 'peak-date-')]/div/span" elif column == "Entry Date": column_locator = "//div[contains(@id, 'entry-date-')]/div/span" else: self.log.info(f"no such column: {column}") elements = self.get_elements(column_locator, "xpath")[:5] self.log.info(f"column: {column}") values[column] = [] for e in elements: if column in ["Size", "Current", "Peak", "Entry"]: num = str(self.get_text(element=e)).replace("-", "") if len(num) > 0: values[column].append(int(num)) elif column == "Country": values[column].append(str(self.get_text(element=e))) elif column in ["Peak Date", "Entry Date"]: if len(str(self.get_text(element=e))) > 0: date_str = str(self.get_text(element=e)) datetime_obj = datetime.datetime.strptime(date_str, self.get_date_format_from_locale()).date() values[column].append(datetime_obj) self.log.info(f"values are: {values}") return values @allure.step("track details - charts apple get values from column") def track_details_charts_apple_get_column_values(self, column): self.scroll_to_track_details() column_locator = "" if column == "Country": column_locator = "//div[contains(@id, 'region-name-')]/div/span" elif column == "Change": column_locator = "//div[contains(@id, 'position-change-')]/div/div/div/div" elif column == "Current": column_locator = "//div[contains(@id, 'current-position-')]/div/span" elif column == "Peak": column_locator = "//div[contains(@id, 'peak-position-')]/div/span" elif column == "Entry": column_locator = "//div[contains(@id, 'entry-position-')]/div/span" elif column == "Peak Date": column_locator = "//div[contains(@id, 'peak-date-')]/div/span" elif column == "Entry Date": column_locator = "//div[contains(@id, 'entry-date-')]/div/span" else: self.log.info("no such column") elements = self.get_elements(column_locator, "xpath") values = [] for e in elements: if column in ["Size", "Current", "Peak", "Entry"]: num = str(self.get_text(element=e)).replace("-", "") if len(num) > 0: values.append(int(num)) else: values.append(0) elif column == "Country": values.append(str(self.get_text(element=e))) elif column in ["Peak Date", "Entry Date"]: if len(str(self.get_text(element=e))) > 0: date_str = str(self.get_text(element=e)) datetime_obj = datetime.datetime.strptime(date_str, "%d/%m/%Y").date() values.append(datetime_obj) else: datetime_obj = datetime.datetime.strptime("01/01/0001", "%d/%m/%Y").date() values.append(datetime_obj) self.log.info("{} values are: {}".format(column, values)) return values @allure.step("track details - charts combined get values from column") def track_details_charts_combined_get_column_values(self, column): self.scroll_to_track_details() column_locator = "" if column == "Country": column_locator = "//div[contains(@id, 'region-name-')]/div/span" elif column == "Spotify Change": column_locator = "//div[contains(@id, 'spotify-position-change-')]/div/div/div[2]" elif column == "Spotify Current Position": column_locator = "//div[contains(@id, 'spotify-current-position-')]/div/span" elif column == "Apple Music Change": column_locator = "//div[contains(@id, 'apple-position-change-')]/div/div/div/div/div" elif column == "Apple Music Current Position": column_locator = "//div[contains(@id, 'apple-current-position-')]/div/span" else: self.log.info("no such column") elements = self.get_elements(column_locator, "xpath") values = [] for e in elements: if column in [ "Spotify Change", "Spotify Current Position", "Apple Music Change", "Apple Music Current Position", ]: num = str(self.get_text(element=e)).replace("-", "") if len(num) > 0: values.append(int(num)) else: values.append(0) elif column == "Country": values.append(str(self.get_text(element=e))) self.log.info("{} values are: {}".format(column, values)) return values @allure.step("TP - TD - charts beta select dsp") def td_charts_beta_select_dsp(self, dsp_name): self.scroll_to_track_details() dsp_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "charts_beta_dsp_dd")) if self.get_text(element=dsp_dd) != dsp_name: self.click_element(*self.locator(self.track_locators, "charts_beta_dsp_dd")) item = self.wait_for_element_clickable(locator=f"//*[@id='track-page-charts-controls-charts-dsp-dd']/div/div/div[.='{dsp_name}']", locator_type="xpath") self.click_element(element=item) self.track_details_charts_beta_verify_dsp(dsp_name) @allure.step("TP - TD - charts beta verify dsp") def track_details_charts_beta_verify_dsp(self, dsp_name): self.scroll_to_track_details() dsp_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "charts_beta_dsp_dd")) dsp = self.get_text(element=dsp_dd) assert_that(dsp).is_equal_to(dsp_name) def td_previous_playlist_get_table_ui(self, column): self.scroll_to_track_details() column_locator = "" if column == "C": column_locator = "//*[contains(@id, 'country-code-')]//../img" elif column == "Name": column_locator = "//*[contains(@id, 'Entity-')]" elif column == "Added": column_locator = "//*[contains(@id, 'added-date-')][string-length(.) > 0]" elif column == "Removed": column_locator = "//*[contains(@id, 'removed-date-')][string-length(.) > 0]" elif column == "Days in Playlist": column_locator = "//*[contains(@id, 'days-in-playlist-')]" elif column == "Followers": column_locator = "//*[contains(@id, 'followers-')]" else: self.log.info("no such column") elements = self.get_elements(column_locator, "xpath") values = [] for e in elements: if column in ["Followers", "Days in Playlist"]: num = str(self.get_text(element=e)).replace("-", "").replace(",", "") if len(num) > 0: values.append(int(num)) else: values.append(0) elif column == "C": values.append(str(e.get_attribute("src")).split(".")[-2].split("/")[-1]) elif column in ["Name", "Owner"]: values.append(str(self.get_text(element=e))) elif column in ["Added", "Removed"]: date_str = str(self.get_text(element=e)) datetime_obj = datetime.datetime.strptime(date_str, self.get_date_format_from_locale()).date() values.append(datetime_obj) self.log.info("{} values are: {}".format(column, values)) return values @allure.step("generate future date") def get_future_date_in_month(self, count): now = datetime.datetime.now() future_date = (now + datetime.timedelta(weeks=count * 4)).date() self.log.info("your future date is: {}".format(future_date)) return future_date @allure.step("track details - get chosen type") def td_get_current_type(self): self.scroll_to_track_details() self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_type")) self.wait_for_element_clickable(*self.locator(self.track_locators, "track_details_type")) return self.get_text(*self.locator(self.track_locators, "track_details_type")) @allure.step("track details - streams tab is active") def track_details_is_streams_tab_active(self, stream): self.scroll_to_track_details() streams = f"//div[contains(@id, '{stream}') and contains(@id, 'scope-bar')]" self.is_tab_selected(streams, "xpath") @allure.step("track details - is table view active") def track_details_is_table_view_active(self): self.is_tab_selected(*self.locator(self.track_locators, "track_details_table_view")) @allure.step("set network conditions") def set_network_conditions(self, offline=False, latency=0, download=100, upload=100): self.driver.set_network_conditions(offline=offline, latency=latency, download_throughput=download * 1024, upload_throughput=upload * 1024) @allure.step("track page - no data in track performance") def verify_performance_no_data_displayed(self): e = self.wait_for_element_visible(*self.locator(self.track_locators, "track_performance_no_data")) is_displayed = self.is_element_displayed(element=e) self.ts.markFinal(is_displayed, "no data in track performance") return is_displayed @allure.step("track page - no data in track performance") def graph_wait_data_displayed(self): self.wait_for_element_not_visible(*self.locator(self.track_locators, "track_performance_no_data")) def block_url(self, param): log = self.driver.execute_script("executeCdpCommand", {"cmd": "Network.setBlockedURLs", "params": {"urls": [param]}})["value"] self.log.info("log: {}".format(log)) @allure.step("track page - get track performance countries chart tooltips count info") def get_track_performance_countries_tooltips(self, param): self.wait_for_element_visible(*self.locator(self.track_locators, "track_performance_countries_markets")) chart = self.get_elements(*self.locator(self.track_locators, "track_performance_countries_markets")) val_percentage = [] val_streams = [] val_country = [] val_streams_full = [] if len(chart) < param: param = len(chart) for e in chart[:param]: e = self.get_elements(*self.locator(self.track_locators, "track_performance_countries_markets"))[chart.index(e)] ActionChains(self.driver).move_to_element(to_element=e).perform() base_locator = "//*[contains(@id, 'tooltip')]/{}" country = self.get_text(locator=base_locator.format("*[1]"), locator_type="xpath") streams_el = self.wait_for_element_visible(locator="(//*[contains(@id, 'tooltip')]/div/span/b)[1]", locator_type="xpath") streams_text = self.get_text(element=streams_el) self.log.info(f"streams text: {streams_text}") streams_full = int(streams_text.replace(",", "")) self.log.info(f"streams int: {streams_full}") percentage = float(str(self.get_text(locator=base_locator.format("/*[2]/*[3]"), locator_type="xpath")).split("(")[-1].split("%")[0]) percentage = self.apply_rounding_percentage(percentage) self.log.info("percentage: {}".format(percentage)) streams = self.apply_rounding(streams_full) val_country.append(country) val_streams.append(streams) val_percentage.append(percentage) val_streams_full.append(streams_full) tooltips = { "countries": val_country, "streams": val_streams, "percentage": val_percentage, "streams_full": val_streams_full, } self.log.info("info from tooltips for countries: {}".format(tooltips)) return tooltips def apply_rounding(self, streams): if streams < 1000: streams = streams elif 1 < streams / 1000000000 < 10: streams = round(streams / 1000000000, 1) elif streams / 1000000 > 10: streams = round(streams / 1000000) elif 1 < streams / 1000000 < 10: streams = round(streams / 1000000, 1) elif streams / 1000 > 10: streams = round(streams / 1000) else: streams = round((streams / 1000) * 10) / 10 return streams def apply_rounding_percentage(self, percentage): if percentage - math.floor(percentage) < 0.5: percentage = math.floor(percentage) else: percentage = math.ceil(percentage) return percentage def read_from_csv(self, path): time.sleep(10) self.log.info(f"path from file: {path}") data = pd.read_csv(path.replace(" ", "%20").replace("–", "%E2%80%93"), on_bad_lines="skip") self.log.info(f"data from file: {data}") return data @allure.step("track page - access exported file") def read_file(self, track, dsp, tab, sources): session_id = self.driver.session_id file_path = "http://{host}:4444/download/{session_id}/{track} - {tab} - {dsp}.csv".format(host=CoreConfig.SELENOID_HOST, session_id=session_id, track=track.name, dsp=dsp, tab=tab) self.log.info("file: {}".format(file_path)) data = self.read_from_csv(file_path) if sources == AppConfig.get("source")["all"]: source_name = "All Streams" elif dsp == AppConfig.get("dsp")["amazon"] and sources == "Playlists": source_name = "Playlist Streams" else: source_name = f"Source {sources} Streams" streams = data.drop(data[data.get("Country") == "UNKNOWN"].index).groupby(by="Country")[source_name].sum().nlargest(10).tolist() streams = [self.apply_rounding(s) for s in streams] if streams == [0]: streams = [] self.log.info("csv streams: {}".format(streams)) return streams @allure.step("track page - click export") def click_export(self): self.scroll_to_element(*self.locator(self.track_locators, "export_button")) export = self.wait_for_element_clickable(*self.locator(self.track_locators, "export_button")) self.click_on_element_js(element=export) self.wait_for_element_clickable(*self.locator(self.track_locators, "export_button")) @allure.step("track page - get track title") def get_track_title(self, ap=False): if ap: title = self.wait_for_element_visible(*self.locator(self.track_locators, "track_title")) track_title = self.get_text(element=title) else: self.wait_for_element_visible(*self.locator(self.track_locators, "title")) track_title = self.get_elements(*self.locator(self.track_locators, "title"))[0] track_title = self.get_text(element=track_title) self.log.info(f"track title: {track_title}") return track_title @allure.step("track page - get streams") def get_streams_values_by_dsp(self): all_totals = "(//span[text()='Total']/following-sibling::*)[{}]" total_locator = all_totals.format(1) spotify_locator = all_totals.format(2) apple_locator = all_totals.format(3) amazon_locator = all_totals.format(4) self.wait_for_element_visible(total_locator, "xpath") time.sleep(2) self.scroll_to_element(total_locator, "xpath") self.page_has_loaded() self.wait_for_element_visible(total_locator, "xpath") time.sleep(2) spotify_value = "0" apple_value = "0" amazon_value = "0" spotify_percentage = "0" apple_percentage = "0" amazon_percentage = "0" total = "0" if len(self.get_elements(spotify_locator, "xpath")) > 0: spotify_value = int(str(self.get_text(spotify_locator, "xpath")).split("\n")[0].replace(",", "").replace("N/A", "0").replace("None", "0")) spotify_percentage = float(str(self.get_text(spotify_locator, "xpath")).split("\n")[1].replace("(", "").replace(")", "").replace("%", "").replace("N/A", "0").replace("None", "0")) if len(self.get_elements(apple_locator, "xpath")) > 0: apple_value = int(str(self.get_text(apple_locator, "xpath")).split("\n")[0].replace(",", "").replace("N/A", "0").replace("None", "0")) apple_percentage = float(str(self.get_text(apple_locator, "xpath")).split("\n")[1].replace("(", "").replace(")", "").replace("%", "").replace("N/A", "0").replace("None", "0")) if len(self.get_elements(amazon_locator, "xpath")) > 0: amazon_value = int(str(self.get_text(amazon_locator, "xpath")).split("\n")[0].replace(",", "").replace("N/A", "0").replace("None", "0")) amazon_percentage = float(str(self.get_text(amazon_locator, "xpath")).split("\n")[1].replace("(", "").replace(")", "").replace("%", "").replace("N/A", "0").replace("None", "0")) if len(self.get_elements(total_locator, "xpath")) > 0: total = int(str(self.get_text(total_locator, "xpath")).replace(",", "").replace("N/A", "0").replace("None", "0")) values = dict( zip( [ "spotify_value", "apple_value", "amazon_value", "spotify_percentage", "apple_percentage", "amazon_percentage", "total_value", ], [ spotify_value, apple_value, amazon_value, spotify_percentage, apple_percentage, amazon_percentage, total, ], ) ) self.log.info("values from track page: {}".format(values)) return values @allure.step("track page - get Leans values - back, forward, total") def get_lean_values(self): lean_forward_count = [] lean_back_count = [] lean_forward_percent = [] lean_back_percent = [] lf_avg = [] lb_avg = [] total_value = 0 if not self.is_youtube_video_page_opened(): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "graph_total")) total_value = int(str(self.get_text(*self.locator(self.track_locators, "graph_total"))).replace(",", "")) self.wait_for_element_visible(*self.locator(self.track_locators, "lean_back")) lean_back_el = self.get_elements(*self.locator(self.track_locators, "lean_back")) for e in lean_back_el: e = self.get_elements(*self.locator(self.track_locators, "lean_back"))[lean_back_el.index(e)] ActionChains(self.driver).move_to_element(to_element=e).perform() lean_back_count.append(int(str(self.get_text(*self.locator(self.track_locators, "tooltip_lean_streams"))).replace(",", ""))) lean_back_percent.append(float(str(self.get_text(*self.locator(self.track_locators, "tooltip_lean_percentage"))).replace("%", ""))) lb_avg.append(int(self.get_text(locator="//*[contains(@id, 'avg-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", ""))) self.wait_for_element_visible(*self.locator(self.track_locators, "lean_forward")) lean_forward_el = list(self.get_elements(*self.locator(self.track_locators, "lean_forward"))) for e in lean_forward_el: e = self.get_elements(*self.locator(self.track_locators, "lean_forward"))[lean_forward_el.index(e)] ActionChains(self.driver).move_to_element(to_element=e).perform() lean_forward_count.append(int(str(self.get_text(*self.locator(self.track_locators, "tooltip_lean_streams"))).replace(",", ""))) lean_forward_percent.append(float(str(self.get_text(*self.locator(self.track_locators, "tooltip_lean_percentage"))).replace("%", ""))) lf_avg.append(int(self.get_text(locator="//*[contains(@id, 'avg-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", ""))) values = { "lean_forward_count": sum(lean_forward_count), "lean_back_count": sum(lean_back_count), "lean_forward_percent": self.apply_rounding_percentage(sum(lean_forward_percent)), "lean_back_percent": self.apply_rounding_percentage(sum(lean_back_percent)), "total": total_value, "lean_forward_by_source": lean_forward_count, "lean_back_by_source": lean_back_count, "lb_avg": lb_avg, "lf_avg": lf_avg, "lb_perc": lean_back_percent, "lf_perc": lean_forward_percent, } self.log.info(f"lb and lf values: {values}") return values @allure.step("track page - get release date") def get_release_date(self): locator = "//*[contains(text(), 'Released:')]" self.wait_for_element_visible(locator, "xpath") e = self.wait_for_element_clickable(locator, "xpath") text = datetime.datetime.strptime(str(self.get_text(element=e)).split(" ")[1].split("\n")[0], self.get_date_format_from_locale()).date() self.log.info("release date is: {}".format(text)) return text @allure.step("Track page - wait for stream performance chart visible") def wait_for_stream_performance_graph_visible(self): self.wait_for_element_visible(*self.locator(self.track_locators, "track_streams_performance-days")) @allure.step("Track page - scan track performance tooltips text") def get_tooltip_info_track_performance(self, param=365 * 2): self.scroll_to_element(*self.locator(self.track_locators, "track_stream_performance_chart")) self.wait_for_stream_performance_graph_visible() e = self.wait_for_element_visible(*self.locator(self.track_locators, "track_stream_performance_chart"), timeout=1) height = int(int(e.size["height"]) / 1.2) width = int(e.size["width"]) + 1 self.log.info("height: {height}, width: {width}".format(height=height, width=width)) step = int(width / param) self.log.info("step: {step}".format(step=step)) spotify_l = [] apple_l = [] amazon_l = [] total_l = [] for t in range(0, width, step): e = self.wait_for_element_visible(*self.locator(self.track_locators, "track_stream_performance_chart"), timeout=1) ActionChains(self.driver).move_to_element_with_offset(to_element=e, xoffset=t, yoffset=height).perform() t = self.wait_for_element_visible(*self.locator(self.track_comparison_page, "tooltip"), timeout=1) text = str(self.get_text(element=t)) if text not in [None, "None", ["None"], [None]]: spotify = int(str(self.get_text("//*[contains(@id, 'tooltip-row-0-total')]/b", "xpath")).replace(",", "").replace("None", "0")) apple = int(str(self.get_text("//*[contains(@id, 'tooltip-row-1-total')]/b", "xpath")).replace(",", "").replace("None", "0")) amazon = int(str(self.get_text("//*[contains(@id, 'tooltip-row-2-total')]/b", "xpath")).replace(",", "").replace("None", "0")) total = int(str(self.get_text("//*[contains(@id, 'tooltip-row-total-value')]", "xpath")).replace(",", "").replace("None", "0")) if spotify not in spotify_l: spotify_l.append(spotify) if apple not in apple_l: apple_l.append(apple) if amazon not in amazon_l: amazon_l.append(amazon) if total not in total_l: total_l.append(total) self.log.info("tooltip text: {}, {}, {}, {}".format(spotify, apple, amazon, total)) values = dict(zip(["spotify", "apple", "amazon", "total"], [spotify_l, apple_l, amazon_l, total_l])) self.log.info("track performance tooltip content: {}".format(values)) return values @allure.step("Track page - track performance verify age groups") def track_performance_verify_age_groups(self, dsp): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "track_streams_performance_age_group_name")) self.page_has_loaded() age_groups_el = self.get_elements(*self.locator(self.track_locators, "track_streams_performance_age_group_name")) age_groups = [self.get_text(element=g) for g in age_groups_el] groups = [] if dsp == AppConfig.get("dsp")["spotify"]: groups = ["0-17", "18-22", "23-27", "28-34", "35-44", "45-59", "60+", "Unkn"] elif dsp == AppConfig.get("dsp")["apple"]: groups = ["0-17", "18-24", "25-34", "35-44", "45-54", "55-64", "65+", "Unkn"] self.ts.markFinal(groups == age_groups, "dsp: {} age groups: {}\n groupd:{} are correct".format(dsp, age_groups, groups)) @allure.step("Track page - track performance verify genders") def track_performance_verify_genders(self, dsp): self.scroll_to_element(*self.locator(self.track_locators, "track_streams_performance_gender_name")) self.wait_for_element_visible(*self.locator(self.track_locators, "track_streams_performance_gender_name")) self.page_has_loaded() genders_el = self.get_elements(*self.locator(self.track_locators, "track_streams_performance_gender_name")) genders = [self.get_text(element=g) for g in genders_el] groups = [] if dsp == AppConfig.get("dsp")["spotify"]: groups = ["Female", "Male", "Non-Binary", "Unkn"] elif dsp == AppConfig.get("dsp")["apple"]: groups = ["Female", "Male", "Unkn"] assert_that(groups).is_equal_to(genders) @allure.step("Track page - track performance get age group streams tooltip") def get_age_groups_tooltip_info(self, global_age=False): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "track_streams_performance_age_group_name")) age_groups_el = self.get_elements(*self.locator(self.track_locators, "track_streams_performance_age_group_name")) percentage_arr = [] streams_arr = [] for e in age_groups_el: ActionChains(self.driver).move_to_element(to_element=e).perform() if global_age: percentage = float(str(self.get_text("//span[contains(@id, 'age')][contains(@id, '-value')]", "xpath")).replace("%", "")) percentage_arr.append(percentage) else: tooltip_el = self.get_text("//span[contains(@id, 'tooltip')][contains(@id, 'streams-value')]", "xpath") streams = int(str(tooltip_el).replace(",", "")) percentage = float( str( self.get_text( "//span[contains(@id, 'tooltip')][contains(@id, 'streams-value')]/preceding-sibling::*", "xpath", ) ).replace("%", "") ) streams_arr.append(streams) percentage_arr.append(percentage) return {"percentage": percentage_arr, "streams": streams_arr} @allure.step("Track page - get streams for genders and ages from api delphi") def get_streams_age_gender_api(self, market, isrc, start_date, end_date, token, dsp): if dsp == AppConfig.get("dsp")["spotify"]: try: ages = [0, 0, 0, 0, 0, 0, 0, 0] api_response = self.api_client.get_spotify_demographics_delphi(market=market, isrc=isrc, start_date=start_date, end_date=end_date, token=token)["body"][0] self.log.info("age bands: {}".format(api_response["age_bands"])) self.log.info("genders: {}".format(api_response["genders"])) self.log.info("age keys: {}".format(dict(api_response["age_bands"]).keys())) self.log.info("gender keys: {}".format(dict(api_response["genders"]).keys())) for age in dict(api_response["age_bands"]).keys(): if "all" not in age: if "0_17" in age: ages[0] = ages[0] + dict(api_response["age_bands"]).get(age) elif "18_22" in age: ages[1] = ages[1] + dict(api_response["age_bands"]).get(age) elif "23_27" in age: ages[2] = ages[2] + dict(api_response["age_bands"]).get(age) elif "28_34" in age: ages[3] = ages[3] + dict(api_response["age_bands"]).get(age) elif "35_44" in age: ages[4] = ages[4] + dict(api_response["age_bands"]).get(age) elif "45_59" in age: ages[5] = ages[5] + dict(api_response["age_bands"]).get(age) elif "60" in age: ages[6] = ages[6] + dict(api_response["age_bands"]).get(age) elif "unknown" in age: ages[7] = ages[7] + dict(api_response["age_bands"]).get(age) genders = [0, 0, 0, 0] for gender in dict(api_response["genders"]).keys(): if "female" == gender: genders[0] = dict(api_response["genders"]).get(gender) elif "male" == gender: genders[1] = dict(api_response["genders"]).get(gender) elif "neutral" == gender: genders[2] = dict(api_response["genders"]).get(gender) elif "unknown" == gender: genders[3] = dict(api_response["genders"]).get(gender) except IndexError: ages = [0, 0, 0, 0, 0, 0, 0, 0] genders = [0, 0, 0, 0] elif dsp == AppConfig.get("dsp")["apple"]: try: ages = [0, 0, 0, 0, 0, 0, 0, 0] api_response = self.api_client.get_apple_demographics_delphi(market=market, isrc=isrc, start_date=start_date, end_date=end_date, token=token)["body"][0] self.log.info("age bands: {}".format(api_response["age_bands"])) self.log.info("genders: {}".format(api_response["genders"])) self.log.info("age keys: {}".format(dict(api_response["age_bands"]).keys())) self.log.info("gender keys: {}".format(dict(api_response["genders"]).keys())) for age in dict(api_response["age_bands"]).keys(): if "all" not in age: if "0_17" in age: ages[0] = ages[0] + dict(api_response["age_bands"]).get(age) elif "18_24" in age: ages[1] = ages[1] + dict(api_response["age_bands"]).get(age) elif "25_34" in age: ages[2] = ages[2] + dict(api_response["age_bands"]).get(age) elif "35_44" in age: ages[3] = ages[3] + dict(api_response["age_bands"]).get(age) elif "45_54" in age: ages[4] = ages[4] + dict(api_response["age_bands"]).get(age) elif "55_64" in age: ages[5] = ages[5] + dict(api_response["age_bands"]).get(age) elif "65" in age: ages[6] = ages[6] + dict(api_response["age_bands"]).get(age) elif "unknown" in age: ages[7] = ages[7] + dict(api_response["age_bands"]).get(age) genders = [0, 0, 0] for gender in dict(api_response["genders"]).keys(): if "female" == gender: genders[0] = dict(api_response["genders"]).get(gender) elif "male" == gender: genders[1] = dict(api_response["genders"]).get(gender) elif "unknown" == gender: genders[2] = dict(api_response["genders"]).get(gender) except IndexError: ages = [0, 0, 0, 0, 0, 0, 0, 0] genders = [0, 0, 0] self.log.info("delphi api: ages: {}, genders: {}".format(ages, genders)) self.ts.markFinal(sum(ages) == sum(genders), "sum ages: {} and genders: {} are equal".format(sum(ages), sum(genders))) return {"ages": ages, "genders": genders} @allure.step("Track page - track performance get gender group streams tooltip") def get_gender_groups_tooltip_info(self, global_gender=False): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "track_streams_performance_gender_name")) age_groups_el = self.get_elements(*self.locator(self.track_locators, "track_streams_performance_gender_name")) percentage_arr = [] streams_arr = [] for e in age_groups_el: ActionChains(self.driver).move_to_element(e).perform() if global_gender: percentage = float(str(self.get_text("//span[contains(@id, 'gender')][contains(@id, '-value')]", "xpath")).replace("%", "")) percentage_arr.append(percentage) else: streams = int(str(self.get_text("//*[contains(@id, 'tooltip')][contains(@id, 'streams-value')]/*", "xpath")).replace(",", "")) percentage = float( str( self.get_text( "//*[contains(@id, 'tooltip')][contains(@id, 'streams-value')]/preceding-sibling::*", "xpath", ) ).replace("%", "") ) streams_arr.append(streams) percentage_arr.append(percentage) return {"percentage": percentage_arr, "streams": streams_arr} @allure.step("Track page - track performance verify streams ages and genders") def track_performance_verify_streams_age_and_gender(self, dsp, market, isrc, start_date, end_date, token): self.track_performance_verify_age_groups(dsp=dsp) self.track_performance_verify_genders(dsp=dsp) age_tooltip_info = self.get_age_groups_tooltip_info() age_streams_ui = age_tooltip_info["streams"] age_percentage_ui = age_tooltip_info["percentage"] gender_tooltip_info = self.get_gender_groups_tooltip_info() gender_streams_ui = gender_tooltip_info["streams"] gender_percentage_ui = gender_tooltip_info["percentage"] streams_api = self.get_streams_age_gender_api(dsp=dsp, market=market, isrc=isrc, start_date=start_date, end_date=end_date, token=token) self.ts.markFinal(streams_api["ages"] == age_streams_ui, "ages ui: {}, api: {}".format(age_streams_ui, streams_api["ages"])) self.ts.markFinal( streams_api["genders"] == gender_streams_ui, "genders ui: {}, api: {}".format(gender_streams_ui, streams_api["genders"]), ) for p in age_percentage_ui: p_expected = round(age_streams_ui[age_percentage_ui.index(p)] / sum(gender_streams_ui) * 100, 1) self.ts.markFinal( round(p_expected - 0.1, 1) <= p <= round(p_expected + 0.1, 1), "age percentage is actual: {}, expected: {}".format(p, p_expected), ) for p in gender_percentage_ui: p_expected = round(gender_streams_ui[gender_percentage_ui.index(p)] / sum(gender_streams_ui) * 100, 1) self.ts.markFinal( round(p_expected - 0.1, 1) <= p <= round(p_expected + 0.1, 1), "gender percentage is actual: {}, expected: {}".format(p, p_expected), ) @allure.step("Track page - verify save and skips") def verify_save_and_skips(self, isrcs, market, token): save_skips_ui = self.get_save_and_skips() start = str(self.get_calendar_start_date()) end = str(self.get_calendar_end_date()) self.scroll_to_element(*self.locator(self.album_page, "tp_header")) self.click_element(*self.locator(self.album_page, "tp_header")) response_api = self.api_client.get_spotify_demographics_delphi_isrcs(isrcs=isrcs, start_date=start, end_date=end, market=market, token=token, combine=False) streams_api = sum(s["streams"] for s in response_api["body"]) # skips_api = sum(s["skips"] for s in response_api["body"]) totals_api = sum(s["saves"]["total"] for s in response_api["body"]) save_skips_api = [ streams_api, totals_api, ] self.ts.markFinal( save_skips_ui[1:] == save_skips_api[1:], "save and skips ui and api are equal: ui: {}, api: {}".format(save_skips_ui, save_skips_api), ) self.ts.markFinal( round(save_skips_ui[0] / save_skips_api[0], 2) in (save_skips_api[0] / 100.0 for save_skips_api[0] in range(98, 102)), "streams ui and api are equal: ui: {}, api: {}".format( round(save_skips_ui[0] / save_skips_api[0], 2), list(save_skips_api[0] / 100.0 for save_skips_api[0] in range(98, 102)), ), ) @allure.step("Track page - get save and skips streams") def get_save_and_skips(self): self.scroll_to_element(*self.locator(self.album_page, "save_and_skips")) self.page_has_loaded() self.wait_for_element_visible(*self.locator(self.album_page, "save_and_skips")) self.wait_for_element_clickable(*self.locator(self.album_page, "save_and_skips")) values_el = self.get_elements(*self.locator(self.album_page, "save_and_skips")) values = [int(str(self.get_text(element=v)).replace(",", "").replace("%", "")) for v in values_el] self.log.info("save and skips values from ui: {}".format(values)) return values @allure.step("Track page - verify track name and sony label") def verify_sony_label(self, name, present=True): track_name = self.get_track_title() self.ts.markFinal(track_name == name, "track name on track page is: {}".format(track_name)) is_displayed = self.is_element_displayed(*self.locator(self.track_locators, "sony_label")) self.ts.markFinal(is_displayed == present, "sony label is present: {}".format(is_displayed)) @allure.step("Track page - verify is sony label presence") def is_sony_label_present(self, present=True): is_displayed = self.is_element_displayed(*self.locator(self.track_locators, "sony_label")) self.ts.markFinal(is_displayed == present, "sony label is present: {}".format(is_displayed)) @allure.step("Track page - Global search for") def global_search_for_and_open_tp(self, track): self.wait_for_element_visible(*self.locator(self.track_locators, "global_search")) search = self.wait_for_element_clickable(*self.locator(self.track_locators, "global_search")) ActionChains(self.driver).move_to_element(to_element=search).click().pause(2).click_and_hold(on_element=search).send_keys(track.name).pause(2).send_keys(" ").release().perform() self.page_has_loaded() loc = f"//*[contains(@class, 'search-item-title')][text()='{track.name}']/following-sibling::*/*[contains(@class, 'search-item-subtitle')][text()='{track.artist}']" self.wait_for_element_visible(locator=loc, locator_type="xpath") self.wait_for_element_clickable(locator=loc, locator_type="xpath") self.click_element(locator=loc, locator_type="xpath") self.wait_for_element_clickable(*self.locator(self.track_locators, "global_search")) self.click_element( locator="//input[@placeholder='Search for tracks, playlists, artists, albums or accounts']/following-sibling::*/*[contains(@class, 'removal')]", locator_type="xpath", ) title = self.get_track_title() self.log.info("Track name: " + track.name) self.ts.markFinal(title == track.name, "track name on track page: {}".format(title)) @allure.step("Track page - get graph total for combined") def get_streams_in_period_total_combined(self): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, "graph_total_combined")) total = int(str(self.get_text(*self.locator(self.track_locators, "graph_total_combined"))).replace(",", "")) self.log.info("streams in period total graph is: {}".format(total)) return total @allure.step("Track page - change source type") def change_source_type(self, param): type_dd = "//*[contains(@id, 'source-types-dd')]" self.scroll_to_element(locator=f"{type_dd}/span", locator_type="xpath") current_type = self.get_text(locator=f"{type_dd}/span[1]", locator_type="xpath") if current_type != param: dd_el = self.wait_for_element_visible(locator=type_dd, locator_type="xpath") self.click_on_element_js(element=dd_el) item = self.wait_for_element_visible(locator=f"{type_dd}/..//*[text()='{param}']", locator_type="xpath") self.click_on_element_js(element=item) time.sleep(2) current_type = self.get_text(locator=f"{type_dd}/span[1]", locator_type="xpath") assert_that(current_type).is_equal_to(param) @allure.step("Track page - verify chose market toggle in track details") def verify_td_markets_toggle_text(self, text): self.scroll_to_track_details() toggle_text = [] for tab in [self.MARKETS_TOP["tab"], self.MARKETS_ALL["tab"]]: toggle_loc = f"//*[contains(@id, '{tab}') and contains(@id, 'bar')]" toggle_el = self.get_element(locator=toggle_loc, locator_type="xpath") toggle = self.get_text(element=toggle_el) toggle_text.append(toggle) self.log.info(f"Toggle text: {toggle_text}") return toggle_text @allure.step("Track page - verify chose market toggle in track details") def verify_selected_td_markets_toggle(self, param): self.scroll_to_track_details() toggle = f"//*[contains(@id, '{param}') and contains(@id, 'bar')]" selected = self.is_tab_selected(locator=toggle, locator_type="xpath") self.ts.markFinal(selected, f"tab: {param} is selected: {selected}") @allure.step("Track page - verify parameter is not in url") def verify_params_not_in_url(self, param): current_url = self.get_url() for p in param: self.ts.markFinal(p not in current_url, f"param: {p} not in current url: {current_url}") @allure.step("Track page - switch market toggle in track details") def td_switch_market_toggle(self, param): self.scroll_to_track_details() toggle = f"//*[contains(@id, '{param}') and contains(@id, 'bar')]" self.page_has_loaded() self.wait_for_element_visible(toggle, "xpath") e = self.wait_for_element_clickable(toggle, "xpath") self.click_on_element_js(element=e) self.verify_selected_td_markets_toggle(param=param) @allure.step("Track page - verify parameter from url") def verify_params_in_url(self, param): for k, v in dict(param).items(): url_value = self.parameter_from_url(k) assert_that(url_value).described_as(k).is_equal_to(str(v)) @allure.step("Track page - get count of available playlists") def td_verify_playlists_presence(self, param): self.scroll_to_track_details() playlists = self.get_elements( locator=f"//*[contains(@id, 'current-table-cell-actions-')]/..//*[contains(@class, '{param}')]", locator_type="xpath", ) self.ts.markFinal(len(playlists) > 0, f"playlists from {param} are present in track details") @allure.step("Track page - verify markets toggle inactive") def td_verify_markets_toggle_inactive(self, inactive=True): self.page_has_loaded() state = self.get_element(*self.locator(self.track_locators, "markets_toggle")).get_attribute("data-state") state_expected = "enabled" if inactive: state_expected = "disabled" self.ts.markFinal(state == state_expected, f"markets toggle is: {state}") @allure.step("Track page - verify hint for playlist switcher") def td_verify_hint_playlist_switcher(self): text = "Global Market doesn't exist for Apple Music.\nPlease select between Top Markets playlists (US, CA, UK, DE, AU, FR) or all playlists." self.scroll_to_track_details() icon = self.get_element(*self.locator(self.track_locators, "td_top_markets_hint")) ActionChains(self.driver).move_to_element(to_element=icon).perform() tooltip = self.get_text(*self.locator(self.track_locators, "td_top_markets_hint_tooltip")) self.ts.markFinal(tooltip == text, f"hint is: {text}") @allure.step("Track page - verify playlist switch toggle displayed") def td_verify_markets_toggle_displayed(self, displayed): state = self.is_element_displayed(*self.locator(self.track_locators, "markets_toggle")) self.ts.markFinal(state == displayed, f"markets toggle is displayed: {state}") @allure.step("Track page - track details get bar charts playlists count") def td_bc_get_playlists_count_on_graphs(self, count): self.wait_for_element_visible(*self.locator(self.track_locators, "td_bc_graph_playlists_count")) self.wait_for_element_clickable(*self.locator(self.track_locators, "td_bc_graph_playlists_count")) count_el = self.get_elements(*self.locator(self.track_locators, "td_bc_graph_playlists_count"))[:count] counts = [int(str(self.get_text(element=c))) for c in count_el] return counts @allure.step("Track page - track details get current playlist count") def td_get_current_playlist_count(self): self.scroll_to_track_details() self.wait_track_details_table_displayed() self.page_has_loaded() time.sleep(5) self.page_has_loaded() e = self.wait_for_element_visible(*self.locator(self.track_locators, "first_playlist")) count = int(str(self.get_text(element=e)).split("(")[1].replace(")", "")) return count @allure.step("Track page - track details verify apple icon and playlists header is displayed") def td_verify_apple_playlists_icon_present(self): icon_locs = "//*[@id='track-details-current-table']//span[contains(@class, 'icon-apple')]" icons = self.get_elements(locator=icon_locs, locator_type="xpath") is_icons_displayed = set([self.is_element_displayed(element=i) for i in icons]) assert_that(is_icons_displayed).is_true() @allure.step("Track page - CPS tab - sort by column") def td_cps_tab_sort_by_column(self, column): self.scroll_to_track_details() self.click_element(locator=f"track-page-current-playlists-and-stations-table-cell-{column}") @allure.step("Track page - PP tab - sort by column") def td_pp_tab_sort_by_column(self, column): loc = f"track-page-past-playlists-and-stations-table-cell-{column}" self.scroll_to_track_details() self.click_element(loc) @allure.step("Track page - get data from table current") def td_current_get_data_all_table_ui(self): self.page_has_loaded() time.sleep(5) names = self.td_cps_get_playlist_names() positions = self.get_positions_from_table() trends = self.td_get_position_trends() added = self.td_get_added_days() track_7 = self.td_get_track_streams_7_days_values() playlist_7 = self.get_playlist_stream_days_from_table() followers = self.td_get_playlist_followers_values() return { "names": names, "positions": positions, "trends": trends, "added": added, "track_7": track_7, "playlist_7": playlist_7, "followers": followers, } @allure.step("Track page - get added days from table") def td_get_added_days(self): self.scroll_to_track_details() days_el = self.get_elements(locator="//*[contains(@id, '-cell-track-days-in-playlist-')]", locator_type="xpath") days = [] for el in days_el: if len(self.get_text(element=el)) == 0: days.append(0) else: days.append(int(self.get_text(element=el))) return days @allure.step("Track page - compare track details playlist with api") def td_compare_table_playlist_with_api(self, playlist): all_playlists = self.api_client.get_apple_playlistswithtrack(isrc=playlist.isrc)["items"] token = self.api_client.authorize() track_7_days = self.api_client.get_consumer_analytics_streams_v1( track=playlist, vendor="apple", token=token, market="global", end_date=playlist.end_date, start_date=playlist.start_date, )["items"] self.log.info(f"playlist from ui: {playlist}") for i in all_playlists: if i["id"] == playlist.playlist_id: self.log.info(f"playlist object from api: {i}") self.ts.markFinal(i["name"] == playlist.name, f'playlist name ui: {playlist.name},\n api: {i["name"]}') for c in i["countries"]: if c["countryCode"] == playlist.market: self.log.info(f"playlist with country code object: {c}") for a, u in zip( ["trackPosition", "streams7Days", "positionChange"], [playlist.position, playlist.playlist_streams, playlist.trend], ): if c[a] is not None: self.ts.markFinal(abs(c[a]) == u, f"playlist {a} ui: {u},\n api: {abs(c[a])}") for i in track_7_days: if i["containerId"] == playlist.playlist_id: self.log.info(f"info for container_id: {playlist.playlist_id}\nresponse: {i}") for m in i["markets"]: if m[0] == playlist.market: self.ts.markFinal(m[1] == playlist.track_streams, f"api: {m[1]}\nui: {playlist.track_streams}") @allure.step("Track page - track details get apple icon links") def td_get_apple_links(self): self.scroll_to_track_details() self.page_has_loaded() loc = "//*[contains(@id, '-table-cell-actions-')]/*/a" attrs = [] self.wait_for_element_visible(locator=loc, locator_type="xpath") elms = self.get_elements(locator=loc, locator_type="xpath") for e in elms: attrs.append(str(self.get_attribute_value(element=e, attribute="href")).replace(CoreConfig.ENV_BASE_URL, "")) self.log.info(f"href from apple icons in track details: {attrs}") return attrs @allure.step("Track page - track details click on playlist name") def td_click_on_playlist_name(self, position, include_all=False): self.scroll_to_track_details() locator = "//div[contains(@id, 'cell-Entity')]//../a[contains(@href, '/playlist/')]" if include_all: locator = f"(//div[contains(@id, 'cell-Entity-')]//../span)[{position + 1}]" self.wait_for_element_clickable(locator, "xpath") if include_all: e = self.get_element(locator, "xpath") else: e = self.get_elements(locator, "xpath")[position - 1] name = self.get_text(element=e) self.click_element(element=e) return name @allure.step("Track page - verify top header chosen market") def verify_top_header_market(self, market): current = self.get_selected_market_name(market) self.ts.markFinal(current, f"current market: {current}\nexpected: {market}") @allure.step("Track page - get positions in track details") def td_get_positions_in_td(self, include_sum=False): self.scroll_to_track_details() el = self.get_elements(locator="//*[contains(@id, '-table-cell-position-')]", locator_type="xpath") positions = [self.get_text(element=e).lower() for e in el] if not include_sum: positions = [int(p) for p in positions if self.sum_value != p.lower()] self.log.info(f"Positions: {positions}") return positions @allure.step("Track page - click on apple icon by index") def td_click_on_apple_icon(self, position, only_clickable=False): self.scroll_to_track_details() selector = f"(//*[contains(@id, '-cell-actions-')]//../*[contains(@class, 'icon-apple')])[{position + 1}]" if only_clickable: selector = f"(//*[contains(@id, '-cell-actions-')]//../a/*[contains(@class, 'icon-apple')])[{position + 1}]" self.scroll_to_element(locator=selector, locator_type="xpath") self.wait_for_element_visible(locator=selector, locator_type="xpath") icon = self.wait_for_element_clickable(locator=selector, locator_type="xpath") self.click_on_element_js(element=icon) @allure.step("Track page - td verify market droplist") def td_verify_market_droplist(self, playlist_name, apple_id, position): market_flags_loc = "//*[contains(@id, '-item-')][contains(@id, '-flag')]/img" market_value_loc = "//*[contains(@id, '-item-')][contains(@id, '-label')]" self.scroll_to_track_details() self.td_search_filter(playlist_name) positions = self.td_get_positions_in_td(include_sum=True) index_sum = positions.index(position) playlist_id = self.td_get_playlist_ids()[0] markets_db = self.sql_client.tp_td_get_markets(playlist_id=playlist_id, apple_id=apple_id) e = self.get_elements(locator="//*[contains(@id, '-cell-country-code-')]", locator_type="xpath")[index_sum] self.click_element(element=e) markets = self.get_elements(locator=market_flags_loc, locator_type="xpath") market_values = self.get_elements(locator=market_value_loc, locator_type="xpath") market_values_ui_all = [self.get_text(element=v) for v in market_values] markets_ui_all = [m.get_attribute("src").split(".")[-2].split("/")[-1] for m in markets] self.ts.markFinal(markets_db == sorted(markets_ui_all), f"db markets: {markets_db} and \nui: {markets_ui_all} match") market_values_ui_other = [] for t in market_values_ui_all: if t not in self.TOP_6_COUNTRIES_VALUES: market_values_ui_other.append(t) self.ts.markFinal(market_values_ui_other == sorted(market_values_ui_other), f"market on ui sorted alphabetically: {market_values_ui_other}") for t in self.TOP_6_COUNTRIES: if t in markets_ui_all: markets_ui_all.remove(t) filter_input = self.get_element(*self.locator(self.track_locators, "td_market_filter")) self.ts.markFinal(self.is_element_displayed(element=filter_input), "STEP 9: filter input is displayed") focused_el = self.driver.switch_to.active_element self.ts.markFinal(focused_el != filter_input, "filter input is not in focus by default") self.send_text(data=markets_ui_all[0], element=filter_input) markets = self.get_elements(locator=market_flags_loc, locator_type="xpath") markets_ui_f = [m.get_attribute("src").split(".")[-2].split("/")[-1] for m in markets] self.ts.markFinal( all(markets_ui_all[0] in m for m in markets_ui_f), f"STEP 10: filter applied fo flags: {markets_ui_all[0]}: {markets_ui_f}", ) close_icon = self.wait_for_element_clickable(*self.locator(self.track_locators, "td_market_filter_close")) self.click_element(element=close_icon) self.clear_text(element=filter_input) self.send_text(market_values_ui_all[0], element=filter_input) market_values = self.get_elements(locator=market_value_loc, locator_type="xpath") market_values_ui = [self.get_text(element=v) for v in market_values] self.ts.markFinal( all(market_values_ui_all[0] in m for m in market_values_ui), f"filter applied fo values: {market_values_ui[0]}: {market_values_ui}", ) close_icon = self.wait_for_element_clickable(*self.locator(self.track_locators, "td_market_filter_close")) self.click_element(element=close_icon) self.clear_text(element=filter_input) self.send_text("%", element=filter_input) t1 = self.is_element_displayed(locator="//*[.='No markets found.']", locator_type="xpath") t2 = self.is_element_displayed(locator="//*[.='Try changing filtering parameters.']", locator_type="xpath") self.ts.markFinal(t1 == t2 == True, "no markets found") close_icon = self.wait_for_element_clickable(*self.locator(self.track_locators, "td_market_filter_close")) self.click_element(element=close_icon) self.clear_text(element=filter_input) market_values = self.get_elements(locator=market_value_loc, locator_type="xpath") market_values_ui_after = [self.get_text(element=v) for v in market_values] self.ts.markFinal(market_values_ui_all == market_values_ui_after, "STEP 11: after clear filtering all markets displayed") self.click_element(element=market_values[0]) self.ts.markFinal(self.is_element_displayed(element=market_values[0]), "STEP 12: market values are not clickable") self.td_switch_to_playlist(self.TD_CURRENT_PLAYLIST_TAB) for i in list(range(1, 3)): self.click_element(element=e) if i in [1, 3]: self.ts.markFinal( self.is_element_displayed(*self.locator(self.track_locators, "td_market_filter")), "td market dropdown opened", ) self.ts.markFinal( not self.is_element_displayed(*self.locator(self.track_locators, "td_market_filter")), "STEP 13: td market dropdown closed", ) hover_market = self.get_element(locator="(//*[contains(@id, '-cell-country-code-')]/..//img)[1]", locator_type="xpath") ActionChains(self.driver).move_to_element(to_element=hover_market).perform() tooltip_locator = f"//*[text()='{market_values_ui_all[0]}, {market_values_ui_all[1]}, and {len(market_values_ui_all) - 2} more']" hint = self.is_element_displayed(locator=tooltip_locator, locator_type="xpath") self.ts.markFinal(hint, f"STEP 14: hint is displayed: {tooltip_locator}") count = int(self.get_text(element=e).replace("+", "")) self.ts.markFinal( count == len(market_values_ui_all) - 2, f"STEP 15: count is {count}\n expected: {len(market_values_ui_all) - 2}", ) @allure.step("Track page - td get all names") def td_get_entity_column_values(self): loc_all = "//*[contains(@id, 'cell-Entity-')]" link_locs = f"{loc_all}//a" self.scroll_to_track_details() time.sleep(2) names = [self.get_text(element=n) for n in self.get_elements(loc_all, "xpath")] links = [] if self.td_is_current_playlist_tab_active() and self.td_get_current_entities() != "Stations": links = [self.get_attribute_value(element=n, attribute="href") for n in self.get_elements(link_locs, "xpath")] return {"names": names, "links": links} @allure.step("Track page - td verify no popup link for SUM row") def verify_no_popup_icon_for_sum_row(self): self.scroll_to_track_details() apple_links = self.get_elements(*self.locator(self.track_locators, "td_apple_links")) positions_with_links = self.td_get_positions_in_td(include_sum=False) self.ts.markFinal(len(apple_links) == len(positions_with_links), "apple links displayed for not positions rows") @allure.step("Track page - td open apple popup") def td_open_apple_popup(self, position=1): self.scroll_to_track_details() self.page_has_loaded() self.wait_for_element_visible(*self.locator(self.track_locators, "td_apple_links")) self.wait_for_element_clickable(*self.locator(self.track_locators, "td_apple_links")) apple_links = self.get_elements(*self.locator(self.track_locators, "td_apple_links")) self.click_element(element=apple_links[position - 1]) self.page_has_loaded() @allure.step("Track page - click apple icon for position") def click_apple_icon_verify_metadata(self, metadata, position=0): self.scroll_to_track_details() self.td_click_on_apple_icon(position, only_clickable=True) self.page_has_loaded() time.sleep(1) self.switch_to_browser_tab(2) tracks = self.apple_charts.get_track_names() tracks = [t[:5] for t in tracks] self.ts.markFinal(metadata["track"][:5] in tracks, f"track {metadata['track']} in {tracks} match") self.close_current_tab() self.switch_to_browser_tab(1) @allure.step("switch to browser tab") def switch_to_browser_tab(self, tab): self.driver.switch_to.window(self.driver.window_handles[tab - 1]) @allure.step("close current tab") def close_current_tab(self): self.driver.close() @allure.step("Track page - get streams count for date and market") def get_api_streams_count(self, market, start_date, end_date, id, vendor="spotify"): isrc = self.api_client.get_isrc_by_spotify_id(market=market, id=id)["external_ids"]["isrc"] streams_tp_api_resp = self.api_client.get_track_per_country(isrc=isrc, start_date=start_date, end_date=end_date, vendor=vendor) streams_tp_api = 0 for r in streams_tp_api_resp: if r["countryCode"] == market: streams_tp_api = r["data"][0]["streams"] return streams_tp_api @allure.step("Track page - verify source type droplist") def verify_source_type_droplist_and_footnote(self, tp=True, all=True): default_source = "By Source" spotify_apple_sources = ["All Streams", default_source, self.dd_lean_back_forward] amazon_only_sources = spotify_apple_sources + ["By Voice", "By Tier"] footnotes = { AppConfig.get("dsp")["spotify"]: "* Saves, gender, and age group data are only available from 09/04/17 onwards. Gender and age group data are available for all sources.", AppConfig.get("dsp")["apple"]: "* Gender and age group data are only available from 08/02/17 onwards.", AppConfig.get("dsp")["amazon"]: "* Amazon Music's demographics data are unavailable.", } dsps = [AppConfig.get("dsp")["spotify"], AppConfig.get("dsp")["apple"]] if tp: dsps = dsps + [AppConfig.get("dsp")["amazon"]] if all: for i in dsps: self.select_dsp(i) self.page_has_loaded() time.sleep(2) default_source_ui = self.get_source_type() self.ts.markFinal(default_source == default_source_ui, f"ui: {default_source_ui}\nexpected: {default_source}") all_sources_el = self.get_elements(*self.locator(self.track_locators, "source_types_dd_all")) all_sources = [self.get_text(element=s) for s in all_sources_el] if i == AppConfig.get("dsp")["amazon"]: self.ts.markFinal(all_sources == amazon_only_sources, f"sources are: {all_sources}") else: assert_that(all_sources).is_equal_to(spotify_apple_sources) email = self.wait_for_element_visible(locator="//*[.='** For questions, email dataanalytics@sonymusic.com.']", locator_type="xpath") email = self.is_element_displayed(element=email) dsp_footnote = self.is_element_displayed(locator=f'//*[.="{footnotes[i]}"]', locator_type="xpath") self.ts.markFinal(email, "email footnote is displayed") self.ts.markFinal(dsp_footnote, f"dsp footnote for: {i} is displayed") else: dsp = self.get_current_dsp() email = self.is_element_displayed(locator="//*[.='** For questions, email dataanalytics@sonymusic.com.']", locator_type="xpath") dsp_footnote = self.is_element_displayed(locator=f'//*[.="{footnotes[dsp]}"]', locator_type="xpath") self.ts.markFinal(email, "email footnote is displayed") self.ts.markFinal(dsp_footnote, f"dsp footnote for: {i} is displayed") @allure.step("Track page - graph get chosen source type") def get_source_type(self): self.wait_for_element_clickable(*self.locator(self.track_locators, "source_type_dd")) type_el = self.wait_for_element_visible(*self.locator(self.track_locators, "source_type_dd")) type = self.get_text(element=type_el) return type @allure.step("Track page - verify source dd present") def verify_source_list_present(self, present=True): source_present = len(self.get_elements(*self.locator(self.track_locators, "streams_and_graphs_sources_dd"))) > 0 self.ts.markFinal(source_present == present, f"source list present: {source_present}") @allure.step("Track page - graph get lean back forward totals") def graph_amazon_get_totals(self, totals="lb_lf"): self.wait_for_element_visible(*self.locator(self.track_locators, f"{totals}_totals")) self.scroll_to_element(*self.locator(self.track_locators, f"{totals}_totals")) self.wait_for_element_visible(*self.locator(self.track_locators, f"{totals}_totals")) totals = self.get_elements(*self.locator(self.track_locators, f"{totals}_totals")) self.ts.markFinal(len(totals) == 6 or 8, f"count of totals: {len(totals)}") totals = [self.get_text(element=t) for t in totals] self.log.info(f"totals: {totals}") return totals @allure.step("Track page - graph verify graph view droplist") def graph_verify_graph_view_droplist(self, country_tab=False): self.scroll_to_element(*self.locator(self.track_locators, "graph_type_dd_all")) self.wait_for_element_visible(*self.locator(self.track_locators, "graph_type_dd_all")) types = self.get_elements(*self.locator(self.track_locators, "graph_type_dd_all")) types = [self.get_text(element=t) for t in types] if country_tab: list_items = ["Line Graph", "Bar Chart"] else: list_items = ["Line Graph", "Area Graph", "Area Graph, %"] self.ts.markFinal(types == list_items, f"graph view types are: {types}") @allure.step("Track page - graph verify chosen graph view") def verify_graph_view(self, view): selector = f"//div[contains(@id, '-{view}-')][contains(@id, '-chart')]/*/*[contains(@id, 'highcharts')]" self.wait_for_element_visible(locator=selector, locator_type="xpath") v = self.is_element_displayed(locator=selector, locator_type="xpath") self.ts.markFinal(v, f"view: {view} is displayed") @allure.step("Track page - graph verify by engagement legend") def graph_verify_legend(self, view=graph_by_engagement): core_selector = "-total" if view == AppConfig.get("dsp")["by_dsp"]: core_selector = "-combined" self.wait_for_element_visible(locator=f"//*[contains(@id, '{core_selector}')]/..//*[contains(@tag, 'Label')]", locator_type="xpath") headers = self.get_elements(locator=f"//*[contains(@id, '{core_selector}')]/..//*[contains(@tag, 'Label')]", locator_type="xpath") total_headers = self.get_elements(locator=f"//*[contains(@id, '{core_selector}')]/..//*[text()='Total']", locator_type="xpath") daily_avgs = self.get_elements(locator=f"//*[contains(@id, '{core_selector}')]/..//*[contains(text(), 'Daily Avg')]", locator_type="xpath") headers = [self.get_text(element=h) for h in headers] daily_avgs = [self.get_text(element=d) for d in daily_avgs] dsp = self.get_current_dsp().upper() total_len = 3 if view == self.graph_by_engagement: headers_exp = [f"{dsp} STREAMS IN PERIOD", "LEAN FORWARD", "LEAN BACK"] daily_avgs_exp = ["Daily Avg", "Daily Avg", "Daily Avg"] elif view == self.graph_by_voice: headers_exp = ["AMAZON STREAMS IN PERIOD", "VOICE CONTROLLED", "NON-VOICE CONTROLLED", "DEVICE TYPE"] daily_avgs_exp = ["Daily Avg", "Daily Avg", "Daily Avg"] elif view == self.graph_by_tier: headers_exp = ["AMAZON STREAMS IN PERIOD", "AD-SUPPORTED", "PRIME", "UNLIMITED"] daily_avgs_exp = ["Daily Avg", "Daily Avg", "Daily Avg", "Daily Avg"] total_len = 4 elif view == AppConfig.get("dsp")["by_dsp"]: headers_exp = ["ALL STREAMS IN PERIOD", "SPOTIFY STREAMS", "APPLE MUSIC STREAMS", "AMAZON STREAMS"] daily_avgs_exp = ["Daily Avg", "Daily Avg", "Daily Avg", "Daily Avg"] total_len = 4 assert_that(headers).is_equal_to(headers_exp) assert_that(len(total_headers)).is_equal_to(total_len) assert_that(daily_avgs).is_equal_to(daily_avgs_exp) @allure.step("Track page - graph get tooltips") def graph_get_tooltips(self): param = self.graph_get_count_days_from_calendar() selector = "graph_plot" self.is_graph_period_displayed() e = self.wait_for_element_visible(*self.locator(self.track_locators, selector)) height = int(e.size["height"]) width = int(e.size["width"]) + 1 self.log.info("height: {height}, width: {width}".format(height=height, width=width)) step = int(width / param) self.log.info("step: {step}".format(step=step)) tooltips = [] for t in range(0, width, step): if len(tooltips) < 1: # self.wait_for_element_visible(*self.locator(self.track_locators, selector), timeout=1) e = self.wait_for_element_clickable(*self.locator(self.track_locators, selector)) ActionChains(self.driver).move_to_element_with_offset(to_element=e, xoffset=t, yoffset=height).perform() t_el = self.wait_for_element_visible(*self.locator(self.track_locators, "chart_tooltip")) if t_el is not None: t_el = self.get_text(element=t_el) text = str(t_el) if text not in [None, "None", ["None"], [None], ""]: if text.strip() not in tooltips: tooltips.append(text.strip()) self.log.info("tooltip text: {}".format(text)) self.log.info("track performance tooltip content: {}".format(tooltips)) return sorted(set(tooltips)) @allure.step("Track page - graph get count days calendar") def graph_get_count_days_from_calendar(self): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "date_field_from")) start_t = self.get_text(element=calendar).split("–")[0] end_t = self.get_text(element=calendar).split("–")[1] start = datetime.datetime.strptime(start_t, self.get_date_format_from_locale()).date() end = datetime.datetime.strptime(end_t, self.get_date_format_from_locale()).date() days_count_exp = (end - start).days + 1 return days_count_exp @allure.step("Track page - verify export") def export_to_file_amazon(self, market_def="", ap=False, source=graph_by_engagement): track_name = self.get_track_title(ap=ap) market = str(self.graph_get_selected_market().replace("Market", "market")) if len(market_def) > 0 and isinstance(market_def, str): market = market_def.upper() elif "markets" not in market: market = self.parameter_from_url(self.str_gr_country).upper() dsp = self.get_current_dsp() self.click_export() self.click_export_as_csv() file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - {market} - {dsp}.csv""" self.log.info(f"file path: {file_path}") if source == self.graph_by_voice: columns_adds = ["Market", "Total Streams", "Voice Controlled Streams", "Non-Voice Controlled Streams"] elif source == self.graph_by_tier: columns_adds = ["Market", "Total Streams", "Add-Supported Streams", "Prime Streams", "Unlimited Streams"] elif source == AppConfig.get("dsp")["by_dsp"]: columns_adds = ["Country", "All Streams", "Spotify Streams", "Apple Streams", "Amazon Streams"] else: columns_adds = ["Market", "Total Streams", "Lean Forward Streams", "Lean Back Streams"] columns = ["Date"] + columns_adds data = self.read_from_csv(file_path) file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") dates_file = [datetime.datetime.strptime(d, self.get_date_format_from_locale()).date() for d in file["Date"]] start_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[0] end_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[1] start = datetime.datetime.strptime(start_t, self.get_date_format_from_locale()).date() end = datetime.datetime.strptime(end_t, self.get_date_format_from_locale()).date() date_range = [] span = end - start for i in range(span.days + 1): d = start + datetime.timedelta(days=i) date_range.append(d) if (market != "All markets") and ("markets" in market): if market_def != "" and len(market_def) > 1: market_def = [m.upper() for m in market_def] market = ",".join(market_def) else: market = str(self.parameter_from_url(self.str_gr_country)).split("%2C") market = [str(m).upper() for m in market] market = str(",".join(market)) market = market.replace(" ", "") if source != AppConfig.get("dsp")["by_dsp"]: file_markets = list(set(file["Market"])) file_markets = [f.replace(" ", "") for f in file_markets] total_streams_ui = int(self.graph_amazon_get_totals()[0].replace(",", "")) lean_forward_ui = int(self.graph_amazon_get_totals()[2].split("\n")[0].replace(",", "")) lean_back_ui = int(self.graph_amazon_get_totals()[4].split("\n")[0].replace(",", "")) self.ts.markFinal(dates_file == date_range, f"Dates: {dates_file} \nand {date_range} match") if source != AppConfig.get("dsp")["by_dsp"]: assert_that(set(file_markets[0])).is_equal_to(set(market)) self.ts.markFinal( sum(file[columns[2]]) == total_streams_ui, f"ui: {total_streams_ui}\n and file: {sum(file[columns[2]])} match", ) self.ts.markFinal(sum(file[columns[3]]) == lean_forward_ui, f"ui: {lean_forward_ui}\n and file: {sum(file[columns[3]])} match") self.ts.markFinal(sum(file[columns[4]]) == lean_back_ui, f"ui: {lean_back_ui}\n and file: {sum(file[columns[4]])} match") @allure.step("Track page - verify export Countries tab") def export_to_file_countries_tab(self): track_name = self.get_track_title() dsp = self.get_current_dsp() streams_ui = self.get_track_performance_countries_tooltips(1)["streams_full"][0] self.click_export() self.click_export_as_csv() file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - Countries - {dsp}.csv""" self.log.info(f"file path: {file_path}") columns = [ "Date", "Country", "All Streams", "Playlist Streams", "Station Streams", "User Playlist Streams", "Search Streams", "Album Streams", "Artist Streams", "Songs Streams", ] data = self.read_from_csv(file_path) file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") dates_file = [datetime.datetime.strptime(d, self.get_date_format_from_locale()).date() for d in file["Date"]] start_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[0] end_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[1] start = datetime.datetime.strptime(start_t, self.get_date_format_from_locale()).date() end = datetime.datetime.strptime(end_t, self.get_date_format_from_locale()).date() date_range = [] span = end - start for i in range(span.days + 1): d = start + datetime.timedelta(days=i) date_range.append(d) date_range = set(date_range) dates_file = set(dates_file) market_ui = self.graph_get_xaxis()[0] streams_file = 0 self.log.info(f"market from ui graph: {market_ui}") for m, v in zip(file[columns[1]], file[columns[2]]): if m == market_ui: streams_file = streams_file + v self.log.info(f"value for {market_ui} from file all streams: {streams_file}") self.ts.markFinal(dates_file == date_range, f"Dates: {dates_file} \nand {date_range} match") self.ts.markFinal(streams_ui == streams_file, f"{streams_ui} and {streams_file} match") @allure.step("Stream and source - choose few Countries") def market_dd_choose_few_countries(self, param, tab="streams_and_graphs", uncheck_selected=True): if tab == "tp_sbm": self.get_streams_in_period_all_by_markets() self.markets_dd_click(tab=tab) country_dd = "//*[contains(text(), '{market}')]" country_choose = f"{country_dd}/preceding-sibling::input" if uncheck_selected: item = self.get_element(locator=country_choose.format(market=self.all_markets), locator_type="xpath") self.click_on_element_js(element=item) if self.is_checked(locator=country_choose.format(market=self.all_markets), locator_type="xpath"): self.click_on_element_js(element=item) for c in param: country = country_choose.format(market=c) c_dd = self.get_element(locator=country, locator_type="xpath") self.click_on_element_js(element=c_dd) if tab == "td_tiktok": self.td_dd_click_apply_country_tiktok() else: self.dd_click_apply() self.is_graph_period_displayed() self.log.info(f"{tab} - choose countries: {param}") @allure.step("Stream and source - click on countries dd") def markets_dd_click(self, tab="streams_and_graphs"): self.is_graph_period_displayed() self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) if "td_" in tab: self.scroll_to_track_details() self.wait_for_element_visible(*self.locator(self.track_locators, f"{tab}_country")) dd = self.wait_for_element_clickable(*self.locator(self.track_locators, f"{tab}_country")) self.click_on_element_js(element=dd) @allure.step("Graph - select predefined period") def select_predefined_period(self, period, hover=False): dp = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=dp) p = self.wait_for_element_visible(locator=f"//*[contains(@id, '-day-picker-{period}')]", locator_type="xpath") if hover: self.hover_on_element(element=p) btn_color = p.value_of_css_property("background-color") assert_that(btn_color).is_equal_to("rgba(218, 218, 230, 1)") self.click_on_element_js(element=p) self.page_has_loaded() @allure.step("Graph legend - get device type tooltips") def get_device_type_tooltips(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "device_type_percentage")) labels = self.get_elements(*self.locator(self.track_locators, "device_type_percentage")) tooltip_streams = [] tooltip_avg = [] tooltip_percentage = [] for l in labels: ActionChains(self.driver).move_to_element(l).click().perform() tooltip_s = int(self.get_text(locator="//*[contains(@id, 'streams-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_a = int(self.get_text(locator="//*[contains(@id, 'avg-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_p = float( self.get_text( locator="//*[contains(@id, '-value') and contains(@id, 'device-type-tooltip') and contains(., '%')]", locator_type="xpath", ).replace("%", "") ) tooltip_streams.append(tooltip_s) tooltip_avg.append(tooltip_a) tooltip_percentage.append(tooltip_p) self.log.info(f"streams dt: {tooltip_streams}") self.log.info(f"avg dt: {tooltip_avg}") self.log.info(f"percentage dt: {tooltip_percentage}") return {"streams": tooltip_streams, "avg": tooltip_avg, "percentage": tooltip_percentage} @allure.step("Track page - get graph total for combined") def graph_get_legend_by_dsp(self): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, "graph_legend_all")) total_el = self.get_elements(*self.locator(self.track_locators, "graph_legend_all")) totals = [self.get_text(element=e) for e in total_el] self.log.info("streams in period total graph is: {}".format(totals)) return totals @allure.step("Track page - export file and extract columns") def export_and_get_csv(self, columns, market_api=""): track_name = self.get_track_title() if self.is_tab_selected_no_assert(*self.locator(self.track_locators, "streams_and_sources_tab")): dsp = self.get_current_dsp() market = str(self.graph_get_selected_market().replace("Market", "market")) if "markets" not in market: if self.str_gr_region in self.get_url(): region = self.parameter_from_url(self.str_gr_region) if region == "reu": market = f"{len(AppConfig.get('regions')['europe']['api'])} markets" elif self.str_gr_country in self.get_url(): market = self.parameter_from_url(self.str_gr_country).upper() else: market = market_api.upper() elif self.is_tab_selected_no_assert(*self.locator(self.track_locators, "countries_tab")): market = "Countries" dsp = self.get_current_dsp() elif self.is_tab_selected_no_assert(*self.locator(self.track_locators, "track-performance-youtube")): market = market_api.upper() dsp = "YouTube" elif self.is_tab_selected_no_assert(*self.locator(self.track_locators, "performance_tiktok_tab")): market = market_api.upper() dsp = "TikTok" self.click_export() self.click_export_as_csv() file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - {market} - {dsp}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") return file @allure.step("Track page - get operating system tooltips") def graph_get_os_tooltips(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "os_percentage")) labels = self.get_elements(*self.locator(self.track_locators, "os_percentage")) tooltip_streams = [] tooltip_avg = [] tooltip_percentage = [] for l in labels: ActionChains(self.driver).move_to_element(l).click().perform() tooltip_s = int(self.get_text(locator="//*[contains(@id, 'streams-value')][contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_a = int(self.get_text(locator="//*[contains(@id, 'avg-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_p = float( self.get_text( locator="//*[contains(@id, '-value') and contains(@id, 'tooltip') and contains(., '%') and contains(@id, 'legend')]", locator_type="xpath", ).replace("%", "") ) tooltip_streams.append(tooltip_s) tooltip_avg.append(tooltip_a) tooltip_percentage.append(tooltip_p) self.log.info(f"streams os: {tooltip_streams}") self.log.info(f"avg os: {tooltip_avg}") self.log.info(f"percentage os: {tooltip_percentage}") return {"streams": tooltip_streams, "avg": tooltip_avg, "percentage": tooltip_percentage} @allure.step("Stream and source - choose region") def stream_and_source_choose_region(self, param, dd="streams_and_graphs"): self.wait_for_element_visible(*self.locator(self.track_locators, f"{dd}_country")) time.sleep(3) graph_country_dd = self.wait_for_element_clickable(*self.locator(self.track_locators, f"{dd}_country")) self.click_on_element_js(element=graph_country_dd) item = self.wait_for_element_visible(locator=f"//*[contains(@class, 'region')][text()='{param}']", locator_type="xpath") self.click_on_element_js(element=item) self.wait_for_element_clickable(*self.locator(self.track_locators, f"{dd}_country")) self.is_graph_period_displayed() self.log.info(f"Stream and source - choose region: {param}") @allure.step("TP - Graph get tooltips totals values") def graph_get_tooltip_totals(self, count=1): e = self.wait_for_element_visible(*self.locator(self.track_locators, "graph_plot")) height = int(e.size["height"]) width = int(e.size["width"]) + 1 self.log.info("height: {height}, width: {width}".format(height=height, width=width)) param = self.graph_get_count_days_from_calendar() * count step = int(width / param) self.log.info("step: {step}".format(step=step)) tooltips = [] for t in range(0, width, step): e = self.get_element(*self.locator(self.track_locators, "graph_plot")) ActionChains(self.driver).move_to_element_with_offset(to_element=e, xoffset=t, yoffset=height).perform() t_el = self.get_elements(*self.locator(self.track_locators, "tooltips_totals")) date_el = self.get_text(locator="(//*[contains(@id, 'chart-tooltip')]/div/div[1])[1]", locator_type="xpath") texts = [self.get_text(element=t) for t in t_el] if texts and date_el not in [None, "None", ["None"], [None], ""]: values = [] percentage = [] tooltip_values = {} date_el = date_el.split(", ")[1] date = datetime.datetime.strptime(date_el, self.get_date_format_from_locale()).date() for t in texts: if " " in t: values.append(int(t.split(" ")[0].replace(",", ""))) percentage.append(int(t.split(" ")[1].split("%")[0].replace("(", ""))) else: values.append(int(t.replace(",", ""))) tooltip_values = {"values": values, "percentage": percentage, "date": date} if tooltip_values not in tooltips: tooltips.append(tooltip_values) self.log.info("track performance tooltip content: {}".format(tooltips)) return tooltips @allure.step("Deselect country in Regions dd") def stream_and_source_deselect_countries(self, market_name, dd="streams_and_graphs", apply=True): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, f"{dd}_country")) self.wait_for_element_clickable(*self.locator(self.track_locators, f"{dd}_country")) time.sleep(3) self.click_element(*self.locator(self.track_locators, f"{dd}_country")) for market in market_name: country_dd = "//*[contains(text(), '{market}')]" country_checkbox = f"{country_dd}/preceding-sibling::input" if self.is_checked(locator=country_checkbox.format(market=market), locator_type="xpath"): self.click_on_element_js(self.get_element(country_checkbox.format(market=market), "xpath")) self.log.info(f"Graph market dd - deselect country: {market}") if apply: if dd == "td_tiktok": self.click_element(locator="(//button[.='Apply'])[2]", locator_type="xpath") else: self.click_element(locator=self.apply_button_loc, locator_type="xpath") self.is_graph_period_displayed() @allure.step("Add countries to already selected in Regions dd") def stream_and_source_add_countries_to_selected(self, market_name): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, "streams_and_graphs_country")) self.wait_for_element_clickable(*self.locator(self.track_locators, "streams_and_graphs_country")) self.click_element(*self.locator(self.track_locators, "streams_and_graphs_country")) for market in market_name: country_dd = "//*[contains(text(), '{market}')]" country_checkbox = f"{country_dd}/preceding-sibling::input" if not self.is_checked(locator=country_checkbox.format(market=market), locator_type="xpath"): self.click_on_element_js(self.get_element(country_checkbox.format(market=market), "xpath")) self.log.info(f"Stream and source - added country: {market}") self.click_element(locator="//button/..//*[text()='Apply']", locator_type="xpath") self.is_graph_period_displayed() @allure.step("Track page - graph is present") def streams_in_period_graph_is_present(self): e = self.is_element_displayed(*self.locator(self.track_locators, "graph_period_string")) self.log.info("Is Graph period displayed: {}".format(e)) return e @allure.step("Track page - no data in track performance") def get_streams_in_period_no_data(self): self.wait_for_element_visible(*self.locator(self.track_locators, "track_performance_no_data")) no_data = self.get_text(*self.locator(self.track_locators, "track_performance_no_data")) self.log.info("No data message is: " + no_data) return no_data @allure.step("Track page - is no data on graph") def graph_is_no_data(self): no_data = self.wait_for_element_visible(*self.locator(self.track_locators, "track_performance_no_data"), timeout=5) if no_data is not None: displayed = True else: displayed = False return displayed @allure.step("TP - get header totals") def get_header_totals(self): self.wait_for_element_visible(*self.locator(self.track_locators, "header_totals")) totals_el = self.get_elements(*self.locator(self.track_locators, "header_totals")) totals = [self.get_text(element=t) for t in totals_el] return totals @allure.step("TP - get graph legend column text for section") def graph_get_legend_columns(self, selector): sel = f"//*[contains(@id, '{selector}')]/div/div/div/div/div/div/span[string-length(text()) > 0]" self.wait_for_element_visible(locator=sel, locator_type="xpath") columns = self.get_elements(locator=sel, locator_type="xpath") text = [self.get_text(element=c) for c in columns] self.log.info(f"{selector}: {text}") return text @allure.step("TP - graph verify By Tier dd") def verify_tier_dd_current(self, option=all_tiers): tier_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "tier_dd")) ui_text = self.get_text(element=tier_dd) assert_that(option).is_equal_to(ui_text) @allure.step("TP - graph verify By Tier dd options") def verify_tiers_dd_options(self): tier_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "tier_dd")) self.click_on_element_js(element=tier_dd) options_list = [] for option in self.tier_options: el = self.get_element(locator=f"//input[@id='{option} ']/following-sibling::span", locator_type="xpath") assert_that(self.is_element_displayed(element=el)).is_true() option_text = self.get_text(element=el) options_list.append(option_text) assert_that(self.tier_options).is_equal_to(options_list) # apply = self.wait_for_element_clickable(locator="(//button[.='Apply'])[1]", locator_type="xpath") # self.click_on_element_js(element=apply) # self.dd_click_apply() self.click_on_element_js(element=tier_dd) @allure.step("TP - graph choose tier options") def choose_tier_options(self, param, apply=True): # self.wait_for_element_visible(*self.locator(self.track_locators, "tp_header")) # self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) tier_dd = self.get_element(*self.locator(self.track_locators, "tier_dd")) self.click_on_element_js(element=tier_dd) tier_option = "//*[contains(text(), '{}')]" tier_choose = f"{tier_option}/preceding-sibling::input" self.tier_dd_uncheck_all() for c in param: tier_option = tier_choose.format(c) item = self.get_element(locator=tier_option, locator_type="xpath") self.click_on_element_js(element=item) if apply: self.dd_click_apply() self.is_graph_period_displayed() time.sleep(4) self.log.info(f"graph choose tier options: {param}") @allure.step("TP - graph verify tier dd option sorting") def tier_dd_verify_option_sorting(self, o): options_loc = "//*[contains(@id, 'tier-dd')]/parent::*/following-sibling::*//../input/following-sibling::span" tier_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "tier_dd")) self.click_on_element_js(element=tier_dd) options_local = self.tier_options.copy() options_local.remove(self.tier_options[0]) for i in o: if i in options_local: options_local.remove(i) options_local = sorted(options_local) options_local = [self.tier_options[0]] + o + options_local list_el = self.get_elements(locator=options_loc, locator_type="xpath") tiers_list = [self.get_text(element=l).strip() for l in list_el] assert_that(tiers_list).is_equal_to(options_local) self.click_on_element_js(element=tier_dd) @allure.step("TP - graph verify tier legend options") def graph_verify_legend_by_tier(self, param): self.wait_for_element_visible(locator="//*[contains(@id, '-total')]/..//*[contains(@tag, 'Label')]", locator_type="xpath") headers = self.get_elements(locator="//*[contains(@id, '-total')]/..//*[contains(@tag, 'Label')]", locator_type="xpath") total_headers = self.get_elements(locator="//*[contains(@id, '-total')]/..//*[text()='Total']", locator_type="xpath") daily_avgs = self.get_elements(locator="//*[contains(@id, '-total')]/..//*[contains(text(), 'Daily Avg')]", locator_type="xpath") headers = [self.get_text(element=h) for h in headers] daily_avgs = [self.get_text(element=d) for d in daily_avgs] param = [p.upper() for p in param] headers_exp = ["AMAZON STREAMS IN PERIOD"] + param daily_avgs_exp = ["Daily Avg"] * len(daily_avgs) total_len = len(daily_avgs) assert_that(headers).is_equal_to(headers_exp) assert_that(len(total_headers)).is_equal_to(total_len) assert_that(daily_avgs).is_equal_to(daily_avgs_exp) @allure.step("TP - click on title") def click_on_title(self): title = self.wait_for_element_visible(*self.locator(self.track_locators, "tp_header")) self.click_on_element_js(element=title) @allure.step("TP - By Tier uncheck all") def tier_dd_uncheck_all(self): tier_option = "//*[contains(text(), '{}')]" tier_choose = f"{tier_option}/preceding-sibling::input" apply_btn = "(//button[.='Apply'])[1]" time.sleep(2) all_item = self.get_element(locator=tier_choose.format(self.all_tiers), locator_type="xpath") self.click_on_element_js(element=all_item) if self.is_checked(locator=tier_choose.format(self.all_tiers), locator_type="xpath"): self.click_on_element_js(element=all_item) is_apply_enabled = self.is_enabled(locator=apply_btn, locator_type="xpath") assert_that(is_apply_enabled).is_false() @allure.step("TP - dd click apply button") def dd_click_apply(self): apply = self.wait_for_element_clickable(locator=self.apply_button_loc, locator_type="xpath") self.click_on_element_js(element=apply) @allure.step("TD - Tiktok - dd click apply button") def td_dd_click_apply_country_tiktok(self): apply = self.wait_for_element_clickable(locator="(//button[.='Apply'])[2]", locator_type="xpath") self.click_on_element_js(element=apply) @allure.step("TP - expand By Tier dd") def expand_tier_dd(self): self.scroll_to_element(*self.locator(self.track_locators, "tier_dd")) tier_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "tier_dd")) self.click_on_element_js(element=tier_dd) @allure.step("TP - by tier dd verify hint") def verify_tier_hint(self, option): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) tier_dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "tier_dd")) ActionChains(self.driver).move_to_element(tier_dd).perform() option = ", ".join(option) loc = f"//*[text()='{option}']" self.log.info(f"locator for hint: {loc}") hint = self.is_element_displayed(locator=loc, locator_type="xpath") assert_that(hint).is_true() @allure.step("TP - verify Total Streams, By Source and Source dd removed") def verify_ts_bs_sdd_removed(self): self.is_element_present() ts = self.is_element_displayed(*self.locator(self.track_locators, "source_type_dd")) bs = self.is_element_displayed(*self.locator(self.track_locators, "streams_and_graphs_sources_dd")) assert_that(ts).is_false() assert_that(bs).is_false() @allure.step("TP - graph get Y axis labels") def graph_get_yaxis(self): self.wait_for_element_visible(*self.locator(self.track_locators, "yaxis")) yaxis = self.get_elements(*self.locator(self.track_locators, "yaxis")) yaxis = [self.get_text(element=y) for y in yaxis] assert_that(len(yaxis)).is_greater_than_or_equal_to(1) return yaxis @allure.step("TP - graph get X axis labels") def graph_get_xaxis(self): self.wait_for_element_visible(*self.locator(self.track_locators, "xaxis")) self.wait_for_element_clickable(*self.locator(self.track_locators, "xaxis")) xaxis = self.get_elements(*self.locator(self.track_locators, "xaxis")) xaxis = [self.get_text(element=y) for y in xaxis] assert_that(len(xaxis)).is_greater_than_or_equal_to(1) self.log.info(f"xaxis labels: {xaxis}") return xaxis @allure.step("Apple playlist page - popup select previous month period") def graph_verify_predefined_periods(self, youtube=False): for p, d in zip(self.dp_predefined_periods, self.dp_predefined_count_days): xaxis_before = self.graph_get_xaxis() self.select_predefined_period(p) days_count = int(self.get_graph_period_displayed()) xaxis_after = self.graph_get_xaxis() latest_date = self.api_client.get_latest_date_date() if youtube: latest_date = self.api_client.get_latest_date_all()["youtube"] date_to_ui = self.get_calendar_end_date() if d == self.dp_predefined_count_days[-1]: assert_that(days_count).is_greater_than_or_equal_to(d - 5) assert_that(days_count).is_less_than_or_equal_to(d + 5) else: assert_that(days_count).is_equal_to(d) assert_that(xaxis_before).is_not_equal_to(xaxis_after) assert_that(latest_date).is_equal_to(date_to_ui) @allure.step("Stream and source - country dd is not displayed") def is_country_dd_removed(self): dd = self.is_element_displayed(*self.locator(self.track_locators, "streams_country_dd")) assert_that(dd).is_false() @allure.step("TP - graph get available dsps") def get_available_dsps(self): self.wait_for_element_visible(*self.locator(self.track_locators, "all_dsps")) dsps_el = self.get_elements(*self.locator(self.track_locators, "all_dsps")) dsps = [self.get_text(element=d) for d in dsps_el] return dsps @allure.step("TP - graph dsp dd verify hover") def dsp_verify_hover(self): dsp_item = f"//*[contains(@id,'dsp-dd')]/..//*[text()='{AppConfig.get('dsp')['total_streams']}']" dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "dsp_picker")) self.click_element(element=dd) item = self.wait_for_element_visible(locator=dsp_item, locator_type="xpath") color_before = item.value_of_css_property("color") self.hover_on_element(locator=dsp_item, locator_type="xpath") color_after = item.value_of_css_property("color") assert_that(color_before).is_not_equal_to(color_after) self.click_on_title() @allure.step("TP - verify no Amazon icon present") def verify_no_amazon_icon(self): icon_amazon = self.is_element_displayed(*self.locator(self.track_locators, "icon_amazon")) assert_that(icon_amazon).is_false() @allure.step("TP - TD verify charts droplist") def td_verify_charts_droplist(self): self.scroll_to_track_details() dd = self.wait_for_element_clickable("track-details-charts-dsp-dd") self.click_element(element=dd) self.wait_for_element_visible(*self.locator(self.track_locators, "charts_droplist")) dlist_el = self.get_elements(*self.locator(self.track_locators, "charts_droplist")) dlist = [self.get_text(element=i).split("(")[0].strip() for i in dlist_el] count = [int(self.get_text(element=i).split("(")[1].split(")")[0]) for i in dlist_el] list_exp = [ self.CHARTS_SPOTIFY_DAILY, self.CHARTS_SPOTIFY_WEEKLY, self.CHARTS_APPLE_MUSIC_DAILY, self.CHARTS_COMBINED_DAILY, ] assert_that(list_exp).is_equal_to(dlist) self.click_element(element=dd) return count @allure.step("TP - TD verify charts columns for dsp") def td_charts_verify_columns(self): selector = "(//*[contains(@id, 'charts-') and contains(@id, '-table-')])[1]/*[string-length(.) > 0]" self.wait_for_element_visible(locator=selector, locator_type="xpath") columns = self.get_elements(locator=selector, locator_type="xpath") columns = [self.get_text(element=c) for c in columns] export_button = self.is_element_displayed(*self.locator(self.track_locators, "charts_export_button")) peak_locator = "//*[contains(@id, 'peak-position-date-') and contains(., '/')]" entry_locator = "//*[contains(@id, 'entry-position-date-') and contains(., '/')]" assert_that(export_button).is_true() self.validate_date(self.get_text(element=self.get_elements(peak_locator, "xpath")[0])) self.validate_date(self.get_text(element=self.get_elements(entry_locator, "xpath")[0])) columns_exp = ["#", "Chart Market", "Rank\nMarket Size", "Position\n#", "Position\nTrend", "Peak, Lifetime\nPosition #", "Peak Lifetime Position #\nDate", "Entry\nPosition #", "Entry Position #\nDate"] assert_that(columns_exp).is_equal_to(columns) @allure.step("TP - TD verify charts beta droplist") def td_charts_beta_verify_droplist(self): dlist = self.get_elements(*self.locator(self.track_locators, "charts_beta_droplist")) dlist = [self.get_text(element=i) for i in dlist] list_exp = [AppConfig.get("dsp")["spotify"], AppConfig.get("dsp")["apple"]] assert_that(list_exp).is_equal_to(dlist) @allure.step("TP - TD charts beta get countries") def td_charts_beta_get_countries(self): self.scroll_to_track_details() base_loc = "//*[contains(@id, 'charts-new-')]/..//" country_values = [] countries_are_present = self.is_element_displayed(locator=f"{base_loc}span[@tag='p']", locator_type="xpath") if countries_are_present: countries = self.get_elements(locator=f"{base_loc}span[@tag='p']", locator_type="xpath") country_values = [self.get_text(element=c) for c in countries] return country_values @allure.step("TP - TD charts verify export - only Spotify implemented") def td_charts_verify_export(self): dsp = self.td_charts_get_selected_dsp() artist_name = self.get_all_artists_name() track_name = self.get_track_title() export = self.wait_for_element_clickable(*self.locator(self.track_locators, "charts_export_button")) self.click_element(element=export) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{dsp} - {artist_name} - {track_name}.csv""" self.log.info(f"file path: {file_path}") columns = [] table_ui = {} if dsp in [self.CHARTS_SPOTIFY_DAILY, self.CHARTS_SPOTIFY_WEEKLY]: columns = [ "Market", "Market Name", "Current Position", "Previous Position", "Peak Position", "Entry Position", "Peak Date", "Entry Date", ] table_ui = self.td_charts_spotify_get_column_values() data = self.read_from_csv(file_path) file = {} for c in columns: file[c] = data.get(c).to_list()[:5] if c in columns[2:-2]: file[c] = [f for f in file[c] if not math.isnan(f)] if c in columns[-2:]: file[c] = [datetime.datetime.strptime(f, AppConfig.get("date_formats")["mm/dd/yy"]).date() for f in file[c] if not str(f) == "nan"] self.log.info(f"file: {file}") if dsp in [self.CHARTS_SPOTIFY_DAILY, self.CHARTS_SPOTIFY_WEEKLY]: assert_that(file[columns[1]]).is_equal_to(table_ui["Country"]) assert_that(file[columns[2]]).is_equal_to(table_ui["Current"]) # assert_that(file[columns[3]]).is_equal_to(table_ui["Change"]) assert_that(file[columns[4]]).is_equal_to(table_ui["Peak"]) assert_that(file[columns[5]]).is_equal_to(table_ui["Entry"]) assert_that(file[columns[6]]).is_equal_to(table_ui["Peak Date"]) assert_that(file[columns[7]]).is_equal_to(table_ui["Entry Date"]) @allure.step("TP - get artist name") def get_artist_name(self): artist = self.wait_for_element_visible(*self.locator(self.track_locators, "artist_name")) artist_name = self.get_text(element=artist) self.log.info("Artist name: " + str(artist_name)) return artist_name @allure.step("TP - TD charts get selected dsp") def td_charts_get_selected_dsp(self): dsp = self.wait_for_element_visible(*self.locator(self.track_locators, "charts_dd_weekly_daily")) return self.get_text(element=dsp).split("(")[0].strip() @allure.step("TP - TD charts verify no data") def td_charts_verify_no_data(self): self.is_graph_period_displayed() self.scroll_to_track_details() no_data = self.wait_for_element_visible(*self.locator(self.track_locators, "charts_no_data")) assert_that(self.is_element_displayed(element=no_data)).is_true() @allure.step("TP - TD verify charts beta tab displayed") def verify_charts_overview_tab_displayed(self, displayed): self.scroll_to_track_details() tab = self.is_element_displayed(*self.locator(self.track_locators, "track_details_charts_overview")) assert_that(tab == displayed).is_true() @allure.step("TP - TD switch to Stations tab") def td_switch_to_stations_tab(self): tab = self.get_element(*self.locator(self.track_locators, "stations_tab")) self.click_on_element_js(element=tab) self.wait_for_element_visible(*self.locator(self.track_locators, "stations_export_button")) self.wait_for_element_clickable(*self.locator(self.track_locators, "stations_export_button")) time.sleep(3) self.td_is_stations_tab_selected() @allure.step("TP - TD is Stations tab selected") def td_is_stations_tab_selected(self): self.scroll_to_element(*self.locator(self.track_locators, "stations_tab")) self.is_tab_selected(*self.locator(self.track_locators, "stations_tab")) @allure.step("TP - TD Stations tab verify columns") def td_stations_verify_columns(self, market_exp): self.scroll_to_track_details() market = self.get_stations_market() latest_date = self.api_client.get_latest_date_date() latest_date = datetime.datetime.strptime(latest_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) columns_ui = self.get_elements(*self.locator(self.track_locators, "stations_columns")) columns_ui = [self.get_text(element=c) for c in columns_ui] if market == AppConfig.get("market")["global"]["name"]: columns_exp = ["", "#", "C", "", "Station", f"Track\nStreams, {latest_date}", "Track\nStreams 7 Days", ""] else: market_add = market_exp["market"].upper() columns_exp = [ "", "#", "C", "", "Station", f"{market_add} Track\nStreams, {latest_date}", f"{market_add} Track\nStreams 7 Days", f"Global Track\nStreams, {latest_date}", "Global Track\nStreams 7 Days", "", ] assert_that(columns_exp).is_equal_to(columns_ui) @allure.step("TP - TD Stations tab get market") def get_stations_market(self): market = self.wait_for_element_visible(*self.locator(self.track_locators, "stations_market")) return self.get_text(element=market) @allure.step("TP - TD Stations tab change market") def td_stations_change_market(self, param): market_ui = self.get_stations_market() if param != market_ui: market = self.wait_for_element_clickable(*self.locator(self.track_locators, "stations_market")) self.click_element(element=market) market_item = self.wait_for_element_clickable(locator=f"//*[@id='track-details-stations-market-dd']//../*[text()='{param}']", locator_type="xpath") self.click_on_element_js(element=market_item) market_ui = self.get_stations_market() assert_that(market_ui).is_equal_to(param) @allure.step("TP - TD Stations compare ui and api") def td_stations_compare_ui_and_api(self, isrc): base_url = self.get_url() index = 3 api_resp_first_st = self.api_client.get_stations_summary(isrc=isrc)["items"][index] api_st_name = api_resp_first_st["data"]["attributes"]["name"] api_gl_latest = api_resp_first_st["total"][1] api_gl_7days = api_resp_first_st["total"][0] self.page_has_loaded() self.td_search_filter(api_st_name) time.sleep(3) ui = self.td_stations_get_all_from_table() assert_that(ui["name"][0]).is_equal_to_ignoring_case(api_st_name) self.ts.markFinal(api_gl_latest in ui["global-streams-latest"], f'{api_gl_latest} in {ui["global-streams-latest"]}') self.ts.markFinal(api_gl_7days in ui["global-streams-7-days"], f'{api_gl_7days} in {ui["global-streams-7-days"]}') assert_that(api_gl_latest).is_greater_than(-1) assert_that(api_gl_7days).is_greater_than(0) self.log.info(f"ui and api global: {ui['name'][0]} {api_st_name}\n{ui['global-streams-latest'][0]} {api_gl_latest}\n{ui['global-streams-7-days'][0]} {api_gl_7days}") local_market = api_resp_first_st["markets"][0] self.open_url(f"{base_url}&tr_det_st_market={local_market[0]}") self.td_search_filter(api_st_name) time.sleep(3) ui = self.td_stations_get_all_from_table() assert_that(ui["name"][0]).is_equal_to(api_st_name) self.ts.markFinal(api_gl_latest in ui["global-streams-latest"], f'{api_gl_latest} in {ui["global-streams-latest"]}') self.ts.markFinal(api_gl_7days in ui["global-streams-7-days"], f'{api_gl_7days} in {ui["global-streams-7-days"]}') api_market_latest = local_market[2] api_market_7days = local_market[1] self.ts.markFinal(api_market_latest in ui["market-streams-latest"], f'{api_market_latest} in {ui["market-streams-latest"]}') self.ts.markFinal(api_market_7days in ui["market-streams-7-days"], f'{api_market_7days} in {ui["market-streams-7-days"]}') assert_that(api_market_latest).is_greater_than(-1) assert_that(api_market_7days).is_greater_than(0) self.log.info(f"ui and api market: {ui['name'][0]} {api_st_name}\n{ui['market-streams-latest'][0]} {api_market_latest}\n{ui['market-streams-7-days'][0]} {api_market_7days}") self.td_filter_click_clear_icon() @allure.step("TP - TD Stations verify columns hover") def stations_verify_columns_hover(self): market = self.get_stations_market() self.wait_for_element_clickable(locator="stations-table-cell-global-streams-7-days") gl_el = self.wait_for_element_visible(locator="stations-table-cell-global-streams-7-days") self.hover_on_element(element=gl_el) tooltip_ui = self.wait_for_element_visible("stations-table-cell-global-streams-7-days-tooltip") tooltip_ui = self.get_text(element=tooltip_ui) tooltip_exp = "Track streams from Stations in the last 7 days." assert_that(tooltip_exp).is_equal_to(tooltip_ui) if market != AppConfig.get("market")["global"]["name"]: self.wait_for_element_clickable(locator="stations-table-cell-market-streams-7-days") m_el = self.wait_for_element_visible(locator="stations-table-cell-market-streams-7-days") self.hover_on_element(element=m_el) tooltip_ui = self.get_text("stations-table-cell-market-streams-7-days-tooltip") assert_that(tooltip_exp).is_equal_to(tooltip_ui) @allure.step("TP - TD Stations get table data") def td_stations_get_all_from_table(self, all_countries=True): ui_values = {} self.hover_on_element(*self.locator(self.track_locators, "stations_export_button")) for c in self.td_stations_columns: if c == "country-code": if all_countries: selector = f"//*[contains(@id, '{c}-')]//../img" else: selector = "//span[not(contains(text(), 'sum'))]/ancestor::div[contains(@id, 'stations-table-cell-position-')]/following-sibling::div[contains(@id, 'stations-table-cell-country-code-')]//../img" elif c == "Entity": selector = f"//div[contains(@id, '{c}-')]/descendant::span[1]" else: selector = f"//*[contains(@id, '{c}-')]" els = self.get_elements(locator=selector, locator_type="xpath") if c == "country-code": els = [e.get_attribute("src").split(".")[-2].split("/")[-1] for e in els] elif c not in ["Entity", "country-code"]: els = [self.get_text(element=e) for e in els] els = [int(e.replace(",", "")) for e in els] else: els = [self.get_text(element=e) for e in els] ui_values[c] = els self.log.info(f"values from stations tab: {ui_values}") return ui_values @allure.step("TP - TD Stations verify hint for name") def stations_verify_hint_for_name(self): selector = "//*[@id='stations-table-cell-name-1']//../span[string-length(text()) > 0]" self.wait_for_element_clickable(locator=selector, locator_type="xpath") name_text = self.get_text(locator=selector, locator_type="xpath") self.hover_on_element(locator=selector, locator_type="xpath") tooltip = self.get_text(locator=self.hint_locator, locator_type="xpath") assert_that(name_text).is_equal_to(tooltip) @allure.step("TP - TD Stations verify flags column") def stations_verify_flags_column(self): selector = "//*[contains(@id, 'country-code-')]//../img" self.wait_for_element_visible(locator=selector, locator_type="xpath") flags_el = self.get_elements(locator=selector, locator_type="xpath") flags = [f.get_attribute("src") for f in flags_el] assert_that(len(flags)).is_greater_than(0) assert_that(all("flags" in f for f in flags)).is_true() @allure.step("TP - TD Stations verify flags column") def stations_verify_dsp_icons_column(self): selector = "//*[contains(@id, 'cell-actions-')]//../a" self.wait_for_element_visible(locator=selector, locator_type="xpath") icons_el = self.get_elements(locator=selector, locator_type="xpath") icons = [f.get_attribute("href") for f in icons_el] assert_that(len(icons)).is_greater_than(0) assert_that(all("https://music.apple.com/us/station/" in f for f in icons)).is_true() @allure.step("TP - TD Stations click on column") def stations_click_on_column(self, column): selector = f"stations-table-cell-{column}" self.wait_for_element_visible(locator=selector) column = self.wait_for_element_clickable(locator=selector) self.click_element(element=column) time.sleep(1) @allure.step("TP - TD Stations verify sorting") def stations_verify_sorting(self, column1, column2, dl): market = self.get_stations_market() sort_asc_desc = True if column1 in ["name", "country-code"]: sort_asc_desc = False if column1 == "market-streams-7-days": col_el = self.wait_for_element_clickable(locator=f"stations-table-cell-{column1}") self.click_element(element=col_el) if column1 == "global-streams-7-days" and market == AppConfig.get("market")["global"]["name"]: col_el = self.wait_for_element_clickable(locator=f"stations-table-cell-{column1}") self.click_element(element=col_el) col_el = self.wait_for_element_clickable(locator=f"stations-table-cell-{column1}") self.click_element(element=col_el) f_values = self.td_stations_get_all_from_table()[column1] s_values = self.td_stations_get_all_from_table()[column2] sort_param = self.desc if column1 in ["name"]: sort_param = self.asc self.verify_params_in_url({self.url_sorting: sort_param, self.stations_sort: dl}) self.log.info(f"\nfirst click: \ncolumn1: {column1}\ncolumn2: {column2}\ndl: {dl}") self.log.info(f"\ncolumn1 values: {f_values}\ncolumn2 values: {s_values}") assert_that(sorted(f_values, reverse=True) or natsorted(f_values, reverse=True)).is_true() column2_sorted = self.second_sort_get_second_values(column1=f_values[:5], column2=s_values[:5], sort2=sort_asc_desc) assert_that(s_values[:5] == column2_sorted or column2_sorted == sorted(column2_sorted, reverse=True) or column2_sorted == natsorted(column2_sorted, reverse=True)).is_true() col_el = self.wait_for_element_clickable(locator=f"stations-table-cell-{column1}") self.click_element(element=col_el) f_values = self.td_stations_get_all_from_table()[column1] s_values = self.td_stations_get_all_from_table()[column2] self.log.info(f"\nsecond click: \ncolumn1: {column1}\ncolumn2: {column2}\ndl: {dl}") self.log.info(f"\ncolumn1 values: {f_values}\ncolumn2 values: {s_values}") sort_param_2 = self.asc rev = False if column1 in ["name", "country-code"]: rev = True if column1 == "name": sort_param_2 = self.desc self.verify_params_in_url({self.url_sorting: sort_param_2, self.stations_sort: dl}) assert_that(sorted(f_values) or natsorted(f_values)).is_true() column2_sorted = self.second_sort_get_second_values(column1=f_values[:5], column2=s_values[:5], sort2=sort_asc_desc)[:5] assert_that(s_values[:5] == column2_sorted or column2_sorted == sorted(column2_sorted, reverse=rev) or column2_sorted == natsorted(column2_sorted, reverse=rev)).is_true() def second_sort_get_second_values(self, column1, column2, sort1=True, sort2=True): df = pd.DataFrame({"column1": column1, "column2": column2}) sorter = column1 sorter_index = dict(zip(sorter, range(len(sorter)))) df["column1"] = df["column1"].map(sorter_index) df.sort_values(["column1", "column2"], ascending=[sort1, sort2], inplace=True) df.drop("column1", 1, inplace=True) return df["column2"].to_list() @allure.step("TP - TD Stations verify non sortable columns sorting") def stations_verify_non_sortable_columns(self): self.scroll_to_element(*self.locator(self.track_locators, "stations_tab")) self.page_has_loaded() time.sleep(5) for c in self.stations_non_sortable_columns: col_el = self.wait_for_element_visible(locator=f"stations-table-cell-{c}") self.click_element(element=col_el) values_before = self.td_stations_get_all_from_table() for c in self.stations_non_sortable_columns: col_el = self.wait_for_element_visible(locator=f"stations-table-cell-{c}") self.click_element(element=col_el) values_after = self.td_stations_get_all_from_table() assert_that(values_before).is_equal_to(values_after) @allure.step("TP - TD Stations verify export hover") def td_verify_export_hover(self): export = self.wait_for_element_clickable(*self.locator(self.track_locators, "stations_export_button")) color_before = export.value_of_css_property("background-color") ActionChains(self.driver).move_to_element(to_element=export).perform() color_after = export.value_of_css_property("background-color") self.ts.markFinal(color_after != color_before, f"color: {color_before}\nafter: {color_after}") self.click_element(*self.locator(self.track_locators, "tp_header")) @allure.step("TP - TD Stations verify export") def stations_verify_export(self, market, isrc): track_name = self.get_track_title() artist_name = self.get_all_artists_name() latest_date = self.api_client.get_latest_date_date() latest_date = datetime.datetime.strptime(latest_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) columns = ["Station", "Station Market", f"Global Track Streams, {latest_date}", "Global Track Streams 7 Days"] if market != AppConfig.get("market")["global"]: columns = columns + [ f"{market['market'].upper()} Track Streams, {latest_date}", f"{market['market'].upper()} Track Streams 7 Days", ] export = self.wait_for_element_clickable(*self.locator(self.track_locators, "stations_export_button")) self.click_element(element=export) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/Stations - {artist_name} - {track_name}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") api_resp = self.api_client.get_stations_summary(isrc=isrc)["items"] is_top_market_selected = self.is_tab_selected_no_assert(locator="track-details-stations-top-markets-scope-bar") if is_top_market_selected and market == AppConfig.get("market")["global"]: api_stations = [s["data"]["attributes"]["name"] for s in api_resp if (any(g[0] in self.TOP_6_COUNTRIES for g in s["markets"]) and not (s.get("data") is None or s.get("data").get("attributes") is None or s.get("data").get("attributes").get("name") is None))] api_market = [c.upper() for c in self.TOP_6_COUNTRIES] api_global_latest = sum(sum(t[2] for t in g["markets"] if t[0] in self.TOP_6_COUNTRIES) for g in api_resp) api_global_7days = sum(sum(t[1] for t in g["markets"] if ((t[0] in self.TOP_6_COUNTRIES) and not (g.get("data") is None or g.get("data").get("attributes") is None or g.get("data").get("attributes").get("name") is None))) for g in api_resp) elif market == AppConfig.get("market")["global"]: api_stations = [s["data"]["attributes"]["name"] for s in api_resp if not (s.get("data") is None or s.get("data").get("attributes") is None or s.get("data").get("attributes").get("name") is None)] api_market = [g["markets"] for g in api_resp] api_market = [val for sublist in api_market for val in sublist] api_market = [t[0].upper() for t in api_market] api_global_latest = sum(sum(t[2] for t in g["markets"]) for g in api_resp) api_global_7days = sum(sum(t[1] for t in g["markets"] if not (g.get("data") is None or g.get("data").get("attributes") is None or g.get("data").get("attributes").get("name") is None)) for g in api_resp) else: api_stations = [s["data"]["attributes"]["name"] for s in api_resp if (any(g[0] == market["market"] for g in s["markets"]) and not (s.get("data") is None or s.get("data").get("attributes") is None or s.get("data").get("attributes").get("name") is None))] api_market = [market["market"].upper()] api_global_latest = sum(sum(t[2] for t in g["markets"] if any(t[0] == market["market"] for t in g["markets"])) for g in api_resp) api_global_7days = sum(sum(t[1] for t in g["markets"] if (any(t[0] == market["market"] for t in g["markets"])) and not (g.get("data") is None or g.get("data").get("attributes") is None or g.get("data").get("attributes").get("name") is None)) for g in api_resp) assert_that(set(file[columns[0]])).is_equal_to(set(api_stations)) file_markets = [str(m).replace("nan", "NA") for m in file[columns[1]]] assert_that(set(file_markets)).is_subset_of(set(api_market)) assert_that(sum(file[columns[2]])).is_equal_to(api_global_latest) assert_that(sum(file[columns[3]])).is_equal_to(api_global_7days) if market != AppConfig.get("market")["global"]: api_market_latest = sum(sum(t[2] for t in g["markets"] if t[0] == market["market"]) for g in api_resp) api_market_7days = sum(sum(t[1] for t in g["markets"] if ((t[0] == market["market"]) and not (g.get("data") is None or g.get("data").get("attributes") is None or g.get("data").get("attributes").get("name") is None))) for g in api_resp) assert_that(sum(file[columns[4]])).is_equal_to(api_market_latest) assert_that(sum(file[columns[5]])).is_equal_to(api_market_7days) @allure.step("TP - get all artists for track") def get_all_artists_name(self): self.wait_for_element_visible(*self.locator(self.track_locators, "all_artists")) artists = self.get_text(*self.locator(self.track_locators, "all_artists")) self.log.info("Artists name: " + artists) return artists @allure.step("TP - stations switch market toggle") def stations_switch_market_toggle(self, param): market = self.get_stations_market() if market == AppConfig.get("market")["global"]["name"]: selector = f"track-details-stations-{param}-scope-bar" toggle = self.wait_for_element_clickable(locator=selector) self.click_element(element=toggle) self.is_tab_selected(locator=selector) @allure.step("TP - stations verify toggle") def stations_verify_toggle(self, param="top-markets"): selector = f"track-details-stations-{param}-scope-bar" self.is_tab_selected(locator=selector) @allure.step("TP - TD verify default filter input") def td_verify_default_filter(self): input_field = self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_field")) icon = self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_icon")) focused_el = self.driver.switch_to.active_element placeholder = self.get_attribute_value(element=input_field, attribute="placeholder") assert_that(self.is_element_displayed(element=input_field)).is_true() assert_that(self.is_element_displayed(element=icon)).is_true() assert_that(input_field).is_not_equal_to(focused_el) assert_that(placeholder).is_equal_to("Filter") color_before = input_field.value_of_css_property("background-color") self.click_element(element=input_field) color_after = input_field.value_of_css_property("background-color") focused_el = self.driver.switch_to.active_element placeholder = self.get_attribute_value(element=input_field, attribute="placeholder") assert_that(input_field).is_equal_to(focused_el) assert_that(self.is_element_displayed(element=input_field)).is_true() assert_that(self.is_element_displayed(element=icon)).is_true() assert_that(placeholder).is_equal_to("Filter") assert_that(color_before).is_not_equal_to(color_after) @allure.step("TP - TD get filter input value") def td_get_filter_value(self): input_field = self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_field")) value = self.get_attribute_value(element=input_field, attribute="value") return value @allure.step("TP - TD is filter placeholder present") def td_is_filter_placeholder_present(self): input_field = self.wait_for_element_visible(*self.locator(self.track_locators, "track_details_filter_field")) value = self.get_attribute_value(element=input_field, attribute="value") if value == "": return True @allure.step("TP - TD verify table empty after filtering") def td_verify_no_results(self): self.page_has_loaded() self.scroll_to_track_details() no_results = self.wait_for_element_visible(*self.locator(self.track_locators, "table_no_results")) no_results_to_show = self.wait_for_element_visible(*self.locator(self.track_locators, "table_no_results_to_show")) no_results_text = self.get_text(element=no_results) no_results_to_show_text = self.get_text(element=no_results_to_show) assert_that(self.is_element_displayed(element=no_results)).is_true() assert_that(no_results_text).is_equal_to("Try another filter.") assert_that(no_results_to_show_text).is_equal_to("No results to show.") @allure.step("TP - TD stations verify labels") def stations_verify_labels(self): label_market = self.get_text(*self.locator(self.track_locators, "st_market_label")) label_stations = self.get_text(*self.locator(self.track_locators, "st_stations_label")) assert_that(label_market).is_equal_to("MARKET") assert_that(label_stations).is_equal_to("STATIONS") @allure.step("TP - TD stations verify toggle hint") def stations_verify_toggle_hint(self): self.hover_on_element(*self.locator(self.track_locators, "st_stations_icon")) hint = self.get_text(*self.locator(self.track_locators, "st_stations_hint")) assert_that(hint).is_equal_to("Global Market doesn’t exist for Apple Music.\nPlease select between Top Markets stations (US, CA,\nUK, DE, AU, FR) or all stations.") @allure.step("TP - TD stations get data from table non sortable") def td_stations_get_positions(self): self.wait_for_element_visible(*self.locator(self.track_locators, "st_positions")) positions = self.get_elements(*self.locator(self.track_locators, "st_positions")) positions = [self.get_text(element=p) for p in positions] return positions @allure.step("TP - TD stations click apple icon") def stations_click_apple_icon(self, sum=True): self.wait_for_element_clickable(*self.locator(self.track_locators, "st_icons")) icons = self.get_elements(*self.locator(self.track_locators, "st_icons")) if sum: positions = self.td_stations_get_positions() index = positions.index("SUM") self.click_element(element=icons[index]) else: self.click_element(element=icons[0]) @allure.step("TP - TD stations verify market dd values") def stations_verify_market_dd_values(self): translationTable = str.maketrans("éàèùâêîôûç", "eaeuaeiouc") values = self.get_elements(*self.locator(self.track_locators, "st_market_dd_values")) values = [self.get_text(element=v).translate(translationTable) for v in values] values_exp = AppConfig.get("stations_markets") assert_that(values).is_equal_to(values_exp) @allure.step("TP - TD stations verify toggle enabled") def stations_verify_toggle_enabled(self, enabled=True): toggle = self.wait_for_element_visible(*self.locator(self.track_locators, "st_toggle")) state = self.get_attribute_value(element=toggle, attribute="data-state") == "enabled" assert_that(state).is_equal_to(enabled) @allure.step("TP - get requests for endpoint in console") def get_events_from_console(self, endpoint, empty=False, wait=5): time.sleep(wait) network = self.driver.get_log("performance") result_list = [] for entry in network: log = json.loads(entry["message"])["message"] if log["method"] == "Network.requestWillBeSent" and (endpoint in log["params"]["documentURL"]): result_list.append(log["params"]["documentURL"]) self.log.info(f"network results: {result_list}") assert_that(len(result_list) == 0).is_equal_to(empty) return result_list @allure.step("TP - TD wait TD visible") def td_wait_td_visible(self): self.scroll_to_track_details() self.wait_for_element_visible(locator="//*[contains(@id, 'table-cell-position-')]", locator_type="xpath") @allure.step("TP - validate api response to schema") def validate_schema(self, schema, response): sb = builder.SchemaBuilder() api_schema = eval(self.read_from_file(param=f"{schema}_schema")[0]) # nosec B307 self.log.info(f"schema from file: {api_schema}") sb.add_schema(schema=api_schema) try: validate(instance=dict(response), schema=sb.to_schema()) valid = True err = "no" except ValidationError as error: valid = False err = error assert_that(valid).described_as(f"Schema validation is failed: {err}").is_true() # sb = builder.SchemaBuilder() # sb.add_object(obj=response) # validate(instance=response, schema=sb.to_schema()) # self.log.info(f'schema : {sb.to_schema()}') @allure.step("read values from file") def read_from_file(self, param): file = open(f"app/src/data/{param}.txt") list = file.readlines() lines = [] for i in list: lines.append(str(i).rstrip()) self.log.info(f"from file: {lines}") return lines @allure.step("TD - TP verify market droplist") def graph_verify_market_droplist(self, count=97): markets = self.get_elements(*self.locator(self.track_locators, "tp_market_items")) markets_items = [self.get_text(element=m) for m in markets] filter_market = self.is_element_displayed(*self.locator(self.track_locators, "td_market_filter")) apply = self.is_element_displayed(locator=self.apply_button_loc, locator_type="xpath") fast_selections = self.is_element_displayed(*self.locator(self.track_locators, "fast_selections")) all_markets = self.is_element_displayed(locator=f"//*[contains(text(), '{self.all_markets}')]", locator_type="xpath") assert_that(filter_market).is_true() assert_that(apply).is_true() assert_that(fast_selections).is_true() assert_that(all_markets).is_true() assert_that(len(markets)).is_greater_than_or_equal_to(count) assert_that(markets_items[1:]).is_sorted() @allure.step("TD - TP countries dd - filter and get markets") def graph_countries_filter_by(self, param, clear=True): if clear: self.click_element(*self.locator(self.track_locators, "tp_market_clear")) filter_market = self.wait_for_element_clickable(*self.locator(self.track_locators, "td_market_filter")) self.send_text(data=param, element=filter_market) @allure.step("TD - TP countries dd - get displayed markets") def graph_countries_dd_get_markets(self): markets = self.get_elements(*self.locator(self.track_locators, "tp_market_items")) markets_items = [self.get_text(element=m) for m in markets] return markets_items @allure.step("TD - TP countries dd - clear icon is displayed") def graph_countries_clear_icon_displayed(self): clear = self.is_element_displayed(*self.locator(self.track_locators, "tp_market_clear")) assert_that(clear).is_true() @allure.step("TD - TP countries dd - no items after filter") def graph_countries_verify_no_items(self): no_markets = self.wait_for_element_visible(*self.locator(self.track_locators, "tp_market_no_items")) assert_that(self.is_element_displayed(element=no_markets)).is_true() @allure.step("TD - TP countries dd - verify hint") def graph_dd_verify_hint(self, param, dd="streams_and_graphs_country"): if len(param) == 1: hint_text = param[0] elif len(param) == 2: hint_text = ", ".join(sorted(param)) else: count_minus_2 = len(param) - 2 hint_text = ", ".join(sorted(param)[:2]) + f", and {count_minus_2} more" self.hover_on_element(*self.locator(self.track_locators, dd)) hint = self.wait_for_element_visible(locator=self.hint_locator, locator_type="xpath") hint = self.get_text(element=hint) assert_that(hint).is_equal_to(hint_text) @allure.step("TD - TP verify export on streams and sources tab") def export_to_file_streams_and_sources_tab(self, tab="", markets=""): ap = False if tab != "": ap = True track_name = self.get_track_title(ap=ap) market = str(self.graph_get_selected_market().replace("Market", "market")) if "markets" not in market: market = self.parameter_from_url(self.str_gr_country).upper() dsp = self.get_current_dsp() self.click_export() if "/track/" in self.get_url(): self.click_export_as_csv() file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - {market} - {dsp}.csv""" column_name = "All Streams" if tab == "Track": file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/Album Tracks – {track_name}.csv""" column_name = "Streams" start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() ids_loc = "//*[contains(@href, '/track/')]" self.wait_for_element_visible(locator=ids_loc, locator_type="xpath") ids = self.get_elements(locator=ids_loc, locator_type="xpath") ids = [self.get_attribute_value(element=i, attribute="href").split("/")[-1] for i in ids] isrcs = [self.api_client.get_isrc_by_spotify_id(market="_gl", id=i)["external_ids"]["isrc"] for i in ids] self.log.info(f"isrcs for track tab: {isrcs}") spotify_totals = [self.api_client.get_track_per_country(isrc=i, start_date=start_date, end_date=end_date, vendor="spotify") for i in isrcs] apple_totals = [self.api_client.get_track_per_country(isrc=i, start_date=start_date, end_date=end_date, vendor="apple") for i in isrcs] spotify_totals = sum(sum(sum(d["streams"] for d in r["data"]) for r in z if r["countryCode"] in markets) for z in spotify_totals) apple_totals = sum(sum(sum(d["streams"] for d in r["data"]) for r in z if r["countryCode"] in markets) for z in apple_totals) if dsp == AppConfig.get("dsp")["spotify"]: totals_ui = spotify_totals elif dsp == AppConfig.get("dsp")["apple"]: totals_ui = apple_totals else: totals_ui = spotify_totals + apple_totals elif dsp in [AppConfig.get("dsp")["spotify"], AppConfig.get("dsp")["apple"], AppConfig.get("dsp")["amazon"]]: totals_ui = int(self.get_streams_in_period_total().replace(",", "")) else: totals_ui = self.get_streams_in_period_total_combined() self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) sum_all_streams_csv = data.sum(numeric_only=True)[column_name] self.log.info(f"sum of data csv: {sum_all_streams_csv}") self.log.info(f"totals ui: {totals_ui}") assert_that(sum_all_streams_csv).is_equal_to(totals_ui) @allure.step("Open Spotify Track/Album page") def open_spotify_page(self, id, page_type): self.driver.get(f"{CoreConfig.ENV_BASE_URL}/spotify/{page_type}/{id}") self.page_has_loaded() @allure.step("TP - Graph get legend container values") def get_container_values(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.wait_for_element_visible(*self.locator(self.track_locators, "container_label")) labels = self.get_elements(*self.locator(self.track_locators, "container_label")) streams = [] for l in labels: self.hover_on_element(element=l) streams.append(int(self.get_text(*self.locator(self.track_locators, "tooltip_lean_streams")).replace(",", ""))) return {"streams": streams} @allure.step("TP - Graph get legend api values") def graph_legend_get_api_values_apple(self, markets, isrc): start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() token = self.api_client.authorize() api_response_per_country = self.api_client.get_track_per_country(isrc=isrc, start_date=start_date, end_date=end_date, vendor="apple") api_age_gender_resp = [ self.get_streams_age_gender_api( dsp=AppConfig.get("dsp")["apple"], market=m, isrc=isrc, start_date=start_date, end_date=end_date, token=token, ) for m in markets ] self.log.info(f"api_age_gender_resp: {api_age_gender_resp}") # graph in total total = sum(sum(d["streams"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) # lean forward library = sum(sum(d["source"]["1"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) external = sum(sum(d["source"]["5"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) voice = sum(sum(d["source"]["7"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) search = sum(sum(d["source"]["2"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) # lean back music_kit = sum(sum(d["source"]["4"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) now_playing = sum(sum(d["source"]["6"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) discovery = sum(sum(d["source"]["3"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) other = sum(sum(d["source"]["0"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) # containers playlist = sum(sum(d["container"]["2"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) none = sum(sum(d["container"]["0"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) album = sum(sum(d["container"]["3"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) radio = sum(sum(d["container"]["1"] for d in r["data"]) for r in api_response_per_country if r["countryCode"] in markets) # age_groups age_values = list(numpy.array([a["ages"] for a in api_age_gender_resp]).sum(axis=0)) # gender values gender_values = list(numpy.array([a["genders"] for a in api_age_gender_resp]).sum(axis=0)) self.log.info("Genders:" + str(gender_values)) api_values = { "total": total, "lf": {"library": library, "external": external, "voice": voice, "search": search}, "lb": {"music_kit": music_kit, "now_playing": now_playing, "discovery": discovery, "other": other}, "container": {"playlist": playlist, "none": none, "album": album, "radio": radio}, "ages": age_values, "genders": gender_values, } self.log.info(f"api values for graph legend: {api_values}") return api_values @allure.step("TP - TD switch to Youtube tab") def td_switch_to_youtube_tab(self): self.wait_for_element_visible(locator="//*[text()='Date']", locator_type="xpath") self.wait_for_element_clickable(locator="//*[text()='Date']", locator_type="xpath") self.scroll_to_element(locator="//*[text()='Date']", locator_type="xpath") tab = self.wait_for_element_clickable(*self.locator(self.track_locators, "youtube_tab")) self.click_element(element=tab) time.sleep(2) self.wait_for_element_visible(*self.locator(self.track_locators, "youtube_export_button")) self.wait_for_element_clickable(*self.locator(self.track_locators, "youtube_export_button")) time.sleep(2) self.td_is_youtube_tab_selected() @allure.step("TP - TD is Youtube tab selected") def td_is_youtube_tab_selected(self): self.scroll_to_element(*self.locator(self.track_locators, "youtube_tab")) self.is_tab_selected(*self.locator(self.track_locators, "youtube_tab")) @allure.step("TP - TD Youtube get all from table") def td_youtube_get_all_from_table(self): self.scroll_to_element(*self.locator(self.track_locators, "youtube_tab")) self.wait_for_element_visible(locator="youtube-table-cell-position-1") self.wait_for_element_visible(locator="//*[contains(@id, 'youtube-table-cell-title-')]/..//a", locator_type="xpath") self.wait_for_element_visible( locator="//*[contains(@id, 'youtube-table-cell-views-end-date-') and not(contains(@id, 'trend'))]", locator_type="xpath", ) self.wait_for_element_visible(locator="//*[contains(@id, 'youtube-table-cell-position-')]", locator_type="xpath") self.wait_for_element_visible(locator="//*[contains(@id, 'youtube-table-cell-title-')][string-length(.) > 0]", locator_type="xpath") positions = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-position-')]", locator_type="xpath") titles = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-title-')][string-length(.) > 0]", locator_type="xpath") self.wait_for_element_visible( locator="//*[contains(@id, 'youtube-table-cell-views-end-date-') and not(contains(@id, 'trend'))]", locator_type="xpath", ) date_views = self.get_elements( locator="//*[contains(@id, 'youtube-table-cell-views-end-date-') and not(contains(@id, 'trend'))]", locator_type="xpath", ) self.wait_for_element_visible(locator="//*[contains(@id, 'youtube-table-cell-views-end-date-trend-')][1]//../span[@tag][contains(., '%')]", locator_type="xpath") date_trends = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-views-end-date-trend-')][1]//../span[@tag][contains(., '%')]", locator_type="xpath") views_7 = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-views-7-days-')]", locator_type="xpath") trends_7 = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-views-end-date-trend-')][2]", locator_type="xpath") views_in_period = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-selected-track-streams-7-days-')]", locator_type="xpath") views_avg_day = self.get_elements( locator="//*[contains(@id, 'youtube-table-cell-views-in-period-')][1]//../*[string-length(text()) > 0]", locator_type="xpath", ) # views_avg_duration = self.get_elements( # locator="//*[contains(@id, 'youtube-table-cell-views-in-period-')][2]", locator_type="xpath" # ) video_ids = self.get_elements(locator="//*[contains(@id, 'youtube-table-cell-title-')]/..//a", locator_type="xpath") positions = [self.get_text(element=e) for e in positions] titles = [self.get_text(element=e) for e in titles] date_views = [int(self.get_text(element=e).replace(",", "").replace("N/A", "0")) for e in date_views] date_trends = [self.get_text(element=e).replace("%", "") for e in date_trends] self.log.info(f"date trends all: {date_trends}") date_trends = [int(d) for d in date_trends] self.log.info(f"date trends int: {date_trends}") views_7 = [int(self.get_text(element=e).replace(",", "").replace("N/A", "0")) for e in views_7] trends_7 = [int(self.get_text(element=e).replace("%", "")) for e in trends_7[:-1]] views_in_period = [int(self.get_text(element=e).replace(",", "")) for e in views_in_period] views_avg_day = [int(self.get_text(element=e).replace(",", "")) for e in views_avg_day] # views_avg_duration = [self.get_text(element=e) for e in views_avg_duration] video_ids = [self.get_attribute_value(element=e, attribute="href").split("=")[-1] for e in video_ids] table_ui = { "positions": positions, "titles": titles, "date_views": date_views, "date_trends": date_trends, "views_7": views_7, "trends_7": trends_7, "views_in_period": views_in_period, "views_avg_day": views_avg_day, # "views_avg_duration": views_avg_duration, "video_ids": video_ids, } self.log.info(f"td youtube table: {table_ui}") return table_ui @allure.step("TP - TD Youtube verify hover for streams in period column header") def td_youtube_verify_hover_columns(self): c_start_date = self.get_calendar_start_date() c_end_date = self.get_calendar_end_date() for l in [ "//*[@id='youtube-table-cell-selected-track-streams-7-days']", "(//*[@id='youtube-table-cell-views-in-period'])[1]", "(//*[@id='youtube-table-cell-views-in-period'])[2]", ]: self.hover_on_element(locator=l, locator_type="xpath") tooltip = self.get_text("//*[contains(@id, 'youtube-table-cell') and contains(@id, 'tooltip')]", "xpath").split("–") t_start_date = datetime.datetime.strptime(tooltip[0], self.get_date_format_from_locale()).strftime("%Y-%m-%d") t_end_date = datetime.datetime.strptime(tooltip[1], self.get_date_format_from_locale()).strftime("%Y-%m-%d") assert_that([t_start_date, t_end_date]).is_equal_to([c_start_date, c_end_date]) @allure.step("TP - TD Youtube get views date from column header") def td_youtube_get_views_date(self): selector = "youtube-table-cell-views-end-date" self.scroll_to_track_details() date = self.wait_for_element_visible(locator=selector) date = self.get_text(element=date).split("\n")[0] date = datetime.datetime.strptime(date, self.get_date_format_from_locale()).strftime("%Y-%m-%d") return date @allure.step("Get list of sources with streams number for list of countries") def graph_legend_get_api_values_spotify(self, markets, start_date, end_date, isrc): streams_tp_api_response = self.api_client.get_track_per_country(isrc=isrc, start_date=start_date, end_date=end_date, vendor="spotify") total = sum(sum(z["streams"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) other = sum(sum(z["sourceOther"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) search = sum(sum(z["sourceSearch"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) artist_page = sum(sum(z["sourceArtist"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) album_page = sum(sum(z["sourceAlbum"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) play_queue = sum(sum(z["sourcePlayQueue"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) chart = sum(sum(z["sourceChart"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) daily_mix = sum(sum(z["sourceDailyMix"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) radio = sum(sum(z["sourceRadio"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) discover_weekly = sum(sum(z["sourceDiscoverWeekly"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) release_radar = sum(sum(z["sourceReleaseRadar"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) playlists = sum(sum(z["sourceOthersPlaylist"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) collection = sum(sum(z["sourceCollection"] for z in r["data"]) for r in streams_tp_api_response if r["countryCode"] in markets) api_values = { "total": total, "lf": { "collection": collection, "play_queue": play_queue, "album_page": album_page, "artist_page": artist_page, "search": search, }, "lb": { "playlists": playlists, "release_radar": release_radar, "discover_weekly": discover_weekly, "radio": radio, "daily_mix": daily_mix, "chart": chart, "other": other, }, } return api_values @allure.step("Track page -> All Streams - get streams") def get_streams_values_all_streams(self): all_totals = "(//span[text()='Total']/following-sibling::*)[{}]" daily_avg = "(//span[text()='Daily Avg']/following-sibling::span)[{}]" total_locator = all_totals.format(1) dsp_locator = all_totals.format(2) total_daily_avg_locator = daily_avg.format(1) dsp_daily_avg_locator = daily_avg.format(2) self.page_has_loaded() dsp_value = "0" dsp_percentage = "0" dsp_daily_avg = "0" total = "0" total_daily_avg = "0" if len(self.get_elements(dsp_locator, "xpath")) > 0: dsp_value = int(str(self.get_text(dsp_locator, "xpath")).split("\n")[0].replace(",", "").replace("N/A", "0").replace("None", "0")) dsp_percentage = float(str(self.get_text(dsp_locator, "xpath")).split("\n")[1].replace("(", "").replace(")", "").replace("%", "").replace("N/A", "0").replace("None", "0")) dsp_daily_avg = int(str(self.get_text(dsp_daily_avg_locator, "xpath")).replace(",", "").replace("N/A", "0").replace("None", "0")) if len(self.get_elements(total_locator, "xpath")) > 0: total = int(str(self.get_text(total_locator, "xpath")).replace(",", "").replace("N/A", "0").replace("None", "0")) total_daily_avg = int(str(self.get_text(total_daily_avg_locator, "xpath")).replace(",", "").replace("N/A", "0").replace("None", "0")) values = dict( zip( ["dsp_value", "dsp_percentage", "dsp_daily_avg" "total_value", "total_daily_avg"], [dsp_value, dsp_percentage, dsp_daily_avg, total, total_daily_avg], ) ) self.log.info("values from track page: {}".format(values)) return values @allure.step("Track page - get save and skips from api") def get_api_save_and_skips_spotify(self, isrcs, start_date, end_date, markets, token): response_api = [self.api_client.get_spotify_demographics_delphi_isrcs(isrcs=isrcs, start_date=start_date, end_date=end_date, market=m, token=token) for m in markets] self.log.info("Save and skips: {}".format(response_api)) streams = sum(response_api[k]["body"][0]["streams"] for k in range(len(markets)) if response_api[k]["body"] if response_api[k]["body"][0]["market"] in markets) saves = sum(response_api[k]["body"][0]["saves"]["total"] for k in range(len(markets)) if response_api[k]["body"] if response_api[k]["body"][0]["market"] in markets) saves_and_skips = dict(zip(["streams", "saves"], [streams, saves])) self.log.info("Saves and skips: {}".format(saves_and_skips)) return saves_and_skips @allure.step("Track page - get save and skips from api") def get_api_age_gender_values_spotify(self, start_date, end_date, markets, isrc, token): api_age_gender_resp = [ self.get_streams_age_gender_api( dsp=AppConfig.get("dsp")["spotify"], market=m, isrc=isrc, start_date=start_date, end_date=end_date, token=token, ) for m in markets ] self.log.info(f"Age groups tooltip info: {api_age_gender_resp}") # age_groups age_values = list(numpy.array([a["ages"] for a in api_age_gender_resp]).sum(axis=0)) # gender values gender_values = list(numpy.array([a["genders"] for a in api_age_gender_resp]).sum(axis=0)) api_age_gender_values = {"ages": age_values, "genders": gender_values} self.log.info(f"api values for graph legend: {api_age_gender_values}") return api_age_gender_values @allure.step("TP - TD Youtube verify hint for last date trend") def td_youtube_verify_hover_trend_column_value(self, position, diff_views, tab="date_trends"): if tab == "date_trends": column = 1 last_date = self.td_youtube_get_views_date() previous_date = (datetime.datetime.strptime(last_date, "%Y-%m-%d") - datetime.timedelta(days=1)).date() else: column = 2 last_date = self.td_youtube_get_views_date() previous_date = (datetime.datetime.strptime(last_date, "%Y-%m-%d") - datetime.timedelta(days=6)).date() last_date_2 = (datetime.datetime.strptime(last_date, "%Y-%m-%d") - datetime.timedelta(days=7)).date() previous_date_2 = (datetime.datetime.strptime(last_date, "%Y-%m-%d") - datetime.timedelta(days=13)).date() last_date_2 = datetime.datetime.strptime(str(last_date_2), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) previous_date_2 = datetime.datetime.strptime(str(previous_date_2), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) last_date = datetime.datetime.strptime(last_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) previous_date = datetime.datetime.strptime(str(previous_date), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) self.hover_on_element( locator=f"//*[@id='youtube-table-cell-views-end-date-trend-{position + 1}'][{column}]//../span", locator_type="xpath", ) hint = self.get_text(locator=self.hint_locator, locator_type="xpath") if diff_views > 0: more_less = "more" else: more_less = "less" if column == 1: hint_expected = f"{abs(diff_views):,} views {more_less} on {last_date} than {previous_date}" else: hint_expected = f"{abs(diff_views):,} views {more_less} on {previous_date}–\n{last_date} than {previous_date_2}–{last_date_2}" assert_that(hint_expected).is_equal_to(hint) @allure.step("TP - TD Youtube change sources") def youtube_change_sources(self, param, dd="td", apply=True): self.is_graph_period_displayed() self.wait_for_element_visible(*self.locator(self.track_locators, f"{dd}_youtube_sources_dd")) time.sleep(4) dd = self.wait_for_element_clickable(*self.locator(self.track_locators, f"{dd}_youtube_sources_dd")) self.click_on_element_js(element=dd) checkboxes_all = self.get_elements("//input[contains(@id, 'Key Sources') or contains(@id, 'Other Sources')]", "xpath") apply_button = self.wait_for_element_visible(locator=self.apply_button_loc, locator_type="xpath") color_default = apply_button.value_of_css_property("background-color") for c in checkboxes_all: self.click_on_element_js(element=c) for c in checkboxes_all: if self.get_attribute_value(element=c, attribute="data-checked") == "checked": self.click_on_element_js(element=c) color_uncheck_all = apply_button.value_of_css_property("background-color") for p in param: item = self.get_element(locator=f"//input[contains(@id, '{p}')]", locator_type="xpath") self.click_on_element_js(element=item) color_checked = apply_button.value_of_css_property("background-color") assert_that(color_default).is_equal_to(color_uncheck_all) assert_that(color_uncheck_all).is_not_equal_to(color_checked) if apply: self.dd_click_apply() @allure.step("TP - DSP change sources") def dsp_change_sources(self, param, apply=True): all_source_id = "All Sources " dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "dsp_sources_dd")) self.click_on_element_js(element=dd) apply_button = self.wait_for_element_visible(locator=self.apply_button_loc, locator_type="xpath") color_default = apply_button.value_of_css_property("background-color") self.click_element(all_source_id) if self.get_attribute_value(element=self.get_element(all_source_id), attribute="data-checked") == "checked": self.click_on_element_js(element=self.get_element(all_source_id)) color_uncheck_all = apply_button.value_of_css_property("background-color") for p in param: item = self.get_element(locator=f"//input[contains(@id, '{p}')]", locator_type="xpath") self.click_on_element_js(element=item) color_checked = apply_button.value_of_css_property("background-color") assert_that(color_default).is_equal_to(color_uncheck_all) assert_that(color_uncheck_all).is_not_equal_to(color_checked) if apply: self.dd_click_apply() @allure.step("TP - switch yo Youtube Performance tab") def switch_to_youtube_video_performance(self): tab = self.wait_for_element_clickable(*self.locator(self.track_locators, "track-performance-youtube")) self.click_element(element=tab) self.wait_for_element_visible(*self.locator(self.track_locators, "track-performance-export-btn")) self.wait_for_element_clickable(*self.locator(self.track_locators, "track-performance-export-btn")) time.sleep(3) self.is_youtube_video_performance_selected() @allure.step("TP - is Youtube Performance tab selected") def is_youtube_video_performance_selected(self): self.scroll_to_element(*self.locator(self.track_locators, "track-performance-youtube")) self.is_tab_selected(*self.locator(self.track_locators, "track-performance-youtube")) @allure.step("TP - Youtube Performance get legend values UI") def youtube_performance_get_legend_values(self): sources = self.get_current_source() legend_values = {} self.is_graph_period_displayed() if sources == AppConfig.get("source")["by_source"]: lean_values = self.get_lean_values() if not self.is_youtube_video_page_opened(): total_sel = "//*[contains(@id, 'total')]/..//*[contains(@id, '-value')]" self.wait_for_element_visible(locator=total_sel, locator_type="xpath") totals = self.get_elements(locator=total_sel, locator_type="xpath") totals = [int(self.get_text(element=t).replace(",", "")) for t in totals] legend_values["views_in_period"] = totals[0] legend_values["views_day"] = totals[1] legend_values["lean_forward_by_source"] = lean_values["lean_forward_by_source"] legend_values["lean_back_by_source"] = lean_values["lean_back_by_source"] legend_values["lb_avg"] = lean_values["lb_avg"] legend_values["lf_avg"] = lean_values["lf_avg"] legend_values["lb_perc"] = lean_values["lb_perc"] legend_values["lf_perc"] = lean_values["lf_perc"] legend_values["age_values"] = self.get_age_groups_tooltip_info(global_age=True)["percentage"] legend_values["gender_values"] = self.get_gender_groups_tooltip_info(global_gender=True)["percentage"] elif sources == AppConfig.get("source")["lf_lb"]: selector = "//*[contains(@id, 'legend')]//../span[2]" self.wait_for_element_visible(locator=selector, locator_type="xpath") values = self.get_elements(locator=selector, locator_type="xpath") legend_values = [self.get_text(element=v).replace(",", "").replace("%", "") for v in values] self.log.info(f"legend_values ui: {legend_values}") return legend_values @allure.step("TP - Youtube Performance get legend values API") def youtube_performance_get_legend_values_api(self, markets, isrc, video_ids): if self.is_youtube_video_page_opened() and self.is_tab_selected_no_assert(locator="youtube-markets"): markets = "%2C".join(markets) else: markets_dd = self.graph_get_selected_market(dd="youtube_vp") if "All Markets" != markets_dd and "Market" in markets_dd: markets = self.parameter_from_url(self.str_gr_country) else: markets = "%2C".join(markets) sources = self.get_current_source() legend_values = {} self.wait_for_element_clickable(*self.locator(self.track_locators, "full_performance_export_btn")) start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() api_responses_video_analytics = [self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=markets, video_id=v) for v in video_ids] legend_values["views_in_period"] = sum(sum(v["metrics"]["views"] for v in a) for a in api_responses_video_analytics) days_count = [] for resp in api_responses_video_analytics: days_count.append(len(set([v["dimensions"]["date"] for v in resp]))) days_count = max(days_count) legend_values["views_day"] = int(legend_values["views_in_period"] / days_count) if not (self.is_youtube_video_page_opened() and self.is_tab_selected_no_assert(locator="youtube-markets")): if sources in [AppConfig.get("source")["by_source"], AppConfig.get("source")["lf_lb"]]: by_source_values = self.youtube_vp_get_legend_values_by_source_api(markets=markets, video_ids=video_ids, days_count=days_count, isrc=isrc, values_api=legend_values) legend_values.update(by_source_values) self.log.info(f"legend_values api: {legend_values}") return legend_values @allure.step("TP - Youtube Performance tab get api values for by source legend") def youtube_vp_get_legend_values_by_source_api(self, markets, video_ids, days_count, isrc, values_api): lf_keys = [ "youtube_search", "shorts", "youtube_channels", "external", "direct_or_unknown", "interactive_video_endscreen", "notifications", "video_cards_and_annotations", "programming_from_claimed_content", "stories", ] lb_keys = [ "suggested_videos", "playlists", "browse_features", "other_youtube_features", "playlist_pages", "youtube_advertising", ] legend_values = {} start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() api_responses_video_analytics = [self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=markets, video_id=v) for v in video_ids] legend_values["lean_forward_by_source"] = [] legend_values["lean_back_by_source"] = [] for k in lf_keys: legend_values["lean_forward_by_source"].append(sum(sum(v["metrics"]["traffic_source_types"][k] for v in a) for a in api_responses_video_analytics)) for k in lb_keys: legend_values["lean_back_by_source"].append(sum(sum(v["metrics"]["traffic_source_types"][k] for v in a) for a in api_responses_video_analytics)) lf_lb_sum = sum(legend_values["lean_forward_by_source"]) + sum(legend_values["lean_back_by_source"]) legend_values["lb_avg"] = [self.apply_rounding_percentage(l / days_count) for l in legend_values["lean_back_by_source"]] legend_values["lf_avg"] = [self.apply_rounding_percentage(l / days_count) for l in legend_values["lean_forward_by_source"]] legend_values["lb_perc"] = [round(l / lf_lb_sum * 100, 1) if (lf_lb_sum > 0) else 0 for l in legend_values["lean_back_by_source"]] legend_values["lf_perc"] = [round(l / lf_lb_sum * 100, 1) if (lf_lb_sum > 0) else 0 for l in legend_values["lean_forward_by_source"]] demogrpahics = self.youtube_vp_get_legend_values_demographics_api(start_date=start_date, end_date=end_date, isrc=isrc, video_ids=video_ids) legend_values.update(demogrpahics) return legend_values @allure.step("TP - Youtube Performance tab get api values for demographics legend") def youtube_vp_get_legend_values_demographics_api(self, start_date, end_date, isrc, video_ids): age_keys = ["all_13_17", "all_18_24", "all_25_34", "all_35_44", "all_45_54", "all_55_64", "all_65_plus"] gender_keys = ["female", "male", "unknown"] api_responses_video_analytics_demographics = self.api_client.get_video_analytics_demographics(start_date=start_date, end_date=end_date, market=AppConfig.get("market")["global"]["api"], isrc=isrc) age_lists = [] gender_lists = [] for id in video_ids: sum_percentage_demographics = self.apply_rounding_percentage(sum(d["metrics"]["age_band_views_percentages"][k] for k in age_keys for d in api_responses_video_analytics_demographics if id == d["dimensions"]["video_id"])) self.log.info(f"sum percentage demographics: {sum_percentage_demographics}") if sum_percentage_demographics == 100: self.log.info(f"sum_percentage_demographics: {sum_percentage_demographics}, video_id: {id}") age_lists.append([v["metrics"]["age_band_views_percentages"][k] for k in age_keys for v in api_responses_video_analytics_demographics if id == v["dimensions"]["video_id"]]) gender_lists.append([v["metrics"]["gender_views_percentages"][k] for k in gender_keys for v in api_responses_video_analytics_demographics if id == v["dimensions"]["video_id"]]) self.log.info(f"age lists: {age_lists}, gender lists: {gender_lists}") legend_values = { "age_v": [round(sum(x) / len(age_lists), 1) for x in zip(*age_lists)], "gender_v": [round(sum(x) / len(gender_lists), 1) for x in zip(*gender_lists)], } self.log.info(f'ages: {legend_values["age_v"]}\n genders: {legend_values["gender_v"]}') if self.apply_rounding_percentage(sum(legend_values["age_v"])) == 100: legend_values["age_values"] = legend_values["age_v"] legend_values["gender_values"] = legend_values["gender_v"] self.log.info(f'in if ages: {legend_values["age_values"]}\n genders: {legend_values["gender_values"]}') else: legend_values["age_values"] = [0, 0, 0, 0, 0, 0, 0] legend_values["gender_values"] = [0, 0, 0] return legend_values @allure.step("TP - Youtube Performance tab verify legend") def verify_legend_video_performance(self, markets, isrc, video_ids): legend_values_ui = self.youtube_performance_get_legend_values() values_api = self.youtube_performance_get_legend_values_api(markets=markets, isrc=isrc, video_ids=video_ids) values_to_verify = [ "lean_forward_by_source", "lean_back_by_source", "lb_avg", "lf_avg", "lb_perc", "lf_perc", "age_values", "gender_values", ] if not self.is_youtube_video_page_opened(): values_to_verify = values_to_verify + ["views_in_period", "views_day"] for i in values_to_verify: assert_that(legend_values_ui[i]).described_as(i).is_equal_to(values_api[i]) return legend_values_ui @allure.step("TP - TD Youtube sort by column") def td_youtube_sort_by_column(self, column): self.scroll_to_track_details() column_header = self.wait_for_element_clickable(locator=f"youtube-table-cell-{column}") self.click_element(element=column_header) @allure.step("TP - TD Youtube check videos") def vp_youtube_check_videos(self, count, ordered=False): select_all_selector = "youtube-video-selector-select-all" video_checkboxes_selector = "//input[contains(@id, 'youtube-video-selector-select-youtube')]" self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) control = self.wait_for_element_clickable(self.vp_youtube_selected_videos) self.click_element(element=control) all_checkbox = self.get_element(select_all_selector) self.click_on_element_js(element=all_checkbox) all_checkbox = self.get_element(select_all_selector) self.click_on_element_js(element=all_checkbox) if self.is_checked(select_all_selector, "id"): self.click_on_element_js(element=all_checkbox) video_checkboxes = list(self.get_elements(locator=video_checkboxes_selector, locator_type="xpath")) for c in list(range(0, count)): if ordered: e = video_checkboxes[c] else: e = random.choice(video_checkboxes) video_checkboxes.remove(e) self.click_on_element_js(element=e) self.dd_click_apply() @allure.step("TP - VP Youtube verify footnote") def vp_youtube_verify_footnote_and_legend(self): footnote_sel = "//span[contains(., '* For questions, email dataanalytics@sonymusic.com.')]" legend_headers_sel = "//*[@id='track-streams-legend-youtube-total']/..//span[string-length(text()) > 0 and not(contains(text(), '%'))][1]" if not self.is_youtube_video_page_opened(): self.scroll_to_element(*self.locator(self.track_locators, "track-performance-youtube")) footnote = self.wait_for_element_visible(locator=footnote_sel, locator_type="xpath") self.wait_for_element_visible(locator=legend_headers_sel, locator_type="xpath") legend_headers = self.get_elements(locator=legend_headers_sel, locator_type="xpath") legend_headers = [self.get_text(element=l) for l in legend_headers] video_dd_selector = self.nvp_youtube_selected_videos if not self.is_youtube_video_page_opened(): video_dd_selector = self.vp_youtube_selected_videos videos_dd_value = self.get_text(locator=video_dd_selector) legend_exp = ["ALL VIEWS IN PERIOD", "Total", "Daily Avg"] if videos_dd_value != "All Videos": legend_exp = legend_exp + ["SELECTED VIDEOS VIEWS IN PERIOD", "Total", "Daily Avg"] assert_that(self.is_element_displayed(element=footnote)).is_true() assert_that(legend_headers).is_equal_to(legend_exp) @allure.step("TP - VP Youtube change view") def vp_youtube_change_source_view(self, param): chosen_item_sel = "//*[contains(@id, 'performance-views-by-sources-dd')]/span[string-length(text()) > 0]" value_el = self.wait_for_element_visible(locator=chosen_item_sel, locator_type="xpath") value_current = self.get_text(element=value_el) if value_current != param: dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "track-performance-views-by-sources-dd")) self.click_element(element=dd) item = self.get_element( locator=f"//*[contains(@id, 'performance-views-by-sources-dd')]/..//*[text()='{param}']", locator_type="xpath", ) self.click_on_element_js(element=item) value = self.wait_for_element_visible(locator=chosen_item_sel, locator_type="xpath") value = self.get_text(element=value) assert_that(value).is_equal_to(param) @allure.step("TP - VP Youtube verify view") def vp_youtube_verify_view(self, param): chosen_item_sel = "//*[contains(@id, 'performance-views-by-sources-dd')]/span" self.wait_for_element_clickable(locator=chosen_item_sel, locator_type="xpath") value_el = self.wait_for_element_visible(locator=chosen_item_sel, locator_type="xpath") value_current = self.get_text(element=value_el) assert_that(value_current).is_equal_to(param) @allure.step("TP - VP Youtube get legend values All Views") def vp_youtube_get_legend_all_views(self): legend_values_sel = "//*[@id='track-streams-legend-youtube-total']/..//*[string-length(text()) > 0][2]" self.wait_for_element_clickable(*self.locator(self.track_locators, "full_performance_export_btn")) self.wait_for_element_visible(locator=legend_values_sel, locator_type="xpath") legend_values = self.get_elements(locator=legend_values_sel, locator_type="xpath") videos_dd_selector = self.vp_youtube_selected_videos if self.is_youtube_video_page_opened(): videos_dd_selector = self.nvp_youtube_selected_videos videos_dd_value = self.get_text(locator=videos_dd_selector) if videos_dd_value == "All Videos": legend_values = [int(self.get_text(element=l).replace(",", "")) for l in legend_values] else: legend_values = [self.get_text(element=l).replace(",", "").replace("(", "").replace(")", "").replace("%", "") for l in legend_values] legend_values = [ int(legend_values[0]), int(legend_values[1]), int(legend_values[2].split("\n")[0]), float(legend_values[2].split("\n")[1]), int(legend_values[3]), ] self.log.info(f"legend values ui: {legend_values}") return legend_values @allure.step("TP - VP Youtube get legend table KPI") def vp_youtube_get_kpi_table(self): table = {} source = self.get_element( locator="//*[contains(@id, 'performance-views-by-sources-dd')]/*[string-length(text()) > 0]", locator_type="xpath", ) source = self.get_text(element=source) columns = self.columns_vp_yt_kpi if source == AppConfig.get("source")["by_avg_view_duration"]: columns = [self.column_video_title, self.column_avg_view_duration] elif source == AppConfig.get("source")["by_likes"]: columns = [ self.column_video_title, "likes-in-period", "avg-likes-per-day", # "likes-dislikes-ration" ] elif source == AppConfig.get("source")["by_dislikes"]: columns = [ self.column_video_title, "dislikes-in-period", "avg-dislikes-per-day", # "likes-dislikes-ration" ] elif source == AppConfig.get("source")["by_comments"]: columns = [self.column_video_title, "comments-in-period", "avg-comments-per-day"] elif source == AppConfig.get("source")["by_shares"]: columns = [self.column_video_title, "shares-in-period", "avg-shares-per-day"] # self.wait_for_element_visible(locator="//*[text()='Date']", locator_type="xpath") # self.scroll_to_element(locator="//*[text()='Date']", locator_type="xpath") for c in columns: elements = self.get_elements(locator=f'//*[contains(@id, "table-kpi-table-cell-{c}-")][string-length(.) > 0]', locator_type="xpath") table[c] = [self.get_text(element=e).replace(",", "").replace("%", "").replace("of", "") for e in elements] if c in [ "views-7-days", "trend-views-7-days", "avg-views-per-day", "avg-likes-per-day", "avg-dislikes-per-day", "likes-dislikes-ration", "avg-comments-per-day", "avg-shares-per-day", ]: self.log.info(f"column kpi: {c}") table[c] = [int(e.replace("NAN", "0")) for e in table[c]] assert_that(table["video-title"][-1]).is_equal_to("Total") # according to the AP-5862 Avg view duration is disabled for now # if source in [AppConfig.get("source")["by_avg_view_duration"], AppConfig.get("source")["by_video"]]: # sum_duration = self.apply_rounding_percentage( # sum(int(d.split(" ")[0]) for d in table[self.column_avg_view_duration][:-1]) # / len(table[self.column_avg_view_duration][:-1]) # ) # diff = sum_duration - int(table[self.column_avg_view_duration][-1]) # self.ts.markFinal(diff in list(range(-1, 2)), f"diff: {diff}") self.log.info(f"kpi table: {table}") return table @allure.step("TP - VP Youtube verify KPI columns hover") def vp_youtube_kpi_verify_columns_hover(self): latest_date = self.api_client.get_latest_date_all()["youtube"] latest_date = datetime.datetime.strptime(latest_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) week_date = str((datetime.datetime.strptime(latest_date, self.get_date_format_from_locale()) - datetime.timedelta(days=6)).date()) week_date = (datetime.datetime.strptime(week_date, "%Y-%m-%d")).strftime(self.get_date_format_from_locale()) two_weeks_date = str((datetime.datetime.strptime(latest_date, self.get_date_format_from_locale()) - datetime.timedelta(days=13)).date()) two_weeks_date = (datetime.datetime.strptime(two_weeks_date, "%Y-%m-%d")).strftime(self.get_date_format_from_locale()) start_date_ui = self.get_calendar_start_date() end_date_ui = self.get_calendar_end_date() calendar_start_date = datetime.datetime.strptime(start_date_ui, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) calendar_end_date = datetime.datetime.strptime(end_date_ui, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) start_end = f"{calendar_start_date}–{calendar_end_date}" names = [] page = "track" if self.is_youtube_video_page_opened(): page = "youtube" source = self.wait_for_element_visible( locator=f"//*[@id='{page}-performance-views-by-sources-dd']/*[string-length(text()) > 0]", locator_type="xpath", ) source = self.get_text(element=source) title = "Title" hints_exp = [ f"{week_date}–{latest_date}", f"Views have to be available\nfor two weeks ({two_weeks_date}–{latest_date})\nfor the trend to calculate.", start_end, start_end, start_end, ] avg_in_period_view_duration = "Avg, In Period\nView Duration" # according to the AP-5862 Avg view duration is disabled for now # names_exp = [ # title, # "7 Days\nViews", # "Views, 7 Days\nTrend", # "In Period\nViews", # "Avg, In Period\nViews/Day", # avg_in_period_view_duration, # ] names_exp = [title, "7 Days\nViews", "Views, 7 Days\nTrend", "In Period\nViews", "Avg, In Period\nViews/Day"] columns = self.columns_vp_yt_kpi if source == AppConfig.get("source")["by_avg_view_duration"]: names_exp = [title, avg_in_period_view_duration] columns = [self.column_video_title, self.column_avg_view_duration] hints_exp = [start_end] elif source == AppConfig.get("source")["by_likes"]: names_exp = [ title, "In Period\nLikes", "Avg, In Period\nLikes/Day", # "In Period\nLikes Ratio" ] columns = [self.column_video_title, "likes-in-period", "avg-likes-per-day", "likes-dislikes-ration"] hints_exp = [start_end, start_end, ""] elif source == AppConfig.get("source")["by_dislikes"]: names_exp = [ title, "In Period\nDislikes", "Avg, In Period\nDislikes/Day", # "In Period\nLikes Ratio" ] columns = [self.column_video_title, "dislikes-in-period", "avg-dislikes-per-day", "likes-dislikes-ration"] hints_exp = [start_end] elif source == AppConfig.get("source")["by_comments"]: names_exp = [title, "In Period\nComments", "Avg, In Period\nComments/Day"] columns = [self.column_video_title, "comments-in-period", "avg-comments-per-day"] hints_exp = [start_end, start_end] elif source == AppConfig.get("source")["by_shares"]: names_exp = [title, "In Period\nShares", "Avg, In Period\nShares/Day"] columns = [self.column_video_title, "shares-in-period", "avg-shares-per-day"] hints_exp = [start_end, start_end] for c in columns: names.append(self.get_text(locator=f"{page}-table-kpi-table-cell-{c}")) hints = [] self.scroll_to_element(locator="//*[text()='Date']", locator_type="xpath") if source == AppConfig.get("source")["by_video"]: columns_hover = self.columns_vp_yt_kpi[1:] else: columns_hover = columns[1:-1] for c in columns_hover: self.hover_on_element(locator=f"{page}-table-kpi-table-cell-{c}") hints.append(self.get_text(*self.locator(self.track_locators, "tooltip"))) for he, h in zip(hints_exp, hints): assert_that(he).is_equal_to(h) self.hover_on_element(locator="//*[text()='Date']", locator_type="xpath") names = [str(n) for n in names if str(n) != "None"] assert_that(names_exp).is_equal_to(names) @allure.step("TP - VP Youtube KPI click on column to sort") def vp_youtube_click_column(self, column): page = "track" if self.is_youtube_video_page_opened(): page = "youtube" c = self.get_element(locator=f"{page}-table-kpi-table-cell-{column}") self.click_on_element_js(element=c) self.hover_on_element(locator=f"{page}-table-kpi-table-cell-video-title-1") @allure.step("TP - VP Youtube KPI verify string all columns") def vp_youtube_kpi_verify_sorting(self): columns = self.columns_vp_yt_kpi page = "track" if self.is_youtube_video_page_opened(): page = "youtube" source = self.get_element( locator=f"//*[@id='{page}-performance-views-by-sources-dd']/*[string-length(text()) > 0]", locator_type="xpath", ) source = self.get_text(element=source) if source == AppConfig.get("source")["by_avg_view_duration"]: columns = [self.column_video_title, self.column_avg_view_duration] elif source == AppConfig.get("source")["by_likes"]: columns = [ self.column_video_title, "likes-in-period", "avg-likes-per-day", # "likes-dislikes-ration" ] elif source == AppConfig.get("source")["by_dislikes"]: columns = [ self.column_video_title, "dislikes-in-period", "avg-dislikes-per-day", # "likes-dislikes-ration" ] elif source == AppConfig.get("source")["by_comments"]: columns = [self.column_video_title, "comments-in-period", "avg-comments-per-day"] elif source == AppConfig.get("source")["by_shares"]: columns = [self.column_video_title, "shares-in-period", "avg-shares-per-day"] for column in columns: self.vp_youtube_click_column(column=column) values_desc = self.vp_youtube_get_kpi_table()[column][:-1] self.vp_youtube_click_column(column=column) values_asc = self.vp_youtube_get_kpi_table()[column][:-1] if column != "trend-views-7-days": if column != self.column_video_title: values_asc = [int(v.split(" ")[0].split("\n")[0]) for v in values_asc if not isinstance(v, int)] values_desc = [int(v.split(" ")[0].split("\n")[0]) for v in values_desc if not isinstance(v, int)] assert_that(values_desc).is_sorted(reverse=True) assert_that(values_asc).is_sorted() else: min_val = min(values_asc) min_trend_index = values_asc.index(min_val) values_asc = values_asc[:min_trend_index] values_desc = values_asc[:min_trend_index] assert_that(values_asc == sorted(values_asc) or values_asc == sorted(values_asc, reverse=True)).described_as(values_asc).is_true() assert_that(values_desc == sorted(values_desc) or values_desc == sorted(values_desc, reverse=True)).described_as(values_desc).is_true() @allure.step("TP - open NVP Youtube") def open_youtube_video_page(self, isrc, market): self.open_url(f"{CoreConfig.ENV_BASE_URL}/youtube/video/{isrc}?market={market}") @allure.step("TP - is NVP Youtube page opened") def is_youtube_video_page_opened(self): url = self.get_url() opened = False if "/youtube/video/" in url: opened = True return opened @allure.step("TP - VP Youtube KPI verify calculations") def kpi_verify_calculations(self, markets, video_id=""): if video_id == "": self.vp_youtube_click_column(column="video-title") self.td_youtube_sort_by_column(column="title") video_id = self.td_youtube_get_all_from_table()["video_ids"][0] kpi_table = self.vp_youtube_get_kpi_table() youtube_latest_date = self.api_client.get_latest_date_all()["youtube"] latest_minus_7 = (datetime.datetime.strptime(youtube_latest_date, "%Y-%m-%d") - datetime.timedelta(days=6)).date() api_resp = self.api_client.get_video_analytics(video_id=video_id, market="%2C".join(markets), start_date=latest_minus_7, end_date=youtube_latest_date) in_period_views_api = sum(sum(v["metrics"]["traffic_source_types"][k] for k in self.youtube_all_sources) for v in api_resp) assert_that(in_period_views_api).is_equal_to(kpi_table["views-7-days"][0]) youtube_minus_7 = (datetime.datetime.strptime(youtube_latest_date, "%Y-%m-%d") - datetime.timedelta(days=7)).date() youtube_minus_14 = (datetime.datetime.strptime(youtube_latest_date, "%Y-%m-%d") - datetime.timedelta(days=13)).date() api_resp_period = self.api_client.get_video_analytics(video_id=video_id, market="%2C".join(markets), start_date=youtube_minus_14, end_date=youtube_minus_7) previous_views_api = sum(sum(v["metrics"]["traffic_source_types"][k] for k in self.youtube_all_sources) for v in api_resp_period) views_diff = in_period_views_api - previous_views_api if previous_views_api != 0: trend_7_days_api = views_diff / previous_views_api * 100 else: trend_7_days_api = 0 assert_that(abs(self.apply_rounding_percentage(trend_7_days_api))).is_equal_to(kpi_table["trend-views-7-days"][0]) start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() api_resp_period = self.api_client.get_video_analytics(video_id=video_id, market="%2C".join(markets), start_date=start_date, end_date=end_date) views_in_period = sum(v["metrics"]["views"] for v in api_resp_period) assert_that(views_in_period).is_equal_to(int(kpi_table["views-in-period"][0].split("\n")[0])) days_count = len(set(d["dimensions"]["date"] for d in api_resp_period)) avg_per_day = self.apply_rounding_percentage(views_in_period / days_count) self.ts.markFinal( avg_per_day - int(kpi_table["avg-views-per-day"][0]) in list(range(-1, 2)), f'{avg_per_day}, {int(kpi_table["avg-views-per-day"][0])}', ) # according to the AP-5862 Avg view duration is disabled for now # avg_duration_api = self.apply_rounding_percentage( # sum(v["metrics"]["average_view_duration_percentage"] for v in api_resp_period) / (days_count * len(markets)) # ) # assert_that(avg_duration_api).is_equal_to(int(kpi_table["avg-views-duration-percent"][0].split(" ")[0])) @allure.step("TP - NVP Youtube check videos") def nvp_youtube_check_videos(self, count): select_all_selector = "youtube-video-selector-select-all" video_checkboxes_selector = "//input[contains(@id, 'youtube-video-selector-select-youtube')]" control = self.wait_for_element_clickable("youtube-videos-control") self.click_element(element=control) all_checkbox = self.get_element(select_all_selector) self.click_on_element_js(element=all_checkbox) self.click_on_element_js(element=all_checkbox) if self.is_checked(select_all_selector, "id"): self.click_on_element_js(element=all_checkbox) video_checkboxes = list(self.get_elements(locator=video_checkboxes_selector, locator_type="xpath")) for c in list(range(0, count)): e = random.choice(video_checkboxes) self.click_on_element_js(element=e) video_checkboxes.remove(e) self.dd_click_apply() @allure.step("TP - NVP Youtube check videos by index") def nvp_youtube_check_videos_by_indexes(self, indexes): select_all_selector = "youtube-video-selector-select-all" video_checkboxes_selector = "//input[contains(@id, 'youtube-video-selector-select-youtube')]" self.is_graph_period_displayed() control = self.wait_for_element_clickable("youtube-videos-control") self.click_on_element_js(element=control) time.sleep(2) self.wait_for_element_visible(select_all_selector) all_checkbox = self.get_element(select_all_selector) self.click_on_element_js(element=all_checkbox) time.sleep(2) self.click_on_element_js(element=all_checkbox) all_checkbox = self.get_element(select_all_selector) if self.is_checked(select_all_selector, "id"): self.click_on_element_js(element=all_checkbox) video_checkboxes = list(self.get_elements(locator=video_checkboxes_selector, locator_type="xpath")) for c in indexes: self.click_on_element_js(element=video_checkboxes[c]) self.dd_click_apply() @allure.step("TP - TD Youtube select video type") def td_youtube_select_type(self, param): self.scroll_to_track_details() dd = self.wait_for_element_clickable(locator="track-details-youtube-type-dd") self.click_element(element=dd) all_types_loc = "//*[contains(@id, 'All Types')]" self.click_element(locator=all_types_loc, locator_type="xpath") if self.is_checked(locator=all_types_loc, locator_type="xpath"): self.click_element(locator=all_types_loc, locator_type="xpath") self.click_element(locator=f"//*[contains(@id, '{param}')]", locator_type="xpath") self.dd_click_apply() @allure.step("TP - VP Youtube verify video dd selected") def vp_youtube_verify_selected_videos_dd(self, param): selected_videos = self.vp_youtube_get_selected_videos_dd() assert_that(param).is_equal_to(selected_videos) @allure.step("TP - VP Youtube get video dd value") def vp_youtube_get_selected_videos_dd(self): self.page_has_loaded() self.is_graph_period_displayed() time.sleep(2) dd_selector = self.vp_youtube_selected_videos if self.is_youtube_video_page_opened(): dd_selector = self.nvp_youtube_selected_videos self.wait_for_element_clickable(locator=dd_selector) selected_videos = self.wait_for_element_visible(locator=dd_selector) return self.get_text(element=selected_videos) @allure.step("TP - verify chosen graph view dd") def verify_graph_view_chosen(self, param): dd = "//*[contains(@id, 'graph-type-dd')]/span" self.wait_for_element_clickable(locator=dd, locator_type="xpath") value = self.wait_for_element_visible(locator=dd, locator_type="xpath") assert_that(param).is_equal_to(self.get_text(element=value)) @allure.step("TP - verify chosen graph view dd") def get_graph_view_enabled_state(self): self.wait_for_element_visible(locator="track-performance-graph-type-dd") graph_view_state = self.is_enabled(locator="track-performance-graph-type-dd") self.log.info("Graph view state: " + str(graph_view_state)) return graph_view_state @allure.step("TP - VP Youtube KPI verify Avg duration percentage calculations") def kpi_verify_calculations_other_views(self, markets, video_id): self.vp_youtube_click_column(column="video-title") kpi_table = self.vp_youtube_get_kpi_table() start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() source = self.wait_for_element_visible( locator="//*[@id='track-performance-views-by-sources-dd']/*[string-length(text()) > 0]", locator_type="xpath", ) source = self.get_text(element=source) api_resp_period = self.api_client.get_video_analytics(video_id=video_id, market="%2C".join(markets), start_date=start_date, end_date=end_date) assert_that(kpi_table["video-title"][:-1] == sorted(kpi_table["video-title"][:-1], reverse=True) or kpi_table["video-title"][:-1] == natsorted(kpi_table["video-title"][:-1], reverse=True)).is_true() api_avg_values = {} for av in ["likes", "dislikes", "comments", "shares"]: sum_all = [] for m in markets: days_count = len([d["dimensions"]["date"] for d in api_resp_period if d["dimensions"]["country_code"] == m]) if days_count > 0: sum_all.append(sum(v["metrics"][av] for v in api_resp_period if v["dimensions"]["country_code"] == m) / days_count) api_avg_values[av] = self.apply_rounding_percentage(sum(sum_all)) if source == AppConfig.get("source")["by_avg_view_duration"]: self.verify_youtube_avg_view_duration(api_resp_period, kpi_table) elif source == AppConfig.get("source")["by_likes"]: self.verify_youtube_by_likes(api_resp_period, kpi_table, api_avg_values) elif source == AppConfig.get("source")["by_dislikes"]: self.verify_youtube_by_dislikes(api_resp_period, kpi_table, api_avg_values) elif source == AppConfig.get("source")["by_comments"]: self.verify_youtube_by_comments(api_resp_period, kpi_table, api_avg_values) elif source == AppConfig.get("source")["by_shares"]: self.verify_youtube_by_shares(api_resp_period, kpi_table, api_avg_values) @allure.step("TP - VP Youtube KPI verify Avg view duration calculations") def verify_youtube_avg_view_duration(self, api_resp_period, kpi_table): avg_duration_api = [] for market in list(set(m["dimensions"]["country_code"] for m in api_resp_period)): avg_duration_api.append( self.apply_rounding_percentage( sum(self.apply_rounding_percentage(v["metrics"]["average_view_duration_percentage"]) for v in api_resp_period if v["dimensions"]["country_code"] == market) / len(set(v["dimensions"]["date"] for v in api_resp_period if v["dimensions"]["country_code"] == market)) ) ) avg_duration_api = self.apply_rounding_percentage(sum(avg_duration_api) / len(list(set(m["dimensions"]["country_code"] for m in api_resp_period)))) assert_that(avg_duration_api).is_equal_to(int(kpi_table[self.column_avg_view_duration][0].split(" ")[0])) @allure.step("TP - VP Youtube KPI verify By Likes calculations") def verify_youtube_by_likes(self, api_resp_period, kpi_table, api_avg_values): likes = sum(v["metrics"]["likes"] for v in api_resp_period) # dilikes = sum(v["metrics"]["dislikes"] for v in api_resp_period) avg_likes = api_avg_values["likes"] # ratio = self.apply_rounding_percentage(likes / (likes + dilikes) * 100) likes_in_period_all_ui = [int(l.split("\n")[0]) for l in kpi_table["likes-in-period"]] self.vp_youtube_change_source_view(param=AppConfig.get("source")["by_dislikes"]) # dislikes_sum = int(self.vp_youtube_get_kpi_table()["dislikes-in-period"][-1]) self.vp_youtube_change_source_view(param=AppConfig.get("source")["by_likes"]) assert_that(likes).is_equal_to(likes_in_period_all_ui[0]) assert_that(sum(likes_in_period_all_ui[:-1])).is_equal_to(likes_in_period_all_ui[-1]) assert_that(avg_likes).is_equal_to(kpi_table["avg-likes-per-day"][0]) sum_likes = self.apply_rounding_percentage(sum(kpi_table["avg-likes-per-day"][:-1]) / len(kpi_table["avg-likes-per-day"][:-1])) sum_likes_ui = kpi_table["avg-likes-per-day"][-1] self.ts.markFinal(sum_likes - sum_likes_ui in list(range(-1, 2)), f"{sum_likes} and {sum_likes_ui} match") # assert_that(ratio).is_equal_to(kpi_table["likes-dislikes-ration"][0]) # assert_that( # self.apply_rounding_percentage( # (int(kpi_table["likes-in-period"][-1]) / (int(kpi_table["likes-in-period"][-1]) + dislikes_sum)) * 100 # ) # ).is_equal_to(kpi_table["likes-dislikes-ration"][-1]) @allure.step("TP - VP Youtube KPI verify By Dislikes calculations") def verify_youtube_by_dislikes(self, api_resp_period, kpi_table, api_avg_values): # likes = sum(v["metrics"]["likes"] for v in api_resp_period) dislikes = sum(v["metrics"]["dislikes"] for v in api_resp_period) avg_dislikes = api_avg_values["dislikes"] # ratio = self.apply_rounding_percentage(likes / (likes + dislikes) * 100) assert_that(dislikes).is_equal_to(int(kpi_table["dislikes-in-period"][0].split("\n")[0])) assert_that(avg_dislikes).is_equal_to(kpi_table["avg-dislikes-per-day"][0]) # assert_that(ratio).is_equal_to(kpi_table["likes-dislikes-ration"][0]) @allure.step("TP - VP Youtube KPI verify By Comments calculations") def verify_youtube_by_comments(self, api_resp_period, kpi_table, api_avg_values): comments = sum(v["metrics"]["comments"] for v in api_resp_period) avg_comments = api_avg_values["comments"] comments_all_ui = [int(c.split("\n")[0]) for c in kpi_table["comments-in-period"]] assert_that(comments).is_equal_to(comments_all_ui[0]) assert_that(sum(comments_all_ui[:-1])).is_equal_to(comments_all_ui[-1]) assert_that(avg_comments).is_equal_to(kpi_table["avg-comments-per-day"][0]) avg_comments_sum_ui = int(sum(kpi_table["avg-comments-per-day"][:-1]) / len(kpi_table["avg-comments-per-day"][:-1])) avg_comments_sum_api = kpi_table["avg-comments-per-day"][-1] self.ts.markFinal( avg_comments_sum_api - avg_comments_sum_ui in list(range(-1, 2)), f"{avg_comments_sum_api}, {avg_comments_sum_ui}", ) @allure.step("TP - VP Youtube KPI verify By Shares calculations") def verify_youtube_by_shares(self, api_resp_period, kpi_table, api_avg_values): shares = sum(v["metrics"]["shares"] for v in api_resp_period) avg_shares = api_avg_values["shares"] assert_that(shares).is_equal_to(int(kpi_table["shares-in-period"][0].split("\n")[0])) assert_that(avg_shares).is_equal_to(kpi_table["avg-shares-per-day"][0]) @allure.step("Track page - graph get color of item name in legend") def get_opacity_legend_item(self, item): e = self.wait_for_element_visible(locator=f"//*[text()='{item}']/parent::*", locator_type="xpath") opacity = e.value_of_css_property("opacity") self.log.info(f"opacity: {opacity}") return opacity @allure.step("Open current url in new browser tab") def open_current_url_in_new_tab(self): current_url = self.get_url() self.switch_to_browser_tab(2) self.open_url(current_url) @allure.step("Replace param in url") def replace_param_in_url(self, param, old, new): url_to_go = self.get_url().replace(f"{param}={old}", f"{param}={new}") self.open_url(url_to_go) @allure.step("Change param in url to new") def change_param_in_url_new(self, param, new): if param in self.get_url(): url_to_go = self.get_url().replace(f"{param}={self.parameter_from_url(param)}", f"{param}={new}") else: url_to_go = f"{self.get_url()}{param}={new}" self.open_url(url_to_go) @allure.step("TP - Open Video page from graph tab") def open_video_page_from_tab(self): tab = self.wait_for_element_clickable("track-performance-youtube-perf") self.click_element(element=tab) video_page_opened = self.is_youtube_video_page_opened() assert_that(video_page_opened).is_true() @allure.step("TP - TD Open Video page TD video tab") def td_open_video_page(self): selector = "//*[contains(@id, 'youtube-table-cell-title-')]//../a" self.scroll_to_element(*self.locator(self.track_locators, "youtube_tab")) self.wait_for_element_clickable(locator=selector, locator_type="xpath") titles = self.get_elements(locator=selector, locator_type="xpath") title = random.choice(titles) self.click_element(element=title) video_page_opened = self.is_youtube_video_page_opened() assert_that(video_page_opened).is_true() @allure.step("NVP - Youtube switch to Views By Market tab") def youtube_switch_to_views_by_market_tab(self): tab = self.wait_for_element_clickable("youtube-markets") self.click_on_element_js(element=tab) self.wait_for_element_clickable(locator="//*[contains(@class, 'export')]", locator_type="xpath") @allure.step("NVP - Youtube switch to Video Performance tab") def nvp_switch_to_video_performance_tab(self): tab = self.wait_for_element_clickable("youtube-videos") self.click_on_element_js(element=tab) self.wait_for_element_clickable(locator="//*[contains(@class, 'export')]", locator_type="xpath") @allure.step("Video page - verify whish tab is selected") def nvp_youtube_verify_tab_selected(self, tab): tab_locator = f"//*[@id='youtube-{tab}']" tab_selected = self.is_tab_selected(locator=tab_locator, locator_type="xpath") assert_that(tab_selected).is_true() @allure.step("TP - Youtube Views By Market change to markets") def nvp_youtube_change_top_markets(self, param): selector_dd = "youtube-full-performance-markets-dd" dd = self.wait_for_element_clickable(selector_dd) self.click_element(element=dd) item = self.get_element(locator=f"//*[@id='{selector_dd}']/..//*[text()='{param}']", locator_type="xpath") self.click_on_element_js(element=item) @allure.step("TP - Youtube Views By Market change view bar chart") def vdm_choose_graph_view_bar_chart(self): dd = self.wait_for_element_clickable( locator="(//*[@id='youtube-full-performance-graph-type-dd']/span[string-length(text()) > 0])[last()]", locator_type="xpath", ) self.click_element(element=dd) item = self.get_element(locator="//*[text()='Bar Chart']", locator_type="xpath") self.click_on_element_js(element=item) @allure.step("TP - Youtube Views By Market change view line graph") def vdm_choose_graph_view_line_graph(self): dd = self.wait_for_element_clickable( locator="(//*[@id='youtube-full-performance-graph-type-dd']/span[string-length(text()) > 0])[last()]", locator_type="xpath", ) self.click_element(element=dd) item = self.get_element(locator="//*[text()='Line Graph']", locator_type="xpath") self.click_on_element_js(element=item) @allure.step("Video Page - verify export button hover") def verify_nvp_export_button_hover(self): self.wait_for_element_visible(*self.locator(self.track_locators, "full_performance_export_btn")) # self.scroll_to_element(*self.locator(self.track_locators, "full_performance_export_btn")) export = self.get_element(*self.locator(self.track_locators, "full_performance_export_btn")) color_before = export.value_of_css_property("background-color") self.hover_on_element(*self.locator(self.track_locators, "full_performance_export_btn")) color_after = export.value_of_css_property("background-color") self.ts.markFinal(color_after != color_before, f"color: {color_before}\nafter: {color_after}") @allure.step("Video Page - Get track name") def get_nvp_track_name(self): track_name = self.wait_for_element_visible(*self.locator(self.track_locators, "full_performance_back_btn")) return self.get_text(element=track_name) @allure.step("Video Page - Navigate back from video page to track page") def navigate_back_from_video_page(self): self.wait_for_element_visible(*self.locator(self.track_locators, "full_performance_back_btn")) back_link = self.wait_for_element_clickable(*self.locator(self.track_locators, "full_performance_back_btn")) self.click_element(element=back_link) self.is_track_title_present() @allure.step("Video Page - verify export - File name, Date and Country for selected period") def nvp_vp_verify_file_name_export_date_country(self, track, param="", markets="", table_data=""): start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() selected_videos = self.vp_youtube_get_selected_videos_dd() track_name = self.get_text(locator="//*[@id='youtube-link-back-link-back' or @id='track-title']", locator_type="xpath") market_name = str(self.graph_get_selected_market()).replace("Markets", "markets") if market_name in self.REGIONS: market_name = f"{len(markets)} markets" elif "markets" not in market_name: market_name = markets[0]["api"].upper() if not self.is_youtube_video_page_opened(): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) export = self.wait_for_element_clickable(*self.locator(self.track_locators, "full_performance_export_btn")) time.sleep(3) self.click_element(element=export) self.click_export_as_csv() # file path verification (if download is failed - file name is wrong) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - {market_name} - YouTube{param}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) data_columns = list(data.keys()) self.log.info("Data columns names: " + str(data_columns)) file = {} for c in data_columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") # date column verification dates_list = [] for d in file["Date"][: file["Date"].index("Selected videos:")]: dates_list.append(d) dates_file = [datetime.datetime.strptime(d, self.get_date_format_from_locale()).date() for d in dates_list[:-1]] start = datetime.datetime.strptime(start_date, "%Y-%m-%d").date() end = datetime.datetime.strptime(end_date, "%Y-%m-%d").date() date_range = [] span = end - start for i in range(span.days + 1): d = start + datetime.timedelta(days=i) date_range.append(d) assert_that(dates_file).is_subset_of(date_range) # videos list verification api_resp_videos = self.api_client.get_delphi_videos( isrc=track, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) video_titles_api = [i["video_title"] for i in api_resp_videos] video_id_api = [i["video_id"] for i in api_resp_videos] if table_data != "": video_titles_api = table_data["titles"] video_id_api = table_data["video_ids"] videos = dict(zip(video_id_api, video_titles_api)) videos_list = [] for v in file["Date"][file["Date"].index("Selected videos:") :]: videos_list.append(v) dd_videos_text = selected_videos if dd_videos_text == "All Videos": video_titles_api.sort() video_titles_api.insert(0, "Selected videos:") else: video_id = str(self.parameter_from_url(self.str_gr_video)).replace(",", " ").split(" ") video_titles_api = [] for v in videos: if v in video_id: video_titles_api.append(videos[v]) video_titles_api.sort() video_titles_api.insert(0, "Selected videos:") self.ts.markFinal(videos_list == video_titles_api, f"Video lists: {videos_list} \nand {video_titles_api} match") # Country values verification if market_name == "All markets": countries_list = [] for c in file["Country"]: countries_list.append(c) file_countries = [x for x in list(set(countries_list)) if str(x) != "nan"] assert_that(market_name).is_equal_to(file_countries[0]) else: if self.str_gr_country in self.get_url(): markets = self.parameter_from_url(self.str_gr_country) else: markets = [m["api"] for m in markets] markets = "&country_code=".join(markets) api_responses_video_analytics = [self.api_client.get_video_analytics(start_date=str(start), end_date=str(end), market=markets, video_id=v) for v in video_id_api] market_names_api = [] for r in api_responses_video_analytics[0]: market_names_api.append(r["dimensions"]["country_code"]) api_markets = list(set(market_names_api)) api_markets_to_compare = [str(m).upper() for m in api_markets] api_markets_to_compare.sort() self.log.info("Market names from api: " + str(api_markets_to_compare)) countries_list = [] for c in file["Country"]: countries_list.append(c) if countries_list[0] not in self.REGIONS: file_countries = [x.replace(",", "").split(" ") for x in list(set(countries_list)) if str(x) != "nan"] assert_that(api_markets_to_compare).is_equal_to(file_countries[0]) @allure.step("Video Page - verify export sources and video columns") def nvp_vp_verify_export(self, market_api, view_selected, track, param="", table_data=""): start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() track_name = self.get_text(locator="//*[@id='youtube-link-back-link-back' or @id='track-title']", locator_type="xpath") market_name = str(self.graph_get_selected_market()).replace("Markets", "markets") if "markets" not in market_name and len(market_api) == 1: market_name = market_api[0].upper() elif market_name in self.REGIONS: market_name = f"{len(market_api)} markets" export = self.wait_for_element_clickable(*self.locator(self.track_locators, "full_performance_export_btn")) self.click_element(element=export) self.click_export_as_csv() # file path verification file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - {market_name} - YouTube{param}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) data_columns = list(data.keys()) self.log.info("Data columns names: " + str(data_columns)) file = {} for c in data_columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") # sources and videos columns verification file_with_videos_only = file.copy() file_with_videos_only.pop("Date") file_with_videos_only.pop("Country") file_with_videos_only_keys = [] for k in file_with_videos_only.keys(): file_with_videos_only_keys.append(k) api_resp_videos = self.api_client.get_delphi_videos( isrc=track, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) video_id_api = [i["video_id"] for i in api_resp_videos] if self.str_gr_video in self.get_url() and self.parameter_from_url(self.str_gr_video) != "all": video_id_api = self.parameter_from_url(self.str_gr_video).split(",") elif table_data != "": video_id_api = table_data["video_ids"] market_api = "%2C".join(market_api) api_responses_video_analytics = [self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=v) for v in video_id_api] view = view_selected if view == AppConfig.get("source")["by_source"]: sources_values = { "total_views": [], "browse_features": [], "programming_from_claimed_content": [], "youtube_channels": [], "direct_or_unknown": [], "interactive_video_endscreen": [], "external": [], "notifications": [], "other_youtube_features": [], "playlist_pages": [], "playlists": [], "shorts": [], "stories": [], "suggested_videos": [], "video_cards_and_annotations": [], "youtube_advertising": [], "youtube_search": [], } sources_values["total_views"].append(sum(sum(v["metrics"]["views"] for v in a) for a in api_responses_video_analytics)) sources_values["browse_features"].append(sum(sum(v["metrics"]["traffic_source_types"]["browse_features"] for v in a) for a in api_responses_video_analytics)) sources_values["programming_from_claimed_content"].append(sum(sum(v["metrics"]["traffic_source_types"]["programming_from_claimed_content"] for v in a) for a in api_responses_video_analytics)) sources_values["youtube_channels"].append(sum(sum(v["metrics"]["traffic_source_types"]["youtube_channels"] for v in a) for a in api_responses_video_analytics)) sources_values["direct_or_unknown"].append(sum(sum(v["metrics"]["traffic_source_types"]["direct_or_unknown"] for v in a) for a in api_responses_video_analytics)) sources_values["interactive_video_endscreen"].append(sum(sum(v["metrics"]["traffic_source_types"]["interactive_video_endscreen"] for v in a) for a in api_responses_video_analytics)) sources_values["external"].append(sum(sum(v["metrics"]["traffic_source_types"]["external"] for v in a) for a in api_responses_video_analytics)) sources_values["notifications"].append(sum(sum(v["metrics"]["traffic_source_types"]["notifications"] for v in a) for a in api_responses_video_analytics)) sources_values["other_youtube_features"].append(sum(sum(v["metrics"]["traffic_source_types"]["other_youtube_features"] for v in a) for a in api_responses_video_analytics)) sources_values["playlist_pages"].append(sum(sum(v["metrics"]["traffic_source_types"]["playlist_pages"] for v in a) for a in api_responses_video_analytics)) sources_values["playlists"].append(sum(sum(v["metrics"]["traffic_source_types"]["playlists"] for v in a) for a in api_responses_video_analytics)) sources_values["shorts"].append(sum(sum(v["metrics"]["traffic_source_types"]["shorts"] for v in a) for a in api_responses_video_analytics)) sources_values["stories"].append(sum(sum(v["metrics"]["traffic_source_types"]["stories"] for v in a) for a in api_responses_video_analytics)) sources_values["suggested_videos"].append(sum(sum(v["metrics"]["traffic_source_types"]["suggested_videos"] for v in a) for a in api_responses_video_analytics)) sources_values["video_cards_and_annotations"].append(sum(sum(v["metrics"]["traffic_source_types"]["video_cards_and_annotations"] for v in a) for a in api_responses_video_analytics)) sources_values["youtube_advertising"].append(sum(sum(v["metrics"]["traffic_source_types"]["youtube_advertising"] for v in a) for a in api_responses_video_analytics)) sources_values["youtube_search"].append(sum(sum(v["metrics"]["traffic_source_types"]["youtube_search"] for v in a) for a in api_responses_video_analytics)) self.log.info("Sources values: " + str(sources_values)) assert_that(int(sources_values["total_views"][0])).is_equal_to(int(sum([float(m) for m in file["Total views"] if not math.isnan(float(m))]))) assert_that(int(sources_values["browse_features"][0])).is_equal_to(int(sum([float(m) for m in file["Browse Features"] if not math.isnan(float(m))]))) assert_that(int(sources_values["programming_from_claimed_content"][0])).is_equal_to(int(sum([float(m) for m in file["Campaign Cards"] if not math.isnan(float(m))]))) assert_that(int(sources_values["youtube_channels"][0])).is_equal_to(int(sum([float(m) for m in file["Channels Page"] if not math.isnan(float(m))]))) assert_that(int(sources_values["direct_or_unknown"][0])).is_equal_to(int(sum([float(m) for m in file["Direct or Unkn"] if not math.isnan(float(m))]))) assert_that(int(sources_values["interactive_video_endscreen"][0])).is_equal_to(int(sum([float(m) for m in file["End Screens"] if not math.isnan(float(m))]))) assert_that(int(sources_values["external"][0])).is_equal_to(int(sum([float(m) for m in file["External"] if not math.isnan(float(m))]))) assert_that(int(sources_values["notifications"][0])).is_equal_to(int(sum([float(m) for m in file["Notifications"] if not math.isnan(float(m))]))) assert_that(int(sources_values["other_youtube_features"][0])).is_equal_to(int(sum([float(m) for m in file["Other YT Features"] if not math.isnan(float(m))]))) assert_that(int(sources_values["playlist_pages"][0])).is_equal_to(int(sum([float(m) for m in file["Playlist Page"] if not math.isnan(float(m))]))) assert_that(int(sources_values["playlists"][0])).is_equal_to(int(sum([float(m) for m in file["Playlists"] if not math.isnan(float(m))]))) assert_that(int(sources_values["shorts"][0])).is_equal_to(int(sum([float(m) for m in file["Shorts"] if not math.isnan(float(m))]))) assert_that(int(sources_values["stories"][0])).is_equal_to(int(sum([float(m) for m in file["Stories"] if not math.isnan(float(m))]))) assert_that(int(sources_values["suggested_videos"][0])).is_equal_to(int(sum([float(m) for m in file["Suggested Videos"] if not math.isnan(float(m))]))) assert_that(int(sources_values["video_cards_and_annotations"][0])).is_equal_to(int(sum([float(m) for m in file["Video Cards & Annotations"] if not math.isnan(float(m))]))) assert_that(int(sources_values["youtube_advertising"][0])).is_equal_to(int(sum([float(m) for m in file["YT Advertising"] if not math.isnan(float(m))]))) assert_that(int(sources_values["youtube_search"][0])).is_equal_to(int(sum([float(m) for m in file["YT Search"] if not math.isnan(float(m))]))) elif view == AppConfig.get("source")["all_views"]: total_views = [sum(sum(v["metrics"]["views"] for v in a) for a in api_responses_video_analytics)] assert_that(int(total_views[0])).is_equal_to(int(sum([float(m) for m in file["Total views"] if not math.isnan(float(m))]))) elif view == AppConfig.get("source")["by_video"]: total_views = [sum(sum(v["metrics"]["views"] for v in a) for a in api_responses_video_analytics)] video_views_api = [] for id in video_id_api: resp = self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=id) video_views_api.append(sum(v["metrics"]["views"] for v in resp)) video_views_file = [] for k in file_with_videos_only_keys[1:]: one_video_views = int(sum([float(m) for m in file_with_videos_only[k] if not math.isnan(float(m))])) video_views_file.append(one_video_views) assert_that(set(video_views_api)).is_equal_to(set(video_views_file)) assert_that(int(total_views[0])).is_equal_to(int(sum([float(m) for m in file["Total views"] if not math.isnan(float(m))]))) elif view == AppConfig.get("source")["by_avg_view_duration"]: avg_duration_api_total = [] for id in video_id_api: api_resp_period = self.api_client.get_video_analytics(video_id=id, market=market_api, start_date=start_date, end_date=end_date) avg_duration_api = [] for market in list(set(m["dimensions"]["country_code"] for m in api_resp_period)): avg_duration_api.append( sum(self.apply_rounding_percentage(v["metrics"]["average_view_duration_percentage"]) for v in api_resp_period if v["dimensions"]["country_code"] == market) / len(set(v["dimensions"]["date"] for v in api_resp_period if v["dimensions"]["country_code"] == market)) ) try: avg_duration_api = self.apply_rounding_percentage(sum(avg_duration_api) / len(list(set(m["dimensions"]["country_code"] for m in api_resp_period)))) except ZeroDivisionError: avg_duration_api = 0 self.log.info("Avg view duration: " + id + " " + str(avg_duration_api)) avg_duration_api_total.append(avg_duration_api) self.log.info("Avg view duration total: " + str(avg_duration_api_total)) avg_view_duration_file = [] for k in file_with_videos_only_keys: try: one_video_avg_view_duration = self.apply_rounding_percentage( sum([int(m.split(" ")[0].replace("%", "")) for m in file_with_videos_only[k] if not math.isnan(float(str(m).split(" ")[0].replace("%", "")))]) / len([int(m.split(" ")[0].replace("%", "")) for m in file_with_videos_only[k] if not math.isnan(float(str(m).split(" ")[0].replace("%", "")))]) ) avg_view_duration_file.append(one_video_avg_view_duration) except ZeroDivisionError: one_video_avg_view_duration = 0 self.log.info("Avg view duration from file: " + str(avg_view_duration_file)) assert_that(set(avg_duration_api_total)).is_equal_to(set(avg_view_duration_file)) elif view == AppConfig.get("source")["by_likes"]: video_likes_api = [] for id in video_id_api: resp = self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=id) video_likes_api.append(sum(v["metrics"]["likes"] for v in resp)) video_likes_file = [] for k in file_with_videos_only_keys: one_video_likes = int(sum([float(m) for m in file_with_videos_only[k] if not math.isnan(float(m))])) video_likes_file.append(one_video_likes) assert_that(set(video_likes_api)).is_equal_to(set(video_likes_file)) elif view == AppConfig.get("source")["by_dislikes"]: video_dislikes_api = [] for id in video_id_api: resp = self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=id) video_dislikes_api.append(sum(v["metrics"]["dislikes"] for v in resp)) video_dislikes_file = [] for k in file_with_videos_only_keys: one_video_dislikes = int(sum([float(m) for m in file_with_videos_only[k] if not math.isnan(float(m))])) video_dislikes_file.append(one_video_dislikes) assert_that(set(video_dislikes_api)).is_equal_to(set(video_dislikes_file)) elif view == AppConfig.get("source")["by_comments"]: video_comments_api = [] for id in video_id_api: resp = self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=id) video_comments_api.append(sum(v["metrics"]["comments"] for v in resp)) video_comments_file = [] for k in file_with_videos_only_keys: one_video_comments = int(sum([float(m) for m in file_with_videos_only[k] if not math.isnan(float(m))])) video_comments_file.append(one_video_comments) assert_that(set(video_comments_api)).is_equal_to(set(video_comments_file)) elif view == AppConfig.get("source")["by_shares"]: video_shares_api = [] for id in video_id_api: resp = self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market=market_api, video_id=id) video_shares_api.append(sum(v["metrics"]["shares"] for v in resp)) video_shares_file = [] for k in file_with_videos_only_keys: one_video_shares = int(sum([float(m) for m in file_with_videos_only[k] if not math.isnan(float(m))])) video_shares_file.append(one_video_shares) assert_that(set(video_shares_api)).is_equal_to(set(video_shares_file)) @allure.step("TP - Youtube LB LF get legend values API") def get_lb_lf_legend_values_api(self, video_ids, isrc, markets): days_count = self.graph_get_count_days_from_calendar() values_api = self.youtube_performance_get_legend_values_api(markets=markets, isrc=isrc, video_ids=video_ids) values_api = [ values_api["views_in_period"], values_api["views_day"], sum(values_api["lean_forward_by_source"]), self.apply_rounding_percentage(sum(values_api["lean_forward_by_source"]) / days_count), sum(values_api["lean_back_by_source"]), self.apply_rounding_percentage(sum(values_api["lean_back_by_source"]) / days_count), ] return values_api @allure.step("TP - Youtube NVP get sidebar values - UI") def nvp_youtube_get_sidebar_values_ui(self): self.is_graph_period_displayed() selector = "//*[contains(@id, 'sidebar')]" self.wait_for_element_visible(locator=selector, locator_type="xpath") elements = self.get_elements(locator=selector, locator_type="xpath") values = [] for e in elements: text = self.get_text(element=e).replace(",", "") self.log.info(f"Sidebar text: {text}") if "%" in text: values.append(int(text.split("\n")[0])) values.append(int(text.split("\n")[1].replace("(", "").replace("%)", ""))) else: values.append(int(text)) return values @allure.step("TP - Youtube NVP get sidebar values - API") def nvp_youtube_get_sidebar_values_api(self, isrc, markets, video_ids): self.is_graph_period_displayed() start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() api_resp_period_all_ids = [self.api_client.get_video_analytics(video_id=video_id, market="%2C".join(markets), start_date=start_date, end_date=end_date) for video_id in video_ids] sum_all = [] for m in markets: for a in api_resp_period_all_ids: days_count = len([d["dimensions"]["date"] for d in a if d["dimensions"]["country_code"] == m]) sum_all.append(days_count) values_views = self.youtube_performance_get_legend_values_api(markets, isrc, video_ids) # IF - for Views By Markets tab selected if self.is_tab_selected_no_assert(locator="youtube-markets"): values_views_ww = self.youtube_performance_get_legend_values_api(["worldwide"], isrc, video_ids) # if all markets or 1 market selected and region - not UK market_ui = self.graph_get_selected_market("youtube_vbm") if len(markets) == 1 and market_ui != "UK": values_all = [values_views_ww["views_in_period"]] # if 2 or more markets selected else: values_views_percentage = self.apply_rounding_percentage(values_views["views_in_period"] / values_views_ww["views_in_period"] * 100) values_all = [values_views_ww["views_in_period"], values_views["views_in_period"], values_views_percentage] # ELSE - for Video Performance tab selected else: values_all = [values_views["views_in_period"], int(values_views["views_in_period"] / max(sum_all))] # avg_duration_all = [] # for resp in api_resp_period_all_ids: # avg_duration_api = [] # for market in list(set(m["dimensions"]["country_code"] for m in resp)): # avg_duration_api.append( # sum( # v["metrics"]["average_view_duration_percentage"] # for v in resp # if v["dimensions"]["country_code"] == market # ) # / len(set(v["dimensions"]["date"] for v in resp if v["dimensions"]["country_code"] == market)) # ) # avg_duration_api = sum(avg_duration_api) / len(list(set(m["dimensions"]["country_code"] for m in resp))) # avg_duration_all.append(avg_duration_api) # values_all.append(self.apply_rounding_percentage(sum(avg_duration_all) / len(avg_duration_all))) for key in ["likes", "dislikes", "comments", "shares"]: value = sum(sum(v["metrics"][key] for v in a) for a in api_resp_period_all_ids) values_all.append(value) return values_all @allure.step("TP - Youtube NVP get top markets from UI") def youtube_nvp_views_by_markets_get_markets(self): selector = "//*[contains(@id, 'item-title')]" time.sleep(3) self.wait_for_element_clickable(locator="//button[.='Export']", locator_type="xpath") self.wait_for_element_visible(locator=selector, locator_type="xpath") self.wait_for_element_clickable(locator=selector, locator_type="xpath") elements = self.get_elements(locator=selector, locator_type="xpath") values = [self.get_text(element=e).lower() for e in elements] return values @allure.step("TP - compare ui and api") def compare_ui_api(self, api, ui): for a, u in zip(api, ui): self.ts.markFinal(a - u in list(range(-1, 2)), f"api: {a}, ui: {u}") @allure.step("TP - Youtuve verify legend for LB/LF") def vp_youtube_verify_footnote_and_legend_lb_lf(self): areas_locator = "//*[contains(@id, 'forward-label') or contains(@id, 'back-label') or contains(@id, '-gender-label') or contains(@id, '-age-label')]" dem_data_locator = "//*[text()='* Demographics data calculates for users logged into Youtube for Global market.']" question_locator = "//*[.='** For questions, email dataanalytics@sonymusic.com.']" lf_locator = "//*[contains(@id, 'lean-forward')]//../span[not(contains(.,'%'))]" lb_locator = "//*[contains(@id, 'lean-back')]//../span[not(contains(.,'%'))]" age_locator = "//*[contains(@id, 'age-label') or contains(@id, 'age-tooltip')]//../span[not(contains(.,'%'))]" gender_locator = "//*[contains(@id, 'gender')]//../span[not(contains(.,'%'))]" source_dd_items = "//input[@id][@type='checkbox']/following-sibling::span" lf_exp = [ "LEAN FORWARD", "YT Search", "Shorts", "Channels Page", "External", "Direct or Unkn", "End Screens", "Notifications", "Video Cards & Annotations", "Campaign Cards", "Stories", ] lb_exp = [ "LEAN BACK", "Suggested Videos", "Playlists", "Browse Features", "Other YT Features", "Playlist Page", "YT Advertising", ] age_exp = ["GLOBAL AGE GROUPS", "13-17", "18-24", "25-34", "35-44", "45-54", "55-64", "65+"] gender_exp = ["GLOBAL GENDER", "Female", "Male", "Unkn"] self.wait_for_element_visible(locator=areas_locator, locator_type="xpath") legend_areas = self.get_elements(locator=areas_locator, locator_type="xpath") legend_areas = [self.get_text(element=l) for l in legend_areas] dem_data = self.is_element_displayed(locator=dem_data_locator, locator_type="xpath") question_str = self.is_element_displayed(locator=question_locator, locator_type="xpath") sources_dd = self.wait_for_element_clickable("youtube-performance-sources-dd") self.click_element(element=sources_dd) self.wait_for_element_visible(locator=source_dd_items, locator_type="xpath") items_ui = self.get_elements(locator=source_dd_items, locator_type="xpath") items_ui = [self.get_text(element=i) for i in items_ui if self.get_text(element=i) not in ["Key Sources", "Other Sources"]] assert_that(legend_areas).is_equal_to(["LEAN FORWARD", "LEAN BACK", "GLOBAL AGE GROUPS", "GLOBAL GENDER"]) assert_that(dem_data).is_true() assert_that(question_str).is_true() for els, exp in zip([lf_locator, lb_locator, age_locator, gender_locator], [lf_exp, lb_exp, age_exp, gender_exp]): elselements = self.get_elements(locator=els, locator_type="xpath") elselements = [self.get_text(element=e) for e in elselements] assert_that(elselements).is_equal_to(exp) assert_that(set(items_ui)).is_equal_to(set(lf_exp[1:] + lb_exp[1:])) self.click_element(element=sources_dd) @allure.step("TP - TD Youtube get ids and titles from table") def td_youtube_get_ids_titles(self): self.scroll_to_element(*self.locator(self.track_locators, "youtube_tab")) selector = "//*[contains(@id, 'youtube-table-cell-title-')]/..//a" self.wait_for_element_visible(locator=selector, locator_type="xpath") titles = self.get_elements(locator=selector, locator_type="xpath") video_ids = self.get_elements(locator=selector, locator_type="xpath") titles = [self.get_text(element=e) for e in titles] video_ids = [self.get_attribute_value(element=e, attribute="href").split("=")[-1] for e in video_ids] table_ui = {"titles": titles, "video_ids": video_ids} self.log.info(f"td youtube table: {table_ui}") return table_ui @allure.step("TP - Youtube verify export inactive") def verify_export_inactive(self): self.wait_for_element_visible(*self.locator(self.track_locators, "full_performance_export_btn")) export = self.get_element(*self.locator(self.track_locators, "full_performance_export_btn")) color_before = export.value_of_css_property("background-color") assert_that(color_before).is_equal_to("rgba(242, 242, 247, 1)") @allure.step("TP - Youtube click export on Views By Markets tab") def youtube_views_by_markets_click_export(self): self.scroll_to_element(locator="//button[.='Export']", locator_type="xpath") export = self.wait_for_element_clickable(locator="//button[.='Export']", locator_type="xpath") self.click_on_element_js(element=export) @allure.step("TP - Youtube verify export on Views By Markets tab") def youtube_views_by_markets_verify_export(self, track, param="", markets=""): export_button = self.wait_for_element_clickable(locator="//button[.='Export']", locator_type="xpath") self.click_element(element=export_button) start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() track_name = self.get_text(locator="//*[@id='youtube-link-back-link-back' or @id='track-title']", locator_type="xpath") file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - By Markets - Youtube{param}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) data_columns = list(data.keys()) self.log.info("Data columns names: " + str(data_columns)) sources_api = [ "views", "browse_features", "programming_from_claimed_content", "youtube_channels", "direct_or_unknown", "interactive_video_endscreen", "external", "notifications", "other_youtube_features", "playlist_pages", "playlists", "shorts", "stories", "suggested_videos", "video_cards_and_annotations", "youtube_advertising", "youtube_search", ] sources_file_columns = [ "Total views", "Browse Features", "Campaign Cards", "Channels Page", "Direct or Unkn", "End Screens", "External", "Notifications", "Other YT Features", "Playlist Page", "Playlists", "Shorts", "Stories", "Suggested Videos", "Video Cards & Annotations", "YT Advertising", "YT Search", ] assert_that(data_columns).is_equal_to(["Date", "Country"] + sources_file_columns) file = {} for c in data_columns: if c != "Date": file[c] = data.dropna().get(c).to_list() else: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") # Date column dates_list = [] for d in file["Date"][: file["Date"].index("Selected videos:")]: dates_list.append(d) dates_file = [datetime.datetime.strptime(d, self.get_date_format_from_locale()).date() for d in dates_list[:-1]] start = datetime.datetime.strptime(start_date, "%Y-%m-%d").date() end = datetime.datetime.strptime(end_date, "%Y-%m-%d").date() date_range = [] span = end - start for i in range(span.days + 1): d = start + datetime.timedelta(days=i) date_range.append(d) assert_that(dates_file).is_subset_of(date_range) # videos list verification if self.is_youtube_video_page_opened and self.str_gr_video not in self.get_url() or self.parameter_from_url(self.str_gr_video) == "all": api_resp_videos = self.api_client.get_delphi_videos( isrc=track, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) video_titles_api = [i["video_title"] for i in api_resp_videos] video_id_api = [i["video_id"] for i in api_resp_videos] elif not self.is_youtube_video_page_opened() and self.str_gr_video not in self.get_url() or self.parameter_from_url(self.str_gr_video) == "all": table_data = self.td_youtube_get_ids_titles() video_titles_api = table_data["titles"] video_id_api = table_data["video_ids"] else: video_id_api = self.parameter_from_url(self.str_gr_video).split(",") api_resp_videos = self.api_client.get_delphi_videos( isrc=track, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) video_titles_api = [a["video_title"] for a in api_resp_videos if a["video_id"] in video_id_api] assert_that(sorted(video_titles_api)).is_equal_to(file["Date"][file["Date"].index("Selected videos:") + 1 :]) # Country file_countries = set(file["Country"]) if markets == "": ui_countries = set(self.youtube_nvp_views_by_markets_get_markets()[:45]) else: ui_countries = set(markets) assert_that(ui_countries).is_subset_of(file_countries) # Sources api_responses_video_analytics = [self.api_client.get_video_analytics(start_date=start_date, end_date=end_date, market="&country_code=".join(ui_countries), video_id=v) for v in video_id_api] for f, a in zip(sources_file_columns, sources_api): if a != "views": api_total = sum(sum(v["metrics"]["traffic_source_types"][a] for v in d if v["metrics"]["traffic_source_types"][a]) for d in api_responses_video_analytics) file_total = sum(file[f]) else: api_total = sum(sum(v["metrics"][a] for v in d if v["metrics"][a]) for d in api_responses_video_analytics) file_total = sum(file[f]) assert_that(api_total).described_as(f).is_equal_to(file_total) @allure.step("TP - TD - Youtube change video type") def td_video_change_type(self, param): all_types = "//input[contains(@id, 'All Types')]" self.scroll_to_track_details() dd = self.wait_for_element_clickable("track-details-youtube-type-dd") self.click_element(element=dd) all = self.get_element(all_types, "xpath") self.click_on_element_js(element=all) if self.is_checked(all_types, "xpath"): self.click_on_element_js(element=all) for p in param: item = self.get_element(f"//input[contains(@id, '{p}')]", "xpath") self.click_on_element_js(element=item) self.click_element(self.apply_button_loc, "xpath") @allure.step("TP - TD - Youtube change video type") def td_video_verify_dd_value(self, dd, value_expected): self.scroll_to_track_details() dd_value_el = self.wait_for_element_visible(f"track-details-youtube-{dd}-dd") dd_value_ui = self.get_text(element=dd_value_el) assert_that(dd_value_ui).is_equal_to(value_expected) @allure.step("TP - TD - Youtube verify export") def td_video_verify_export(self, market="", param=""): track_name = self.get_text(locator="//*[@id='youtube-link-back-link-back' or @id='track-title']", locator_type="xpath") artist_name = self.get_all_artists_name() export = self.wait_for_element_clickable(*self.locator(self.track_locators, "stations_export_button")) self.click_element(element=export) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/Videos - {artist_name} - {track_name}{param}.csv""" self.log.info(f"file path: {file_path}") data = self.read_from_csv(file_path) data_columns = list(data.keys()) self.log.info("Data columns names: " + str(data_columns)) youtube_date = self.api_client.get_latest_date_all()["youtube"] youtube_date = datetime.datetime.strptime(youtube_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) column_country = "Country" column_video_type = "Video Type" column_title = "Title" column_publish_date = "Publish Date" # column_latest_date_views = f"{youtube_date} Views" column_7_days_views = "7 Days Views" column_in_period_views = "In Period Views" column_avg_in_periods = "Avg. In Period Views/Day" columns_expected = [ column_country, column_video_type, column_title, column_publish_date, column_7_days_views, column_in_period_views, column_avg_in_periods, ] assert_that(columns_expected).is_subset_of(data_columns) file = {} for c in data_columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") assert_that([int(v.replace(",", "")) for v in file[column_in_period_views]]).is_sorted(reverse=True) if market != "": market_ui = market else: market_ui = self.graph_get_selected_market("td_youtube").replace("Markets", "markets") table_ui = self.td_youtube_get_all_from_table() video_types_ui = [t.split("\n")[1].split("\n")[0] for t in table_ui["titles"]] titles_ui = [t.split("\n")[0] for t in table_ui["titles"]] publish_dates_ui = [t.split("\n")[3].split("\n")[0] for t in table_ui["titles"]] latest_date_views_ui = table_ui["date_views"][:-1] date_7_views_ui = table_ui["views_7"][:-1] in_period_views_ui = table_ui["views_in_period"][:-1] views_avg_day_ui = table_ui["views_avg_day"] assert_that([market_ui]).is_equal_to(list(set(file[column_country]))) assert_that(sorted(video_types_ui)).is_equal_to(sorted([t.upper() for t in file[column_video_type]])) assert_that(sorted(titles_ui)).is_equal_to(sorted(file[column_title])) assert_that(sorted(publish_dates_ui)).is_equal_to(sorted(file[column_publish_date])) assert_that(sorted(latest_date_views_ui)).is_equal_to(sorted([int(v.replace(",", "")) for v in file[data_columns[4]]])) assert_that(sorted(date_7_views_ui)).is_equal_to(sorted([int(v.replace(",", "")) for v in file[column_7_days_views]])) assert_that(sorted(in_period_views_ui)).is_equal_to(sorted([int(v.replace(",", "")) for v in file[column_in_period_views]])) assert_that(sorted(views_avg_day_ui)).is_equal_to(sorted([int(v.replace(",", "")) for v in file[column_avg_in_periods]])) @allure.step("TP - If source dd is present on the page") def if_source_dd_present(self, dd, present=True): dd = self.is_element_displayed(*self.locator(self.track_locators, f"{dd}_youtube_sources_dd")) assert_that(dd).is_equal_to(present) @allure.step("TP - TD - VBM Youtube verify source filter") def youtube_vbm_verify_source_filter(self, param): dd = self.wait_for_element_visible(*self.locator(self.track_locators, "vbm_youtube_sources_dd")) assert_that(self.get_text(element=dd)).is_equal_to(param) @allure.step("TP - TD - VBM Youtube verify source filter") def youtube_vbm_verify_sources_dd_values(self): dd = self.wait_for_element_clickable(*self.locator(self.track_locators, "vbm_youtube_sources_dd")) self.click_element(element=dd) self.wait_for_element_visible("//input[@id]/following-sibling::span", "xpath") items = self.get_elements("//input[@id]/following-sibling::span", "xpath") items = [self.get_text(element=i) for i in items] assert_that(items).is_equal_to( [ "Key Sources", "Browse Features", "External", "Notifications", "Playlist Page", "Playlists", "Suggested Videos", "Video Cards & Annotations", "YT Advertising", "YT Search", "Other Sources", "Campaign Cards", "Channels Page", "Direct or Unkn", "End Screens", "Other YT Features", "Shorts", "Stories", ] ) self.click_element(element=dd) @allure.step("TP - Youtube VP - click on side panel") def click_on_side_panel(self): panel = self.wait_for_element_visible("//*[text()='Views in Period']", "xpath") self.click_element(element=panel) @allure.step("TP - Youtube VP - VBM get graph barchart views") def get_graph_vbm_barchart_views(self, count=5): selector = "//*[contains(@class, 'highcharts-point')]" selector_markets = "//*[contains(@class, 'xaxis')]/span" self.wait_for_element_clickable(selector, "xpath") if count == "": bars = self.get_elements(selector, "xpath") else: bars = self.get_elements(selector, "xpath")[:count] source_views = [] all_views = [] for b in bars: self.hover_on_element(element=b) tooltip = self.get_text(self.hint_locator, "xpath") source_views.append(int(tooltip.split("\n")[2].split(" ")[0].replace(",", ""))) all_views.append(int(tooltip.split("\n")[4].replace(",", ""))) self.wait_for_element_visible(selector_markets, "xpath") if count == "": markets = self.get_elements(selector_markets, "xpath") else: markets = self.get_elements(selector_markets, "xpath")[:count] markets = [self.get_text(element=m) for m in markets] self.log.info(f"views: {source_views}\n {all_views}\n{markets}") return {"source_views": source_views, "all_views": all_views, "markets": markets} @allure.step("TP - Youtube VP - VBM verify footnote") def youtube_nvp_vbm_verify_footnote(self, present=True): selector = "//*[text()='* Hold shift and select a market to see the data for it quickly.']" footnote = self.wait_for_element_visible(selector, "xpath") assert_that(self.is_element_displayed(element=footnote)).is_equal_to(present) @allure.step("TP - Youtube VP - VBM verify market list") def vbm_verify_market_list(self): selector_dd = "youtube-full-performance-graph-type-dd" selector_items = f"(//*[@id='{selector_dd}']//../div)[1]" self.wait_for_element_visible(selector_dd) items_ui = self.get_text(selector_items, "xpath") assert_that(items_ui).is_equal_to("Top MarketsSony OfficesAll Markets") @allure.step("TP - Youtube verify selected markets in graph dd") def graph_verify_selected_countries_and_hover(self, region, param, countries_strict="", strict=False): selected_markets_selector = "//input[@data-checked='checked']/following-sibling::*" region_icon_selector = f"//*[contains(@class, 'region-text')][text()='{region}']/..//*[contains(@class, 'icon-info')]" self.wait_for_element_visible(selected_markets_selector, "xpath") markets = self.graph_market_dd_get_selected() self.hover_on_element(region_icon_selector, "xpath") if region != self.REGION_EX_US: # hint = self.get_text(self.hint_locator, 'xpath').replace('\n', ' ') # self.log.info(f'{region} hint: {hint.split(", ")}') if not strict: assert_that(markets).is_subset_of(param) else: assert_that(markets).is_equal_to(countries_strict) assert_that(markets).is_sorted() # assert_that(hint).is_equal_to(', '.join(param)) else: icon = self.is_element_displayed(region_icon_selector, "xpath") assert_that(icon).is_false() return len(markets) @allure.step("TP - market dd - get selected markets") def graph_market_dd_get_selected(self): selected_markets_selector = "//input[@id][@data-checked='checked']/following-sibling::*[not(text()='Editorial') and not(text()='Personalized')]" markets = self.get_elements(selected_markets_selector, "xpath") markets = [self.get_text(element=m).strip() for m in markets] return markets @allure.step("TP - Graph - click on title") def click_on_graph_title(self): header = self.wait_for_element_clickable(*self.locator(self.track_locators, "tp_header")) self.click_element(element=header) @allure.step("TP - Graph - market dd verify regions") def graph_market_dd_verify_regions(self): region_selector = "//*[contains(@class, 'region')]" self.wait_for_element_visible(region_selector, "xpath") regions = self.get_elements(region_selector, "xpath") regions = [self.get_text(element=r) for r in regions] assert_that(regions).is_equal_to(self.REGIONS) @allure.step("TP - Graph - market dd verify chosen region is in bold") def graph_region_verify_bold(self, region, is_bold=True): region_selector = f"//*[contains(@class, 'region') and text()='{region}']" self.markets_dd_click() region_el = self.wait_for_element_visible(region_selector, "xpath") font = region_el.value_of_css_property("font-weight") self.log.info(f"bold: {is_bold}, attr css: {font}") assert_that(font == "700").is_equal_to(is_bold) self.markets_dd_click() @allure.step("TP - Graph get legend api values Amazon") def graph_legend_get_api_values_amazon(self, markets, isrc): start_date = self.get_calendar_start_date() end_date = self.get_calendar_end_date() api_response_per_country = self.api_client.get_amazon_tracks(isrc=isrc, start_date=start_date, end_date=end_date)["items"] api_values = {"total": {}, "lf": {}, "lb": {}} sst = [s["selection_source_type"] for s in api_response_per_country if s["country_code"] in markets] api_values["total"] = sum(s["streams"] for s in api_response_per_country if s["country_code"] in markets) api_values["lf"]["user_playlist"] = sum(s["auto_playlist"] + s["recently_added"] + s["recently_played"] + s["user_playlist"] + s["genre"] for s in sst) for v in ["songs", "album", "artist", "search"]: api_values["lf"][v] = sum(s[v] for s in sst) api_values["lb"]["playlists"] = sum(s["gno_prime_playlist"] + s["gno_unl_playlist"] + s["golden_playlist"] + s["prime_playlist"] + s["shared_playlist"] + s["unlimited_playlist"] + s["personalize_playlist"] for s in sst) api_values["lb"]["station"] = sum( s["amf_station"] + s["amf_station_seed"] + s["custom_mix"] + s["error"] + s["prime_station"] + s["prime_station_seed"] + s["similarity"] + s["similarity_station"] + s["station"] + s["undefined"] + s["unknown"] + s["unl_station_seed"] + s["unlimited_station"] + s["unlimited_station_se"] for s in sst ) self.log.info(f"api values for graph legend: {api_values}") return api_values @allure.step("selecting first day period in previous month") def select_previous_mounth_first_day_period(self): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) previous_month_picker = "DayPicker-NavButton--prev" self.driver.execute_script("document.getElementsByClassName('" + previous_month_picker + "')[0].click();") first = self.wait_for_element_visible(*self.locator(self.track_locators, "firstDayOfPreviousMonth")) last = self.wait_for_element_visible(*self.locator(self.track_locators, "firstDayOfPreviousMonth")) self.click_on_element_js(element=first) self.click_on_element_js(element=last) self.is_graph_period_displayed() @allure.step("Graph legend - get Sources tooltips") def get_graph_legend_sources_tooltips(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) items_locator = "//*[contains(@id, 'sources-label')]/..//span[contains(., '%')]" self.wait_for_element_visible(items_locator, "xpath") labels = self.get_elements(items_locator, "xpath") tooltip_streams = [] tooltip_avg = [] tooltip_percentage = [] for l in labels: ActionChains(self.driver).move_to_element(l).click().perform() tooltip_s = int(self.get_text(locator="//*[contains(@id, 'streams-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_a = int(self.get_text(locator="//*[contains(@id, 'avg-value') and contains(@id, 'tooltip')]", locator_type="xpath").replace(",", "")) tooltip_p = float( self.get_text( locator="//*[contains(@id, '-value') and contains(@id, 'tooltip') and contains(., '%')]", locator_type="xpath", ).replace("%", "") ) tooltip_streams.append(tooltip_s) tooltip_avg.append(tooltip_a) tooltip_percentage.append(tooltip_p) self.log.info(f"streams sources: {tooltip_streams}") self.log.info(f"avg sources: {tooltip_avg}") self.log.info(f"percentage source: {tooltip_percentage}") return {"streams": tooltip_streams, "avg": tooltip_avg, "percentage": tooltip_percentage} @allure.step("Get track id from url") def get_track_id_from_url(self): url = self.get_url() track_id = url.split("?")[0].split("/")[-1] return track_id @allure.step("Select period - month and year") def select_month_period(self, param): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) time.sleep(1) for i in list(range(0, 120)): previous_month_picker = "DayPicker-NavButton--prev" self.driver.execute_script("document.getElementsByClassName('" + previous_month_picker + "')[0].click();") month_displayed = self.wait_for_element_visible("(//*[@class='DayPicker-Caption'])[1]/*[string-length(text()) > 0]", "xpath") month_displayed = self.get_text(element=month_displayed) if month_displayed == param: break assert_that(month_displayed).is_equal_to(param) first = self.wait_for_element_visible(*self.locator(self.track_locators, "firstDayOfPreviousMonth")) last = self.wait_for_element_visible(*self.locator(self.track_locators, "lastDayOfPreviousMonth")) time.sleep(1) self.click_on_element_js(element=first) time.sleep(1) self.click_on_element_js(element=last) self.is_graph_period_displayed() @allure.step("Select period - today") def select_today_period(self): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) today_selector = "//*[contains(@class, 'today')][string-length(text()) > 0]" first = self.wait_for_element_visible(today_selector, "xpath") time.sleep(1) self.click_on_element_js(element=first) time.sleep(1) self.click_on_element_js(element=first) self.is_graph_period_displayed() @allure.step("New Video Page - Youtube API get By Markets Streams") def get_youtube_streams_by_markets_api(self, markets, t_isrc, sources="all"): start = self.get_calendar_start_date() end = self.get_calendar_end_date() if sources == "all": sources_youtube = self.youtube_all_sources else: sources_youtube = sources api_resp_videos = self.api_client.get_delphi_videos( isrc=t_isrc, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) if self.str_gr_video not in self.get_url() or self.parameter_from_url(self.str_gr_video) == "all": video_id_api = [i["video_id"] for i in api_resp_videos] else: video_id_api = self.parameter_from_url(self.str_gr_video).split(",") api_youtube_resp = [self.api_client.get_video_analytics(market=",".join(markets + ["worldwide"]), start_date=start, end_date=end, video_id=i) for i in video_id_api] youtube_days_count = {} youtube_streams = {} for m in markets: youtube_days_count[m] = [] youtube_streams[m] = 0 youtube_streams_ww = 0 if sources == "all": for resp in api_youtube_resp: for r in resp: if r["dimensions"]["country_code"] == m: youtube_days_count[m].append(r["dimensions"]["date"]) youtube_streams[m] += r["metrics"]["views"] elif r["dimensions"]["country_code"] == "worldwide": youtube_streams_ww += r["metrics"]["views"] else: for resp in api_youtube_resp: for r in resp: if r["dimensions"]["country_code"] == m: youtube_days_count[m].append(r["dimensions"]["date"]) youtube_streams[m] += sum(r["metrics"]["traffic_source_types"][ks] for ks in sources_youtube) elif r["dimensions"]["country_code"] == "worldwide": youtube_streams_ww += sum(r["metrics"]["traffic_source_types"][ks] for ks in sources_youtube) youtube_days_count[m] = len(list(set(youtube_days_count[m]))) result_youtube = dict(sorted(youtube_streams.items(), key=operator.itemgetter(1), reverse=True)) self.log.info(f"youtube streams: {result_youtube}, worldwide: {youtube_streams_ww}") youtube_average = {} for k in result_youtube.keys(): if youtube_days_count[k] > 0: youtube_average[k] = self.apply_rounding_percentage(result_youtube[k] / youtube_days_count[k]) else: youtube_average[k] = 0 self.log.info(f"youtube average: {youtube_average}") percentage = {m: round((result_youtube[m] / youtube_streams_ww) * 100, 1) if youtube_streams_ww > 0 else 0 for m in result_youtube.keys()} api_val = {"views": result_youtube, "avg": youtube_average, "percentage": percentage} self.log.info(f"api val: {api_val}") return api_val @allure.step("New Video Page - Youtube verify By Markets legend and countries") def verify_by_markets_legend_and_countries(self, countries, legend_market_header): self.verify_by_markets_legend(legend_market_header) countries_ui = self.get_elements("//*[contains(@id,'item-title')]", "xpath") countries_ui = [self.get_text(element=c).lower() for c in countries_ui] assert_that(set(countries_ui)).is_equal_to(set(countries)) @allure.step("New Video Page - Youtube verify By Markets legend") def verify_by_markets_legend(self, legend_market_header): selector_legend_header = "//*[contains(@id,'Legend') and contains(@id,'-title') and not(contains(@id,'-item'))]" self.wait_for_element_visible(selector_legend_header, "xpath") footnote = self.wait_for_element_visible("//span[contains(., '* For questions, email dataanalytics@sonymusic.com.')]", "xpath") legend_header_ui = self.get_elements(selector_legend_header, "xpath") legend_header_ui = [self.get_text(element=l) for l in legend_header_ui] assert_that(legend_header_ui).is_equal_to(legend_market_header) assert_that(self.is_element_displayed(element=footnote)).is_true() @allure.step("Youtube NVP - verify sidebar values calculations") def verify_sidebar_values(self, isrc, markets): sidebar_values_ui = self.nvp_youtube_get_sidebar_values_ui() url_current = self.get_url() if self.str_gr_video in url_current and self.parameter_from_url(self.str_gr_video) != "all": video_ids = self.parameter_from_url(self.str_gr_video).split(",") else: api_resp = self.api_client.get_delphi_videos( isrc=isrc, params="group_by=date%2Cvideo_id&sort_by=views&limit=20&views=1000&expand_to=related_isrcs&content_type=partner_uploaded%2Cpremium_ugc&", ) video_ids = [i["video_id"] for i in api_resp] sidebar_values_api = self.nvp_youtube_get_sidebar_values_api(isrc=isrc, video_ids=video_ids, markets=markets) assert_that(sidebar_values_api).is_equal_to(sidebar_values_ui) @allure.step("Youtube NVP - get VBM legend values") def by_markets_get_legend_values(self): legend_markets_el_selector = "//*[contains(@id, '-item-title')]" legend_percs_el_selector = "//*[contains(@id, '-item-percent')]" tooltip_perc_selector = "//*[contains(@id, '-item-value')]" tooltip_streams_selector = "//*[contains(@id, '-item-streams-value')]" tooltip_avg_selector = "//*[contains(@id, '-item-avg-value')]" all_val = {} percentage_legend_all = [] self.wait_for_element_visible(legend_markets_el_selector, "xpath") self.wait_for_element_visible(legend_percs_el_selector, "xpath") legend_markets = self.get_elements(legend_markets_el_selector, "xpath") legend_percs = self.get_elements(legend_percs_el_selector, "xpath") for m, p in zip(legend_markets, legend_percs): market_legend = self.get_text(element=m).lower() perc_legend = int(self.get_text(element=p).replace("%", "").replace("N/A", "0")) percentage_legend_all.append(perc_legend) all_val[market_legend] = {} ActionChains(self.driver).move_to_element(to_element=m).perform() all_val[market_legend]["percentage"] = float(self.get_text(tooltip_perc_selector, "xpath").replace("%", "").replace("N/A", "0")) all_val[market_legend]["views"] = int(self.get_text(tooltip_streams_selector, "xpath").replace(",", "").replace("N/A", "0")) all_val[market_legend]["avg"] = int(self.get_text(tooltip_avg_selector, "xpath").replace(",", "").replace("N/A", "0")) perc_api = self.apply_rounding_percentage(all_val[market_legend]["percentage"]) assert_that(perc_legend).is_equal_to(perc_api) assert_that(percentage_legend_all[:-1]).is_sorted(reverse=True) self.log.info(f"by markets ui values: {all_val}") return all_val @allure.step("Youtube NVP - get by markets legend markets - UI") def by_markets_get_legend_markets_ui(self): legend_markets_el_selector = "//*[contains(@id, '-item-title')]" self.wait_for_element_visible(legend_markets_el_selector, "xpath") legend_markets = self.get_elements(legend_markets_el_selector, "xpath") legend_markets = [self.get_text(element=m).lower() for m in legend_markets] self.log.info(f"by markets ui markets: {legend_markets}") return legend_markets @allure.step("TP - verify date picker ui") def verify_date_picker(self): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) today_selector = "//*[contains(@class, 'today')]" first = self.wait_for_element_visible(today_selector, "xpath") color_today = first.value_of_css_property("color") from_to = self.get_elements("//*[contains(@id, 'day-picker-field')]", "xpath") from_to_background = set(e.value_of_css_property("background-color") for e in from_to) assert_that(color_today).is_equal_to("rgba(255, 60, 129, 1)") assert_that(from_to_background).is_equal_to({"rgba(255, 255, 255, 1)"}) self.click_on_element_js(element=calendar) @allure.step("TP - VP - verify video selector hover") def verify_video_selector_hover(self, tooltip_exp=""): self.hover_on_element("youtube-videos") icon_sel = "//*[contains(@id, 'videos-control')]" if tooltip_exp == "": video_selector_text = self.vp_youtube_get_selected_videos_dd() else: video_selector_text = tooltip_exp self.hover_on_element(icon_sel, "xpath") tooltip_text = self.get_text(self.hint_locator, "xpath") assert_that(self.is_element_displayed(icon_sel, "xpath")).is_true() assert_that(video_selector_text).is_equal_to(tooltip_text) @allure.step("TP - VP - get video selector hint") def get_video_selector_hover(self): icon_sel = "//*[contains(@id, 'videos-control')]//../*[contains(@class, 'icon-new-window')]" icon = self.wait_for_element_visible(icon_sel, "xpath") self.hover_on_element("youtube-videos") self.hover_on_element(element=icon) tooltip_text = self.get_text(self.hint_locator, "xpath").replace("\n", "") return tooltip_text @allure.step("TP - NVP - get title") def get_nvp_video_metadata(self, one_video=True): self.nvp_youtube_get_sidebar_values_ui() title_back_button = self.wait_for_element_visible("youtube-link-back-link-back") title_el = self.wait_for_element_visible("youtube-videos-control") title = self.get_text(element=title_el) label = self.get_text("youtube-videos-type-label") assert_that("/spotify/track/" in title_back_button.get_attribute("href")).described_as(title_back_button.get_attribute("href")).is_true() metadata = {"title": title, "label": label} if one_video: self.wait_for_element_clickable("//*[@id='youtube-channel-page-link']/a", "xpath") image_el = self.wait_for_element_visible("//*[contains(@class, 'icon-play')]/parent::div/img", "xpath") image = image_el.get_attribute("src") channel = self.get_text("youtube-channel-name-title").replace("By ", "") published_date = self.get_text("//*[@tag='p'][contains(text(), '/') and not(contains(text(), '–'))]", "xpath") channel_link = self.get_attribute_value(locator="//*[@id='youtube-channel-page-link']/a", locator_type="xpath", attribute="href") video_link = self.get_attribute_value(locator="//*[@id='youtube-video-page-link']/a", locator_type="xpath", attribute="href").split("=") assert_that(video_link[0]).is_equal_to("https://www.youtube.com/watch?v") assert_that(channel_link).starts_with("https://www.youtube.com/channel") metadata = {"title": title, "label": label, "image": image, "channel": channel, "published_date": published_date, "channel_link": channel_link.split("/")[-1], "video_link": video_link[-1]} self.log.info(f"header metadata: {metadata}") return metadata @allure.step("TP -select markets_count") def select_markets_count(self, param, tab="streams_and_graphs", uncheck_selected=True): self.markets_dd_click(tab=tab) country_dd = "//*[contains(text(), '{market}')]" country_choose = f"{country_dd}/preceding-sibling::input" country_input_selector = "//input[@type='checkbox'][contains(@id, ' ')]" if uncheck_selected: item = self.get_element(locator=country_choose.format(market=self.all_markets), locator_type="xpath") self.click_on_element_js(element=item) if self.is_checked(locator=country_choose.format(market=self.all_markets), locator_type="xpath"): self.click_on_element_js(element=item) country_input_elements = self.get_elements(country_input_selector, "xpath") param = list(range(1, param + 1)) for c in param: country = country_input_elements[c] self.click_on_element_js(element=country) self.dd_click_apply() self.is_graph_period_displayed() self.log.info(f"{tab} - choose countries: {len(param)}") if "/spotify/album/" not in self.get_url(): return self.parameter_from_url(self.str_gr_country).split(",") @allure.step("Star track and verify that it is starred") def star_track(self): self.wait_for_element_visible(*self.locator(self.track_locators, "star_button")) self.wait_for_element_clickable(*self.locator(self.track_locators, "star_button")) unstarred_button = self.get_element(*self.locator(self.track_locators, "star_button")) unstarred_state = unstarred_button.value_of_css_property("background-color") self.log.info("Button color before: " + str(unstarred_state)) assert_that(unstarred_state).is_equal_to(self.UNSTARRED_TRACK_BUTTON_COLOR) self.click_element(element=unstarred_button) starred_hint = self.wait_for_element_visible(locator="//*[text()='Track successfully starred']", locator_type="xpath") hint = self.get_text(element=starred_hint) assert_that(hint).is_equal_to("Track successfully starred") self.wait_for_element_visible(*self.locator(self.track_locators, "star_button")) starred_button = self.get_element(*self.locator(self.track_locators, "star_button")) starred_state = starred_button.value_of_css_property("background-color") self.log.info("Button color after: " + str(starred_state)) assert_that(starred_state).is_equal_to(self.STARRED_TRACK_BUTTON_COLOR_HOVERED) @allure.step("Unstar track and verify that it is unstarred") def unstar_track(self): self.wait_for_element_visible(*self.locator(self.track_locators, "star_button")) starred_button = self.get_element(*self.locator(self.track_locators, "star_button")) starred_state = starred_button.value_of_css_property("background-color") self.log.info("Starred button color: " + str(starred_state)) assert_that(starred_state).is_equal_to(self.STARRED_TRACK_BUTTON_COLOR) self.click_element(element=starred_button) starred_hint = self.wait_for_element_visible(locator="//*[text()='Track successfully unstarred']", locator_type="xpath") hint = self.get_text(element=starred_hint) assert_that(hint).is_equal_to("Track successfully unstarred") self.wait_for_element_visible(*self.locator(self.track_locators, "star_button")) unstarred_button = self.get_element(*self.locator(self.track_locators, "star_button")) unstarred_state = unstarred_button.value_of_css_property("background-color") self.log.info("Unstarred button color: " + str(unstarred_state)) assert_that(unstarred_state).is_equal_to(self.UNSTARRED_TRACK_BUTTON_COLOR_HOVERED) @allure.step("Streams by markets - get stremas in period values") def get_streams_in_period_all_by_markets(self): selector = "//*[contains(@id, 'in-period-value') or contains(@id, 'selected-markets-value')]" self.wait_for_element_visible(selector, "xpath") values_el = self.get_elements(selector, "xpath") values = [self.get_text(element=v).replace(",", "").replace("%", "").replace("(", "").replace(")", "") for v in values_el] values = [float(v) for v in values] self.log.info(f"values by markets in period: {values}") return values @allure.step("Calendar - select custom date range") def calendar_select_date_range(self, date_range): calendar = self.wait_for_element_visible(*self.locator(self.track_locators, "calendar_icon")) self.click_on_element_js(element=calendar) time.sleep(1) param = f"{date_range[0].split(' ')[0]} {date_range[0].split(' ')[-1]}" for i in list(range(0, 120)): previous_month_picker = "DayPicker-NavButton--prev" self.driver.execute_script("document.getElementsByClassName('" + previous_month_picker + "')[0].click();") month_displayed = self.wait_for_element_visible("(//*[@class='DayPicker-Caption'])[1]/*[string-length(text()) > 0]", "xpath") month_displayed = str(self.get_text(element=month_displayed)) if month_displayed == param: break assert_that(month_displayed).is_equal_to(param) day_sel = "//*[contains(@aria-label, '{}')]" first = self.wait_for_element_visible(day_sel.format(date_range[0]), "xpath") last = self.wait_for_element_visible(day_sel.format(date_range[1]), "xpath") time.sleep(1) self.click_element(element=first) time.sleep(1) self.click_element(element=last) self.is_graph_period_displayed() @allure.step("TP, AP - verify By Markets icon hint") def graph_verify_top_markets_icon_hint(self): start = self.get_calendar_start_date() end = self.get_calendar_end_date() start = datetime.datetime.strptime(str(start), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) end = datetime.datetime.strptime(str(end), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) expected_hint = f"Top 15 markets depend on the selected period ({start}–{end})." self.hover_on_element("(//*[contains(@id, '-hint-icon')])[2]", "xpath") hint_text_ui = self.get_text("//*[contains(@id, '-hint-icon-tooltip')]", "xpath").replace("\n", "") assert_that(expected_hint).is_equal_to(hint_text_ui) @allure.step("TP - TD switch to Tiktok tab") def td_switch_to_tiktok_tab(self): self.wait_for_element_visible(locator="//*[text()='Date']", locator_type="xpath") self.wait_for_element_clickable(locator="//*[text()='Date']", locator_type="xpath") self.scroll_to_element(locator="//*[text()='Date']", locator_type="xpath") tab = self.wait_for_element_clickable(*self.locator(self.track_locators, "details_tiktok_tab")) self.click_element(element=tab) time.sleep(2) self.wait_for_element_visible(*self.locator(self.track_locators, "details_tiktok_creations_dd")) self.wait_for_element_clickable(*self.locator(self.track_locators, "details_tiktok_creations_dd")) time.sleep(2) self.is_tab_selected(*self.locator(self.track_locators, "details_tiktok_tab")) @allure.step("Track Performance - switch to Tiktok tab") def tp_switch_to_tiktok_tab(self): self.scroll_to_element(*self.locator(self.track_locators, "tp_header")) self.switch_to_tab("performance_tiktok_tab") self.is_tab_selected(*self.locator(self.track_locators, "performance_tiktok_tab")) @allure.step("Track Details - Tiktok - Filtering by creations contents") def td_filter_by_creations_tiktok(self, values): self.wait_for_element_clickable(*self.locator(self.track_locators, "details_tiktok_creations_dd")) creations_dd = self.get_element(*self.locator(self.track_locators, "details_tiktok_creations_dd")) self.click_element(element=creations_dd) user_generated = "track-details-creation-filter-dd-checkbox-ugc" premium_generated = "track-details-creation-filter-dd-checkbox-pgc" for locator in [user_generated, premium_generated]: if self.is_checked(locator=locator, locator_type="id"): element = self.get_element(locator=locator) self.click_on_element_js(element=element) for value in values: checkbox = self.get_element(f"track-details-creation-filter-dd-checkbox-{value}") self.click_on_element_js(element=checkbox) apply_btn = self.get_element("//*[contains(@id, 'apply-btn')]", "xpath") self.click_on_element_js(element=apply_btn) @allure.step("TP - Tiktok - Selecting type") def tp_select_type_tiktok(self, value): self.wait_for_element_visible(*self.locator(self.track_locators, "tp_tiktok_type_dd")) self.click_element(*self.locator(self.track_locators, "tp_tiktok_type_dd")) market_item = "//*[text()='{}']".format(value) market_item = self.get_element(market_item, "xpath") self.click_on_element_js(market_item) @allure.step("TP - Tiktok - Verify type") def tp_verify_by_creations_views_type_tiktok(self, value): value_ui = self.wait_for_element_visible(*self.locator(self.track_locators, "tp_tiktok_type_dd")) value_ui = self.get_text(element=value_ui) assert_that(value_ui).is_equal_to(value) @allure.step("TP - Tiktok - Selecting content type") def tp_select_content_type_tiktok(self, value): self.wait_for_element_visible(*self.locator(self.track_locators, "tp_tiktok_content_type_dd")) self.wait_for_element_clickable(*self.locator(self.track_locators, "tp_tiktok_content_type_dd")) self.click_element(*self.locator(self.track_locators, "tp_tiktok_content_type_dd")) market_item = "//*[text()='{}']".format(value) market_item = self.get_element(market_item, "xpath") self.click_on_element_js(market_item) @allure.step("TP - Tiktok - Verify content type") def tp_verify_type_tiktok(self, value): value_ui = self.wait_for_element_visible(*self.locator(self.track_locators, "tp_tiktok_content_type_dd")) value_ui = self.get_text(element=value_ui) assert_that(value_ui).is_equal_to(value) @allure.step("TP - Tiktok - get top markets total and average - API") def get_tiktok_top_total_avg_api(self, isrc, metric): start = self.get_calendar_start_date() end = self.get_calendar_end_date() resp = self.api_client.get_tiktok_top_resp(isrc, start, end, metric)["tiktok"] total = sum(r[metric] for r in resp) avg = self.apply_rounding_percentage(total / self.graph_get_count_days_from_calendar()) values = {"total": total, "avg": avg} self.log.info(f"api values for: {metric}: {values}") return values @allure.step("TP - Tiktok - get top markets total and average - UI") def get_tiktok_total_avg(self): selector = "//*[text()='Total' or text()='Daily Avg']/following-sibling::*" self.wait_for_element_visible(selector, "xpath") els = self.get_elements(selector, "xpath") values = [int(self.get_text(element=e).replace(",", "")) for e in els] values = {"total": values[0], "avg": values[1]} self.log.info(f"ui values: {values}") return values @allure.step("TP - Tiktok - TD - verify content type") def td_tiktok_verify_content_type(self, type_exp): dd = self.wait_for_element_visible(*self.locator(self.track_locators, "details_tiktok_creations_dd")) type_ui = self.get_text(element=dd) assert_that(type_exp).is_equal_to(type_ui) @allure.step("TP - Tiktok - Graph - verify content type") def graph_tiktok_verify_content_type(self, type_exp): dd = self.wait_for_element_visible("//*[contains(@id, 'track-performance')][contains(@id, 'metric-type-dd')]/span[1]", "xpath") type_ui = self.get_text(element=dd) assert_that(type_exp).is_equal_to(type_ui) @allure.step("Youtube - NVP - VBM - get bar chart tooltip graph values") def get_youtube_vbm_bar_chart_tooltip_values(self, param=""): bars_selector = "//*[contains(@class, 'highcharts-point')]" countriel_labels_selector = "//*[contains(@class, 'xaxis-labels')]/*" self.wait_for_element_visible(bars_selector, "xpath") self.wait_for_element_clickable(bars_selector, "xpath") time.sleep(2) bars_el = self.get_elements(bars_selector, "xpath") self.wait_for_element_visible(countriel_labels_selector, "xpath") self.wait_for_element_clickable(countriel_labels_selector, "xpath") countries_label_el = self.get_elements(countriel_labels_selector, "xpath") if param != "": bars_el = [bars_el[param]] countries_label_el = [countries_label_el[param]] tooltip_data_all = {} for b, c in zip(bars_el, countries_label_el): country = self.get_text(element=c).lower() b_index = bars_el.index(b) self.wait_for_element_visible(bars_selector, "xpath") self.wait_for_element_clickable(bars_selector, "xpath") bars_el = self.get_elements(bars_selector, "xpath") ActionChains(self.driver).move_to_element(to_element=bars_el[b_index]).perform() full_tooltip = self.get_text("//*[contains(@id, 'tooltip')]", "xpath") c_total_perc = self.get_text("(//*[contains(@id, 'tooltip')]/..//*[contains(@id, 'property-value')])[1]", "xpath") all_total = int(self.get_text("(//*[contains(@id, 'tooltip')]/..//b)[2]", "xpath").replace(",", "")) if c_total_perc == "0": c_total = int(c_total_perc) c_perc = int(c_total_perc) else: c_total_perc = c_total_perc.replace(",", "").replace("(", "").replace("%)", "").split(" ") c_total = float(c_total_perc[0]) c_perc = float(c_total_perc[1]) calculated_perc = round((c_total / all_total) * 100, 1) assert_that(c_perc).is_equal_to(calculated_perc) data = {country: {"views": c_total, "perc": c_perc, "total": all_total, "full_str": full_tooltip}} tooltip_data_all.update(data) self.log.info(f"youtube vbm bar chart data graph tooltip: {tooltip_data_all}") return tooltip_data_all @allure.step("TikTok - TikTok by Markets button verification") def verify_tiktok_by_markets_button(self): self.wait_for_element_clickable(*self.locator(self.track_locators, "tp_tiktok_by_markets_btn")) self.click_element(*self.locator(self.track_locators, "tp_tiktok_by_markets_btn")) selected_dsp = self.get_text(*self.locator(self.track_locators, "dsp_picker")) selected_type_tt = self.get_text(*self.locator(self.track_locators, "tp_tiktok_type_dd")) selected_market = self.get_text(*self.locator(self.track_locators, "tp_sbm_country")) self.is_tab_selected(*self.locator(self.track_locators, "countries_tab")) assert_that(selected_dsp).is_equal_to(AppConfig.get("dsp")["tiktok"]) assert_that(selected_type_tt).is_equal_to(self.TIKTOK_BY_CREATIONS) assert_that(selected_market).is_equal_to(self.top_markets) @allure.step("TP - NVP Youtube check video with trending") def nvp_youtube_check_videos_with_trending(self): select_all_selector = "youtube-video-selector-select-all" videos_with_trending_selector = "//*[contains(@class, 'icon-fire')]/ancestor::*/*[contains(@id, 'row')]//input" video_count_sel = "//*[@id='youtube-videos-type-label' and not(text()='0 videos')]" self.wait_for_element_visible(video_count_sel, "xpath") control = self.wait_for_element_clickable("youtube-videos-control") self.click_element(element=control) all_checkbox = self.get_element(select_all_selector) self.click_on_element_js(element=all_checkbox) self.click_on_element_js(element=all_checkbox) if self.is_checked(select_all_selector, "id"): self.click_on_element_js(element=all_checkbox) video_with_trending_checkboxes = list(self.get_elements(locator=videos_with_trending_selector, locator_type="xpath")) assert_that(video_with_trending_checkboxes).is_not_empty() self.click_on_element_js(element=video_with_trending_checkboxes[0]) self.dd_click_apply() trending_title = self.get_text(*self.locator(self.track_locators, "yt_trending_title")) assert_that(trending_title).is_equal_to(self.YT_TRENDING_TITLE) @allure.step("Video page - YT Trending switch the tab") def nvp_youtube_trending_switch_tab(self, tab): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) tab_locator = "//*[@id='youtube-trending-controls-view-type-{}--scope-bar']".format(tab) tab_to_select = self.get_element(locator=tab_locator, locator_type="xpath") self.click_on_element_js(tab_to_select) @allure.step("Video page - YT Trending switch overview controls") def nvp_youtube_trending_switch_overview_control(self, control): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) control_locator = "//*[@id='youtube-trending-controls-{}--scope-bar']".format(control) control_to_select = self.get_element(locator=control_locator, locator_type="xpath") self.click_on_element_js(control_to_select) @allure.step("Video page - YT Trending data filtering") def nvp_youtube_trending_filtering(self, sort_value, checkbox_params, apply=True): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) filter_icon = self.wait_for_element_visible(*self.locator(self.track_locators, "yt_trending_filter_icon")) self.click_element(element=filter_icon) sort_by_dd_locator = "youtube-trending-controls-filter-dd--filter-dd" sort_by_dd_element = self.get_element(locator=sort_by_dd_locator) self.click_on_element_js(element=sort_by_dd_element) sort_by_dd_value = f"//*[@id='youtube-trending-controls-filter-dd--filter-dd']/child::div//*[contains(text(), '{sort_value}')]" sort_by_dd_value_element = self.get_element(locator=sort_by_dd_value, locator_type="xpath") self.click_on_element_js(element=sort_by_dd_value_element) featured_in_locator = "youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-featured" not_featured_in_locator = "youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-not-featured" for locator in [featured_in_locator, not_featured_in_locator]: if self.is_checked(locator=locator, locator_type="id"): element = self.get_element(locator=locator) self.click_on_element_js(element=element) for param in checkbox_params: checkbox = self.get_element(f"youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-{param}") self.click_on_element_js(element=checkbox) apply_btn = self.get_element("//*[contains(@id, 'apply-btn')]", "xpath") if apply: self.click_on_element_js(element=apply_btn) elif not apply: self.click_element(element=filter_icon) @allure.step("Video page - YT Trending filtering - check apply button is disabled") def nvp_youtube_trending_apply_button_state(self): apply_btn_state = self.is_enabled(locator="//*[contains(@id, 'apply-btn')]", locator_type="xpath") return apply_btn_state @allure.step("Video page - YT Trending export") def click_trending_export(self): self.scroll_to_element(*self.locator(self.track_locators, "trending-export")) export = self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-export")) self.click_on_element_js(element=export) self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-export")) @allure.step("TP - verify all markets in market dd") def verify_all_markets_dd(self, dd="track-performance-streams-country-dd", markets=AppConfig.get("stations_markets")): translationTable = str.maketrans("éàèùâêîôûç", "eaeuaeiouc") dd_el = self.wait_for_element_clickable(dd) self.click_element(element=dd_el) self.wait_for_element_visible(*self.locator(self.track_locators, "tp_market_items")) markets_ui = self.get_elements(*self.locator(self.track_locators, "tp_market_items"))[1:] markets_ui = [self.get_text(element=m).translate(translationTable) for m in markets_ui] markets_ui = set(m for m in markets_ui if m not in ["User Generated", "Premium Generated"] and "All Markets" not in m) assert_that(markets_ui).is_equal_to(set(markets[1:])) @allure.step("Track page - By Markets verify tiktok export") def by_markets_tiktok_export_verification(self, isrc, markets_api, tt_type): track_name = self.get_track_title() dsp = self.get_current_dsp() self.click_export() self.click_export_as_csv() file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{track_name} - Countries - {dsp}.csv""" self.log.info(f"file path: {file_path}") columns = ["Date", "Country", "Creations", "Views"] time.sleep(15) data = self.read_from_csv(file_path) self.log.info(f"pandas data: {data}") file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") # verify columns file_columns = list(data.columns) assert_that(file_columns).is_equal_to(columns) # verify dates dates_file = [datetime.datetime.strptime(d, self.get_date_format_from_locale()).date() for d in file["Date"]] start_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[0] end_t = self.get_text(*self.locator(self.track_locators, "date_field_from")).split("–")[1] start = datetime.datetime.strptime(start_t, self.get_date_format_from_locale()).date() end = datetime.datetime.strptime(end_t, self.get_date_format_from_locale()).date() date_range = [] span = end - start for i in range(span.days + 1): d = start + datetime.timedelta(days=i) date_range.append(d) date_range = set(date_range) dates_file = set(dates_file) assert_that(dates_file).is_subset_of(date_range) # verify sorting ui_countries_list = self.youtube_nvp_views_by_markets_get_markets()[:45] ui_countries = [u.upper() for u in ui_countries_list] ordered_countries = {} file_countries = [str(x).replace("nan", "NA") for x in file["Country"] if x not in ordered_countries] file_countries_original_list = [] for i in file_countries: if i not in file_countries_original_list: file_countries_original_list.append(i) assert_that(file_countries_original_list).is_sorted() dates_file_ordered_my_market = data.groupby(by="Country", sort=False).get_group(name=ui_countries[0]) assert_that(dates_file_ordered_my_market["Date"]).is_sorted() # verify markets start = self.get_calendar_start_date() end = self.get_calendar_end_date() tiktok_api_resp = self.api_client.get_tiktok_tracks_analytics(isrc=isrc, start=start, end=end, markets=markets_api) tiktok_markets_api = list(tiktok_api_resp["breakdowns"]["totals"].keys()) tiktok_markets_api_final = [m.upper() for m in tiktok_markets_api] assert_that(set(tiktok_markets_api_final)).is_equal_to(set(file_countries)) # creations + views creations_api = sum(tiktok_api_resp["breakdowns"]["totals"][m]["creations"] for m in tiktok_markets_api) views_api = sum(tiktok_api_resp["breakdowns"]["totals"][m]["video_views"] for m in tiktok_markets_api) creations_file_sum = sum(file["Creations"]) views_file_sum = sum(file["Creations"]) if tt_type == "By Creations": assert_that(creations_api).is_equal_to(creations_file_sum) elif tt_type == "By Views": assert_that(views_api).is_equal_to(views_file_sum) @allure.step("Track page - Navigate to DSP Comparison page") def tp_navigate_to_dsp_comparison(self): self.wait_for_element_clickable(*self.locator(self.track_locators, "dsp_comparison_btn")) dsp_comparison_button = self.get_element(*self.locator(self.track_locators, "dsp_comparison_btn")) self.click_element(element=dsp_comparison_button) @allure.step("Track page - Navigate to Album page") def tp_navigate_to_album(self): album_link = self.wait_for_element_clickable(*self.locator(self.track_locators, "album_link")) self.click_element(element=album_link) @allure.step("Youtube - get Trending details table data") def get_trending_details_table(self): core_selector = "//*[contains(@id, 'youtube-trending-table-{}-')]" column_selectors = ["country-name", "current-position", "trend-position"] data = {} for c in column_selectors: column_sel = core_selector.format(c) self.wait_for_element_visible(column_sel, "xpath") self.scroll_to_element("(" + column_sel + ")" + "[last()]", "xpath") c_els = self.get_elements(column_sel, "xpath") c_els = [self.get_text(element=ce) for ce in c_els] if c == "current-position" or c == "trend-position": c_els = [int(ce) for ce in c_els if ce != ""] data.update({c: c_els}) peak_date_days = ["(//*[contains(@id, 'youtube-trending-table-peak-position') and not(contains(@id, 'date'))])[position()>1]", f"{core_selector.format('peak-position-date')}[1]", f"{core_selector.format('peak-position-date')}[2]"] for c in peak_date_days: self.log.info(f"trending xpath: {c}") self.wait_for_element_visible(c, "xpath") c_els = self.get_elements(c, "xpath") c_els = [int(self.get_text(element=ce)) if c != peak_date_days[1] else datetime.datetime.strptime(self.get_text(element=ce), self.get_date_format_from_locale()).date() for ce in c_els] if c == peak_date_days[0]: column_name = "peak-position" elif c == peak_date_days[1]: column_name = "peak-lifetime-date" else: column_name = "peak-lifetime-days" data.update({column_name: c_els}) self.log.info(f"youtube trending table data: {data}") return data @allure.step("Youtube - Trending details table sort by column") def sort_trending_details_table(self, column): type = "xpath" if column == "peak-lifetime-date": column_header_selector = "//*[@id='youtube-trending-table-peak-position-date'][1]" elif column == "peak-lifetime-days": column_header_selector = "//*[@id='youtube-trending-table-peak-position-date'][2]" else: column_header_selector = f"youtube-trending-table-{column}" type = "id" column_el = self.wait_for_element_clickable(column_header_selector, type) self.click_element(element=column_el) @allure.step("Youtube - Trending details get calendar date") def get_trending_calendar_date(self): date_sel = "//input[contains(@class, 'singlePicker')][contains(@value, '/')]" self.scroll_to_element("//*[text()='Trending Music Videos']", "xpath") date_ui = str(self.get_element(date_sel, "xpath").get_attribute("value")) return datetime.datetime.strptime(date_ui, self.get_date_format_from_locale()).strftime("%Y-%m-%d") @allure.step("Video page - YT Trending verify data filtering") def nvp_youtube_trending_verify_filtering(self, sort_value, checkbox_params): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) filter_icon = self.wait_for_element_visible(*self.locator(self.track_locators, "yt_trending_filter_icon")) filter_icon_background = filter_icon.value_of_css_property("color") assert_that(filter_icon_background).is_equal_to(self.YT_TRENDING_FILTERING_ICON_COLOR) self.click_element(element=filter_icon) sort_by_dd_locator = "youtube-trending-controls-filter-dd--filter-dd" sort_by_selected_value_locator = f"(//*[@id='youtube-trending-controls-filter-dd--filter-dd']//*[contains(text(), '{sort_value}')])[2]" sort_by_selected_value = self.get_element(locator=sort_by_selected_value_locator, locator_type="xpath") is_bold = sort_by_selected_value.value_of_css_property("font-weight") self.log.info("Is sort by: " + str(is_bold)) assert_that(is_bold).is_equal_to("700") sort_by_text = self.get_text(locator=sort_by_dd_locator) checkboxes_locator = "youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-{}" assert_that(sort_by_text).is_equal_to(sort_value) for l in checkbox_params: assert_that(self.is_checked(locator=checkboxes_locator.format(l), locator_type="id")).is_true() self.click_element(element=filter_icon) @allure.step("Video page - YT Trending verify overview controls") def nvp_youtube_trending_verify_overview_control(self, tab): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) control_locator = "//*[@id='youtube-trending-controls-{}--scope-bar']".format(tab) control_selected = self.is_tab_selected(locator=control_locator, locator_type="xpath") assert_that(control_selected).is_true() @allure.step("Video page - YT Trending verify placeholder") def nvp_youtube_trending_verify_placeholder(self): placeholder_locator = "//*[text()='Select a single video to begin seeing data.']" self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) placeholder_el = self.wait_for_element_visible(placeholder_locator, "xpath") assert_that(self.is_element_displayed(element=placeholder_el)).is_true() @allure.step("Video page - YT Trending verify trending details export button") def verify_youtube_trending_export_button(self, present=True): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) if not present: button_export = self.is_element_displayed(*self.locator(self.track_locators, "trending-export")) assert_that(button_export).is_equal_to(present) else: button_export = self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-export")) color_before = button_export.value_of_css_property("background-color") self.hover_on_element(element=button_export) color_after = button_export.value_of_css_property("background-color") cursor = button_export.value_of_css_property("cursor") assert_that(cursor).is_equal_to("pointer") assert_that(color_before).is_not_equal_to(color_after) @allure.step("Video page - YT Trending verify trending details export button") def verify_youtube_trending_popop_export_button(self): button_export = self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-popup-export")) color_before = button_export.value_of_css_property("background-color") self.hover_on_element(element=button_export) color_after = button_export.value_of_css_property("background-color") cursor = button_export.value_of_css_property("cursor") assert_that(cursor).is_equal_to("pointer") assert_that(color_before).is_not_equal_to(color_after) @allure.step("Video page - YT Trending Details - verify export") def nvp_trending_details_verify_export(self): date_trending = self.get_trending_calendar_date() date_trending = datetime.datetime.strptime(date_trending, "%Y-%m-%d").strftime(self.get_date_file_format_from_locale()) track_name = self.get_text(self.nvp_youtube_selected_videos) table_ui = self.get_trending_details_table() self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) button_export = self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-export")) self.click_element(element=button_export) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/{date_trending} - {track_name} - Trending.csv""" self.log.info(f"file path: {file_path}") country_column = "Country" columns = [country_column, "Position #", "Position Trend", "Peak, Lifetime Position #", "Peak, Lifetime Position # Date", "On Chart, Lifetime days"] data = self.read_from_csv(file_path) self.log.info(f"pandas data: {data}") file = {} for c in columns: file[c] = data.get(c).to_list() self.log.info(f"file: {file}") # verify file_columns = list(data.columns) assert_that(file_columns).is_equal_to(columns) assert_that(file[country_column]).is_sorted() assert_that(sorted(table_ui["country-name"])).is_equal_to(file[country_column]) assert_that(set(table_ui["current-position"])).is_equal_to(set(file["Position #"])) assert_that(set(table_ui["trend-position"])).is_equal_to(set(abs(int(str(f).replace("Re-Entry", "0").replace("New", "0"))) for f in file["Position Trend"])) assert_that(set(table_ui["peak-position"])).is_equal_to(set(file["Peak, Lifetime Position #"])) assert_that(set(table_ui["peak-lifetime-date"])).is_equal_to(set(datetime.datetime.strptime(d, AppConfig.get("date_formats")["mm/dd/yy"]).date() for d in file["Peak, Lifetime Position # Date"])) assert_that(set(table_ui["peak-lifetime-days"])).is_equal_to(set(file["On Chart, Lifetime days"])) @allure.step("Video page - YT Trending Details - open popup") def nvp_youtube_trending_open_popup(self, position=1): popup_icon_locator = f"youtube-trending-table-current-position-{position}" icon = self.wait_for_element_clickable(popup_icon_locator) self.click_element(element=icon) assert_that(self.is_element_displayed("youtube-trending-modal-window-title")).is_true() @allure.step("Video page - YT Trending Details - Popup - verify trending") def nvp_youtube_trending_popup_verify_export(self): video_title = self.get_text("youtube-trending-modal-window-video-main-info-videos-title") market = self.get_text("//*[contains(text(), 'YouTube Trending Videos')]", "xpath").split(" ")[-1] market_code = self.sql_client.get_country_code_by_market_name(market) positions_api = self.get_trending_popup_positions_api(market_code) button_export = self.wait_for_element_clickable(*self.locator(self.track_locators, "trending-popup-export")) self.click_element(element=button_export) file_path = f"""http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/Trending Position over time - {video_title} - {market_code.upper()}.csv""" self.log.info(f"file path: {file_path}") columns = ["Date", "Country", "Video Title", "Position"] data = self.read_from_csv(file_path) self.log.info(f"pandas data: {data}") file = {} for c in list(data.columns): file[c] = data.get(c).dropna().to_list() self.log.info(f"file: {file}") # verify file_columns = list(data.columns) date_column_values = [datetime.datetime.strptime(f, self.get_date_format_from_locale()).date() for f in file["Date"]] start = self.get_calendar_start_date() start = datetime.datetime.strptime(start, "%Y-%m-%d").date() date_range = [] days_count = self.graph_get_count_days_from_calendar() for i in range(days_count): d = start + datetime.timedelta(days=i) date_range.append(d) assert_that(file_columns).is_equal_to(columns) assert_that(date_column_values).is_sorted() assert_that(date_column_values).is_equal_to(date_range) assert_that({market}).is_equal_to(set(file["Country"])) assert_that({video_title}).is_equal_to(set(file["Video Title"])) assert_that(sorted(positions_api)).is_equal_to([f for f in file["Position"] if f != "N/A"]) @allure.step("Track Page - NVP - Trending Popup - get positions") def get_trending_popup_positions_api(self, market): # date = self.get_trending_calendar_date() video_id = self.parameter_from_url(self.str_gr_video) start = self.get_calendar_start_date() end = self.get_calendar_end_date() positions_api = self.api_client.get_charts_youtube_video_positions(video_id, market, start, end)["items"] positions_api = [i["position"] for i in positions_api] return positions_api @allure.step("Track Page - NVP - Trending - expand datepicker element") def scroll_to_trending_datepicker(self): self.scroll_to_element(*self.locator(self.track_locators, "yt_trending_title")) datepicker = self.is_element_displayed(*self.locator(self.track_locators, "date_picker")) assert_that(datepicker).is_true() @allure.step("NVP -> Trending - datepicker grid verification") def trending_datepicker_grid_verification(self, grid_date): first_weekday_locator = "(//div[@class='DayPicker-Weekday'])[1]" selected_date_locator = "//div[contains(@class, 'DayPicker-Day--selected')]" # check grid first weekday is monday weekday_el = self.get_element(locator=first_weekday_locator, locator_type="xpath") weekday_text = self.get_text(element=weekday_el) self.log.info("First weekday " + weekday_text) assert_that(weekday_text).is_equal_to(self.CALENDAR_GRID_FIRST_WEEKDAY) # check grid default selected date grid_selected_date = self.get_attribute_value(locator=selected_date_locator, locator_type="xpath", attribute="aria-label") grid_selected_date_formatted = datetime.datetime.strptime(grid_selected_date, "%a %b %d %Y").strftime("%Y-%m-%d") self.log.info("Selected date " + str(grid_selected_date_formatted)) assert_that(str(grid_selected_date_formatted)).is_equal_to(str(grid_date)) # additional checks reset_button_el = self.get_element(*self.locator(self.track_locators, "trending_date_picker_reset_button")) reset_button = self.is_element_displayed(element=reset_button_el) reset_button_active = reset_button_el.value_of_css_property("color") ActionChains(self.driver).move_to_element(reset_button_el).perform() reset_button_hover = reset_button_el.value_of_css_property("background-color") assert_that(reset_button).is_true() assert_that(reset_button_active).is_equal_to("rgba(0, 0, 0, 1)") assert_that(reset_button_hover).is_equal_to("rgba(218, 218, 230, 1)") @allure.step("NVP -> Trending - check video last available date in the datepicker grid") def verify_trending_datepicker_last_available_date(self, date): date_formatted = datetime.datetime.strptime(date, "%Y-%m-%d").date() grid_date = datetime.datetime.strptime(date, "%Y-%m-%d").strftime("%a %b %d %Y") grid_disabled_after_max_date = date_formatted + datetime.timedelta(days=1) grid_disabled_after_max_date_formatted = datetime.datetime.strptime(str(grid_disabled_after_max_date), "%Y-%m-%d").strftime("%a %b %d %Y") # dates locators grid_date_locator = f"//div[@aria-label='{grid_date}']" grid_disabled_after_max_date_locator = f"//div[@aria-label='{grid_disabled_after_max_date_formatted}']" # dates verification grid_max_date_el = self.get_element(locator=grid_date_locator, locator_type="xpath") grid_disabled_after_max_date_el = self.get_element(locator=grid_disabled_after_max_date_locator, locator_type="xpath") grid_max_date_disabled_state = self.get_attribute_value(element=grid_max_date_el, attribute="aria-disabled") grid_after_max_date_disabled_state = self.get_attribute_value(element=grid_disabled_after_max_date_el, attribute="aria-disabled") assert_that(grid_max_date_disabled_state).is_equal_to("false") assert_that(grid_after_max_date_disabled_state).is_equal_to("true") def get_date_format_from_locale(self): locale_format = locale.getdefaultlocale()[0] if locale_format == "en_GB": date_format = "dd/mm/yy" else: date_format = "mm/dd/yy" self.log.info(f"Locale : {locale_format}") return AppConfig.get("date_formats")[date_format] def get_date_file_format_from_locale(self): return AppConfig.get("date_formats")["mm-dd-yy"] @allure.step("NVP -> Trending - check video first available date in the datepicker grid") def verify_trending_datepicker_first_available_date(self, date): date_api_formatted = datetime.datetime.strptime(date, "%Y-%m-%d").date() grid_date = datetime.datetime.strptime(date, "%Y-%m-%d").strftime("%a %b %d %Y") grid_disabled_before_min_date = date_api_formatted - datetime.timedelta(days=1) grid_disabled_before_min_date_formatted = datetime.datetime.strptime(str(grid_disabled_before_min_date), "%Y-%m-%d").strftime("%a %b %d %Y") # dates locators grid_date_locator = f"//div[@aria-label='{grid_date}']" grid_disabled_before_min_date_locator = f"//div[@aria-label='{grid_disabled_before_min_date_formatted}']" # dates verification grid_min_date_el = self.get_element(locator=grid_date_locator, locator_type="xpath") grid_disabled_before_min_date_el = self.get_element(locator=grid_disabled_before_min_date_locator, locator_type="xpath") grid_min_date_disabled_state = self.get_attribute_value(element=grid_min_date_el, attribute="aria-disabled") grid_before_min_date_disabled_state = self.get_attribute_value(element=grid_disabled_before_min_date_el, attribute="aria-disabled") assert_that(grid_min_date_disabled_state).is_equal_to("false") assert_that(grid_before_min_date_disabled_state).is_equal_to("true") @allure.step("NVP -> Trending - check available period for selected video in the datepicker grid") def verify_trending_datepicker_available_period(self, video_id): grid_available_dates_locator = "//*[contains(@class, 'DayPicker-Day') and contains(@aria-disabled, 'false')]" backward_arrow_locator = "//span[contains(@class, 'icon-prev')]" max_date_api = self.api_client.get_video_trending_date(video_id=video_id)["video"]["max"] min_date_api = self.api_client.get_video_trending_date(video_id=video_id)["video"]["min"] max_date = datetime.datetime.strptime(max_date_api, "%Y-%m-%d").date() min_date = datetime.datetime.strptime(min_date_api, "%Y-%m-%d").date() days_api = rrule.rrule(rrule.DAILY, dtstart=min_date, until=max_date).count() if max_date.day > min_date.day: months = rrule.rrule(rrule.MONTHLY, dtstart=min_date, until=max_date).count() - 1 else: months = rrule.rrule(rrule.MONTHLY, dtstart=min_date, until=max_date).count() self.log.info("Numer of months: " + str(months)) backward_arrow = self.get_element(locator=backward_arrow_locator, locator_type="xpath") grid_dates_list = [] for n in range(months + 1): grid_available_dates = self.get_elements(locator=grid_available_dates_locator, locator_type="xpath") for date in grid_available_dates: grid_dates_list.append(date) is_date_disabled = self.get_attribute_value(element=date, attribute="aria-disabled") assert_that(is_date_disabled).is_equal_to("false") self.click_element(element=backward_arrow) assert_that(days_api).is_equal_to(len(grid_dates_list)) @allure.step("NVP -> Trending - verify datepicker arrows background color") def verify_trending_datepicker_arrows_background(self): prev_years_arrow_locator = "//span[contains(@class, 'icon-backward')]/parent::div" next_years_arrow_locator = "//span[contains(@class, 'icon-forward')]/parent::div" prev_month_arrow_locator = "//span[contains(@class, 'icon-prev')]/parent::div" next_month_arrow_locator = "//span[contains(@class, 'icon-next')]/parent::div" arrows = [prev_years_arrow_locator, next_years_arrow_locator, prev_month_arrow_locator, next_month_arrow_locator] for arrow in arrows: arrow_el = self.get_element(locator=arrow, locator_type="xpath") color_before_hover = arrow_el.value_of_css_property("background-color") self.log.info("color before hover: {}".format(color_before_hover)) ActionChains(self.driver).move_to_element(to_element=arrow_el).perform() color_after_hover = arrow_el.value_of_css_property("background-color") self.log.info("color after hover: {}".format(color_after_hover)) assert_that(color_before_hover).is_not_equal_to(color_after_hover) assert_that(color_after_hover).is_equal_to("rgba(229, 245, 254, 1)") self.click_element(element=arrow_el) @allure.step("NVP -> Trending - verify trending home market card") def verify_trending_home_market_card(self, market): if market in [AppConfig.get("market")["global"]["name"], AppConfig.get("market")["albania"]["name"]]: markets_locator = "//span[contains(@id, 'youtube-market-card')][contains(@id, 'name-text')]" markets_els = self.get_elements(locator=markets_locator, locator_type="xpath") markets = [self.get_text(element=c) for c in markets_els] assert_that(markets).does_not_contain("Home Market") else: card_locator = f"youtube-market-card-{market}" card_icon_locator = f"//*[@id='youtube-market-card-{market}']/*[contains(@class, 'icon-home')]" card_border = self.get_element(locator=card_locator).value_of_css_property("border") assert_that(self.is_element_displayed(card_icon_locator, "xpath")).is_true() assert_that(card_border).is_equal_to(self.YT_TRENDING_HOME_MARKET_CARD_BORDER) @allure.step("Verify date format - UI") def validate_date(self, date_ui): self.log.info(f"date to validate: {date_ui}") try: datetime.datetime.strptime(date_ui, self.get_date_format_from_locale()) except ValueError: assert_that(True).described_as(date_ui).is_false() @allure.step("TP - get header tooltips") def get_header_tooltips(self): icon_selector = "//*[contains(@id, 'market-value')]/..//*[contains(@class, 'icon-info')]" self.scroll_to_element(icon_selector, "xpath") self.wait_for_element_visible(icon_selector, "xpath") icon_els = self.get_elements(icon_selector, "xpath") tooltip_texts = [] for icon in icon_els: self.hover_on_element(element=icon) text_el = self.wait_for_element_visible("//*[contains(text(), 'Since')]", "xpath") text = self.get_text(element=text_el) tooltip_texts.append(text) self.click_on_graph_title() self.log.info(f"tooltip_texts: {tooltip_texts}") return tooltip_texts @allure.step("TP - verify tiktok comparison clock icon") def verify_tt_comparison_clock_icon(self): icon_locator = "track-performance-icon-hint" self.hover_on_element(icon_locator) tooltip = self.get_text(self.hint_locator, "xpath") dates = [t.split(" ")[-1].strip() for t in tooltip.split(".") if t != ""] self.log.info(f"dates: {dates}") for date in dates: self.validate_date(date) @allure.step("TP - Details - click export") def td_click_export(self): self.scroll_to_track_details() time.sleep(10) self.scroll_to_track_details() export_button_locator = "//*[contains(@id, 'controls-export-btn')]" export_button = self.wait_for_element_clickable(export_button_locator, "xpath") self.click_element(element=export_button) @allure.step("TP - get image source") def get_image_source(self): loc = "(//a[contains(@href, 'spotify:track:')]/img)[2]" image_el = self.wait_for_element_visible(loc, "xpath") src_attr = image_el.get_attribute("src") return src_attr @allure.step("Open Top Header market dd") def open_top_header_market_dd(self): market_dd = self.wait_for_element_visible(*self.locator(self.track_locators, "market_picker")) self.click_element(element=market_dd) self.is_element_displayed(*self.locator(self.track_locators, "top_header_market_filter")) @allure.step("Top Header markets list present") def is_top_header_markets_list_present(self): markets_list_locator = "//*[contains(@id, 'header-market-switcher-item')][contains(@id, 'label')]" markets_list = self.get_elements(locator=markets_list_locator, locator_type="xpath") for market in markets_list: market_is_present = self.is_element_displayed(element=market) assert_that(market_is_present).is_true() @allure.step("Top Header markets get markets list") def get_top_header_markets_list(self): markets_list_locator = "//*[contains(@id, 'header-market-switcher-item')][contains(@id, 'label')]" markets_list = self.get_elements(locator=markets_list_locator, locator_type="xpath") markets = [] for market in markets_list: market_name = self.get_text(market) markets.append(market_name) return markets @allure.step("Top Header markets - enter search value") def top_header_markets_enter_search_value(self, text): self.wait_for_element_visible(*self.locator(self.track_locators, "top_header_market_filter")) self.clear_text(*self.locator(self.track_locators, "top_header_market_filter")) self.send_text(text, *self.locator(self.track_locators, "top_header_market_filter")) @allure.step("Top Header markets - Check for filtered values in the dd") def top_header_markets_is_filtered_by(self, value): markets_list_locator = "//*[contains(@id, 'header-market-switcher-item')][contains(@id, 'label')]" self.wait_for_element_visible(locator=markets_list_locator, locator_type="xpath") markets_list = self.get_elements(locator=markets_list_locator, locator_type="xpath") markets_list_texts = [self.get_text(element=t) for t in markets_list] for t in markets_list_texts: assert_that(t.lower()).contains(value.lower()) @allure.step("Top Header markets - Value is present in the dd") def top_header_markets_value_is_present_in_dd(self, value): value_locator = f"//*[contains(text(), '{value}')]" self.wait_for_element_visible(locator=value_locator, locator_type="xpath") market = self.get_element(locator=value_locator, locator_type="xpath") market_is_present = self.is_element_present(element=market) assert_that(market_is_present).is_true() @allure.step("Top Header markets - clear text") def top_header_markets_clear_text(self): self.wait_for_element_clickable(*self.locator(self.track_locators, "top_header_market_clear_icon")) self.click_element(*self.locator(self.track_locators, "top_header_market_clear_icon")) @allure.step("Top Header markets - filtering no results") def top_header_markets_verify_no_results(self): no_markets_locator = "//*[text()='No markets found.']" filtering_parameters_locator = "//*[text()='Try changing filtering parameters.']" no_markets_el = self.get_element(locator=no_markets_locator, locator_type="xpath") filtering_parameters_el = self.get_element(locator=filtering_parameters_locator, locator_type="xpath") no_markets_text = self.get_text(element=no_markets_el) filtering_parameters_text = self.get_text(element=filtering_parameters_el) assert_that(no_markets_text).is_equal_to("No markets found.") assert_that(filtering_parameters_text).is_equal_to("Try changing filtering parameters.") @allure.step("Track Performance - streams and sources tab is active") def track_performance_is_tab_active(self, tab): tab_locator = "//div[contains(@id, 'track-performance-{}')]".format(tab) self.is_tab_selected(tab_locator, "xpath") @allure.step("Track Performance - calendar navigate forward") def calendar_navigate_forward(self): navigate_loc = "//*[contains(@class, 'next')]" el = self.wait_for_element_clickable(navigate_loc, "xpath") self.click_on_element_js(element=el) @allure.step("Full Performance - Youtube trending get regions list") def yt_trending_get_regions_list(self): regions_list_locator = "//div[contains(@id, 'youtube-market-card')]//ancestor::div[3]/span" regions_els = self.get_elements(locator=regions_list_locator, locator_type="xpath") regions_list = [self.get_text(element=region) for region in regions_els] regions_modified = [] for region in regions_list: if region in ["EUROPE", "LATIN-IBERIA", "OCEANIA", "OTHER"]: region_modified = str(region).title() regions_modified.append(region_modified) else: regions_modified.append(region) self.log.info("Regions list: " + str(regions_modified)) return regions_modified @allure.step("Full Performance - Youtube trending regions mapping verification") def yt_trending_region_markets_verification(self, regions): for region in regions: region_locator = f"//*[text()='{region['name']}']/parent::div//span[contains(@id, 'youtube-market-card')][contains(@id, 'country-name-text')]" region_els = self.get_elements(locator=region_locator, locator_type="xpath") countries = [self.get_text(element=country) for country in region_els] for country in countries: if country == "Home Market": countries.remove(country) assert_that(countries).is_equal_to(region["countries"]) @allure.step("Full Performance - Youtube trending markets and positions by regions") def yt_trending_get_markets_and_positions_by_regions(self, regions): markets_positions_list = {} for region in regions: markets_locator = f"//*[text()='{region}']/parent::div//span[contains(@id, 'youtube-market-card')][contains(@id, 'name-text')]" video_position_locator = f"//*[text()='{region}']/parent::div//span[contains(@id, 'youtube-market-card')][contains(@id, 'position-text')]" markets_els = self.get_elements(locator=markets_locator, locator_type="xpath") videos_position_els = self.get_elements(locator=video_position_locator, locator_type="xpath") markets_els_text = [self.get_text(element=country) for country in markets_els] videos_position_els_text = [self.get_text(element=position) for position in videos_position_els] els_list = [] for m, p in zip(markets_els_text, videos_position_els_text): els_by_market = {"market": m, "position": p} els_list.append(els_by_market) markets_positions_list[region] = els_list self.log.info("Trending info: " + str(markets_positions_list)) return markets_positions_list @allure.step("Full Performance - Youtube trending markets and positions by markets") def yt_trending_get_markets_and_positions_by_markets(self): markets_positions_list = {} markets_locator = "//span[contains(@id, 'youtube-market-card')][contains(@id, 'name-text')]" video_position_locator = "//span[contains(@id, 'youtube-market-card')][contains(@id, 'position-text')]" markets_els = self.get_elements(locator=markets_locator, locator_type="xpath") videos_position_els = self.get_elements(locator=video_position_locator, locator_type="xpath") markets_els_text = [self.get_text(element=country) for country in markets_els] videos_position_els_text = [self.get_text(element=position) for position in videos_position_els] markets_positions_list = [] for m, p in zip(markets_els_text, videos_position_els_text): els_by_market = {"market": m, "position": p} markets_positions_list.append(els_by_market) self.log.info("Trending info: " + str(markets_positions_list)) return markets_positions_list @allure.step("Full Performance - Youtube trending markets and position sorting by regions") def yt_trending_verify_markets_and_positions_by_regions_sorting(self, sort_by, regions): markets_and_positions = self.yt_trending_get_markets_and_positions_by_regions(regions) for region in regions: if sort_by == self.YT_TRENDING_SORT_BY_ALPHABETICAL: markets = [markets_and_positions[region][t]["market"] for t in range(len(markets_and_positions[region]))] markets_by_region = {region: markets} assert_that(markets_by_region[region]).is_equal_to(sorted(markets_by_region[region])) elif sort_by == self.YT_TRENDING_SORT_BY_VIDEO_POSITION: actual_positions = [int(str(markets_and_positions[region][p]["position"]).split("#")[1]) for p in range(len(markets_and_positions[region])) if markets_and_positions[region][p]["position"] != "–"] positions_by_region = {region: actual_positions} assert_that(positions_by_region[region]).is_equal_to(sorted(positions_by_region[region])) markets_with_empty_position = [markets_and_positions[region][p]["market"] for p in range(len(markets_and_positions[region])) if markets_and_positions[region][p]["position"] == "–"] markets_by_empty_position = {region: markets_with_empty_position} if len(markets_by_empty_position[region]) > 0: assert_that(markets_by_empty_position[region]).is_equal_to(sorted(markets_by_empty_position[region])) @allure.step("Full Performance - Youtube trending markets and position sorting by markets") def yt_trending_verify_markets_and_positions_by_markets_sorting(self, sort_by): markets_and_positions = self.yt_trending_get_markets_and_positions_by_markets() if sort_by == self.YT_TRENDING_SORT_BY_ALPHABETICAL: markets = [markets_and_positions[t]["market"] for t in range(len(markets_and_positions))] assert_that(markets).is_equal_to(sorted(markets)) elif sort_by == self.YT_TRENDING_SORT_BY_VIDEO_POSITION: actual_positions = [int(str(markets_and_positions[p]["position"]).split("#")[1]) for p in range(len(markets_and_positions)) if markets_and_positions[p]["position"] != "–"] assert_that(actual_positions).is_equal_to(sorted(actual_positions)) markets_with_empty_position = [markets_and_positions[p]["market"] for p in range(len(markets_and_positions)) if markets_and_positions[p]["position"] == "–"] if len(markets_with_empty_position) > 0: assert_that(markets_with_empty_position).is_equal_to(sorted(markets_with_empty_position)) @allure.step("Full Performance - Youtube trending default cards states by markets") def yt_trending_verify_default_cards_states_by_markets(self): markets_and_positions = self.yt_trending_get_markets_and_positions_by_markets() actual_positions = [int(str(markets_and_positions[p]["position"]).split("#")[1]) for p in range(len(markets_and_positions)) if markets_and_positions[p]["position"] != "–"] empty_positions = [markets_and_positions[p]["position"] for p in range(len(markets_and_positions)) if markets_and_positions[p]["position"] == "–"] assert_that(len(actual_positions)).is_greater_than(0) assert_that(len(empty_positions)).is_greater_than(0) @allure.step("Full Performance - Youtube trending regions hiding verification") def yt_trending_region_hiding_verification(self, region, sort_value, checkbox_params): regions_list_locator = "//div[contains(@id, 'youtube-market-card')]//ancestor::div[3]/span" featured_countries_locator = f"//*[text()='{region['name'].upper()}']/parent::div//span[contains(@id, 'youtube-market-card')][contains(@id, 'position-text')]" regions_els_before = self.get_elements(locator=regions_list_locator, locator_type="xpath") regions_list_before = [self.get_text(element=region) for region in regions_els_before] featured_countries_els = self.get_elements(locator=featured_countries_locator, locator_type="xpath") featured_state_list = [self.get_text(element=featured_country) for featured_country in featured_countries_els] self.nvp_youtube_trending_filtering(sort_value=sort_value, checkbox_params=checkbox_params) if checkbox_params == self.featured: for state in featured_state_list: assert_that(state).is_not_equal_to("-") elif checkbox_params == self.not_featured: for state in featured_state_list: assert_that(state).is_equal_to("-") regions_els_after = self.get_elements(locator=regions_list_locator, locator_type="xpath") regions_list_after = [self.get_text(element=region) for region in regions_els_after] assert_that(regions_list_before).is_not_equal_to(regions_list_after) assert_that(region).is_not_in(regions_list_after) @allure.step("Full Performance - Youtube trending verify selected filter options") def yt_trending_verify_selected_filter_options(self, expected_sort_by, exp_featured, exp_not_featured): filter_icon = self.wait_for_element_visible(*self.locator(self.track_locators, "yt_trending_filter_icon")) self.click_element(element=filter_icon) sort_by_dd_locator = "youtube-trending-controls-filter-dd--filter-dd" sort_by_dd_element = self.get_element(locator=sort_by_dd_locator) sort_by_dd_value = self.get_text(element=sort_by_dd_element) featured_in_locator = "youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-featured" not_featured_in_locator = "youtube-trending-controls-filter-dd-spotify-filter-dd-checkbox-not-featured" featured_in_checked = self.get_attribute_value(locator=featured_in_locator, attribute="data-checked") not_featured_in_checked = self.get_attribute_value(locator=not_featured_in_locator, attribute="data-checked") assert_that(sort_by_dd_value).is_equal_to(expected_sort_by) assert_that(featured_in_checked).is_equal_to(exp_featured) assert_that(not_featured_in_checked).is_equal_to(exp_not_featured) self.click_element(element=filter_icon) @allure.step("Full Performance - Youtube trending verify market position") def yt_trending_verify_market_position(self, tab, market, video_id, date): trending_info = self.api_client.get_yt_trending_for_video(video_id=video_id, date=date) position = [trending_info[t]["data"]["current_position"] for t in range(len(trending_info)) if trending_info[t]["country_code"] == market] api_market_position = {"market": market, "position": position[0]} if tab == self.YT_TRENDING_OVERVIEW_TAB: ui_position_loc = f"youtube-market-card-{market}-position-text" ui_position_el = self.get_element(locator=ui_position_loc) ui_position = self.get_text(element=ui_position_el) ui_position = ui_position.split("#")[1] elif tab == self.YT_TRENDING_DETAILS_TAB: table_markets = self.get_trending_details_table()["country-name"] market_name = self.sql_client.get_market_name_by_country_code(country_code=market) index = table_markets.index(market_name) + 1 ui_position_loc = f"youtube-trending-table-current-position-{index}" ui_position_el = self.get_element(locator=ui_position_loc) ui_position = self.get_text(element=ui_position_el) assert_that(str(api_market_position["position"])).is_equal_to(ui_position) return ui_position @allure.step("Full Performance - Youtube trending verify trend value") def yt_trending_verify_trend_value(self, tab, market, video_id, date): trending_info = self.api_client.get_yt_trending_for_video(video_id=video_id, date=date) trend = [trending_info[t]["data"]["trend"] for t in range(len(trending_info)) if trending_info[t]["country_code"] == market] self.log.info("Api trend: " + str(trend)) api_market_trend = {"market": market, "trend": trend[0]} if tab == self.YT_TRENDING_OVERVIEW_TAB: ui_trend_locator = f"(//*[@id='youtube-market-card-{market}-position-text']/parent::div//span)[last()]" elif tab == self.YT_TRENDING_DETAILS_TAB: table_markets = self.get_trending_details_table()["country-name"] market_name = self.sql_client.get_market_name_by_country_code(country_code=market) index = table_markets.index(market_name) + 1 ui_trend_locator = f"(//div[@id='youtube-trending-table-trend-position-{index}']//span)[last()]" ui_trend_el = self.get_element(locator=ui_trend_locator, locator_type="xpath") trend_color = ui_trend_el.value_of_css_property("color") self.log.info("Trend color: " + str(trend_color)) if trend_color == "rgba(245, 67, 54, 1)": ui_trend = -int(self.get_text(element=ui_trend_el)) assert_that(-api_market_trend["trend"]).is_equal_to(ui_trend) else: ui_trend = int(self.get_text(element=ui_trend_el)) assert_that(-api_market_trend["trend"]).is_equal_to(ui_trend) self.log.info("Trending trend: " + str(ui_trend)) return ui_trend @allure.step("Full Performance - Youtube trending verify trend arrow") def yt_trending_verify_trend_arrow(self, tab, market, trend): if tab == self.YT_TRENDING_OVERVIEW_TAB: zero_trend_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-arrow-right')]" negative_trend_diag_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-arrow-diag-bottom')]" negative_trend_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-arrow-down')]" positive_trend_diag_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-arrow-diag-top')]" positive_trend_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-arrow-up')]" elif tab == self.YT_TRENDING_DETAILS_TAB: table_markets = self.get_trending_details_table()["country-name"] market_name = self.sql_client.get_market_name_by_country_code(country_code=market) index = table_markets.index(market_name) + 1 zero_trend_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-arrow-right')]" negative_trend_diag_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-arrow-diag-bottom')]" negative_trend_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-arrow-down')]" positive_trend_diag_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-arrow-diag-top')]" positive_trend_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-arrow-up')]" if trend == 0: zero_trend = self.is_element_displayed(locator=zero_trend_locator, locator_type="xpath") assert_that(zero_trend).is_true() elif -4 <= trend < 0: negative_trend_diag = self.is_element_displayed(locator=negative_trend_diag_locator, locator_type="xpath") assert_that(negative_trend_diag).is_true() elif trend < -4: negative_trend = self.is_element_displayed(locator=negative_trend_locator, locator_type="xpath") assert_that(negative_trend).is_true() elif 0 < trend <= 4: positive_trend_diag = self.is_element_displayed(locator=positive_trend_diag_locator, locator_type="xpath") assert_that(positive_trend_diag).is_true() elif 4 < trend: positive_trend = self.is_element_displayed(locator=positive_trend_locator, locator_type="xpath") assert_that(positive_trend).is_true() @allure.step("Full Performance - Youtube trending verify featured in card") def yt_trending_verify_featured_in_card(self, market, video_id, date): market_region = market["market"] flag_icon = self.is_element_displayed(f"youtube-market-card-{market_region}-icon") market_el = self.get_element(f"youtube-market-card-{market_region}-country-name-text") market_name = self.get_text(element=market_el) assert_that(flag_icon).is_true() assert_that(market_name).is_equal_to(market["name"]) self.yt_trending_verify_market_position(tab=self.YT_TRENDING_OVERVIEW_TAB, market=market["market"], video_id=video_id, date=date) trend = self.yt_trending_verify_trend_value(tab=self.YT_TRENDING_OVERVIEW_TAB, market=market["market"], video_id=video_id, date=date) self.yt_trending_verify_trend_arrow(tab=self.YT_TRENDING_OVERVIEW_TAB, market=market["market"], trend=trend) @allure.step("Full Performance - Youtube trending verify not featured in card") def yt_trending_verify_not_featured_in_card(self, market): market_region = market["market"] card_el = self.get_element(f"youtube-market-card-{market_region}") card_background = card_el.value_of_css_property("background-color") flag_icon = self.is_element_displayed(f"youtube-market-card-{market_region}-icon") market_el = self.get_element(f"youtube-market-card-{market_region}-country-name-text") market_name = self.get_text(element=market_el) position_el = self.get_element(f"youtube-market-card-{market_region}-position-text") position = self.get_text(element=position_el) assert_that(card_background).is_equal_to("rgba(249, 249, 251, 1)") assert_that(flag_icon).is_true() assert_that(market_name).is_equal_to(market["name"]) assert_that(position).is_equal_to("–") @allure.step("Full Performance - Youtube trending verify blue dot") def yt_trending_verify_blue_dot(self, tab, market, new_entry=True): if tab == self.YT_TRENDING_OVERVIEW_TAB: blue_dot_locator = f"//*[@id='youtube-market-card-{market}-position-text']/parent::div//span[contains(@class, 'icon-chart-circle')]" elif tab == self.YT_TRENDING_DETAILS_TAB: table_markets = self.get_trending_details_table()["country-name"] market_name = self.sql_client.get_market_name_by_country_code(country_code=market) index = table_markets.index(market_name) + 1 blue_dot_locator = f"//*[@id='youtube-trending-table-trend-position-{index}']//span[contains(@class, 'icon-chart-circle')]" blue_dot = self.get_element(locator=blue_dot_locator, locator_type="xpath") is_blue_dot_present = self.is_element_present(element=blue_dot) assert_that(is_blue_dot_present).is_true() ActionChains(self.driver).move_to_element(to_element=blue_dot).perform() if new_entry: hint = self.is_element_present(locator="//*[text()='New Entry']", locator_type="xpath") assert_that(hint).is_true() elif not new_entry: hint = self.is_element_present(locator="//*[text()='Re-Entry']", locator_type="xpath") assert_that(hint).is_true() @allure.step("TP - TD - Change DSPs") def td_change_dsp(self, param, tab="current"): self.scroll_to_track_details() dsp_dd_loc = "//*[contains(@id, 'controls-dsp-dd')]" all_dsps = "All DSPs " if isinstance(param, str): param = [param] dsp_dd = self.get_element(dsp_dd_loc, "xpath") self.click_on_element_js(element=dsp_dd) self.wait_for_element_clickable(locator=all_dsps) all_el = self.get_element(all_dsps) self.click_element(element=all_el) if self.is_checked(all_dsps, "id"): self.wait_for_element_clickable(locator=all_dsps) all_el = self.get_element(all_dsps) self.click_element(element=all_el) for p in param: self.click_element(f"{p} ") self.click_element("(//button[.='Apply'])[1]", "xpath") selected_dsps = self.td_get_current_dsp() if len(param) == 1: assert_that(selected_dsps).is_equal_to(param[0]) elif len(param) == 2 and tab == "current:": assert_that(selected_dsps).is_equal_to("2 DSPs") elif len(param) == 2 and tab == "past": assert_that(selected_dsps).is_equal_to("All DSPs") elif len(param) == 3: assert_that(selected_dsps).is_equal_to("All DSPs") @allure.step("TP - TD - get current") def td_get_current_dsp(self): self.scroll_to_track_details() dsp_dd_loc = "//*[contains(@id, 'controls-dsp-dd')]" dsp_dd = self.get_element(dsp_dd_loc, "xpath") return self.get_text(element=dsp_dd) @allure.step("TP - TD - Change entities") def td_change_entities(self, param): dsp_dd_loc = "//*[contains(@id, 'entities-filter-dd')]" item_loc = "track-page-current-playlists-and-stations-controls-entities-filter-dd-checkbox-{}" if isinstance(param, str): param = [param.lower()] dsp_dd = self.wait_for_element_clickable(dsp_dd_loc, "xpath") self.click_element(element=dsp_dd) for loc in ["stations", "playlists"]: if self.is_checked(item_loc.format(loc), "id"): el = self.get_element(item_loc.format(loc)) self.click_on_element_js(element=el) for loc in param: el = self.get_element(item_loc.format(loc.lower())) self.click_on_element_js(element=el) self.click_element("(//button[.='Apply'])[1]", "xpath") @allure.step("TP - TD - Verify tabs") def td_verify_tabs(self): loc = "//*[contains(@id, 'track-page-details') and contains(@id, 'tab')]" els = self.get_elements(loc, "xpath") texts = [self.get_text(element=t) for t in els] assert_that(texts).is_equal_to(["CURRENT PLAYLISTS & STATIONS", "PAST PLAYLISTS", "CHARTS", "YOUTUBE", "TIKTOK\nBETA"]) @allure.step("TP - TD - Verify back to top button") def td_verify_back_to_top_button(self): loc = "trackback-to-top" self.scroll_to_track_details() assert_that(self.is_element_displayed(loc)).is_true() button_back = self.wait_for_element_clickable(loc) self.click_element(element=button_back) self.is_track_title_present() @allure.step("TP - TD - Verify CP&S verify elements") def td_cps_verify_elements(self): self.scroll_to_track_details() locs = [ "track-page-current-playlists-and-stations-controls-dsp-dd", "track-page-current-playlists-and-stations-controls-entities-filter-dd", "track-page-current-playlists-and-stations-controls-type-filter-dd", "track-page-current-playlists-and-stations-controls-owner-categories-dd", "track-page-current-playlists-and-stations-controls-owner-markets-dd", "track-page-current-playlists-and-stations-controls-filter-input", "track-page-current-playlists-and-stations-controls-export-btn", "track-page-current-playlists-and-stations-controls-top-markets--scope-bar", "track-page-current-playlists-and-stations-controls-all-markets-scope-bar", "track-details-current-table", ] for loc in locs: assert_that(self.is_element_displayed(loc)).described_as(loc).is_true() @allure.step("TP - TD - Verify CP&S verify i icon hover") def td_cps_verify_icon_hover(self): icon_loc = "track-page-current-playlists-and-stations-controls-top-markets-hint-icon" tooltip_loc = "track-page-current-playlists-and-stations-controls-top-markets-hint-icon-tooltip" self.scroll_to_track_details() self.hover_on_element(icon_loc) tooltip = self.get_text(tooltip_loc) assert_that(tooltip).is_equal_to( """The Top Markets list for Apple Music and Amazon is compiled from 6 markets (US, CA, UK, DE, AU, FR), plus Global Market for Spotify.""" ) @allure.step("TP - TD - Verify CP&S station art and icon") def td_verify_art_and_station_icon(self, station_dsp): art_loc = "track-page-current-playlists-and-stations-table-cell-cover-1" if station_dsp == self.APPLE: icon_loc = "//img/following-sibling::*/*[contains(@class, 'icon')]" elif station_dsp == self.AMAZON: icon_loc = "//span[contains(@class, 'icon-amazon')]" assert_that(self.is_element_displayed(art_loc)).is_true() assert_that(self.is_element_displayed(icon_loc, "xpath")).is_true() @allure.step("TP - TD - CPS - verify columns") def td_cps_verify_columns(self): loc = "//*[@id='track-details-current-table-header']//*[@id]" end = self.get_calendar_end_date() end = datetime.datetime.strptime(str(end), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) self.wait_track_details_table_displayed(False) els = self.get_elements(loc, "xpath") columns_ui = [self.get_text(element=e) for e in els] if "DSPs" in self.td_get_current_dsp(): assert_that(columns_ui).is_equal_to(["#", "C", "", "Entity", "Position\n#", "Position\nTrend", "Added\nDays", "Streams, Latest Day\nTrack", "Streams, 7 Days\nTrack", "Streams, 7 Days\nEntity", "Playlist\nFollowers"]) else: assert_that(columns_ui).is_equal_to(["#", "C", "", "Entity", "Position\n#", "Position\nTrend", "Added\nDays", f"Streams,\n{end}\nTrack", "Streams, 7 Days\nTrack", "Streams, 7 Days\nEntity", "Playlist\nFollowers"]) @allure.step("TP - TD - PP - verify columns") def td_pp_verify_columns(self): loc = "//*[@id='track-details-previous-table-header']//*[@id]" end = self.get_calendar_end_date() end = datetime.datetime.strptime(str(end), "%Y-%m-%d").strftime(self.get_date_format_from_locale()) els = self.get_elements(loc, "xpath") columns_ui = [self.get_text(element=e) for e in els] assert_that(columns_ui).is_equal_to(["#", "C", "", "Entity", "", "Track\nAdded", "Track\nRemoved", "in Playlist\nDays", "Playlist\nFollowers"]) @allure.step("TP - TD - CPS - get country by hover") def td_get_country_hover(self, index=1): loc = f"(//*[contains(@id, 'table-cell-country-code-')]//img)[{index}]" self.hover_on_element(loc, "xpath") tooltip = self.get_text(self.hint_locator, "xpath") return tooltip @allure.step("TP - TD - CPS - get position tooltip") def td_get_position_tooltip(self, index=1): self.wait_for_element_clickable(f"(//*[contains(@id, 'chart-position-')])[{index}]", "xpath") self.hover_on_element(f"(//*[contains(@id, 'chart-position-')])[{index}]", "xpath") tooltip = self.get_text(self.hint_locator, "xpath") self.log.info(f"UI tooltip text: {tooltip}") return tooltip @allure.step("TP - TD - CPS - get first added tooltip") def td_get_first_added_tooltip(self): loc = "(//*[contains(@id, 'days-in-playlist-')]//span[string-length(text()) > 0])[1]" tooltip_loc = "//*[contains(text(), 'First added:')]" self.wait_for_element_visible(loc, "xpath") self.wait_for_element_clickable(loc, "xpath") self.hover_on_element(loc, "xpath") tooltip_text = self.get_text(tooltip_loc, "xpath").replace("First added: ", "") return tooltip_text @allure.step("TP - TD - CPS - cell market dd - verify filter focus") def td_market_cell_dd_verify_filter_focus(self): loc = "track-page-current-playlists-and-stations-table-cell-market-dd-filter-input" input = self.get_element(loc) focused_el = self.driver.switch_to.active_element placeholder = self.get_attribute_value(element=input, attribute="placeholder") assert_that(input).is_not_equal_to(focused_el) assert_that(placeholder).is_equal_to("Filter markets") @allure.step("TP - TD - CPS - cell market dd - filter") def td_market_cell_filter(self, param): loc = "track-page-current-playlists-and-stations-table-cell-market-dd-filter-input" input = self.get_element(loc) self.send_text(data=param, element=input) @allure.step("TP - TD - CPS - cell market dd - verify hover") def td_verify_market_dd_cell_hover(self, markets_ui): self.scroll_to_track_details() loc = "track-page-current-playlists-and-stations-table-cell-market-dd" el = self.wait_for_element_clickable(loc) market_len_min_2 = len(markets_ui) - 2 assert_that(int(self.get_text(loc))).is_equal_to(market_len_min_2) self.hover_on_element(element=el) tooltip = self.get_text(self.hint_locator, "xpath") assert_that(f"{markets_ui[0]}, {markets_ui[1]}, and {market_len_min_2} more").is_equal_to(tooltip) @allure.step("TP - TD - CPS - verify SUM row") def td_verify_sum_row_ui(self): art_loc = "//*[contains(@id, 'cover-1')]" name_loc = "//*[contains(@id, 'Entity-1')]" playlist_icon_loc = "//*[contains(@id, 'Entity-1')]//span[text()='Playlist' or text()='Station']" for loc in [art_loc, name_loc, playlist_icon_loc]: assert_that(self.is_element_displayed(loc, "xpath")).described_as(loc).is_true() url_before = self.get_url() self.click_element(name_loc, "xpath") url_after = self.get_url() assert_that(url_before).is_equal_to(url_after) @allure.step("TP - TD - CPS - get positions nums") def td_get_positions_nums(self): loc = "//*[not(contains(@id, 'change')) and contains(@id, 'cell-track-position-') or contains(@id, 'past-playlists-and-stations-table-cell-playlist-details-button')]" els = self.get_elements(loc, "xpath") values = [self.get_text(element=e) for e in els] values_int = [] for v in values: if len(v) == 0: values_int.append(0) else: values_int.append(int(v)) return values_int @allure.step("TP - TD - CPS - get current entities") def td_get_current_entities(self): dsp_dd_loc = "//*[contains(@id, 'entities-filter-dd')]" self.scroll_to_track_details() entity = self.get_element(dsp_dd_loc, "xpath") return self.get_text(element=entity) @allure.step("TP - TD - PP -verify export button and playlists icon present") def td_pp_verify_export_button_and_playlist_icon(self): locs = ["//*[contains(@id, 'controls-export-btn')]", "//*[contains(text(), 'Playlists (')]"] for loc in locs: assert_that(self.is_element_displayed(loc, "xpath")).described_as(loc).is_true() @allure.step("TP - TD - verify no data") def td_verify_no_data(self): loc = "//*[text()='No data available.']" assert_that(self.is_element_displayed(loc, "xpath")).described_as(loc).is_true() @allure.step("TP - TD - scroll down") def td_scroll_down(self): loc = "(//*[contains(@id, 'cell-position')])[last()]" loc_all = "//*[contains(@id, 'cell-position')]" self.scroll_to_track_details() self.wait_for_element_visible(loc_all, "xpath") self.scroll_to_element(loc, "xpath") @allure.step("TP - TD - verify latest day column hover") def td_verify_latest_date_column_hover(self): loc_column = "track-page-current-playlists-and-stations-table-cell-track-streams-latest-day" loc_tooltip = "track-page-current-playlists-and-stations-table-cell-track-streams-latest-day-tooltip" self.hover_on_element(loc_column) text = self.get_text(loc_tooltip) assert_that(text).is_equal_to( """Track streams from this playlist for the latest date available.""" ) @allure.step("TP - TD - CPS verify export") def td_cps_verify_export(self, entities=["Playlist"], dsp="", market="global"): end_date = self.get_calendar_end_date() self.td_click_export() title = self.get_track_title() artist = self.get_all_artists_name() end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d").strftime(self.get_date_format_from_locale()) file_path_core = f"http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/" file = self.read_from_csv(file_path_core + f"Current Playlists and Stations - {artist} - {title}.csv") file_columns = list(file.columns) if dsp == AppConfig.get("dsp")["all_dsps"]: columns_exp = [name, entity, personalized, dsp, streams_track, ww_streams_7_days_track, market_streams_7_days_track, ww_streams_7_days_entity, market_streams_7_days_entity, position, added_days, owner_market, owner_category, owner_account, link, followers] = [ "Name", "Entity", "Personalized?", "DSP", "Streams, Latest Day", "Worldwide Streams, 7 Days Track", "Market Streams, 7 Days Track", "Worldwide Streams 7 Days, Entity", "Market Streams 7 Days, Entity", "Position", "Added days", "Owner Market", "Owner Category", "Owner Account", "Link", "Followers", ] dsps_exp = {"Spotify", "Apple Music", "Amazon"} else: columns_exp = [name, entity, personalized, dsp, streams_track, ww_streams_7_days_track, market_streams_7_days_track, ww_streams_7_days_entity, market_streams_7_days_entity, position, added_days, owner_market, owner_category, owner_account, link, followers] = [ "Name", "Entity", "Personalized?", "DSP", f"Streams, {end_date} Track", "Worldwide Streams, 7 Days Track", "Market Streams, 7 Days Track", "Worldwide Streams 7 Days, Entity", "Market Streams 7 Days, Entity", "Position", "Added days", "Owner Market", "Owner Category", "Owner Account", "Link", "Followers", ] dsps_exp = {"Spotify"} count_to_verify = 3 assert_that(file_columns).is_equal_to(columns_exp) assert_that(self.td_cps_get_playlist_names()[:count_to_verify]).is_subset_of(file[name]) assert_that(set(entities)).is_subset_of(set(file[entity])) assert_that(set(file[dsp])).is_subset_of(dsps_exp) assert_that(set(p for p in self.td_get_positions_nums()[:count_to_verify] if p > 0)).is_subset_of(set(file[position])) assert_that(set(d for d in self.td_get_added_days()[:count_to_verify] if d > 0)).is_subset_of(set(file[added_days])) assert_that(set(d for d in self.td_cps_get_streams_latest_day_values()[:count_to_verify] if d > 0)).is_subset_of(file[streams_track]) if market == "global": assert_that(set(d for d in self.td_cps_get_market_streams_7_days_values()[:count_to_verify] if d > 0)).is_subset_of(file[ww_streams_7_days_track]) assert_that(set(d for d in self.td_cps_get_streams_7_days_entity_values()[:count_to_verify] if d > 0)).is_subset_of(file[ww_streams_7_days_entity]) else: assert_that(set(d for d in self.td_cps_get_market_streams_7_days_values()[:count_to_verify] if d > 0)).is_subset_of(file[market_streams_7_days_track]) assert_that(set(d for d in self.td_cps_get_streams_7_days_entity_values()[:count_to_verify] if d > 0)).is_subset_of(file[market_streams_7_days_entity]) assert_that(set(self.td_get_playlist_followers_values())).is_subset_of(set(file[followers])) assert_that(file[ww_streams_7_days_track]).is_sorted(reverse=True) @allure.step("TP - TD - CPS get column int values") def td_cps_get_column_int_values(self, loc): els = self.get_elements(loc, "xpath") values = [int(self.get_text(element=v).replace(",", "")) for v in els[:-1] if len(self.get_text(element=v).replace(",", "")) > 0] return values @allure.step("TP - TD - CPS get streams latest day column values") def td_cps_get_streams_latest_day_values(self): loc = "//*[contains(@id, 'streams-latest-day-') and not(contains(@id, 'tooltip'))]" return self.td_cps_get_column_int_values(loc) @allure.step("TP - TD - CPS get streams latest day column values") def td_cps_get_market_streams_7_days_values(self): loc = "//*[contains(@id, 'streams-7-days-') and not(contains(@id, 'selected-playlist'))]" return self.td_cps_get_column_int_values(loc) @allure.step("TP - TD - CPS get streams latest day column values") def td_cps_get_streams_7_days_entity_values(self): loc = "//*[contains(@id, 'selected-playlist-streams-7-days-')]" return self.td_cps_get_column_int_values(loc) @allure.step("TP - TD - Past Playlists verify export") def td_pp_verify_export(self, market_p="global", owner_category_p=""): self.td_click_export() title = self.get_track_title() artist = self.get_all_artists_name() file_path_core = f"http://{CoreConfig.SELENOID_HOST}:4444/download/{self.driver.session_id}/" file = self.read_from_csv(file_path_core + f"Past Playlists - {artist} - {title}.csv") file_columns = list(file.columns) columns_exp = [market_c, name, personalized, owner_category_f, track_added, track_removed, followers, uri] = ["Market", "Name", "Personalized?", "Owner Category", "Track Added", "Track Removed", "Followers", "URI"] count_to_verify = 3 assert_that(file_columns).is_equal_to(columns_exp) assert_that(set(self.td_cps_get_playlist_names()[:count_to_verify])).is_subset_of(file[name]) assert_that(set(self.td_previous_playlist_get_table_ui("Added")[:count_to_verify])).is_subset_of(datetime.datetime.strptime(t, self.get_date_format_from_locale()).date() for t in file[track_added]) assert_that(set(self.td_previous_playlist_get_table_ui("Removed")[:count_to_verify])).is_subset_of(datetime.datetime.strptime(t, self.get_date_format_from_locale()).date() for t in file[track_removed]) assert_that([i for i in self.td_get_playlist_ids()[:count_to_verify]]).is_subset_of([f.split(":")[-1].split("/")[-1] for f in file[uri]]) assert_that(set(self.td_get_playlist_followers_values())).is_subset_of(set(file[followers])) if market_p != "global": assert_that({market_p.upper()}).is_equal_to(set(file[market_c])) if owner_category_p != "": assert_that({owner_category_p}).is_equal_to(set(file[owner_category_f])) assert_that(file.dropna().get(track_removed).to_list()).is_sorted(key=lambda date: datetime.datetime.strptime(date, self.get_date_format_from_locale()), reverse=True) @allure.step("Track Performance - Is graph type enabled") def tp_is_graph_type_enabled(self): dd_el = self.get_element(*self.locator(self.track_locators, "graph_type_dd")) dd_background_color = dd_el.value_of_css_property("background-color") dd_text_color = dd_el.value_of_css_property("color") self.log.info(f"DD background color: {dd_background_color}") self.log.info(f"DD text color: {dd_text_color}") if dd_background_color == "rgba(248, 248, 251, 1)" and dd_text_color == "rgba(135, 136, 141, 1)": return False else: return True @allure.step("TP - star unstar and verify UI") def star_unstar_track_and_verify_ui(self, star=True): starred_loc = "//*[contains(@class, 'icon-star')]" color_before = self.wait_for_element_clickable(starred_loc, "xpath").value_of_css_property("color") self.click_element(starred_loc, "xpath") hint_loc_core = "//*[text()='Track successfully {}']" if star: hint_loc = "starred" else: hint_loc = "unstarred" hint = self.wait_for_element_visible(locator=hint_loc_core.format(hint_loc), locator_type="xpath") assert_that(self.is_element_displayed(element=hint)).described_as(hint_loc_core.format(hint_loc)).is_true() self.click_on_title() color_after = self.wait_for_element_clickable(starred_loc, "xpath").value_of_css_property("color") assert_that(color_before).is_not_equal_to(color_after) @allure.step("NVP -> Trending - verify trending home market in Details tab") def verify_trending_home_market(self, market): home_market_loc = "//*[@id='youtube-trending-table-home-market-badge']" home_market_is_present = self.is_element_present(locator=home_market_loc, locator_type="xpath") if home_market_is_present: home_market_name_loc = "//*[@id='youtube-trending-table-home-market-badge']/preceding-sibling::span" home_market_name_el = self.get_element(locator=home_market_name_loc, locator_type="xpath") home_market = self.get_text(element=home_market_name_el) assert_that(home_market).is_equal_to(market) else: return False @allure.step("Full Performance - Verify details table") def nvp_trending_details_table_verification(self, video_id, trending_date): api_response = self.api_client.get_yt_trending_for_video(video_id=video_id, date=trending_date) ui_table = self.get_trending_details_table() # header header_names_el = self.get_elements(locator="//*[@id='youtube-trending-table-header']/div", locator_type="xpath") header_text = [str(self.get_text(element=t)).replace("\n", " ") for t in header_names_el] self.log.info("Header text: " + str(header_text)) assert_that(str(header_text[1:])).is_equal_to("['#', '', 'Country', 'Position #', 'Position Trend', 'Peak, Lifetime Position #', 'Peak, Lifetime Position # Date', 'On Chart, Lifetime Days']") # default sorting table_position = ui_table["current-position"] assert_that(table_position).is_equal_to(sorted(table_position)) # columns comparison api_position = [api_response[t]["data"]["current_position"] for t in range(len(api_response)) if api_response[t]["data"] is not None] api_position_trend = [abs(api_response[t]["data"]["trend"]) for t in range(len(api_response)) if api_response[t]["data"] is not None] api_peak_position = [api_response[t]["data"]["peak_position"] for t in range(len(api_response)) if api_response[t]["data"] is not None] api_peak_position_date = [api_response[t]["data"]["peak_position_date"] for t in range(len(api_response)) if api_response[t]["data"] is not None] api_lifetime_days = [api_response[t]["data"]["in_chart_days"] for t in range(len(api_response)) if api_response[t]["data"] is not None] ui_peak_position_date = [str(d) for d in ui_table["peak-lifetime-date"]] assert_that(set(table_position)).is_equal_to(set(api_position)) assert_that(set(ui_table["trend-position"])).is_equal_to(set(api_position_trend)) assert_that(set(ui_table["peak-position"])).is_equal_to(set(api_peak_position)) assert_that(set(ui_peak_position_date)).is_equal_to(set(api_peak_position_date)) assert_that(set(ui_table["peak-lifetime-days"])).is_equal_to(set(api_lifetime_days)) @allure.step("TP - TD - click on dd") def td_click_on_dd(self, param): loc = f"//*[contains(@id, 'controls-{param}-dd')]" self.scroll_to_track_details() dd = self.get_element(loc, "xpath") self.click_on_element_js(element=dd) @allure.step("TP - TD - get dd values") def td_dd_get_values(self): loc = "//input[contains(@id, ' ')][@type='checkbox']/following-sibling::*" els = self.get_elements(loc, "xpath") values = [self.get_text(element=v) for v in els if len(self.get_text(element=v)) > 0] return values @allure.step("TP - TD - verify apply button active") def td_verify_apply_button_active(self, active=True, station_dd=False): loc = "(//button[.='Apply'])[last()]" if station_dd: loc = "(//button[.='Apply'])[1]" self.wait_for_element_visible(loc, "xpath") assert_that(self.is_enabled(loc, "xpath")).is_equal_to(active) def td_dd_click_on_item(self, param): loc = f"//*[contains(@id, '{param}')]" self.click_element(loc, "xpath") @allure.step("TP - TD - get tooltip for dd") def td_get_tooltip_for_dd(self, param): loc = f"//*[contains(@id, 'controls-{param}-dd')]" self.scroll_to_track_details() dd = self.wait_for_element_clickable(loc, "xpath") self.hover_on_element(element=dd) text = self.get_text(self.hint_locator, "xpath") return text @allure.step("TP - TD - type dd - click on item") def td_type_dd_click_on_item(self, param): loc = f"//*[text()='{param}']/preceding-sibling::input" self.click_element(loc, "xpath") @allure.step("TP - TD - type dd - verify checkbox values") def td_type_dd_verify_values(self): loc = "//*[contains(@id, 'type-filter-dd-checkbox-')]/following-sibling::span" values = [self.get_text(element=v) for v in self.get_elements(loc, "xpath")] assert_that(values).is_equal_to(["Editorial", "Personalized"]) @allure.step("TP - TD - type dd - verify personalized icon hover") def td_verify_personalized_icon_hover(self): loc = "//*[contains(@id, 'type-filter-dd')]/parent::*/following-sibling::*/..//*[contains(@class, 'icon-info')]" assert_that(self.is_element_displayed(loc, "xpath")).is_true() self.hover_on_element(loc, "xpath") text = self.get_text(self.hint_locator, "xpath") assert_that(text).is_equal_to("Personalized playlists are available for Spotify only.") @allure.step("TP - TD - verify dd disabled") def td_verify_dd_disabled(self, param, disabled=True): loc = f"//*[contains(@id, 'controls-{param}-dd')]" assert_that(self.is_enabled(loc, "xpath")).is_not_equal_to(disabled) @allure.step("TP - TD - verify Type dd hidden") def td_verify_type_dd_hidden(self): loc = "//*[contains(@id, 'controls') and contains(@id, 'dd')][string-length(.) > 0]" self.wait_for_element_visible(loc, "xpath") values = [self.get_text(element=v) for v in self.get_elements(loc, "xpath")] assert_that(values).does_not_contain("All Types") @allure.step("TP - TD - verify entity dd expanded") def td_verify_entity_filter_expanded(self): title_loc = "//*[contains(@id, 'entities-filter-dd-title')]" items_loc = "//input[contains(@id, 'entities-filter')][@type='checkbox']/following-sibling::*" assert_that(self.get_text(title_loc, "xpath")).is_equal_to("ENTITIES") assert_that([self.get_text(element=i).split(" ")[0] for i in self.get_elements(items_loc, "xpath")]).is_equal_to(["Playlists", "Stations"]) @allure.step("TP - TD - entity dd - click on item") def td_dd_entities_click_item(self, param): loc = f"//*[contains(@id, 'checkbox-{param}')]" el = self.get_element(loc, "xpath") self.click_on_element_js(element=el) @allure.step("TP - TD - Charts tab - Overview - get markets") def get_markets_overview_charts_tab(self): loc = "//*[contains(@id, 'charts?market')]" self.wait_for_element_visible(loc, "xpath") markets = [self.get_text(element=m) for m in self.get_elements(loc, "xpath")] self.log.info(f"charts tab - markets: {markets}") return markets @allure.step("TP - click export as CSV") def click_export_as_csv(self): if "/track/" in self.get_url(): self.scroll_to_element("//*[text()='Track Summary']", "xpath") csv_button = self.wait_for_element_clickable(*self.locator(self.track_locators, "export_csv")) self.click_element(element=csv_button) @allure.step("TP - TD - Current Playlists and Stations - get Spotify streams 7 days by playlists id") def get_spotify_api_streams_7_days_by_playlists_id(self, track_isrc, latest_date, market_api, playlists_id, ww_streams=False): api_response = self.api_client.get_playlists_spotify_by_track(isrc=track_isrc, end_date=latest_date, market=market_api)["items"] streams_7_days_api = [] if not ww_streams: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: streams_7_days_api.append(playlist_api["streams"]["local7Days"]) else: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: streams_7_days_api.append(playlist_api["streams"]["global7Days"]) self.log.info(f"API streams 7 days: {streams_7_days_api}") return streams_7_days_api @allure.step("TP - TD - Current Playlists and Stations - get Apple streams 1 or 7 days by playlists id") def get_apple_api_streams_1_7_days_by_playlists_id(self, track_isrc, start_date, end_date, market, playlists_id, token): streams_api = self.api_client.get_consumer_analytics_streams_v1(track=track_isrc, vendor="apple", market=market["api"], start_date=start_date, end_date=end_date, token=token)["items"] market_streams_api = [] for playlist_ui in playlists_id: for playlist_api in streams_api: if playlist_ui == playlist_api["containerId"]: for m in playlist_api["markets"]: if m[0] == market["market"]: market_streams_api.append(m[1]) self.log.info(f"API streams: {market_streams_api}") return market_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Spotify streams 1 or 7 days by playlists id") def get_spotify_api_streams_1_7_days_by_playlists_id(self, track_isrc, latest_date, market_api, playlists_id, streams_days_1_7, ww_streams=False): api_response = self.api_client.get_playlists_spotify_by_track(isrc=track_isrc, end_date=latest_date, market=market_api)["items"] streams_api = [] if not ww_streams: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: if streams_days_1_7 == 1: streams_api.append(playlist_api["streams"]["local1Day"]) elif streams_days_1_7 == 7: streams_api.append(playlist_api["streams"]["local7Days"]) else: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: if streams_days_1_7 == 1: streams_api.append(playlist_api["streams"]["global1Day"]) elif streams_days_1_7 == 7: streams_api.append(playlist_api["streams"]["global7Days"]) self.log.info(f"API streams: {streams_api}") return streams_api @allure.step("TP - TD - Current Playlists and Stations - get Apple Stations streams by name and country code") def get_apple_stations_api_streams_1_7_days_by_name_and_country(self, track_isrc, stations_info, streams_days_1_7): streams_api = self.api_client.get_stations_summary(isrc=track_isrc)["items"] stations_streams_api = [] for item in range(len(stations_info["Entity"])): for station_api in range(len(streams_api)): for market in range(len(streams_api[station_api]["markets"])): if streams_api[station_api]["data"] is not None: if stations_info["Entity"][item] == streams_api[station_api]["data"]["attributes"]["name"] and stations_info["country-code"][item] == streams_api[station_api]["markets"][market][0]: if streams_days_1_7 == 1: stations_streams_api.append(streams_api[station_api]["markets"][market][2]) elif streams_days_1_7 == 7: stations_streams_api.append(streams_api[station_api]["markets"][market][1]) self.log.info(f"API streams: {stations_streams_api}") return stations_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Amazon playlists streams by playlists id") def get_amazon_api_streams_1_7_days_by_playlists_id(self, track_isrc, market, playlists_id, streams_days_1_7): streams_api = self.api_client.get_amazon_playlists_list(isrc=track_isrc, market=market, dsp="amazon")["items"] market_streams_api = [] for playlist_ui in playlists_id: for playlist_api in streams_api: if playlist_ui == playlist_api["playlist_id"]: if streams_days_1_7 == 1: market_streams_api.append(playlist_api["streaming_for_1_days"]["isrc_in_playlist"]) elif streams_days_1_7 == 7: market_streams_api.append(playlist_api["streaming_for_7_days"]["isrc_in_playlist"]) self.log.info(f"API streams: {market_streams_api}") return market_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Amazon Stations streams by name and country code") def get_amazon_stations_api_streams_1_7_days_by_name_and_country(self, track_isrc, market, stations_info, streams_days_1_7): streams_api = self.api_client.get_amazon_stations(isrc=track_isrc, market=market)["items"] stations_streams_api = [] for item in range(len(stations_info["Entity"])): for station_api in range(len(streams_api)): for streams_by_market in range(len(streams_api[station_api]["streams"])): if stations_info["Entity"][item] == streams_api[station_api]["station_name"] and stations_info["country-code"][item] == streams_api[station_api]["streams"][streams_by_market]["country_code"]: if streams_days_1_7 == 1: stations_streams_api.append(streams_api[station_api]["streams"][streams_by_market]["streaming_for_1_days"]["isrc_in_station"]) elif streams_days_1_7 == 7: stations_streams_api.append(streams_api[station_api]["streams"][streams_by_market]["streaming_for_7_days"]["isrc_in_station"]) self.log.info(f"API streams: {stations_streams_api}") return stations_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Spotify in playlist streams 7 days by playlists id") def get_spotify_api_in_playlist_streams_7_days_by_playlists_id(self, track_isrc, latest_date, market_api, playlists_id, ww_streams=False): api_response = self.api_client.get_playlists_spotify_by_track(isrc=track_isrc, end_date=latest_date, market=market_api)["items"] streams_api = [] if not ww_streams: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: streams_api.append(playlist_api["marketStreams7Days"]) else: for playlist_api in api_response: for playlist_ui in playlists_id[:5]: if playlist_ui == playlist_api["spotifyLink"]: streams_api.append(playlist_api["globalStreams7Days"]) self.log.info(f"API streams: {streams_api}") return streams_api @allure.step("TP - TD - Current Playlists and Stations - get Apple in playlist streams 7 days by playlists id") def get_apple_api_in_playlist_streams_7_days_by_playlists_id(self, track_isrc, market, playlists_id): streams_api = self.api_client.get_apple_playlistswithtrack(isrc=track_isrc)["items"] in_playlist_streams_api = [] for playlist_ui in playlists_id: for playlist_api in streams_api: if playlist_ui == playlist_api["id"]: for m in playlist_api["countries"]: if m["countryCode"] == market["market"]: in_playlist_streams_api.append(m["streams7Days"]) self.log.info(f"API streams: {in_playlist_streams_api}") return in_playlist_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Amazon playlists in playlist streams by playlists id") def get_amazon_api_in_playlist_streams_7_days_by_playlists_id(self, track_isrc, market, playlists_id): streams_api = self.api_client.get_amazon_playlists_list(isrc=track_isrc, market=market, dsp="amazon")["items"] market_in_playlist_streams_api = [] for playlist_ui in playlists_id: for playlist_api in streams_api: if playlist_ui == playlist_api["playlist_id"]: market_in_playlist_streams_api.append(playlist_api["streaming_for_7_days"]["playlist"]) self.log.info(f"API streams: {market_in_playlist_streams_api}") return market_in_playlist_streams_api @allure.step("TP - TD - Current Playlists and Stations - get Amazon Stations in playlist streams by name and country code") def get_amazon_stations_api_in_playlist_streams_7_days_by_name_and_country(self, track_isrc, market, stations_info): streams_api = self.api_client.get_amazon_stations(isrc=track_isrc, market=market)["items"] stations_in_playlist_streams_api = [] for item in range(len(stations_info["Entity"])): for station_api in range(len(streams_api)): for streams_by_market in range(len(streams_api[station_api]["streams"])): if stations_info["Entity"][item] == streams_api[station_api]["station_name"] and stations_info["country-code"][item] == streams_api[station_api]["streams"][streams_by_market]["country_code"]: stations_in_playlist_streams_api.append(streams_api[station_api]["streams"][streams_by_market]["streaming_for_7_days"]["station"]) self.log.info(f"API streams: {stations_in_playlist_streams_api}") return stations_in_playlist_streams_api @allure.step("TP - TD - CP&S - verify Streams 7 days Entity hover") def td_verify_streams_7_days_entity_hover(self): loc = "(//div[contains(@id, 'playlist-streams-7-days')])[1]" assert_that(self.is_element_displayed(loc, "xpath")).is_true() self.hover_on_element(loc, "xpath") text = self.get_text(self.hint_locator, "xpath") self.log.info(f"Hint text: {text}") assert_that(text).is_equal_to( """SME streams from this station or playlist within the last 7 days.""" )