import logging import time import allure from appium.webdriver.common.mobileby import MobileBy from appium.webdriver.common.touch_action import TouchAction from ui_automation_framework.utils import CoreConfig from ui_automation_framework.utils import logger as cl from app.src.api.facade import ApiClient from app.src.api.models.auth_model import AuthData from app.src.pages.navigation_page import Navigation from app.src.ui_elements.button_ui_element import ButtonUIElement from app.src.ui_elements.input_ui_element import InputUIElement from app.src.ui_elements.label_ui_element import LabelUIElement from app.src.ui_elements.list_ui_element import ListUIElement class ProfilePage(Navigation): log = cl.Logger(logging.DEBUG) def __init__(self, driver): super().__init__(driver) self.api = ApiClient() self.api_notification = ApiClient() self.token = self.api.authorize() self.notifications_token = self.api_notification.authorize(AuthData(CoreConfig.NOTIFICATIONS_EMAIL, CoreConfig.NOTIFICATIONS_PASSWORD)) self.driver = driver self.profile_locators = self.get_page_locators("ProfilePage", "profile_elements.json") MARKET_LOCATOR_BY_NAME = '**/XCUIElementTypeOther[`name == "toggle-styled" AND label CONTAINS "{}"`]' MARKET_LOCATOR_BY_POSITION = '**/XCUIElementTypeOther[`name == "toggle-styled"`][{}]' @property def bn_markets(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "markets_btn"), "Markets") @property def bn_markets_notification_settings(self): return ButtonUIElement( self.driver, self.locator(self.profile_locators, "notificatons_settings_markets_btn"), "Markets on notification screen", ) @property def bn_notifications(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "notifications_btn"), "Notifications") @property def in_markets_search(self): return InputUIElement(self.driver, self.locator(self.profile_locators, "markets_search_field"), "Markets search") @property def lt_search_results(self): return ListUIElement( self.driver, (MobileBy.IOS_CLASS_CHAIN, '**/XCUIElementTypeOther[`name == "toggle-styled" AND label == "{}"`]'), ( MobileBy.IOS_CLASS_CHAIN, '**/XCUIElementTypeOther[`name == "toggle-styled" and label CONTAINS[cd] "{}"`]', ), (MobileBy.IOS_CLASS_CHAIN, '**/XCUIElementTypeOther[`name == "toggle-styled"`]'), name="Search results", ) @property def lb_notifications(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "notifications_toggle"), "Notifications toggle") @property def bn_clear(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "clear_button"), "Clear") @property def lb_markets_header(self): return LabelUIElement(self.driver, ('**/XCUIElementTypeStaticText[`label == "Markets"`]', "class-chain"), "Markets header") @property def bn_markets_settings_done(self): # TODO: to navigation? return ButtonUIElement(self.driver, self.locator(self.profile_locators, "markets_settings_done_btn"), "Done") @property def bn_markets_settings_done_inactive(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "markets_settings_done_inactive_btn"), "Done") @property def bn_markets_cancel(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "markets_settings_cancel_btn"), "Cancel") @property def lb_notification_settings_title(self): return LabelUIElement( self.driver, self.locator(self.profile_locators, "notifications_settings_title"), "Notification settings title", ) @property def lb_notification_settings_text_helper(self): return LabelUIElement( self.driver, ('**/XCUIElementTypeStaticText[`label BEGINSWITH "Market selections"`]', "class-chain"), "Notification settings text helper", ) @property def lb_notification_settings_charts_and_playlists(self): return LabelUIElement( self.driver, ('**/XCUIElementTypeStaticText[`label == "CHARTS & PLAYLISTS"`]', "class-chain"), "Charts and playlists header", ) @property def lb_spotify_dsp(self): # it is a checkbox return LabelUIElement(self.driver, self.locator(self.profile_locators, "spotify_dsp_toggle"), "Spotify dsp") @property def lb_apple_dsp(self): # it is a checkbox return LabelUIElement(self.driver, self.locator(self.profile_locators, "apple_dsp_toggle"), "Apple dsp") @property def lb_starred_tracks_settings(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "starred_tracks_settings_label")) @property def lb_starred_playlists_settings(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "starred_playlists_settings_label")) @property def bn_reset_notifications(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "notificatons_reset_btn"), "Reset notification settings") @property def lb_notifications_settings_sub_header(self): return LabelUIElement( self.driver, ("**/XCUIElementTypeOther[`label BEGINSWITH 'STARRED'`]", "class-chain"), "Notification settings sub-header", ) @property def lb_markets_no_result(self): return LabelUIElement(self.driver, ('**/XCUIElementTypeOther[`name == "figure"`]', "class-chain"), "No results placeholder") @property def bn_markets_done(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "markets_done_btn")) @property def bn_feedback_done(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "feedback_done_btn")) @property def bn_logout(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "logout_button")) @property def bn_leave_feedback(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "leave_feedback_btn")) @property def lb_markets_settings_title(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "markets_settings_title")) @property def lt_selected_markets(self): return ListUIElement( self.driver, all_elements_locator=(MobileBy.IOS_CLASS_CHAIN, self.locator(self.profile_locators, "selected_market")[0]), ) @property def lt_clear_icon_selected_markets(self): return ListUIElement( self.driver, all_elements_locator=( MobileBy.IOS_CLASS_CHAIN, self.locator(self.profile_locators, "clear_x_icon_selected_market")[0], ), ) @property def bn_first_selected_market(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "first_selected_market_clear_icon")) @property def lb_email_value(self): return ButtonUIElement(self.driver, self.locator(self.profile_locators, "email_value")) @property def lb_username(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "email_value")) def get_market_code_element(self, code): return LabelUIElement( self.driver, (f'label == "{code}" AND name == "{code}" AND value == "{code}"', "predicate"), "Market code element", ) @property def lb_version(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "version")) @property def lb_current_market(self): return LabelUIElement(self.driver, self.locator(self.profile_locators, "current_market")) @allure.step("Opening markets selection screen in profile settings") def open_markets(self): self.bn_markets.click() return self @allure.step("Opening markets settings for notifications") def open_notification_markets_settings(self): self.bn_markets_notification_settings.click() return self @allure.step("Opening global notifications settings") def open_notification_settings(self): self.bn_notifications.click() return self @allure.step("Selecting specified market") def select_market(self, market): self.click_on_market_in_markets_list(market) self.click_markets_done() return self @allure.step("Clicking on market from the list") def click_on_market_in_markets_list(self, market): locator = f'**/XCUIElementTypeOther[`name == "toggle-styled" AND label == "{market}"`]' # self.wait_for_element_visible(locator, "class-chain") # element = self.get_element(locator, "class-chain") # self.driver.execute_script("mobile: scroll", {"element": element, "toVisible": True}) # self.wait_for_element_visible(locator, "class-chain") self.click_element(locator, "class-chain") return self @allure.step("Clicking Done button on markets list") def click_markets_done(self): self.bn_markets_done.click() return self @allure.step("Clicking Done on feedback form") def click_feedback_done(self): self.bn_feedback_done.click() return self @allure.step("Selecting market via the search field") def select_market_via_search(self, query): self.bn_markets_done.wait(to_assert=False) self.in_markets_search.send_text(query) self.click_element(self.MARKET_LOCATOR_BY_NAME.format(query), "class-chain") self.bn_markets_done.click() return self @allure.step("Selecting market via the search field") def select_market_via_search_without_submit(self, query): self.in_markets_search.clear_text() self.in_markets_search.send_text(query) self.click_element(self.MARKET_LOCATOR_BY_NAME.format(query), "class-chain") return self @allure.step("Logging out") def logout(self): self.bn_logout.click() return self @allure.step("Clicking leave feedback") def click_feedback(self): self.bn_leave_feedback.click() return self @allure.step("Clicking Spotify toggle") def click_spotify_dsp_toggle(self): location = self.lb_spotify_dsp.location size = self.driver.get_window_size() TouchAction(self.driver).tap(x=size["width"] - 30, y=location["y"] + 26).perform() return self @allure.step("Clicking Apple toggle") def click_apple_dsp_toggle(self): location = self.lb_apple_dsp.location size = self.driver.get_window_size() TouchAction(self.driver).tap(x=size["width"] - 30, y=location["y"] + 26).perform() return self @allure.step("Clicking notifications toggle") def click_notifications_toggle(self): element = self.wait_for_element_visible(*self.locator(self.profile_locators, "notifications_toggle")) location = element.location size = self.driver.get_window_size() TouchAction(self.driver).tap(x=size["width"] - 30, y=location["y"] + 26).perform() return self @allure.step("Clicking notifications RESET button") def click_notification_settings_reset_button(self): self.bn_reset_notifications.click() return self @allure.step("Clearing selected notifications markets from top widget") def clear_all_selected_markets(self): selected_markets = len(self.lt_clear_icon_selected_markets.elements) if selected_markets > 0: for i in range(selected_markets): self.bn_first_selected_market.click() return self @allure.step("Clearing selected notifications markets from markets list") def clear_all_selected_markets_from_the_list(self): for element in self.lt_selected_markets.elements: element.click() return self @allure.step("Trying to select 11 markets from the list") def select_11_markets_from_market_list(self): for i in range(1, 12): self.click_element(self.MARKET_LOCATOR_BY_POSITION.format(i), "class-chain") return self @allure.step("Selecting market from the list by position") def select_market_from_list_by_position(self, position): self.click_element(self.MARKET_LOCATOR_BY_POSITION.format(position), "class-chain") return self @allure.step("Clearing the search field") def clear_search_field(self): self.bn_clear.click() self.close_keyboard_by_swipe() return self @allure.step("Clicking done button on notifications markets") def click_markets_settings_done_button(self): self.bn_markets_settings_done.click() return self @allure.step("Clicking clear button on notifications markets") def clear_all_selected_markets_via_clear_btn(self): element = self.wait_for_element_present(*self.locator(self.profile_locators, "markets_clear_btn")) self.click_element(element=element) return self @allure.step("Retrieving user email") def get_user_email(self): self.lb_email_value.wait(to_assert=False) email = self.lb_email_value.label return email @allure.step("Saving market name") def get_market_name_by_position_with_icons(self, position): locator = self.MARKET_LOCATOR_BY_POSITION.format(position) self.wait_for_element_visible(locator, "class-chain") return self.get_attribute_value(locator, "class-chain", None, "label") @allure.step("Checking feedback from is opened") def is_feedback_form_opened(self): self.wait_for_element_visible(*self.locator(self.profile_locators, "leave_feedback_form")) if self.is_element_displayed(*self.locator(self.profile_locators, "leave_feedback_form")): return True @allure.step("Checking profile page is opened") def is_profile_page_opened(self): return self.lb_email_value.is_visible() @allure.step("Verifying version format") def is_version_format_valid(self): verion_string = self.lb_version.label.partition("#")[2].split(".") if len(verion_string) == 3: return True @allure.step("Verifying notifications settings screen is opened") def is_notifications_settings_opened(self): return self.lb_notification_settings_title.is_visible() @allure.step("Verifying settings are in default state") def are_settings_in_default_state(self): # TODO: does it really work? spotify = bool(self.lb_starred_tracks_settings.enabled) apple = bool(self.lb_starred_playlists_settings.enabled) return spotify and apple @allure.step("Verifying notifications settings are hidden") def are_settings_hidden(self): return not self.lb_spotify_dsp.is_visible() and not self.lb_apple_dsp.is_visible() @allure.step("Verifying notifications settings are in OFF state on profile screen") def are_global_settings_off(self): return "Off" in self.bn_notifications.text @allure.step("Verifying global notifications settings were saved") def are_global_settings_saved_in_on_state(self): time.sleep(1) settings_resp = self.api.common.get_user_data_api_v1_settings() return settings_resp.data.vendors.apple and settings_resp.data.vendors.spotify @allure.step("Verifying notifications markets screen is opened") def is_notifications_market_settings_opened(self): return self.lb_markets_settings_title.is_visible() @allure.step("Verifying done button is in inactive state") def is_markets_done_button_inactive(self): return self.bn_markets_settings_done_inactive.is_visible() @allure.step("Verifying market indicator shows 10 markets selected") def are_10_markets_selected(self): return "10 OF 10" in self.markets_selected @allure.step("Verifying market indicator shows 0 markets selected") def are_0_markets_selected(self): return "0 OF 10" in self.markets_selected @property def markets_selected(self): return self.get_text(*self.locator(self.profile_locators, "selected_markets_counter")) @allure.step("Verifying selected markets were saved") def are_selected_markets_saved_for_notifications_user(self, markets): """ verifying market codes for saved markets in settings endpoint :param markets: dict with market codes as values """ settings_resp = self.api_notification.common.get_user_data_api_v1_settings(headers={"X-App-Slug": "apollo", "x-version": "2"}) markets_list = list(markets.values()) for market in markets_list: if market not in settings_resp["data"]["markets"]: return False else: return True def open_profile_screen_and_select_market(self, market): self.select_profile_tab() self.open_markets() self.select_market_via_search(market) return self def click_cancel_on_market_settings(self): self.bn_markets_cancel.click() return self