Initial QSfera import
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
|
||||
from helpers.WebUIHelper import authorize_via_webui
|
||||
from helpers.ConfigHelper import get_config
|
||||
from helpers.SetupClientHelper import (
|
||||
create_user_sync_path,
|
||||
get_temp_resource_path,
|
||||
set_current_user_sync_path,
|
||||
)
|
||||
from helpers.SyncHelper import listen_sync_status_for_item
|
||||
from helpers.AppHelper import app
|
||||
|
||||
|
||||
class AccountConnectionWizard:
|
||||
SERVER_ADDRESS_BOX = SimpleNamespace(
|
||||
by=By.ACCESSIBILITY_ID,
|
||||
selector="QApplication.Settings.centralwidget.dialogStack.SetupWizardWidget.contentWidget.ServerUrlSetupWizardPage.urlLineEdit",
|
||||
)
|
||||
NEXT_BUTTON = SimpleNamespace(
|
||||
by=By.ACCESSIBILITY_ID,
|
||||
selector="QApplication.Settings.centralwidget.dialogStack.SetupWizardWidget.nextButton",
|
||||
)
|
||||
ACCEPT_CERTIFICATE_YES = SimpleNamespace(
|
||||
by=By.NAME,
|
||||
selector="Yes",
|
||||
)
|
||||
SELECT_LOCAL_FOLDER = SimpleNamespace(by=None, selector=None)
|
||||
DIRECTORY_NAME_BOX = SimpleNamespace(
|
||||
by=By.ACCESSIBILITY_ID,
|
||||
selector="QApplication.Settings.centralwidget.dialogStack.SetupWizardWidget.contentWidget.AccountConfiguredWizardPage.advancedConfigGroupBox.advancedConfigGroupBoxContentWidget.localDirectoryGroupBox.chooseLocalDirectoryButton",
|
||||
)
|
||||
CHOOSE_FOLDER_BUTTON = SimpleNamespace(by=By.NAME, selector="Choose")
|
||||
OAUTH_CREDENTIAL_PAGE = SimpleNamespace(by=None, selector=None)
|
||||
COPY_URL_TO_CLIPBOARD_BUTTON = SimpleNamespace(
|
||||
by=By.NAME,
|
||||
selector="Copy URL",
|
||||
)
|
||||
CONF_SYNC_MANUALLY_RADIO_BUTTON = SimpleNamespace(
|
||||
by=By.NAME, selector="Configure synchronization manually"
|
||||
)
|
||||
ADVANCED_CONFIGURATION_CHECKBOX = SimpleNamespace(
|
||||
by=By.NAME,
|
||||
selector="Advanced configuration",
|
||||
)
|
||||
DIRECTORY_NAME_EDIT_BOX = SimpleNamespace(
|
||||
by=By.ACCESSIBILITY_ID,
|
||||
selector="QApplication.QFileDialog.fileNameEdit",
|
||||
)
|
||||
SYNC_EVERYTHING_RADIO_BUTTON = SimpleNamespace(by=None, selector=None)
|
||||
|
||||
@staticmethod
|
||||
def add_server(server_url):
|
||||
url_input = app().find_element(
|
||||
AccountConnectionWizard.SERVER_ADDRESS_BOX.by,
|
||||
AccountConnectionWizard.SERVER_ADDRESS_BOX.selector,
|
||||
)
|
||||
url_input.clear()
|
||||
url_input.send_keys(get_config("localBackendUrl"))
|
||||
|
||||
AccountConnectionWizard.next_step()
|
||||
|
||||
@staticmethod
|
||||
def accept_certificate():
|
||||
buttons = app().find_elements(
|
||||
AccountConnectionWizard.ACCEPT_CERTIFICATE_YES.by,
|
||||
AccountConnectionWizard.ACCEPT_CERTIFICATE_YES.selector,
|
||||
)
|
||||
# click the last button
|
||||
last_button = buttons.pop()
|
||||
last_button.click()
|
||||
|
||||
@staticmethod
|
||||
def add_user_credentials(username, password):
|
||||
AccountConnectionWizard.oidc_login(username, password)
|
||||
|
||||
@staticmethod
|
||||
def oidc_login(username, password):
|
||||
AccountConnectionWizard.browser_login(username, password)
|
||||
|
||||
@staticmethod
|
||||
def copy_login_url():
|
||||
app().find_element(
|
||||
AccountConnectionWizard.COPY_URL_TO_CLIPBOARD_BUTTON.by,
|
||||
AccountConnectionWizard.COPY_URL_TO_CLIPBOARD_BUTTON.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def browser_login(username, password):
|
||||
AccountConnectionWizard.copy_login_url()
|
||||
authorize_via_webui(username, password)
|
||||
|
||||
@staticmethod
|
||||
def next_step():
|
||||
app().find_element(
|
||||
AccountConnectionWizard.NEXT_BUTTON.by,
|
||||
AccountConnectionWizard.NEXT_BUTTON.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def select_sync_folder(user):
|
||||
# create sync folder for user
|
||||
sync_path = create_user_sync_path(user)
|
||||
|
||||
AccountConnectionWizard.select_advanced_config()
|
||||
app().find_element(
|
||||
AccountConnectionWizard.DIRECTORY_NAME_BOX.by,
|
||||
AccountConnectionWizard.DIRECTORY_NAME_BOX.selector,
|
||||
).click()
|
||||
dir_location_input = app().find_element(
|
||||
AccountConnectionWizard.DIRECTORY_NAME_EDIT_BOX.by,
|
||||
AccountConnectionWizard.DIRECTORY_NAME_EDIT_BOX.selector,
|
||||
)
|
||||
dir_location_input.clear()
|
||||
dir_location_input.send_keys(sync_path)
|
||||
app().find_element(
|
||||
AccountConnectionWizard.CHOOSE_FOLDER_BUTTON.by,
|
||||
AccountConnectionWizard.CHOOSE_FOLDER_BUTTON.selector,
|
||||
).click()
|
||||
return os.path.join(sync_path, get_config('syncConnectionName'))
|
||||
|
||||
@staticmethod
|
||||
def set_temp_folder_as_sync_folder(folder_name):
|
||||
sync_path = get_temp_resource_path(folder_name)
|
||||
|
||||
# clear the current path
|
||||
squish.mouseClick(
|
||||
squish.waitForObject(AccountConnectionWizard.SELECT_LOCAL_FOLDER)
|
||||
)
|
||||
|
||||
squish.waitForObject(AccountConnectionWizard.SELECT_LOCAL_FOLDER).setText("")
|
||||
|
||||
squish.type(
|
||||
squish.waitForObject(AccountConnectionWizard.SELECT_LOCAL_FOLDER),
|
||||
sync_path,
|
||||
)
|
||||
set_current_user_sync_path(sync_path)
|
||||
return sync_path
|
||||
|
||||
@staticmethod
|
||||
def add_account(account_details):
|
||||
AccountConnectionWizard.add_account_information(account_details)
|
||||
AccountConnectionWizard.next_step()
|
||||
|
||||
@staticmethod
|
||||
def add_account_information(account_details):
|
||||
if account_details["server"]:
|
||||
AccountConnectionWizard.add_server(account_details["server"])
|
||||
AccountConnectionWizard.accept_certificate()
|
||||
if account_details["user"]:
|
||||
AccountConnectionWizard.add_user_credentials(
|
||||
account_details["user"],
|
||||
account_details["password"],
|
||||
)
|
||||
sync_path = ""
|
||||
if account_details["sync_folder"]:
|
||||
AccountConnectionWizard.select_advanced_config()
|
||||
sync_path = AccountConnectionWizard.set_temp_folder_as_sync_folder(
|
||||
account_details["sync_folder"]
|
||||
)
|
||||
elif account_details["user"]:
|
||||
sync_path = AccountConnectionWizard.select_sync_folder(
|
||||
account_details["user"]
|
||||
)
|
||||
if sync_path:
|
||||
# listen for sync status
|
||||
listen_sync_status_for_item(sync_path)
|
||||
|
||||
@staticmethod
|
||||
def select_manual_sync_folder_option():
|
||||
app().find_element(
|
||||
AccountConnectionWizard.CONF_SYNC_MANUALLY_RADIO_BUTTON.by,
|
||||
AccountConnectionWizard.CONF_SYNC_MANUALLY_RADIO_BUTTON.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def select_download_everything_option():
|
||||
squish.clickButton(
|
||||
squish.waitForObject(AccountConnectionWizard.SYNC_EVERYTHING_RADIO_BUTTON)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def is_new_connection_window_visible():
|
||||
visible = False
|
||||
try:
|
||||
squish.waitForObject(AccountConnectionWizard.SERVER_ADDRESS_BOX)
|
||||
visible = True
|
||||
except:
|
||||
pass
|
||||
return visible
|
||||
|
||||
@staticmethod
|
||||
def is_credential_window_visible():
|
||||
visible = False
|
||||
try:
|
||||
squish.waitForObject(AccountConnectionWizard.OAUTH_CREDENTIAL_PAGE)
|
||||
visible = True
|
||||
except:
|
||||
pass
|
||||
return visible
|
||||
|
||||
@staticmethod
|
||||
def select_advanced_config():
|
||||
app().find_element(
|
||||
AccountConnectionWizard.ADVANCED_CONFIGURATION_CHECKBOX.by,
|
||||
AccountConnectionWizard.ADVANCED_CONFIGURATION_CHECKBOX.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def can_change_local_sync_dir():
|
||||
can_change = False
|
||||
try:
|
||||
squish.waitForObjectExists(AccountConnectionWizard.SELECT_LOCAL_FOLDER)
|
||||
squish.clickButton(
|
||||
squish.waitForObject(AccountConnectionWizard.DIRECTORY_NAME_BOX)
|
||||
)
|
||||
squish.waitForObjectExists(AccountConnectionWizard.CHOOSE_FOLDER_BUTTON)
|
||||
can_change = True
|
||||
except:
|
||||
pass
|
||||
return can_change
|
||||
|
||||
@staticmethod
|
||||
def is_sync_everything_option_checked():
|
||||
return squish.waitForObjectExists(
|
||||
AccountConnectionWizard.SYNC_EVERYTHING_RADIO_BUTTON
|
||||
).checked
|
||||
|
||||
@staticmethod
|
||||
def get_local_sync_path():
|
||||
return str(
|
||||
squish.waitForObjectExists(
|
||||
AccountConnectionWizard.SELECT_LOCAL_FOLDER
|
||||
).displayText
|
||||
)
|
||||
@@ -0,0 +1,172 @@
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
|
||||
from pageObjects.Toolbar import Toolbar
|
||||
from helpers.UserHelper import get_displayname_for_user
|
||||
from helpers.SetupClientHelper import substitute_inline_codes
|
||||
from helpers.UserHelper import get_displayname_for_user
|
||||
from helpers.AppHelper import app
|
||||
from helpers.SyncHelper import wait_for
|
||||
|
||||
|
||||
class AccountSetting:
|
||||
ACCOUNT_CONNECTION_CONTAINER = SimpleNamespace(
|
||||
by=By.NAME, selector="Sync connections"
|
||||
)
|
||||
MANAGE_ACCOUNT_BUTTON = SimpleNamespace(by=By.NAME, selector="Manage Account")
|
||||
ACCOUNT_MENU = SimpleNamespace(by=By.NAME, selector="{menu_item}")
|
||||
CONFIRM_REMOVE_CONNECTION_BUTTON = SimpleNamespace(
|
||||
by=By.NAME, selector="Remove connection"
|
||||
)
|
||||
ACCOUNT_CONNECTION_LABEL = SimpleNamespace(
|
||||
by=By.XPATH,
|
||||
selector="//list[@name='Folder Sync']//label",
|
||||
)
|
||||
LOG_BROWSER_WINDOW = SimpleNamespace(by=None, selector=None)
|
||||
ACCOUNT_LOADING = SimpleNamespace(by=None, selector=None)
|
||||
DIALOG_STACK = SimpleNamespace(by=None, selector=None)
|
||||
CONFIRMATION_YES_BUTTON = SimpleNamespace(by=None, selector=None)
|
||||
|
||||
@staticmethod
|
||||
def account_action(action):
|
||||
connections = app().find_elements(
|
||||
AccountSetting.ACCOUNT_CONNECTION_CONTAINER.by,
|
||||
AccountSetting.ACCOUNT_CONNECTION_CONTAINER.selector,
|
||||
)
|
||||
manage_button = None
|
||||
for connection in connections:
|
||||
# use the active connection
|
||||
if connection.get_attribute("showing") == "true":
|
||||
manage_button = connection.find_element(
|
||||
AccountSetting.MANAGE_ACCOUNT_BUTTON.by,
|
||||
AccountSetting.MANAGE_ACCOUNT_BUTTON.selector,
|
||||
)
|
||||
break
|
||||
manage_button.click()
|
||||
app().find_element(
|
||||
AccountSetting.ACCOUNT_MENU.by,
|
||||
AccountSetting.ACCOUNT_MENU.selector.format(menu_item=action),
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def remove_account_connection():
|
||||
AccountSetting.account_action("Remove")
|
||||
app().find_element(
|
||||
AccountSetting.CONFIRM_REMOVE_CONNECTION_BUTTON.by,
|
||||
AccountSetting.CONFIRM_REMOVE_CONNECTION_BUTTON.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def logout():
|
||||
AccountSetting.account_action("Log out")
|
||||
|
||||
@staticmethod
|
||||
def login():
|
||||
AccountSetting.account_action("Log in")
|
||||
|
||||
@staticmethod
|
||||
def get_account_connection_label():
|
||||
labels = app().find_elements(
|
||||
AccountSetting.ACCOUNT_CONNECTION_LABEL.by,
|
||||
AccountSetting.ACCOUNT_CONNECTION_LABEL.selector,
|
||||
)
|
||||
# first label is the sync status label
|
||||
return labels[0].text
|
||||
|
||||
@staticmethod
|
||||
def is_connecting():
|
||||
return "Connecting to" in AccountSetting.get_account_connection_label()
|
||||
|
||||
@staticmethod
|
||||
def is_user_signed_out():
|
||||
return "Signed out" in AccountSetting.get_account_connection_label()
|
||||
|
||||
@staticmethod
|
||||
def is_user_signed_in():
|
||||
return "Connected" in AccountSetting.get_account_connection_label()
|
||||
|
||||
@staticmethod
|
||||
def wait_until_connection_is_configured(timeout=5000):
|
||||
result = squish.waitFor(
|
||||
AccountSetting.is_connecting,
|
||||
timeout,
|
||||
)
|
||||
|
||||
if not result:
|
||||
raise TimeoutError(
|
||||
"Timeout waiting for connection to be configured for "
|
||||
+ str(timeout)
|
||||
+ " milliseconds"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def wait_until_account_is_connected(timeout=5000):
|
||||
result = wait_for(
|
||||
AccountSetting.is_user_signed_in,
|
||||
timeout,
|
||||
)
|
||||
|
||||
if not result:
|
||||
raise TimeoutError(
|
||||
"Timeout waiting for the account to be connected for "
|
||||
+ str(timeout)
|
||||
+ " milliseconds"
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def wait_until_sync_folder_is_configured(timeout=5000):
|
||||
result = squish.waitFor(
|
||||
lambda: not squish.waitForObjectExists(
|
||||
AccountSetting.ACCOUNT_LOADING
|
||||
).visible,
|
||||
timeout,
|
||||
)
|
||||
|
||||
if not result:
|
||||
raise TimeoutError(
|
||||
"Timeout waiting for sync folder to be connected for "
|
||||
+ str(timeout)
|
||||
+ " milliseconds"
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def press_key(key):
|
||||
key = key.replace('"', "")
|
||||
key = f"<{key}>"
|
||||
squish.nativeType(key)
|
||||
|
||||
@staticmethod
|
||||
def is_log_dialog_visible():
|
||||
visible = False
|
||||
try:
|
||||
visible = squish.waitForObjectExists(
|
||||
AccountSetting.LOG_BROWSER_WINDOW
|
||||
).visible
|
||||
except:
|
||||
pass
|
||||
return visible
|
||||
|
||||
@staticmethod
|
||||
def remove_connection_for_user(username):
|
||||
Toolbar.open_account(username)
|
||||
AccountSetting.remove_account_connection()
|
||||
|
||||
@staticmethod
|
||||
def wait_until_account_is_removed(username, timeout=10000):
|
||||
displayname = get_displayname_for_user(username)
|
||||
displayname = substitute_inline_codes(displayname)
|
||||
|
||||
def account_removed():
|
||||
account = Toolbar.get_account(username)
|
||||
return account is None
|
||||
|
||||
result = wait_for(account_removed, timeout)
|
||||
|
||||
if not result:
|
||||
raise TimeoutError(
|
||||
"Timeout waiting for account to be removed for "
|
||||
+ str(timeout)
|
||||
+ " milliseconds"
|
||||
)
|
||||
@@ -0,0 +1,216 @@
|
||||
# from objectmaphelper import RegularExpression
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.common.exceptions import NoSuchElementException
|
||||
|
||||
from helpers.FilesHelper import build_conflicted_regex
|
||||
from helpers.ConfigHelper import get_config
|
||||
from helpers.AppHelper import app
|
||||
|
||||
|
||||
class Activity:
|
||||
TAB_CONTAINER = SimpleNamespace(by=None, selector=None)
|
||||
SUBTAB_CONTAINER = SimpleNamespace(
|
||||
by=By.CLASS_NAME, selector="[page tab | {tab_name}]"
|
||||
)
|
||||
NOT_SYNCED_TABLE = SimpleNamespace(by=None, selector=None)
|
||||
LOCAL_ACTIVITY_FILTER_BUTTON = SimpleNamespace(by=By.NAME, selector="Filter")
|
||||
LOCAL_ACTIVITY_FILTER_OPTION_SELECTOR = SimpleNamespace(by=By.NAME, selector=None)
|
||||
LOCAL_ACTIVITY_TABLE = SimpleNamespace(by=By.NAME, selector="Local activity table")
|
||||
FILTER_BUTTON_SELECTED_STATE = SimpleNamespace(
|
||||
by=By.XPATH, selector="//*[contains(@name, '1 Filter')]"
|
||||
)
|
||||
NOT_SYNCED_FILTER_BUTTON = SimpleNamespace(by=None, selector=None)
|
||||
NOT_SYNCED_FILTER_OPTION_SELECTOR = SimpleNamespace(by=None, selector=None)
|
||||
SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR = SimpleNamespace(by=None, selector=None)
|
||||
NOT_SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR = SimpleNamespace(by=None, selector=None)
|
||||
SYNCED_ACTIVITY_STATUS = SimpleNamespace(by=By.NAME, selector=None)
|
||||
|
||||
@staticmethod
|
||||
def get_not_synced_file_selector(resource):
|
||||
return {
|
||||
"column": 1,
|
||||
"container": Activity.NOT_SYNCED_TABLE,
|
||||
"text": resource,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_not_synced_status(row):
|
||||
return squish.waitForObjectExists(
|
||||
{
|
||||
"column": 6,
|
||||
"row": row,
|
||||
"container": Activity.NOT_SYNCED_TABLE,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
).text
|
||||
|
||||
@staticmethod
|
||||
def click_tab(tab_name):
|
||||
selector = Activity.SUBTAB_CONTAINER.selector.format(tab_name=tab_name)
|
||||
app().find_element(Activity.SUBTAB_CONTAINER.by, selector).click()
|
||||
|
||||
@staticmethod
|
||||
def check_file_exist(filename):
|
||||
squish.waitForObjectExists(
|
||||
Activity.get_not_synced_file_selector(
|
||||
RegularExpression(build_conflicted_regex(filename))
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def is_resource_blacklisted(filename):
|
||||
result = squish.waitFor(
|
||||
lambda: Activity.has_sync_status(filename, "Blacklisted"),
|
||||
get_config("maxSyncTimeout") * 1000,
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def is_resource_ignored(filename):
|
||||
result = squish.waitFor(
|
||||
lambda: Activity.has_sync_status(filename, "File Ignored"),
|
||||
get_config("maxSyncTimeout") * 1000,
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def is_resource_excluded(filename):
|
||||
result = squish.waitFor(
|
||||
lambda: Activity.has_sync_status(filename, "Excluded"),
|
||||
get_config("maxSyncTimeout") * 1000,
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def has_sync_status(filename, status):
|
||||
try:
|
||||
app().find_element(Activity.SYNCED_ACTIVITY_STATUS.by, status)
|
||||
return True
|
||||
except NoSuchElementException:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def select_synced_filter(sync_filter):
|
||||
menu = app().find_element(
|
||||
Activity.LOCAL_ACTIVITY_FILTER_BUTTON.by,
|
||||
Activity.LOCAL_ACTIVITY_FILTER_BUTTON.selector,
|
||||
)
|
||||
menu.click()
|
||||
|
||||
# NOTE: Filter options are not visible in the accessibility tree.
|
||||
# As a workaround, select the second filter option (which is an account filter).
|
||||
# This means we cannot select a specific account filter for now.
|
||||
menu.send_keys(Keys.ARROW_DOWN)
|
||||
menu.send_keys(Keys.ARROW_DOWN)
|
||||
menu.send_keys(Keys.ENTER)
|
||||
# confirm filter is applied
|
||||
app().find_element(
|
||||
Activity.FILTER_BUTTON_SELECTED_STATE.by,
|
||||
Activity.FILTER_BUTTON_SELECTED_STATE.selector,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_synced_file_selector(resource):
|
||||
return {
|
||||
"column": Activity.get_synced_table_column_number_by_name("File"),
|
||||
"container": Activity.LOCAL_ACTIVITY_TABLE,
|
||||
"text": resource,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_synced_table_column_number_by_name(column_name):
|
||||
return squish.waitForObject(
|
||||
{
|
||||
"container": Activity.SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR,
|
||||
"text": column_name,
|
||||
"type": "HeaderViewItem",
|
||||
"visible": True,
|
||||
}
|
||||
)["section"]
|
||||
|
||||
@staticmethod
|
||||
def has_activity(resource, action, account):
|
||||
try:
|
||||
row = app().find_element(By.NAME, resource)
|
||||
row_y = row.rect['y']
|
||||
# check other properties using current row position
|
||||
action_cells = app().find_elements(By.NAME, action)
|
||||
found_action_cell = False
|
||||
for action_el in action_cells:
|
||||
if action_el.rect['y'] == row_y:
|
||||
found_action_cell = True
|
||||
break
|
||||
if not found_action_cell:
|
||||
raise NoSuchElementException(
|
||||
f'Activity for "{resource}" does not have "{action}" action'
|
||||
)
|
||||
account_cells = app().find_elements(By.NAME, account)
|
||||
found_account_cell = False
|
||||
for account_el in account_cells:
|
||||
if account_el.rect['y'] == row_y:
|
||||
found_account_cell = True
|
||||
break
|
||||
if not found_account_cell:
|
||||
raise NoSuchElementException(
|
||||
f'Activity for "{resource}" does not have "{account}" account label'
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def select_not_synced_filter(filter_option):
|
||||
squish.clickButton(squish.waitForObject(Activity.NOT_SYNCED_FILTER_BUTTON))
|
||||
squish.activateItem(
|
||||
squish.waitForObjectItem(
|
||||
Activity.NOT_SYNCED_FILTER_OPTION_SELECTOR, filter_option
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_not_synced_table_column_number_by_name(column_name):
|
||||
return squish.waitForObject(
|
||||
{
|
||||
"container": Activity.NOT_SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR,
|
||||
"text": column_name,
|
||||
"type": "HeaderViewItem",
|
||||
"visible": True,
|
||||
}
|
||||
)["section"]
|
||||
|
||||
@staticmethod
|
||||
def check_not_synced_table(resource, status, account):
|
||||
try:
|
||||
file_row = squish.waitForObject(
|
||||
Activity.get_not_synced_file_selector(resource),
|
||||
get_config("lowestSyncTimeout") * 1000,
|
||||
)["row"]
|
||||
squish.waitForObjectExists(
|
||||
{
|
||||
"column": Activity.get_not_synced_table_column_number_by_name(
|
||||
"Status"
|
||||
),
|
||||
"row": file_row,
|
||||
"container": Activity.NOT_SYNCED_TABLE,
|
||||
"text": status,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
)
|
||||
squish.waitForObjectExists(
|
||||
{
|
||||
"column": Activity.get_not_synced_table_column_number_by_name(
|
||||
"Account"
|
||||
),
|
||||
"row": file_row,
|
||||
"container": Activity.NOT_SYNCED_TABLE,
|
||||
"text": account,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
@@ -0,0 +1,42 @@
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
|
||||
from pageObjects.AccountConnectionWizard import AccountConnectionWizard
|
||||
from helpers.WebUIHelper import authorize_via_webui
|
||||
from helpers.AppHelper import app
|
||||
|
||||
|
||||
class EnterPassword:
|
||||
LOGIN_CONTAINER = SimpleNamespace(by=None, selector=None)
|
||||
LOGIN_USER_LABEL = SimpleNamespace(
|
||||
by=By.XPATH,
|
||||
selector="//filler[@name='Login required']//label[contains(@name, 'Connecting')]",
|
||||
)
|
||||
USERNAME_BOX = SimpleNamespace(by=None, selector=None)
|
||||
LOGOUT_BUTTON = SimpleNamespace(by=None, selector=None)
|
||||
|
||||
def get_username(self):
|
||||
# Parse username from the login label:
|
||||
label = (
|
||||
app()
|
||||
.find_element(
|
||||
EnterPassword.LOGIN_USER_LABEL.by,
|
||||
EnterPassword.LOGIN_USER_LABEL.selector,
|
||||
)
|
||||
.text
|
||||
)
|
||||
username = label.split(" ", maxsplit=2)[1]
|
||||
return username.capitalize()
|
||||
|
||||
def oidc_relogin(self, username, password):
|
||||
AccountConnectionWizard.copy_login_url()
|
||||
authorize_via_webui(username, password)
|
||||
|
||||
def relogin(self, username, password, oauth=False):
|
||||
self.oidc_relogin(username, password)
|
||||
|
||||
def login_after_setup(self, username, password):
|
||||
self.oidc_relogin(username, password)
|
||||
|
||||
def accept_certificate(self):
|
||||
AccountConnectionWizard.accept_certificate()
|
||||
@@ -0,0 +1,297 @@
|
||||
from datetime import datetime
|
||||
import test
|
||||
import names
|
||||
import squish
|
||||
import object # pylint: disable=redefined-builtin
|
||||
|
||||
|
||||
class PublicLinkDialog:
|
||||
PUBLIC_LINKS_TAB = {
|
||||
"container": names.sharingDialog_qt_tabwidget_tabbar_QTabBar,
|
||||
"text": "Public Links",
|
||||
"type": "TabItem",
|
||||
}
|
||||
PASSWORD_CHECKBOX = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "checkBox_password",
|
||||
"type": "QCheckBox",
|
||||
"visible": 1,
|
||||
}
|
||||
PASSWORD_INPUT_FIELD = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "lineEdit_password",
|
||||
"type": "QLineEdit",
|
||||
"visible": 1,
|
||||
}
|
||||
EXPIRYDATE_CHECKBOX = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "checkBox_expire",
|
||||
"type": "QCheckBox",
|
||||
"visible": 1,
|
||||
}
|
||||
CREATE_SHARE_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "createShareButton",
|
||||
"type": "QPushButton",
|
||||
"visible": 1,
|
||||
}
|
||||
PUBLIC_LINK_NAME = {
|
||||
"column": 0,
|
||||
"container": names.oCC_ShareLinkWidget_linkShares_QTableWidget,
|
||||
"row": 0,
|
||||
"type": "QModelIndex",
|
||||
}
|
||||
EXPIRATION_DATE_FIELD = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "qt_spinbox_lineedit",
|
||||
"type": "QLineEdit",
|
||||
"visible": 1,
|
||||
}
|
||||
READ_ONLY_RADIO_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "radio_readOnly",
|
||||
"type": "QRadioButton",
|
||||
"visible": 1,
|
||||
}
|
||||
READ_WRITE_RADIO_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "radio_readWrite",
|
||||
"type": "QRadioButton",
|
||||
"visible": 1,
|
||||
}
|
||||
UPLOAD_ONLY_RADIO_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "radio_uploadOnly",
|
||||
"type": "QRadioButton",
|
||||
"visible": 1,
|
||||
}
|
||||
DELETE_LINK_BUTTON = {
|
||||
"container": names.oCC_ShareLinkWidget_linkShares_QTableWidget,
|
||||
"type": "QToolButton",
|
||||
"occurrence": 2,
|
||||
}
|
||||
CONFIRM_LINK_DELETE_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"text": "Delete",
|
||||
"type": "QPushButton",
|
||||
}
|
||||
UPDATE_PASSWORD_BUTTON = {
|
||||
"container": names.qt_tabwidget_stackedwidget_OCC_ShareLinkWidget_OCC_ShareLinkWidget,
|
||||
"name": "pushButton_setPassword",
|
||||
"type": "QPushButton",
|
||||
"visible": 1,
|
||||
}
|
||||
|
||||
DATE_FORMATS = [
|
||||
"%m/%d/%Y",
|
||||
"%d/%m/%Y",
|
||||
"%Y-%m-%d",
|
||||
"%d-%m-%Y",
|
||||
"%Y/%m/%d",
|
||||
"%m/%d/%y",
|
||||
"%d/%m/%y",
|
||||
]
|
||||
# to store current default public link expiry date
|
||||
default_expiry_date = ""
|
||||
|
||||
@staticmethod
|
||||
def parse_date(date):
|
||||
for date_format in PublicLinkDialog.DATE_FORMATS:
|
||||
try:
|
||||
date = str(datetime.strptime(date, date_format))
|
||||
date = date.split(" ", maxsplit=1)[0]
|
||||
break
|
||||
except:
|
||||
pass
|
||||
return date
|
||||
|
||||
@staticmethod
|
||||
def set_default_expiry_date(default_date):
|
||||
PublicLinkDialog.default_expiry_date = PublicLinkDialog.parse_date(default_date)
|
||||
|
||||
@staticmethod
|
||||
def get_default_expiry_date():
|
||||
return PublicLinkDialog.default_expiry_date
|
||||
|
||||
@staticmethod
|
||||
def open_public_link_tab():
|
||||
squish.mouseClick(squish.waitForObject(PublicLinkDialog.PUBLIC_LINKS_TAB))
|
||||
|
||||
@staticmethod
|
||||
def create_public_link(password="", permissions="", expire_date=""):
|
||||
permission_locator = ""
|
||||
if permissions:
|
||||
permission_locator = PublicLinkDialog.get_radio_object_for_permssion(
|
||||
permissions
|
||||
)
|
||||
|
||||
if permission_locator:
|
||||
squish.clickButton(squish.waitForObject(permission_locator))
|
||||
|
||||
if password:
|
||||
PublicLinkDialog.set_password(password)
|
||||
|
||||
if expire_date:
|
||||
PublicLinkDialog.set_expiration_date(expire_date)
|
||||
|
||||
squish.clickButton(squish.waitForObject(PublicLinkDialog.CREATE_SHARE_BUTTON))
|
||||
squish.waitFor(
|
||||
lambda: (
|
||||
squish.waitForObject(PublicLinkDialog.PUBLIC_LINK_NAME).displayText
|
||||
== "Public link"
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def toggle_password():
|
||||
squish.clickButton(squish.waitForObject(PublicLinkDialog.PASSWORD_CHECKBOX))
|
||||
|
||||
@staticmethod
|
||||
def set_password(password):
|
||||
if not squish.waitForObjectExists(PublicLinkDialog.PASSWORD_CHECKBOX).checked:
|
||||
PublicLinkDialog.toggle_password()
|
||||
|
||||
squish.mouseClick(squish.waitForObject(PublicLinkDialog.PASSWORD_INPUT_FIELD))
|
||||
squish.type(
|
||||
squish.waitForObject(PublicLinkDialog.PASSWORD_INPUT_FIELD),
|
||||
password,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def toggle_expiration_date():
|
||||
squish.clickButton(squish.waitForObject(PublicLinkDialog.EXPIRYDATE_CHECKBOX))
|
||||
|
||||
@staticmethod
|
||||
def set_expiration_date(expire_date):
|
||||
enabled = squish.waitForObjectExists(
|
||||
PublicLinkDialog.EXPIRYDATE_CHECKBOX
|
||||
).checked
|
||||
if not enabled:
|
||||
PublicLinkDialog.toggle_expiration_date()
|
||||
|
||||
if not expire_date == "default":
|
||||
exp_date = datetime.strptime(expire_date, "%Y-%m-%d")
|
||||
exp_year = exp_date.year - 2000
|
||||
squish.mouseClick(
|
||||
squish.waitForObject(PublicLinkDialog.EXPIRATION_DATE_FIELD)
|
||||
)
|
||||
# Move the cursor to year (last) field and enter the year
|
||||
squish.nativeType("<Ctrl+Right>")
|
||||
squish.nativeType("<Ctrl+Right>")
|
||||
squish.nativeType(exp_year)
|
||||
|
||||
# Move the cursor to day (middle) field and enter the day
|
||||
squish.nativeType("<Ctrl+Left>")
|
||||
squish.nativeType(exp_date.day)
|
||||
|
||||
# Move the cursor to month (first) field and enter the month
|
||||
# Backspace works most of the time, so we clear the data using backspace
|
||||
squish.nativeType("<Ctrl+Left>")
|
||||
squish.nativeType("<Ctrl+Left>")
|
||||
squish.nativeType("<Right>")
|
||||
squish.nativeType("<Backspace>")
|
||||
squish.nativeType("<Backspace>")
|
||||
squish.nativeType(exp_date.month)
|
||||
squish.nativeType("<Return>")
|
||||
|
||||
actual_date = str(
|
||||
squish.waitForObjectExists(
|
||||
PublicLinkDialog.EXPIRATION_DATE_FIELD
|
||||
).displayText
|
||||
)
|
||||
expected_date = f"{exp_date.month}/{exp_date.day}/{exp_year}"
|
||||
if not actual_date == expected_date:
|
||||
test.log(
|
||||
f"Expected date: {expected_date} is not same as that of actual date: {actual_date}"
|
||||
+ ", trying workaround"
|
||||
)
|
||||
# retry with workaround
|
||||
PublicLinkDialog.set_expiration_date_with_workaround(
|
||||
exp_year, exp_date.month, exp_date.day
|
||||
)
|
||||
actual_date = str(
|
||||
squish.waitForObjectExists(
|
||||
PublicLinkDialog.EXPIRATION_DATE_FIELD
|
||||
).displayText
|
||||
)
|
||||
if not actual_date == expected_date:
|
||||
test.fail(
|
||||
f"workaround failed:\nactual date: {actual_date}\nexpected date: {expected_date}"
|
||||
)
|
||||
else:
|
||||
default_date = str(
|
||||
squish.waitForObjectExists(
|
||||
PublicLinkDialog.EXPIRATION_DATE_FIELD
|
||||
).displayText
|
||||
)
|
||||
PublicLinkDialog.set_default_expiry_date(default_date)
|
||||
|
||||
# This workaround is needed because the above function 'set_expiration_date' can not set the month field sometime.
|
||||
# See for more details: https://github.com/owncloud/client/issues/9218
|
||||
@staticmethod
|
||||
def set_expiration_date_with_workaround(year, month, day):
|
||||
squish.mouseClick(squish.waitForObject(PublicLinkDialog.EXPIRATION_DATE_FIELD))
|
||||
|
||||
# date can only be set to future date. But sometimes it can not modify the month field in first attempt.
|
||||
# date format is 'm/d/yy', so we have to edit 'month' first
|
||||
# then 'day' and then 'year'.
|
||||
# Delete data from month field
|
||||
squish.nativeType("<Delete>")
|
||||
squish.nativeType("<Delete>")
|
||||
squish.nativeType(month)
|
||||
squish.nativeType(day)
|
||||
squish.nativeType(year)
|
||||
squish.nativeType("<Return>")
|
||||
|
||||
@staticmethod
|
||||
def get_radio_object_for_permssion(permissions):
|
||||
permission_locator = None
|
||||
if permissions in ("Download / View", "Viewer"):
|
||||
permission_locator = PublicLinkDialog.READ_ONLY_RADIO_BUTTON
|
||||
elif permissions in ("Download / View / Edit", "Editor"):
|
||||
permission_locator = PublicLinkDialog.READ_WRITE_RADIO_BUTTON
|
||||
elif permissions in ("Upload only (File Drop)", "Contributor"):
|
||||
permission_locator = PublicLinkDialog.UPLOAD_ONLY_RADIO_BUTTON
|
||||
else:
|
||||
raise LookupError("No such radio object found for given permission")
|
||||
|
||||
return permission_locator
|
||||
|
||||
@staticmethod
|
||||
def create_public_link_with_role(role):
|
||||
permission_locator = PublicLinkDialog.get_radio_object_for_permssion(role)
|
||||
|
||||
squish.clickButton(squish.waitForObject(permission_locator))
|
||||
squish.clickButton(squish.waitForObject(PublicLinkDialog.CREATE_SHARE_BUTTON))
|
||||
squish.waitFor(
|
||||
lambda: (
|
||||
squish.findObject(PublicLinkDialog.PUBLIC_LINK_NAME).displayText
|
||||
== "Public link"
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def change_password(password):
|
||||
PublicLinkDialog.set_password(password)
|
||||
squish.clickButton(
|
||||
squish.waitForObject(PublicLinkDialog.UPDATE_PASSWORD_BUTTON)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def delete_public_link():
|
||||
squish.clickButton(squish.waitForObject(PublicLinkDialog.DELETE_LINK_BUTTON))
|
||||
squish.clickButton(
|
||||
squish.waitForObject(PublicLinkDialog.CONFIRM_LINK_DELETE_BUTTON)
|
||||
)
|
||||
squish.waitFor(
|
||||
lambda: (not object.exists(PublicLinkDialog.DELETE_LINK_BUTTON)),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_expiration_date():
|
||||
default_date = str(
|
||||
squish.waitForObjectExists(
|
||||
PublicLinkDialog.EXPIRATION_DATE_FIELD
|
||||
).displayText
|
||||
)
|
||||
return PublicLinkDialog.parse_date(default_date)
|
||||
@@ -0,0 +1,101 @@
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
|
||||
from helpers.AppHelper import app
|
||||
|
||||
|
||||
class Settings:
|
||||
CHECKBOX_OPTION_ITEM = SimpleNamespace(by=None, selector=None)
|
||||
NETWORK_OPTION_ITEM = SimpleNamespace(by=None, selector=None)
|
||||
ABOUT_BUTTON = SimpleNamespace(by=By.NAME, selector="About")
|
||||
ABOUT_DIALOG = SimpleNamespace(by=By.CLASS_NAME, selector="[page tab | About]")
|
||||
ABOUT_DIALOG_OK_BUTTON = SimpleNamespace(by=By.NAME, selector="OK")
|
||||
GENERAL_SETTING_START_ON_LOGIN = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel/*[@name='Start on Login']"
|
||||
)
|
||||
GENERAL_SETTING_LANGUAGE = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel/label[@name='Language']"
|
||||
)
|
||||
ADVANCED_SETTING_SYNC_HIDDEN_FILES = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel/*[@name='Sync hidden files']"
|
||||
)
|
||||
ADVANCED_SETTING_EDIT_IGNORED_FILES = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel/*[@name='Edit Ignored Files']"
|
||||
)
|
||||
ADVANCED_SETTING_LOG_SETTINGS = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel/*[@name='Log Settings']"
|
||||
)
|
||||
NETWORK_SETTING_DOWNLOAD_BANDWIDTH = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel[@name='Download Bandwidth']"
|
||||
)
|
||||
NETWORK_SETTING_UPLOAD_BANDWIDTH = SimpleNamespace(
|
||||
by=By.XPATH, selector="//panel[@name='Upload Bandwidth']"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_checkbox_option_selector(name):
|
||||
selector = Settings.CHECKBOX_OPTION_ITEM.copy()
|
||||
selector.update({"name": name})
|
||||
if name == "languageDropdown":
|
||||
selector.update({"type": "QComboBox"})
|
||||
elif name in ("ignoredFilesButton", "logSettingsButton"):
|
||||
selector.update({"type": "QPushButton"})
|
||||
return selector
|
||||
|
||||
@staticmethod
|
||||
def get_network_option_selector(name):
|
||||
selector = Settings.NETWORK_OPTION_ITEM.copy()
|
||||
selector.update({"name": name})
|
||||
return selector
|
||||
|
||||
@staticmethod
|
||||
def has_general_setting(setting):
|
||||
if setting.lower() == "start on login":
|
||||
locator = Settings.GENERAL_SETTING_START_ON_LOGIN
|
||||
elif setting.lower() == "language":
|
||||
locator = Settings.GENERAL_SETTING_LANGUAGE
|
||||
else:
|
||||
raise ValueError(f"Unknown general setting: {setting}")
|
||||
return app().find_element(locator.by, locator.selector).is_displayed()
|
||||
|
||||
@staticmethod
|
||||
def has_advanced_setting(setting):
|
||||
if setting.lower() == "sync hidden files":
|
||||
locator = Settings.ADVANCED_SETTING_SYNC_HIDDEN_FILES
|
||||
elif setting.lower() == "edit ignored files":
|
||||
locator = Settings.ADVANCED_SETTING_EDIT_IGNORED_FILES
|
||||
elif setting.lower() == "log settings":
|
||||
locator = Settings.ADVANCED_SETTING_LOG_SETTINGS
|
||||
else:
|
||||
raise ValueError(f"Unknown advanced setting: {setting}")
|
||||
return app().find_element(locator.by, locator.selector).is_displayed()
|
||||
|
||||
@staticmethod
|
||||
def has_network_setting(setting):
|
||||
if setting.lower() == "download bandwidth":
|
||||
locator = Settings.NETWORK_SETTING_DOWNLOAD_BANDWIDTH
|
||||
elif setting.lower() == "upload bandwidth":
|
||||
locator = Settings.NETWORK_SETTING_UPLOAD_BANDWIDTH
|
||||
else:
|
||||
raise ValueError(f"Unknown network setting: {setting}")
|
||||
return app().find_element(locator.by, locator.selector).is_displayed()
|
||||
|
||||
@staticmethod
|
||||
def open_about_dialog():
|
||||
app().find_element(
|
||||
Settings.ABOUT_BUTTON.by, Settings.ABOUT_BUTTON.selector
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def has_about_dialog():
|
||||
return (
|
||||
app()
|
||||
.find_element(Settings.ABOUT_DIALOG.by, Settings.ABOUT_DIALOG.selector)
|
||||
.is_displayed()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def close_about_dialog():
|
||||
app().find_element(
|
||||
Settings.ABOUT_DIALOG_OK_BUTTON.by, Settings.ABOUT_DIALOG_OK_BUTTON.selector
|
||||
).click()
|
||||
@@ -0,0 +1,131 @@
|
||||
from types import SimpleNamespace
|
||||
from appium.webdriver.common.appiumby import AppiumBy as By
|
||||
from selenium.common.exceptions import NoSuchElementException
|
||||
|
||||
from helpers.ConfigHelper import get_config
|
||||
from helpers.AppHelper import app
|
||||
|
||||
|
||||
class SyncConnection:
|
||||
ACCOUNT_CONNECTION_CONTAINER = SimpleNamespace(
|
||||
by=By.NAME, selector="Sync connections"
|
||||
)
|
||||
FOLDER_SYNC_CONNECTION_MENU_BUTTON = SimpleNamespace(
|
||||
by=By.NAME,
|
||||
selector="{sync_folder},Success,Local folder: {sync_path}{sync_folder}",
|
||||
)
|
||||
MENU_ITEM = SimpleNamespace(by=By.NAME, selector=None)
|
||||
SELECTIVE_SYNC_APPLY_BUTTON = SimpleNamespace(by=None, selector=None)
|
||||
CANCEL_FOLDER_SYNC_CONNECTION_DIALOG = SimpleNamespace(by=None, selector=None)
|
||||
CONFIRM_FOLDER_SYNC_CONNECTION_REMOVE = SimpleNamespace(
|
||||
by=By.NAME, selector="Remove Space"
|
||||
)
|
||||
PERMISSION_ERROR_LABEL = SimpleNamespace(by=None, selector=None)
|
||||
|
||||
@staticmethod
|
||||
def get_current_account_connection():
|
||||
connections = app().find_elements(
|
||||
SyncConnection.ACCOUNT_CONNECTION_CONTAINER.by,
|
||||
SyncConnection.ACCOUNT_CONNECTION_CONTAINER.selector,
|
||||
)
|
||||
for connection in connections:
|
||||
# use the active connection
|
||||
if connection.get_attribute("showing") == "true":
|
||||
return connection
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def open_menu(sync_folder=None):
|
||||
if sync_folder is None:
|
||||
sync_folder = get_config('syncConnectionName')
|
||||
|
||||
connection = SyncConnection.get_current_account_connection()
|
||||
menu_button = connection.find_element(
|
||||
SyncConnection.FOLDER_SYNC_CONNECTION_MENU_BUTTON.by,
|
||||
SyncConnection.FOLDER_SYNC_CONNECTION_MENU_BUTTON.selector.format(
|
||||
sync_folder=sync_folder,
|
||||
sync_path=get_config('currentUserSyncPath'),
|
||||
),
|
||||
)
|
||||
menu_button.native_click(button='right')
|
||||
|
||||
@staticmethod
|
||||
def perform_action(action):
|
||||
SyncConnection.open_menu()
|
||||
app().find_element(SyncConnection.MENU_ITEM.by, action).click()
|
||||
|
||||
@staticmethod
|
||||
def force_sync():
|
||||
SyncConnection.perform_action("Force sync now")
|
||||
|
||||
@staticmethod
|
||||
def pause_sync():
|
||||
SyncConnection.perform_action("Pause sync")
|
||||
|
||||
@staticmethod
|
||||
def resume_sync():
|
||||
SyncConnection.perform_action("Resume sync")
|
||||
|
||||
@staticmethod
|
||||
def has_menu_item(item):
|
||||
return squish.waitForObjectItem(SyncConnection.MENU_ITEM, item)
|
||||
|
||||
@staticmethod
|
||||
def menu_item_exists(menu_item):
|
||||
obj = SyncConnection.MENU_ITEM.copy()
|
||||
obj.update({"type": "QAction", "text": menu_item})
|
||||
return object.exists(obj)
|
||||
|
||||
@staticmethod
|
||||
def choose_what_to_sync():
|
||||
SyncConnection.open_menu()
|
||||
SyncConnection.perform_action("Choose what to sync")
|
||||
|
||||
@staticmethod
|
||||
def has_sync_connection(sync_folder):
|
||||
connection = SyncConnection.get_current_account_connection()
|
||||
try:
|
||||
connection.find_element(
|
||||
SyncConnection.FOLDER_SYNC_CONNECTION_MENU_BUTTON.by,
|
||||
SyncConnection.FOLDER_SYNC_CONNECTION_MENU_BUTTON.selector.format(
|
||||
sync_folder=sync_folder,
|
||||
sync_path=get_config('currentUserSyncPath'),
|
||||
),
|
||||
)
|
||||
return True
|
||||
except NoSuchElementException:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def remove_folder_sync_connection():
|
||||
SyncConnection.perform_action("Remove Space")
|
||||
|
||||
@staticmethod
|
||||
def cancel_folder_sync_connection_removal():
|
||||
squish.clickButton(
|
||||
squish.waitForObject(SyncConnection.CANCEL_FOLDER_SYNC_CONNECTION_DIALOG)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def confirm_folder_sync_connection_removal():
|
||||
app().find_element(
|
||||
SyncConnection.CONFIRM_FOLDER_SYNC_CONNECTION_REMOVE.by,
|
||||
SyncConnection.CONFIRM_FOLDER_SYNC_CONNECTION_REMOVE.selector,
|
||||
).click()
|
||||
|
||||
@staticmethod
|
||||
def wait_for_error_label(to_exist=True):
|
||||
"""Wait for permission error label to appear or disappear"""
|
||||
status = squish.waitFor(
|
||||
lambda: object.exists(SyncConnection.PERMISSION_ERROR_LABEL) == to_exist,
|
||||
get_config("maxSyncTimeout") * 1000,
|
||||
)
|
||||
if not status:
|
||||
action = "appear" if to_exist else "disappear"
|
||||
raise AssertionError(f"Permission error label did not {action}")
|
||||
|
||||
@staticmethod
|
||||
def get_permission_error_message():
|
||||
"""Get the permission error message text"""
|
||||
SyncConnection.wait_for_error_label(True) # Wait for label to appear
|
||||
return str(squish.waitForObject(SyncConnection.PERMISSION_ERROR_LABEL).text)
|
||||
@@ -0,0 +1,283 @@
|
||||
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,
|
||||
)
|
||||
@@ -0,0 +1,181 @@
|
||||
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
|
||||
Reference in New Issue
Block a user