from types import SimpleNamespace from urllib.parse import urlparse from appium.webdriver.common.appiumby import AppiumBy as By from selenium.common.exceptions import NoSuchElementException from helpers.AppHelper import app from helpers.ConfigHelper import get_config from helpers.UserHelper import get_displayname_for_user from helpers.SyncHelper import wait_for class Toolbar: TOOLBAR_ROW = SimpleNamespace(by=None, selector=None) NAVIGATION_BAR = SimpleNamespace( by=By.XPATH, selector="//*[@name='Navigation bar']/.." ) ACCOUNT_TAB = SimpleNamespace(by=By.CLASS_NAME, selector="[page tab | {text}]") ADD_ACCOUNT_BUTTON = SimpleNamespace( by=By.CLASS_NAME, selector="[push button | Add Account]" ) ACTIVITY_TAB = SimpleNamespace(by=By.CLASS_NAME, selector="[page tab | Activity]") SETTINGS_TAB = SimpleNamespace(by=By.CLASS_NAME, selector="[page tab | Settings]") QUIT_BUTTON = SimpleNamespace(by=By.CLASS_NAME, selector="[push button | Quit]") CONFIRM_QUIT_BUTTON = SimpleNamespace( by=By.NAME, selector="Yes", ) TOOLBAR_ITEMS = ["Add Account", "Activity", "Settings", "Quit"] @staticmethod def wait_toolbar_enabled(): toolbar = app().find_element( Toolbar.NAVIGATION_BAR.by, Toolbar.NAVIGATION_BAR.selector ) timeout = get_config('maxSyncTimeout') * 1000 enabled = wait_for( lambda: toolbar.is_enabled(), timeout, ) if not enabled: raise AssertionError(f"Toolbar is not enabled within {timeout} ms") @staticmethod def get_item_selector(item_name): return { "container": names.dialogStack_quickWidget_QQuickWidget, "text": item_name, "type": "Label", "visible": True, } @staticmethod def has_tab(tab_name): if tab_name.lower() == "add account": tab = Toolbar.ADD_ACCOUNT_BUTTON elif tab_name.lower() == "activity": tab = Toolbar.ACTIVITY_TAB elif tab_name.lower() == "settings": tab = Toolbar.SETTINGS_TAB elif tab_name.lower() == "quit": tab = Toolbar.QUIT_BUTTON else: raise ValueError(f"Unknown tab: {tab_name}") return app().find_element(tab.by, tab.selector).is_displayed() @staticmethod def open_activity(): tab = app().find_element(Toolbar.ACTIVITY_TAB.by, Toolbar.ACTIVITY_TAB.selector) # ISSUE: https://github.com/opencloud-eu/desktop/pull/879 # Cannot select navigation tab by click event # Select the navigation tab using keyboard events as a workaround # TODO: Remove the workaround and uncomment 'click' action # tab.click() tab.native_click() if tab.get_attribute("checked") != "true": raise AssertionError("Activity tab is not active") @staticmethod def open_new_account_setup(): app().find_element( Toolbar.ADD_ACCOUNT_BUTTON.by, Toolbar.ADD_ACCOUNT_BUTTON.selector, ).click() @staticmethod def open_account(username): account_tab = Toolbar.get_account(username) # ISSUE: https://github.com/opencloud-eu/desktop/pull/879 # Cannot activate account tab by click event # Select the account tab using keyboard events as a workaround # TODO: Remove the workaround and uncomment 'click' action # account_tab.click() account_tab.native_click() # confirm account is active if account_tab.get_attribute("checked") != "true": raise AssertionError(f"Account is not active: {username}") @staticmethod def get_displayed_account_text(displayname, host): return str( squish.waitForObjectExists( Toolbar.get_item_selector(displayname + "\n" + host) ).text ) @staticmethod def open_settings_tab(): tab = app().find_element(Toolbar.SETTINGS_TAB.by, Toolbar.SETTINGS_TAB.selector) # ISSUE: https://github.com/opencloud-eu/desktop/pull/879 # Cannot select navigation tab by click event # Select the navigation tab using keyboard events as a workaround # TODO: Remove the workaround and uncomment 'click' action # tab.click() tab.native_click() if tab.get_attribute("checked") != "true": raise AssertionError("Settings tab is not active") @staticmethod def quit_qsfera(): app().find_element(Toolbar.QUIT_BUTTON.by, Toolbar.QUIT_BUTTON.selector).click() app().find_element( Toolbar.CONFIRM_QUIT_BUTTON.by, Toolbar.CONFIRM_QUIT_BUTTON.selector ).click() @staticmethod def get_accounts(): accounts = {} selectors = {} children_obj = object.children(squish.waitForObjectExists(Toolbar.TOOLBAR_ROW)) account_idx = 1 for obj in children_obj: if hasattr(obj, "accountState"): account_info = { "displayname": str(obj.accountState.account.davDisplayName), "hostname": str(obj.accountState.account.hostName), "initials": str(obj.accountState.account.initials), "current": obj.checked, } account_locator = Toolbar.ACCOUNT_TAB.copy() if account_idx > 1: account_locator.update({"occurrence": account_idx}) account_locator.update({"text": account_info["hostname"]}) accounts[account_info["displayname"]] = account_info selectors[account_info["displayname"]] = obj account_idx += 1 return accounts, selectors @staticmethod def get_account(username): display_name = get_displayname_for_user(username) server_host = urlparse(get_config('localBackendUrl')).netloc account_label = f"{display_name}@{server_host}" account = None try: account = app().find_element( Toolbar.ACCOUNT_TAB.by, Toolbar.ACCOUNT_TAB.selector.format(text=account_label), ) except NoSuchElementException: pass return account @staticmethod def get_active_account(): accounts, selectors = Toolbar.get_accounts() for account, info in accounts.items(): if info["current"]: return info, selectors[account] return None, None @staticmethod def account_has_focus(username): account = Toolbar.get_account(username) return account.get_attribute("checked") == "true" @staticmethod def account_exists(username): account = Toolbar.get_account(username) return account is not None