test/start application with custom data folder

#10293
This commit is contained in:
Vladimir Druzhinin 2023-05-19 21:10:38 +02:00 committed by Iuri Matias
parent fc15f82e1b
commit 4da388b5bc
13 changed files with 147 additions and 47 deletions

0
test/ui-test/__init__.py Normal file
View File

View File

@ -1,23 +1,29 @@
import configs
import drivers.SquishDriver as driver import drivers.SquishDriver as driver
import drivers.SquishDriverVerification as verification import drivers.SquishDriverVerification as verification
import drivers.SDKeyboardCommands as keyCommands import drivers.SDKeyboardCommands as keyCommands
def start_application(app_name: str):
driver.start_application(app_name) def start_application(app_data_dir=configs.path.STATUS_APP_DATA, clear_user_data: bool = True):
driver.start_application(app_data_dir=app_data_dir, clear_user_data=clear_user_data)
def click_on_an_object(objName: str): def click_on_an_object(objName: str):
driver.click_obj_by_name(objName) driver.click_obj_by_name(objName)
def input_text(text: str, objName: str): def input_text(text: str, objName: str):
driver.type_text(objName, text) driver.type_text(objName, text)
def object_not_enabled(objName: str): def object_not_enabled(objName: str):
verification.verify_object_enabled(objName, 500, False) verification.verify_object_enabled(objName, 500, False)
def str_to_bool(string: str): def str_to_bool(string: str):
return string.lower() in ["yes", "true", "1", "y", "enabled"] return string.lower() in ["yes", "true", "1", "y", "enabled"]
def clear_input_text(objName: str): def clear_input_text(objName: str):
keyCommands.press_select_all(objName) keyCommands.press_select_all(objName)
keyCommands.press_backspace(objName) keyCommands.press_backspace(objName)

View File

@ -1 +1,2 @@
from . import squish from . import path
from . import squish

View File

@ -0,0 +1,10 @@
import os
from utils.system_path import SystemPath
ROOT: SystemPath = SystemPath(__file__).resolve().parent.parent.parent
TMP: SystemPath = ROOT / 'tmp'
AUT: SystemPath = SystemPath(os.getenv('AUT_PATH', ROOT.parent.parent / 'bin' / 'nim_status_client'))
STATUS_APP_DATA = TMP / 'Status'
STATUS_USER_DATA: SystemPath = STATUS_APP_DATA / 'data'

View File

@ -1,3 +1,3 @@
UI_LOAD_TIMEOUT_MSEC = 5000 UI_LOAD_TIMEOUT_MSEC = 5000
APP_LOAD_TIMEOUT_MSEC = 60000 APP_LOAD_TIMEOUT_MSEC = 60000
PROCESS_LOAD_TIMEOUT_MSEC = 10000

View File

@ -10,18 +10,20 @@
import copy import copy
import sys import sys
import test import test
import time
import configs import configs
import names import names
import object import object
import objectMap import objectMap
import toplevelwindow
import utils.FileManager as filesMngr
# IMPORTANT: It is necessary to import manually the Squish drivers module by module. # IMPORTANT: It is necessary to import manually the Squish drivers module by module.
# More info in: https://kb.froglogic.com/display/KB/Article+-+Using+Squish+functions+in+your+own+Python+modules+or+packages # More info in: https://kb.froglogic.com/display/KB/Article+-+Using+Squish+functions+in+your+own+Python+modules+or+packages
import squish
import toplevelwindow
from objectmaphelper import Wildcard from objectmaphelper import Wildcard
from utils.system_path import SystemPath
from .aut import * # noqa
from .context import * # noqa
from .elements import * # noqa from .elements import * # noqa
# The default maximum timeout to find ui object # The default maximum timeout to find ui object
@ -36,18 +38,16 @@ _MAX_WAIT_APP_TIMEOUT = 15000
_SEARCH_IMAGES_PATH = "../shared/searchImages/" _SEARCH_IMAGES_PATH = "../shared/searchImages/"
def start_application(app_name: str, attempt=2): def start_application(
try: fp: SystemPath = configs.path.AUT,
ctx = squish.startApplication(app_name) app_data_dir: SystemPath = configs.path.STATUS_APP_DATA,
assert squish.waitFor(lambda: ctx.isRunning, _MAX_WAIT_APP_TIMEOUT), 'Start application error' clear_user_data: bool = True
toplevelwindow.ToplevelWindow(squish.waitForObject(names.statusDesktop_mainWindow)).maximize() ):
except (AssertionError, RuntimeError): if clear_user_data:
if attempt: filesMngr.clear_directory(str(app_data_dir / 'data'))
[ctx.detach() for ctx in squish.applicationContextList()] app_data_dir.mkdir(parents=True, exist_ok=True)
time.sleep(1) ExecutableAut(fp).start(f'--datadir={app_data_dir}')
start_application(app_name, attempt - 1) toplevelwindow.ToplevelWindow(squish.waitForObject(names.statusDesktop_mainWindow)).maximize()
else:
raise
# Waits for the given object is loaded, visible and enabled. # Waits for the given object is loaded, visible and enabled.

View File

@ -17,14 +17,17 @@ _MAX_WAIT_CLOSE_APP_TIMEOUT = 20
import traceback import traceback
def verify_screen(objName: str, timeout: int=1000): def verify_screen(objName: str, timeout: int=1000):
from drivers.SquishDriver import is_loaded_visible_and_enabled
result = is_loaded_visible_and_enabled(objName, timeout) result = is_loaded_visible_and_enabled(objName, timeout)
test.verify(result, f'Verifying screen for real-name {objName}') test.verify(result, f'Verifying screen for real-name {objName}')
def verify_object_enabled(objName: str, timeout: int=_MIN_WAIT_OBJ_TIMEOUT, condition: bool=True): def verify_object_enabled(objName: str, timeout: int=_MIN_WAIT_OBJ_TIMEOUT, condition: bool=True):
from drivers.SquishDriver import is_loaded_visible_and_enabled
result = is_loaded_visible_and_enabled(objName, timeout) result = is_loaded_visible_and_enabled(objName, timeout)
test.verify(result[0] == condition, "Checking if object enabled") test.verify(result[0] == condition, "Checking if object enabled")
def verify_text_matching(objName: str, text: str): def verify_text_matching(objName: str, text: str):
from drivers.SquishDriver import is_text_matching
test.verify(is_text_matching(objName, text), "Checking if text matches") test.verify(is_text_matching(objName, text), "Checking if text matches")
def verify_text_matching_insensitive(obj, text: str): def verify_text_matching_insensitive(obj, text: str):

View File

@ -0,0 +1,28 @@
import configs
from utils.system_path import SystemPath
import squish
from . import context
class ExecutableAut:
def __init__(self, fp: SystemPath):
self.fp = fp
self.ctx = None
def start(self, *args, attempt: int = 2):
args = ' '.join([self.fp.name] + [str(arg) for arg in args])
try:
self.ctx = squish.startApplication(args)
assert squish.waitFor(lambda: self.ctx.isRunning, configs.squish.APP_LOAD_TIMEOUT_MSEC)
except (AssertionError, RuntimeError):
if attempt:
self.detach()
self.start(*args, attempt - 1)
else:
raise
@staticmethod
def detach():
context.detach()

View File

@ -0,0 +1,12 @@
import configs
import squish
import time
def detach():
for ctx in squish.applicationContextList():
ctx.detach()
assert squish.waitFor(
lambda: not ctx.isRunning, configs.squish.PROCESS_LOAD_TIMEOUT_MSEC), 'Detach application failed'
# TODO: close by ctx.pid and then detach
time.sleep(5)

View File

@ -0,0 +1,24 @@
import os
import pathlib
class SystemPath(pathlib.Path):
_accessor = pathlib._normal_accessor # noqa
_flavour = pathlib._windows_flavour if os.name == 'nt' else pathlib._posix_flavour # noqa
def rmtree(self, ignore_errors=False):
children = list(self.iterdir())
for child in children:
if child.is_dir():
child.rmtree(ignore_errors=ignore_errors)
else:
try:
child.unlink()
except OSError as e:
if not ignore_errors:
raise
try:
self.rmdir()
except OSError:
if not ignore_errors:
raise

View File

@ -4,20 +4,21 @@
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../testSuites/global_shared/")) sys.path.append(os.path.join(os.path.dirname(__file__), "../../../testSuites/global_shared/"))
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../src/")) sys.path.append(os.path.join(os.path.dirname(__file__), "../../../src/"))
import drivers.SquishDriver as driver
from steps.commonInitSteps import context_init from steps.commonInitSteps import context_init
@OnScenarioStart @OnScenarioStart
def hook(context): def hook(context):
context_init(context, testSettings) context_init(context, testSettings)
context.userData["scenario_name"] = context._data["title"] context.userData["scenario_name"] = context._data["title"]
@OnScenarioEnd @OnScenarioEnd
def hook(context): def hook(context):
ctx = currentApplicationContext() driver.detach()
ctx.detach()
assert waitFor(lambda: not ctx.isRunning, _app_closure_timeout), 'Detach application failed'
@OnStepEnd @OnStepEnd
def hook(context): def hook(context):
context.userData["step_name"] = context._data["text"] context.userData["step_name"] = context._data["text"]

View File

@ -4,6 +4,7 @@ import os
import utils.FileManager as filesMngr import utils.FileManager as filesMngr
import common.Common as common import common.Common as common
import configs
from screens.StatusWelcomeScreen import StatusWelcomeScreen from screens.StatusWelcomeScreen import StatusWelcomeScreen
from screens.StatusMainScreen import StatusMainScreen from screens.StatusMainScreen import StatusMainScreen
@ -58,13 +59,12 @@ def context_init(context, testSettings, screenshot_on_fail = True):
context.userData[_fixtures_root] = os.path.join(joined_path, "fixtures/") context.userData[_fixtures_root] = os.path.join(joined_path, "fixtures/")
def a_first_time_user_lands_on(context): def a_first_time_user_lands_on(context):
filesMngr.erase_directory(context.userData[_status_data_folder]) common.start_application()
common.start_application(context.userData[_aut_name])
def a_user_starts_the_application_with_a_specific_data_folder(context, data_folder_path): def a_user_starts_the_application_with_a_specific_data_folder(context, data_folder_path):
filesMngr.clear_directory(context.userData["status_data_folder_path"]) filesMngr.clear_directory(configs.path.STATUS_USER_DATA)
filesMngr.copy_directory(data_folder_path, context.userData["status_data_folder_path"]) filesMngr.copy_directory(data_folder_path, str(configs.path.STATUS_USER_DATA))
common.start_application(context.userData[_aut_name]) common.start_application(clear_user_data=False)
def a_first_time_user_lands_on_and_generates_new_key(context): def a_first_time_user_lands_on_and_generates_new_key(context):
a_first_time_user_lands_on(context) a_first_time_user_lands_on(context)
@ -76,8 +76,7 @@ def a_user_lands_on_and_generates_new_key(context):
welcome_screen.generate_new_key() welcome_screen.generate_new_key()
def a_first_time_user_lands_on_and_navigates_to_import_seed_phrase(context): def a_first_time_user_lands_on_and_navigates_to_import_seed_phrase(context):
filesMngr.erase_directory(context.userData[_status_data_folder]) common.start_application()
filesMngr.start_application(context.userData[_aut_name])
welcome_screen = StatusWelcomeScreen() welcome_screen = StatusWelcomeScreen()
welcome_screen.agree_terms_conditions_and_navigate_to_import_seed_phrase() welcome_screen.agree_terms_conditions_and_navigate_to_import_seed_phrase()

View File

@ -17,13 +17,14 @@ import time
# ***************************************************************************** # *****************************************************************************
import common.Common as common import common.Common as common
import steps.commonInitSteps as init_steps import steps.commonInitSteps as init_steps
from drivers.SquishDriver import start_application import drivers.SquishDriver as driver
from screens.StatusChatScreen import StatusChatScreen from screens.StatusChatScreen import StatusChatScreen
from screens.StatusMainScreen import StatusMainScreen from screens.StatusMainScreen import StatusMainScreen
_statusMain = StatusMainScreen() _statusMain = StatusMainScreen()
_statusChat = StatusChatScreen() _statusChat = StatusChatScreen()
######################### #########################
### PRECONDITIONS region: ### PRECONDITIONS region:
######################### #########################
@ -32,30 +33,37 @@ _statusChat = StatusChatScreen()
def step(context, data_folder_path): def step(context, data_folder_path):
init_steps.a_user_starts_the_application_with_a_specific_data_folder(context, data_folder_path) init_steps.a_user_starts_the_application_with_a_specific_data_folder(context, data_folder_path)
@Given("the user restarts the app") @Given("the user restarts the app")
def step(context): def step(context):
the_user_restarts_the_app(context) the_user_restarts_the_app(context)
@Given("the user joins chat room \"|any|\"") @Given("the user joins chat room \"|any|\"")
def step(context, room): def step(context, room):
the_user_joins_chat_room(room) the_user_joins_chat_room(room)
@Given("the user clicks on escape key") @Given("the user clicks on escape key")
def step(context): def step(context):
_statusMain.click_escape() _statusMain.click_escape()
@Given("the user clears input \"|any|\"") @Given("the user clears input \"|any|\"")
def step(context, input_component): def step(context, input_component):
common.clear_input_text(input_component) common.clear_input_text(input_component)
@Given("the user inputs the following \"|any|\" with ui-component \"|any|\"") @Given("the user inputs the following \"|any|\" with ui-component \"|any|\"")
def step(context, text, obj): def step(context, text, obj):
the_user_inputs_the_following_text_with_uicomponent(text, obj) the_user_inputs_the_following_text_with_uicomponent(text, obj)
@Given("the user clicks on the following ui-component \"|any|\"") @Given("the user clicks on the following ui-component \"|any|\"")
def step(context: any, obj: str): def step(context: any, obj: str):
the_user_clicks_on_the_following_ui_component(obj) the_user_clicks_on_the_following_ui_component(obj)
######################### #########################
### ACTIONS region: ### ACTIONS region:
######################### #########################
@ -63,24 +71,29 @@ def step(context: any, obj: str):
@When("the user restarts the app") @When("the user restarts the app")
def step(context): def step(context):
the_user_restarts_the_app(context) the_user_restarts_the_app(context)
@When("the user inputs the following \"|any|\" with ui-component \"|any|\"") @When("the user inputs the following \"|any|\" with ui-component \"|any|\"")
def step(context, text, obj): def step(context, text, obj):
the_user_inputs_the_following_text_with_uicomponent(text, obj) the_user_inputs_the_following_text_with_uicomponent(text, obj)
@When("the user clicks on the following ui-component \"|any|\"") @When("the user clicks on the following ui-component \"|any|\"")
def step(context: any, obj: str): def step(context: any, obj: str):
init_steps.the_user_clicks_on_the_following_ui_component(obj) init_steps.the_user_clicks_on_the_following_ui_component(obj)
@When("the user joins chat room \"|any|\"") @When("the user joins chat room \"|any|\"")
def step(context, room): def step(context, room):
the_user_joins_chat_room(room) the_user_joins_chat_room(room)
# TODO remove when we have a reliable local mailserver # TODO remove when we have a reliable local mailserver
@When("the user waits |any| seconds") @When("the user waits |any| seconds")
def step(context, amount): def step(context, amount):
time.sleep(2) time.sleep(2)
######################### #########################
### VERIFICATIONS region: ### VERIFICATIONS region:
######################### #########################
@ -88,21 +101,24 @@ def step(context, amount):
@Then("the following ui-component \"|any|\" is not enabled") @Then("the following ui-component \"|any|\" is not enabled")
def step(context, obj): def step(context, obj):
common.object_not_enabled(obj) common.object_not_enabled(obj)
########################################################################### ###########################################################################
### COMMON methods used in different steps given/when/then region: ### COMMON methods used in different steps given/when/then region:
########################################################################### ###########################################################################
def the_user_restarts_the_app(context: any): def the_user_restarts_the_app(context: any):
[ctx.detach() for ctx in squish.applicationContextList()] driver.detach()
start_application(context.userData["aut_name"]) driver.start_application(clear_user_data=False)
def the_user_joins_chat_room(room: str): def the_user_joins_chat_room(room: str):
init_steps.the_user_joins_chat_room(room) init_steps.the_user_joins_chat_room(room)
def the_user_inputs_the_following_text_with_uicomponent(text: str, obj): def the_user_inputs_the_following_text_with_uicomponent(text: str, obj):
common.input_text(text, obj) common.input_text(text, obj)
def the_user_clicks_on_the_following_ui_component(obj): def the_user_clicks_on_the_following_ui_component(obj):
init_steps.the_user_clicks_on_the_following_ui_component(obj) init_steps.the_user_clicks_on_the_following_ui_component(obj)