from types import SimpleNamespace from appium.webdriver.common.appiumby import AppiumBy as By from selenium.webdriver.common.keys import Keys from helpers.SetupClientHelper import get_current_user_sync_path from helpers.AppHelper import app class SyncConnectionWizard: CHOOSE_LOCAL_SYNC_FOLDER = SimpleNamespace( by=By.ACCESSIBILITY_ID, selector="localFolderLineEdit" ) BACK_BUTTON = SimpleNamespace(by=By.NAME, selector="< Back") NEXT_BUTTON = SimpleNamespace(by=By.NAME, selector="Next >") SELECTIVE_SYNC_ROOT_FOLDER = SimpleNamespace(by=None, selector=None) ADD_SYNC_CONNECTION_BUTTON = SimpleNamespace( by=By.XPATH, selector="//dialog[@name='Add Space']//*[@name='Add Space']" ) REMOTE_FOLDER_TREE = SimpleNamespace(by=None, selector=None) SELECTIVE_SYNC_TREE_HEADER = SimpleNamespace(by=None, selector=None) CANCEL_FOLDER_SYNC_CONNECTION_WIZARD = SimpleNamespace( by=By.NAME, selector="Cancel" ) SPACES_LIST = SimpleNamespace(by=By.NAME, selector="Spaces list") SPACE_NAME_SELECTOR = SimpleNamespace(by=By.NAME, selector="{space_name},") CREATE_REMOTE_FOLDER_BUTTON = SimpleNamespace(by=None, selector=None) CREATE_REMOTE_FOLDER_INPUT = SimpleNamespace(by=None, selector=None) CREATE_REMOTE_FOLDER_CONFIRM_BUTTON = SimpleNamespace(by=None, selector=None) REFRESH_BUTTON = SimpleNamespace(by=None, selector=None) REMOTE_FOLDER_SELECTION_INPUT = SimpleNamespace(by=None, selector=None) ADD_FOLDER_SYNC_BUTTON = SimpleNamespace(by=None, selector=None) WARN_LABEL = SimpleNamespace(by=None, selector=None) CHOOSE_WHAT_TO_SYNC_FOLDER_TREE = SimpleNamespace(by=None, selector=None) @staticmethod def set_sync_path_oc(sync_path): if not sync_path: sync_path = get_current_user_sync_path() sync_path_input = app().find_element( SyncConnectionWizard.CHOOSE_LOCAL_SYNC_FOLDER.by, SyncConnectionWizard.CHOOSE_LOCAL_SYNC_FOLDER.selector, ) sync_path_input.clear() sync_path_input.send_keys(sync_path) SyncConnectionWizard.next_step() @staticmethod def set_sync_path(sync_path=""): SyncConnectionWizard.set_sync_path_oc(sync_path) @staticmethod def next_step(): next_button = app().find_element( SyncConnectionWizard.NEXT_BUTTON.by, SyncConnectionWizard.NEXT_BUTTON.selector, ) if not next_button.is_enabled(): raise AssertionError("Next button is not enabled") next_button.click() @staticmethod def back(): squish.clickButton(squish.waitForObject(SyncConnectionWizard.BACK_BUTTON)) @staticmethod def select_remote_destination_folder(folder): squish.mouseClick( squish.waitForObjectItem(SyncConnectionWizard.REMOTE_FOLDER_TREE, folder) ) SyncConnectionWizard.next_step() @staticmethod def deselect_all_remote_folders(): element = app().find_element( SyncConnectionWizard.ADD_SYNC_CONNECTION_BUTTON.by, SyncConnectionWizard.ADD_SYNC_CONNECTION_BUTTON.selector, ) element.send_keys(Keys.ARROW_DOWN) element.native_send_keys(Keys.SPACE) # uncheck the root folder @staticmethod def sort_by(header_text): squish.mouseClick( squish.waitForObject( { "container": SyncConnectionWizard.SELECTIVE_SYNC_TREE_HEADER, "text": header_text, "type": "HeaderViewItem", "visible": True, } ) ) @staticmethod def add_sync_connection(): app().find_element( SyncConnectionWizard.ADD_SYNC_CONNECTION_BUTTON.by, SyncConnectionWizard.ADD_SYNC_CONNECTION_BUTTON.selector, ).click() @staticmethod def get_item_name_from_row(row_index): folder_row = { "row": row_index, "container": SyncConnectionWizard.SELECTIVE_SYNC_ROOT_FOLDER, "type": "QModelIndex", } return str(squish.waitForObjectExists(folder_row).displayText) @staticmethod def is_root_folder_checked(): state = squish.waitForObject(SyncConnectionWizard.SELECTIVE_SYNC_ROOT_FOLDER)[ "checkState" ] return state == "checked" @staticmethod def cancel_folder_sync_connection_wizard(): app().find_element( SyncConnectionWizard.CANCEL_FOLDER_SYNC_CONNECTION_WIZARD.by, SyncConnectionWizard.CANCEL_FOLDER_SYNC_CONNECTION_WIZARD.selector, ).click() @staticmethod def select_space(space_name): spaces_list = app().find_element( SyncConnectionWizard.SPACES_LIST.by, SyncConnectionWizard.SPACES_LIST.selector, ) space_item = spaces_list.find_element( SyncConnectionWizard.SPACE_NAME_SELECTOR.by, SyncConnectionWizard.SPACE_NAME_SELECTOR.selector.format( space_name=space_name ), ) # ISSUE: https://github.com/opencloud-eu/desktop/pull/879 # Cannot select space by click event # Select space using keyboard events as a workaround # TODO: Remove 'send_keys' and uncomment 'click' action space_item.send_keys(Keys.ARROW_DOWN) # space_item.click() if space_item.get_attribute("selected") != "true": raise AssertionError("Failed to select the space: " + space_name) @staticmethod def sync_space(space_name): SyncConnectionWizard.set_sync_path(get_current_user_sync_path()) SyncConnectionWizard.select_space(space_name) SyncConnectionWizard.next_step() SyncConnectionWizard.add_sync_connection() @staticmethod def create_folder_in_remote_destination(folder_name): squish.clickButton( squish.waitForObject(SyncConnectionWizard.CREATE_REMOTE_FOLDER_BUTTON) ) squish.type( squish.waitForObject(SyncConnectionWizard.CREATE_REMOTE_FOLDER_INPUT), folder_name, ) squish.clickButton( squish.waitForObject( SyncConnectionWizard.CREATE_REMOTE_FOLDER_CONFIRM_BUTTON ) ) @staticmethod def refresh_remote(): squish.clickButton(squish.waitForObject(SyncConnectionWizard.REFRESH_BUTTON)) @staticmethod def is_remote_folder_selected(folder_selector): return squish.waitForObjectExists(folder_selector).selected @staticmethod def open_sync_connection_wizard(): squish.mouseClick( squish.waitForObject(SyncConnectionWizard.ADD_FOLDER_SYNC_BUTTON) ) @staticmethod def get_local_sync_path(): return str( squish.waitForObjectExists( SyncConnectionWizard.CHOOSE_LOCAL_SYNC_FOLDER ).displayText ) @staticmethod def get_warn_label(): return str(squish.waitForObjectExists(SyncConnectionWizard.WARN_LABEL).text) @staticmethod def is_add_sync_folder_button_enabled(): return squish.waitForObjectExists( SyncConnectionWizard.ADD_FOLDER_SYNC_BUTTON ).enabled @staticmethod def select_or_unselect_folders_to_sync(folders, select=True): expected_state = "true" if select else "false" if select: SyncConnectionWizard.deselect_all_remote_folders() for folder_path in folders: parents = folder_path.strip("/").split("/") target_folder = parents.pop() parent_element = None parent_position = 0 for parent in parents: p_elements = app().find_elements(By.NAME, parent) # select nested folders based on the position of the parent folder for p_element in p_elements: if ( p_element.get_attribute("checked") == 'true' and p_element.rect["x"] > parent_position ): parent_element = p_element parent_position = p_element.rect["x"] break parent_element.native_double_click() # expand the folder # retry once if the folder is not expanded if parent_element.is_selected(): print('[WARN] Folder was not expanded, retrying with space key') # expand using space key parent_element.native_click() parent_element.native_send_keys(Keys.SPACE) if parent_element.is_selected(): raise AssertionError(f'Failed to expand folder: {parent}') folder_element = None target_folders = app().find_elements(By.NAME, target_folder) # select the folder that is inside the current parent position for folder in target_folders: if folder.rect["x"] > parent_position: folder_element = folder break is_checked = folder_element.get_attribute("checked") # return early if the folder is already in the expected state. if is_checked == expected_state: return folder_element.native_click() if not folder_element.is_selected(): raise AssertionError(f"Failed to focus folder: {target_folder}") folder_element.native_send_keys(Keys.SPACE) # toggle the folder selection is_checked = folder_element.get_attribute("checked") if is_checked != expected_state: raise AssertionError( f"Failed to {'select' if select else 'unselect'} folder: {folder_path}" ) @staticmethod def confirm_choose_what_to_sync_selection(): app().find_element(By.NAME, "OK").click() @staticmethod def __handle_folder_selection(folders, should_select, new_sync_connection_wizard): SyncConnectionWizard.select_or_unselect_folders_to_sync(folders, should_select) if new_sync_connection_wizard: SyncConnectionWizard.add_sync_connection() else: SyncConnectionWizard.confirm_choose_what_to_sync_selection() @staticmethod def unselect_folders_to_sync(folders, new_sync_connection_wizard=False): SyncConnectionWizard.__handle_folder_selection( folders, should_select=False, new_sync_connection_wizard=new_sync_connection_wizard, ) @staticmethod def select_folders_to_sync(folders, new_sync_connection_wizard=False): SyncConnectionWizard.__handle_folder_selection( folders, should_select=True, new_sync_connection_wizard=new_sync_connection_wizard, )