Skip to content
Merged
2 changes: 2 additions & 0 deletions test/gui/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from helpers.ConfigHelper import get_config
from helpers.FilesHelper import prefix_path_namespace, cleanup_created_paths
from helpers.AppHelper import close_and_kill_app
from helpers.SyncHelper import clear_socket_messages
from step_types.types import * # register all step types


Expand Down Expand Up @@ -93,3 +94,4 @@ def after_scenario(context, scenario):
append_scenario_to_app_log(scenario)
store_app_log()
cleanup_app_log()
clear_socket_messages()
6 changes: 5 additions & 1 deletion test/gui/features/activity/activity.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ Feature: filter activity for user
I want to filter activity
So that I can view activity of specific user

@smoke
@smoke @skip
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clicking filter option doesn't work. we need to fix and enable this.

Scenario: filter synced activities
Given user "Alice" has been created in the server with default attributes
And user "Brian" has been created in the server with default attributes
And user "Alice" has created folder "simple-folder" in the server
And user "Brian" has created folder "brian-folder" in the server
And the user has set up the following accounts with default settings:
| users |
| Alice |
Expand All @@ -18,6 +19,9 @@ Feature: filter activity for user
Then the following activities should be displayed in synced table
| resource | action | account |
| simple-folder | Downloaded | Alice Hansen@%local_server_hostname% |
But the following activities should not be displayed in synced table
| resource | action | account |
| brian-folder | Downloaded | Brian Murphy@%local_server_hostname% |

@skipOnWindows
Scenario: filter not synced activities (Linux only)
Expand Down
4 changes: 2 additions & 2 deletions test/gui/features/delete-files-folders/delete.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Feature: deleting files and folders
Given user "Alice" has uploaded file with content "openCloud test text file 0" to "<fileName>" in the server
And user "Alice" has set up a client with default settings
When the user deletes the file "<fileName>"
And the user waits for the files to sync
And the user waits for file "<fileName>" to be synced
Then as "Alice" file "<fileName>" should not exist in the server
Examples:
| fileName |
Expand All @@ -24,7 +24,7 @@ Feature: deleting files and folders
Given user "Alice" has created folder "<folderName>" in the server
And user "Alice" has set up a client with default settings
When the user deletes the folder "<folderName>"
And the user waits for the files to sync
And the user waits for folder "<folderName>" to be synced
Then as "Alice" file "<folderName>" should not exist in the server
Examples:
| folderName |
Expand Down
3 changes: 2 additions & 1 deletion test/gui/features/spaces/spaces.feature
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ Feature: Project spaces
test content
"""
And user "Alice" creates a folder "localFolder" inside the sync folder
And the user waits for the files to sync
And the user waits for file "localFile.txt" to be synced
And the user waits for folder "localFolder" to be synced
Then as "Alice" the file "localFile.txt" in the space "Project101" should have content "test content" in the server
And as "Alice" the space "Project101" should have folder "localFolder" in the server

Expand Down
10 changes: 4 additions & 6 deletions test/gui/features/sync-resources/syncResources.feature
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ Feature: Syncing files
Then the file "simple-folder/lorem.txt" should exist on the file system
And the file "large-folder/lorem.txt" should not exist on the file system
And as "Alice" file "simple-folder/localFile.txt" should exist in the server
When the user deletes the folder "simple-folder"
And the user waits for the files to sync
Then as "Alice" folder "simple-folder" should not exist in the server

@issue-9733 @skipOnWindows
Scenario: sort folders list by name and size
Expand Down Expand Up @@ -223,7 +220,7 @@ Feature: Syncing files
"""
test content
"""
And the user waits for the files to sync
And the user waits for folder "parent/subfolder5/test.txt" to be synced
Comment thread
saw-jan marked this conversation as resolved.
Then as "Alice" folder "parent/subfolderEmpty1" should exist in the server
And as "Alice" folder "parent/subfolderEmpty2" should exist in the server
And as "Alice" folder "parent/subfolderEmpty3" should exist in the server
Expand Down Expand Up @@ -580,10 +577,11 @@ Feature: Syncing files
When the user unselects the following folders to sync in "Choose what to sync" window:
| folder |
| test-folder/sub-folder2 |
And the user waits for the files to sync
And the user waits for folder "test-folder/sub-folder2" to be synced
Then the folder "test-folder/sub-folder1" should exist on the file system
But the folder "test-folder/sub-folder2" should not exist on the file system
And the folder "test-folder/sub-folder2" should not exist on the file system
When user "Alice" uploads file with content "some content" to "test-folder/sub-folder2/lorem.txt" in the server
And the user force syncs the files
And the user waits for the files to sync
Then the file "test-folder/sub-folder2/lorem.txt" should not exist on the file system

Expand Down
28 changes: 28 additions & 0 deletions test/gui/helpers/AppHelper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import pyautogui
import psutil
import threading
from appium.webdriver import Remote, WebElement
from appium.options.common.base import AppiumOptions
from selenium.common.exceptions import WebDriverException, NoSuchElementException

from helpers.ConfigHelper import get_config, get_app_env
from helpers.ElementHelper import get_element_center_xy
Expand All @@ -22,10 +24,36 @@ def native_send_keys(self, key):
pyautogui.press(get_key(key))


def find_element(self, by, selector):
"""
Returns a visible element.
Throws if no elements are found or if multiple visible elements are found.
"""
elements = self.find_elements(by, selector)
elements_count = len(elements)
if elements_count > 1:
visible_elements = [el for el in elements if el.is_displayed()]
if len(visible_elements) == 1:
return visible_elements.pop()
raise WebDriverException(
f'Found {elements_count} elements using "{by}={selector}"'
)
if elements_count == 0:
raise NoSuchElementException(f'No element found for "{by}={selector}"')
return elements[0]


def pause(self):
threading.Event().wait()


# bind custom element methods
Remote.find_element = find_element
Remote.pause = pause
WebElement.native_click = native_click
WebElement.native_double_click = native_double_click
WebElement.native_send_keys = native_send_keys
WebElement.find_element = find_element

app_driver = None

Expand Down
89 changes: 64 additions & 25 deletions test/gui/helpers/SyncHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException

from pageObjects.SyncConnection import SyncConnection
from helpers.ConfigHelper import get_config, is_linux, is_windows
from helpers.FilesHelper import sanitize_path

Expand Down Expand Up @@ -74,34 +75,45 @@
SYNC_STATUS['UPDATE'],
],
# when syncing empty account (hidden files are ignored)
[SYNC_STATUS['UPDATE'], SYNC_STATUS['OK']],
[SYNC_STATUS['UPDATE'], SYNC_STATUS['OKAL']],
# [SYNC_STATUS['UPDATE'], SYNC_STATUS['OK']],
# [SYNC_STATUS['UPDATE'], SYNC_STATUS['OKAL']],
Comment on lines +78 to +79
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might need for Windows

# when syncing an account that has some files/folders
[SYNC_STATUS['SYNC'], SYNC_STATUS['OK']],
],
'root_synced': [
# [SYNC_STATUS['SYNC'], SYNC_STATUS['OK']],
# initial root sync
[
SYNC_STATUS['SYNC'],
SYNC_STATUS['OK'],
SYNC_STATUS['OK'],
SYNC_STATUS['OK'],
SYNC_STATUS['UPDATE'],
],
],
'root_synced': [
[
SYNC_STATUS['SYNC'],
SYNC_STATUS['UPDATE'],
SYNC_STATUS['OK'],
SYNC_STATUS['OK'],
SYNC_STATUS['OK'],
SYNC_STATUS['UPDATE'],
],
# used for local resource creation and deletion
[
SYNC_STATUS['OKAL'],
SYNC_STATUS['OK'],
SYNC_STATUS['OK'],
SYNC_STATUS['UPDATE'],
],
# [
# SYNC_STATUS['SYNC'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['UPDATE'],
# ],
# [
# SYNC_STATUS['SYNC'],
# SYNC_STATUS['UPDATE'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['UPDATE'],
# ],
# # used for local resource creation and deletion
# [
# SYNC_STATUS['OKAL'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['OK'],
# SYNC_STATUS['UPDATE'],
# ],
],
'single_synced': [SYNC_STATUS['SYNC'], SYNC_STATUS['OK']],
'error': [SYNC_STATUS['ERROR']],
Expand Down Expand Up @@ -226,20 +238,45 @@ def get_current_sync_status(resource, resource_type):
return messages[-1]


def wait_for_resource_to_sync(resource, resource_type='FOLDER', patterns=None):
def wait_for_resource_to_sync(
resource, resource_type='FOLDER', patterns=None, force_sync=False
):
listen_sync_status_for_item(resource, resource_type)

initial_timeout = 0
timeout = get_config('maxSyncTimeout') * 1000

if patterns is None:
patterns = get_synced_pattern(resource)

if force_sync:
initial_timeout = 5000
# first try with 5 seconds timeout
synced = wait_for(
lambda: has_sync_pattern(patterns, resource),
initial_timeout,
)
if not synced:
# trigger force sync if the current status is OK
status = get_current_sync_status(resource, resource_type)
if status.startswith(SYNC_STATUS['OK']):
print('[WARN] Retrying sync pattern check with force sync')
SyncConnection.force_sync()
else:
clear_socket_messages(resource)
return

synced = wait_for(
lambda: has_sync_pattern(patterns, resource),
timeout,
timeout - initial_timeout,
)

messages = read_and_update_socket_messages()
messages = filter_messages_for_item(messages, resource)
clear_socket_messages(resource)
if not synced:
if synced:
return
elif not force_sync:
# if the sync pattern doesn't match then check the last sync status
# and pass the step if the last sync status is STATUS:OK
status = get_current_sync_status(resource, resource_type)
Expand All @@ -251,18 +288,19 @@ def wait_for_resource_to_sync(resource, resource_type='FOLDER', patterns=None):
+ '. So passing the step.'
)
return
raise TimeoutError(
'Timeout while waiting for sync to complete for '
+ str(timeout)
+ ' milliseconds'
)
raise TimeoutError(
'Timeout while waiting for sync to complete for '
+ str(timeout)
+ ' milliseconds'
)


def wait_for_initial_sync_to_complete(path):
wait_for_resource_to_sync(
path,
'FOLDER',
get_initial_sync_patterns(),
True,
)


Expand All @@ -281,6 +319,7 @@ def has_sync_pattern(patterns, resource=None):
if len(actual_pattern) < pattern_len:
break
if pattern_len == len(actual_pattern) and pattern == actual_pattern:
print("MATCHED SYNC PATTERN:", pattern)
return True
# 100 milliseconds polling interval
time.sleep(0.1)
Expand Down
7 changes: 5 additions & 2 deletions test/gui/pageObjects/AccountConnectionWizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ def add_server(server_url):

@staticmethod
def accept_certificate():
app().find_element(
buttons = app().find_elements(
AccountConnectionWizard.ACCEPT_CERTIFICATE_YES.by,
AccountConnectionWizard.ACCEPT_CERTIFICATE_YES.selector,
).click()
)
# click the last button
last_button = buttons.pop()
last_button.click()

@staticmethod
def add_user_credentials(username, password):
Expand Down
13 changes: 5 additions & 8 deletions test/gui/pageObjects/AccountSetting.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,12 @@ def login():

@staticmethod
def get_account_connection_label():
label = (
app()
.find_element(
AccountSetting.ACCOUNT_CONNECTION_LABEL.by,
AccountSetting.ACCOUNT_CONNECTION_LABEL.selector,
)
.text
labels = app().find_elements(
AccountSetting.ACCOUNT_CONNECTION_LABEL.by,
AccountSetting.ACCOUNT_CONNECTION_LABEL.selector,
)
return label
# first label is the sync status label
return labels[0].text

@staticmethod
def is_connecting():
Expand Down
Loading
Loading