import logging import time from datetime import datetime, timedelta import allure from assertpy import assert_that 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.src.pages.track_page import TrackPage class DSPComparison(BasePage): log = cl.Logger(logging.DEBUG) all_markets = "All Markets" tiktok_dsp = "TikTok" spotify_dsp = "Spotify" creations = "Creations" views = "Views" active_save_button_color = "rgba(255, 198, 25, 1)" up_position = "arrow-up" edit = "edit" save_btn = "confirm" cancel_btn = "cancel" by_markets_tab = "by-markets" by_performance_tab = "by-performance" def __init__(self, driver): super().__init__(driver) self.driver = driver self.dsp_comparison_locators = self.get_page_locators("DSPComparison", "dsp_comparison_elements.json") self.track_page = TrackPage(self.driver) self.ts = TestStatus(self.driver) @allure.step("DSP Comparison page - title is present") def title_is_present(self): el = self.wait_for_element_visible(*self.locator(self.dsp_comparison_locators, "dsp_comparison_title")) title = self.is_element_displayed(element=el) self.log.info("DSP Comparison title is displayed:" + str(title)) assert_that(title).is_true() @allure.step("DSP Comparison page - KPI for 7 days collapse expand") def kpi_for_7_days_collapse_expand(self): self.wait_for_element_clickable(*self.locator(self.dsp_comparison_locators, "kpi_for_7_days_collapse")) collapse_button = self.get_element(*self.locator(self.dsp_comparison_locators, "kpi_for_7_days_collapse")) self.click_element(element=collapse_button) @allure.step("DSP Comparison page - Open graph menu and check each function") def open_graph_menu_item(self, item, item_position=1): menu_with_position_locator = f"(//span[contains(@class, 'icon-ellipsis-vertical')])[{item_position}]" item_locator = f"//button//span[contains(@class, 'icon-{item}')]" self.scroll_to_element(menu_with_position_locator, "xpath") menu_btn = self.wait_for_element_clickable(locator=menu_with_position_locator, locator_type="xpath") self.click_element(element=menu_btn) item_el = self.get_element(locator=item_locator, locator_type="xpath") self.click_element(element=item_el) @allure.step("DSP Comparison page - Close pop-up or side panel") def close_pop_up(self): self.wait_for_element_clickable(*self.locator(self.dsp_comparison_locators, "close_icon")) close_button = self.get_element(*self.locator(self.dsp_comparison_locators, "close_icon")) self.click_element(element=close_button) @allure.step("DSP Comparison page - Number of graphs") def get_number_of_graphs(self): graph_container_locator = "//*[contains(@id, 'tiktok-comparison-breadcrumbs')][contains(@id, '-container')]" number_of_graphs = len(self.get_elements(locator=graph_container_locator, locator_type="xpath")) self.log.info("Number of graphs present: " + str(number_of_graphs)) return number_of_graphs @allure.step("DSP Comparison page - Delete graph") def delete_graph(self, graph_position): menu_with_position_locator = f"(//span[contains(@class, 'icon-ellipsis-vertical')])[{graph_position}]" delete_locator = "//button//span[contains(@class, 'icon-delete')]" number_of_graphs_before = self.get_number_of_graphs() self.wait_for_element_clickable(locator=menu_with_position_locator, locator_type="xpath") menu_btn = self.get_element(locator=menu_with_position_locator, locator_type="xpath") self.click_element(element=menu_btn) item_el = self.get_element(locator=delete_locator, locator_type="xpath") self.click_element(element=item_el) confirm_delete = self.get_element(*self.locator(self.dsp_comparison_locators, "delete_btn")) self.click_element(element=confirm_delete) number_of_graphs_after = self.get_number_of_graphs() assert_that(number_of_graphs_before - 1).is_equal_to(number_of_graphs_after) @allure.step("DSP Comparison page - Edit menu opened") def is_edit_menu_opened(self): el = self.wait_for_element_visible(*self.locator(self.dsp_comparison_locators, "edit_menu_title")) title = self.is_element_displayed(element=el) self.log.info("DSP Comparison edit menu title is displayed:" + str(title)) assert_that(title).is_true() @allure.step("DSP Comparison page - choose markets") def markets_dd_choose_markets(self, params, region=False): markets_dd = "//*[contains(text(), '{market}')]" market_choose = f"{markets_dd}/preceding-sibling::input" apply_el = "(//button[.='Apply'])[1]" dd = self.get_element(*self.locator(self.dsp_comparison_locators, "markets_dd")) self.click_on_element_js(element=dd) item = self.get_element(locator=market_choose.format(market=self.all_markets), locator_type="xpath") self.click_on_element_js(element=item) if self.track_page.is_checked(locator=market_choose.format(market=self.all_markets), locator_type="xpath"): self.click_on_element_js(element=item) if not region: for c in params: country = market_choose.format(market=c) c_dd = self.get_element(locator=country, locator_type="xpath") self.click_on_element_js(element=c_dd) self.log.info(f"DSP Comparison - choose markets: {params}") apply_btn = self.get_element(locator=apply_el, locator_type="xpath") self.click_on_element_js(element=apply_btn) else: region = "".join(params) item = self.get_element(locator=f"//*[contains(@class, 'region')][text()='{region}']", locator_type="xpath") self.click_on_element_js(element=item) self.log.info(f"DSP Comparison - choose region: {region}") @allure.step("DSP Comparison page - choose dsp") def choose_dsp(self, dsp): dsp_dd = self.get_element(*self.locator(self.dsp_comparison_locators, "dsp_dd")) self.click_element(element=dsp_dd) dsp_value_locator = f"//*[@id='tiktok-comparison-modal-window-dsp-dd']/*//*[text()='{dsp}']" dsp_value = self.get_element(locator=dsp_value_locator, locator_type="xpath") self.click_element(element=dsp_value) @allure.step("DSP Comparison page - choose kpi") def choose_kpi(self, kpi): kpi_dd = self.get_element(*self.locator(self.dsp_comparison_locators, "kpi_dd")) self.click_element(element=kpi_dd) kpi_value_locator = f"//*[contains(@id, 'tiktok-comparison-tiktok-kpi-graph')]/div//*[contains(text(), '{kpi}')]" kpi_value = self.get_element(locator=kpi_value_locator, locator_type="xpath") self.click_element(element=kpi_value) @allure.step("DSP Comparison page - change sources") def change_sources(self, param, apply=True): sources_dd = self.get_element(*self.locator(self.dsp_comparison_locators, "sources_dd")) self.click_element(element=sources_dd) all_sources_locator = "//input[@id='All Sources ']" all_sources = self.get_element(locator=all_sources_locator, locator_type="xpath") checkbox_all_sources = all_sources.value_of_css_property("data-checked") apply_btn_locator = "(//*[contains(text(), 'Apply')]/ancestor::button)[1]" apply_btn = self.get_element(locator=apply_btn_locator, locator_type="xpath") color_before = apply_btn.value_of_css_property("background-color") if checkbox_all_sources == "not-checked": self.click_on_element_js(element=all_sources) self.click_on_element_js(element=all_sources) else: self.click_on_element_js(element=all_sources) color_uncheck_all = apply_btn.value_of_css_property("background-color") for p in param: item = self.get_element(locator=f"//input[@id='{p} ']", locator_type="xpath") self.click_on_element_js(element=item) color_after = apply_btn.value_of_css_property("background-color") assert_that(color_before).is_equal_to(color_uncheck_all) assert_that(color_uncheck_all).is_not_equal_to(color_after) if apply: self.click_on_element_js(element=apply_btn) @allure.step("DSP Comparison page - save or cancel changes") def save_cancel_changes(self, button, bulk_apply=False): button_locator = f"//*[@id='tiktok-comparison-modal-window-button-{button}']" bulk_checkbox_locator = "tiktok-comparison-modal-window-market-bulk-checkbox" button_el = self.get_element(locator=button_locator, locator_type="xpath") bulk_checkbox = self.get_element(locator=bulk_checkbox_locator) bulk_checkbox_selected = self.get_attribute_value(element=bulk_checkbox, attribute="data-checked") == "checked" if button == self.save_btn: button_color = button_el.value_of_css_property("background-color") assert_that(button_color).is_equal_to(self.active_save_button_color) if bulk_apply != bulk_checkbox_selected: self.click_element(locator=bulk_checkbox_locator) self.click_element(element=button_el) @allure.step("DSP Comparison page - open for isrc") def open(self, param): self.open_url(f"{CoreConfig.ENV_BASE_URL}/tiktok/comparison/{param}") track_title_present = self.is_element_displayed("tiktok-comparison-link-back-link-back") assert_that(track_title_present).is_true() @allure.step("DSP Comparison page - get cards data - UI") def get_cards_data_ui(self, card): top_values_sel = f"//*[contains(@id, '{card}-latest')]" left_values_sel = f"//*[contains(@id, '{card}-period') or contains(@id, '{card}-left')]" right_values_sel = f"//*[contains(@id, '{card}-avg') or contains(@id, '{card}-right')]" self.wait_for_element_visible(top_values_sel, "xpath") self.wait_for_element_visible(left_values_sel, "xpath") self.wait_for_element_visible(right_values_sel, "xpath") top_values_el = self.get_elements(top_values_sel, "xpath") left_values_el = self.get_elements(left_values_sel, "xpath") right_values_el = self.get_elements(right_values_sel, "xpath") top_values = [self.get_text(element=t).strip().replace("%", "").replace(",", "") for t in top_values_el] left_values = [self.get_text(element=t).strip().replace("%", "").replace(",", "") for t in left_values_el] right_values = [self.get_text(element=t).strip().replace("%", "").replace(",", "").replace("Avg ", "") for t in right_values_el] s = str((datetime.strptime(top_values[0], self.track_page.get_date_format_from_locale()) - timedelta(days=6)).date().strftime(self.track_page.get_date_format_from_locale())) assert_that(f"{s}–{top_values[0]}").is_equal_to(left_values[0]) assert_that(left_values[0]).is_equal_to(right_values[0]) assert_that(left_values[2]).is_equal_to(right_values[2]) data = { "top": {"date": datetime.strptime(top_values[0], self.track_page.get_date_format_from_locale()).strftime("%Y-%m-%d"), "value": int(top_values[1]), "percentage": int(top_values[2])}, "left": {"value": int(left_values[1]), "percentage": int(left_values[2])}, "right": {"value": int(right_values[1])}, } self.log.info(f"card {card} data: {data}") return data @allure.step("DSP Comparison page - Edit menu opened") def is_add_menu_opened(self): el = self.wait_for_element_visible(*self.locator(self.dsp_comparison_locators, "add_graph_title")) title = self.is_element_displayed(element=el) self.log.info("DSP Comparison add menu title is displayed:" + str(title)) assert_that(title).is_true() @allure.step("DSP Comparison page - open add graph menu") def open_add_graph_menu(self): self.wait_for_element_clickable(*self.locator(self.dsp_comparison_locators, "add_graph_btn")) add_btn = self.get_element(*self.locator(self.dsp_comparison_locators, "add_graph_btn")) self.click_element(element=add_btn) self.is_add_menu_opened() @allure.step("DSP Comparison page - switch tab") def switch_tab(self, tab): tab_locator = f"//*[@id='tiktok-comparison-header-scope-bar-{tab}']" self.wait_for_element_clickable(locator=tab_locator, locator_type="xpath") tab_el = self.get_element(locator=tab_locator, locator_type="xpath") self.click_element(element=tab_el) time.sleep(2) is_tab_selected = self.get_attribute_value(locator=tab_locator, locator_type="xpath", attribute="data-selected") assert_that(is_tab_selected).is_equal_to("selected") @allure.step("DSP Comparison page - back link to track page") def back_to_track_page(self): self.wait_for_element_clickable(*self.locator(self.dsp_comparison_locators, "back_link")) back_link = self.get_element(*self.locator(self.dsp_comparison_locators, "back_link")) self.click_element(element=back_link) @allure.step("DSP Comparison page - verify graphs default state") def verify_graphs_default_state(self): graph_titles_sel = "//*[contains(@id, 'breadcrumbs')]/..//*[@tag][string-length(.) > 0]" dates_sel = "//*[text()='Date']" by_performance_default_titles = ["TIKTOK CREATIONS", "ALL MARKETS", "TIKTOK VIEWS", "ALL MARKETS", "SPOTIFY STREAMS", "ALL SOURCES", "ALL MARKETS"] by_markets_default_titles = ["TIKTOK CREATIONS", "TOP MARKETS", "TIKTOK VIEWS", "TOP MARKETS", "SPOTIFY STREAMS", "ALL SOURCES", "TOP MARKETS"] if self.get_attribute_value(locator="tiktok-comparison-header-scope-bar-by-performance", attribute="data-selected") == "selected": titles_exp = by_performance_default_titles else: titles_exp = by_markets_default_titles self.wait_for_element_visible(graph_titles_sel, "xpath") graph_titles = self.get_elements(graph_titles_sel, "xpath") graph_titles = [self.get_text(element=g).upper() for g in graph_titles] self.wait_for_element_visible(dates_sel, "xpath") date_titles = self.get_elements(dates_sel, "xpath") date_titles = [self.get_text(element=g).lower() for g in date_titles] calendar_days_count = self.track_page.graph_get_count_days_from_calendar() assert_that(calendar_days_count).is_equal_to(28) assert_that(graph_titles).is_equal_to(titles_exp) assert_that(date_titles).is_equal_to(["date", "date", "date"]) @allure.step("DSP Comparison page - get last tooltip data from graph with index") def get_last_tooltip_data_from_graph_with_index(self, param, param2="", spotify=False): graphs_sel = f"(//*[contains(@class, 'highcharts-plot-border')])[{param+3}]" for i in [1, 2, 3]: self.wait_for_element_visible(f"(//*[text()='Date'])[{i}]", "xpath") count_days = self.track_page.graph_get_count_days_from_calendar() e = self.wait_for_element_visible(graphs_sel, "xpath") height = int(int(e.size["height"]) / 5) width = int(e.size["width"]) + 1 self.log.info("height: {height}, width: {width}".format(height=height, width=width)) step = int(width / count_days) self.log.info("step: {step}".format(step=step)) tooltip_data = {} for t in range(0, width, step): e = self.wait_for_element_visible(locator=graphs_sel, locator_type="xpath", timeout=1) ActionChains(self.driver).move_to_element_with_offset(to_element=e, xoffset=t, yoffset=height).perform() if param2 == "": param2 = param base_tooltip_sel = f"(//*[contains(@id, 'chart-tooltip')])[{param2}]" tt = self.wait_for_element_visible(locator=base_tooltip_sel, locator_type="xpath", timeout=1) text = str(self.get_text(element=tt)) if text not in ["", None, "None", ["None"], [None]]: date_sel = f"{base_tooltip_sel}//../*[contains(@id, 'header')]" date = self.get_text(date_sel, "xpath").split(" ")[1] date = str((datetime.strptime(date, self.track_page.get_date_format_from_locale())).date()) value_and_percentage_sel = f"({base_tooltip_sel}//../*[contains(@id, 'value') and contains(., '%')])[1]/*" if spotify: value_and_percentage_sel = "//*[contains(@id, 'chart-tooltip-row-total-value')]" value = int(self.get_text(value_and_percentage_sel, "xpath").replace(",", "")) else: value_and_percentage_text = self.get_elements(value_and_percentage_sel, "xpath") value_and_percentage_text = [int(self.get_text(element=v).strip().replace("%)", "").replace("(", "").replace(",", "")) for v in value_and_percentage_text] value = value_and_percentage_text[0] tooltip_data.update({date: {"value": value, "full": text}}) self.log.info(f"tooltip data: {tooltip_data}") return tooltip_data @allure.step("DSP Comparison page -> By Markets - get cards data - UI") def get_by_markets_cards_data_ui(self, card): top_values_sel = f"//*[contains(@id, '{card}-latest')]" left_values_sel = f"//*[contains(@id, '{card}-period') or contains(@id, '{card}-left')]" right_values_sel = f"//*[contains(@id, '{card}-avg') or contains(@id, '{card}-right')]" self.wait_for_element_visible(top_values_sel, "xpath") self.wait_for_element_visible(left_values_sel, "xpath") self.wait_for_element_visible(right_values_sel, "xpath") top_values_el = self.get_element(top_values_sel, "xpath") left_values_el = self.get_elements(left_values_sel, "xpath") right_values_el = self.get_elements(right_values_sel, "xpath") top_values = self.get_text(element=top_values_el).split("–") left_values = [self.get_text(element=t).strip().replace(",", "") for t in left_values_el] right_values = [self.get_text(element=t).strip().replace("Top Market: ", "").replace("%", "").replace(",", "").replace("(", "").replace(")", "") for t in right_values_el] data = { "top": {"start_date": datetime.strptime(top_values[0], self.track_page.get_date_format_from_locale()).strftime("%Y-%m-%d"), "end_date": datetime.strptime(top_values[1], self.track_page.get_date_format_from_locale()).strftime("%Y-%m-%d")}, "left": {"market": str(left_values[0]), "value": int(left_values[1])}, "right": {"market": str(right_values[0]), "value": int(right_values[1]), "percentage": int(right_values[2])}, } self.log.info(f"card {card} data: {data}") return data @allure.step("Stream and source - choose Source") def change_source_values(self, source_names): dd = self.wait_for_element_visible(locator="//*[@id='tiktok-comparison-modal-window-controls-label-sources']/following-sibling::*/..//button[@id]", locator_type="xpath") self.click_on_element_js(element=dd) if self.get_text(element=dd) == AppConfig.get("source")["all"]: source_all = f"""//input[contains(@id, '{AppConfig.get("source")["all"]}')]""" all_sources = self.get_element(source_all, "xpath") self.click_on_element_js(element=all_sources) for source_name in source_names: source = f"""//input[contains(@id, '{source_name}')]""" source_el = self.get_element(source, "xpath") self.click_on_element_js(element=source_el) apply = self.wait_for_element_visible(locator="(//*[text()='Apply'])[1]", locator_type="xpath") self.click_on_element_js(element=apply)