diff --git a/test/ui-test/src/common/Common.py b/test/ui-test/src/common/Common.py new file mode 100644 index 0000000000..c461a5f11c --- /dev/null +++ b/test/ui-test/src/common/Common.py @@ -0,0 +1,12 @@ + + +class Common: + + def __init__(self): + pass + + def click_on_an_object(self, obj): + click_obj_by_name(obj) + + def input_text(self, obj, text): + type(obj, text) diff --git a/test/ui-test/src/drivers/SquishDriver.py b/test/ui-test/src/drivers/SquishDriver.py index 34a4584058..95655d0316 100755 --- a/test/ui-test/src/drivers/SquishDriver.py +++ b/test/ui-test/src/drivers/SquishDriver.py @@ -1,7 +1,7 @@ #****************************************************************************** # Status.im #*****************************************************************************/ -#/** +# /** # * \file SquishDriver.py # * # * \date February 2022 @@ -14,13 +14,13 @@ from enum import Enum import squish import object import names +import test -# The default maximum timeout to find ui object -_MAX_WAIT_OBJ_TIMEOUT = 5000 #[milliseconds] -# Waits for the given object is loaded, visible and enabled. -# It returns a tuple: True in case it is found. Otherwise, false. And the object itself. -def is_loaded_visible_and_enabled(objName, timeout = _MAX_WAIT_OBJ_TIMEOUT): +_MAX_WAIT_OBJ_TIMEOUT = 5000 + + +def is_loaded_visible_and_enabled(objName, timeout=_MAX_WAIT_OBJ_TIMEOUT): obj = None try: obj = squish.waitForObject(getattr(names, objName), timeout) @@ -28,8 +28,12 @@ def is_loaded_visible_and_enabled(objName, timeout = _MAX_WAIT_OBJ_TIMEOUT): except LookupError: return False, obj -# Waits for the given object is loaded and might be not visible and/or not enabled: -# It returns a tuple: True in case it is found. Otherwise, false. And the object itself. + +def verify_screen_is_loaded(objName, timeout=_MAX_WAIT_OBJ_TIMEOUT): + result = is_loaded_visible_and_enabled(objName, timeout) + test.verify(result, True) + + def is_loaded(objName): obj = None try: @@ -37,27 +41,27 @@ def is_loaded(objName): return True, obj except LookupError: return False, obj - -# It checks if the given object is visible and enabled. + + def is_visible_and_enabled(obj): return obj.visible and obj.enabled -# Given a specific object, get a specific child. -def get_child(obj, child_index = None): + +def get_child(obj, child_index=None): if None == child_index: return object.children(obj) else: return object.children(obj)[child_index] -# It executes the click action into the given object: + def click_obj(obj): try: squish.mouseClick(obj, squish.Qt.LeftButton) return True except LookupError: return False - -# It executes the click action into object with given object name: + + def click_obj_by_name(objName): try: obj = squish.waitForObject(getattr(names, objName)) @@ -65,12 +69,30 @@ def click_obj_by_name(objName): return True except LookupError: return False - -# It types the specified text into the given object (as if the user had used the keyboard): + + +def check_obj_by_name(objName): + try: + obj = squish.waitForObject(getattr(names, objName)) + obj.checked = True + return True + except LookupError: + return False + + +def verify_text(objName, text): + try: + obj = squish.waitForObject(getattr(names, objName)) + test.compare(obj.text, text, "Found the following text " + text) + return True + except LookupError: + return False + + def type(objName, text): try: obj = squish.findObject(getattr(names, objName)) squish.type(obj, text) return True except LookupError: - return False \ No newline at end of file + return False diff --git a/test/ui-test/src/screens/StatusChatScreen.py b/test/ui-test/src/screens/StatusChatScreen.py new file mode 100644 index 0000000000..897770e6ae --- /dev/null +++ b/test/ui-test/src/screens/StatusChatScreen.py @@ -0,0 +1,7 @@ + + +class StatusChatScreen: + + def __init__(self): + pass + diff --git a/test/ui-test/src/screens/StatusWelcomeScreen.py b/test/ui-test/src/screens/StatusWelcomeScreen.py new file mode 100644 index 0000000000..910cea46a1 --- /dev/null +++ b/test/ui-test/src/screens/StatusWelcomeScreen.py @@ -0,0 +1,63 @@ +#****************************************************************************** +# Status.im +#*****************************************************************************/ +# /** +# * \file StatusWelcomeScreen.py +# * +# * \date May 2022 +# * \brief Sign Up and Login for new users to the app. +# *****************************************************************************/ + + +class AgreementPopUp(Enum): + ACKNOWLEDGE_CHECKBOX = "acknowledge_checkbox" + TERMS_OF_USE_CHECK_BOX = "termsOfUseCheckBox_StatusCheckBox" + GET_STARTED_BUTTON = "getStartedStatusButton_StatusButton" + + +class SignUpComponents(Enum): + NEW_TO_STATUS = "mainWindow_I_am_new_to_Status_StatusBaseText" + GENERATE_NEW_KEYS = "mainWindow_Generate_new_keys_StatusBaseText" + USERNAME_INPUT = "mainWindow_edit_TextEdit" + NEXT_BUTTON = "mainWindow_Next_StatusBaseText" + NEXT_STATUS_BUTTON = "mainWindow_nextBtn_StatusButton" + NEW_PASSWORD_BUTTON = "mainWindow_New_password_PlaceholderText" + PASSWORD_INPUT = "loginView_passwordInput" + CONFIRM_PASSWORD = "mainWindow_Confirm_password_PlaceholderText" + PASSWORD_CONFIRM_INPUT = "mainWindow_inputValue_StyledTextField" + CREATE_PASSWORD = "mainWindow_Create_password_StatusBaseText" + CONFIRM_PASSWORD_AGAIN = "mainWindow_Confirm_you_password_again_PlaceholderText" + FINALIZE_PASSWORD_STEP = "mainWindow_Finalise_Status_Password_Creation_StatusBaseText" + PASSWORD_PREFERENCE = "mainWindow_I_prefer_to_use_my_password_StatusBaseText" + + +class StatusWelcomeScreen(): + + def __init__(self): + verify_screen_is_loaded(AgreementPopUp.ACKNOWLEDGE_CHECKBOX.value) + + def agree_terms_conditions_and_generate_new_key(self): + verify_text(AgreementPopUp.ACKNOWLEDGE_CHECKBOX.value, "I acknowledge that Status Desktop is in Beta and by using it, I take the full responsibility for all risks concerning my data and funds.") + click_obj_by_name(AgreementPopUp.ACKNOWLEDGE_CHECKBOX.value) + check_obj_by_name(AgreementPopUp.TERMS_OF_USE_CHECK_BOX.value) + click_obj_by_name(AgreementPopUp.GET_STARTED_BUTTON.value) + click_obj_by_name(SignUpComponents.NEW_TO_STATUS.value) + click_obj_by_name(SignUpComponents.GENERATE_NEW_KEYS.value) + + def input_username_and_password_and_finalize_sign_up(self, username, password): + type(SignUpComponents.USERNAME_INPUT.value, username) + click_obj_by_name(SignUpComponents.NEXT_BUTTON.value) + click_obj_by_name(SignUpComponents.NEXT_STATUS_BUTTON.value) + + click_obj_by_name(SignUpComponents.NEW_PASSWORD_BUTTON.value) + type(SignUpComponents.PASSWORD_INPUT.value, password) + click_obj_by_name(SignUpComponents.CONFIRM_PASSWORD.value) + type(SignUpComponents.PASSWORD_CONFIRM_INPUT.value, password) + click_obj_by_name(SignUpComponents.CREATE_PASSWORD.value) + + click_obj_by_name(SignUpComponents.CONFIRM_PASSWORD_AGAIN.value) + type(SignUpComponents.PASSWORD_INPUT.value, password) + + click_obj_by_name(SignUpComponents.FINALIZE_PASSWORD_STEP.value) + click_obj_by_name(SignUpComponents.PASSWORD_PREFERENCE.value) + diff --git a/test/ui-test/testSuites/suite_statusLogin/shared/scripts/names.py b/test/ui-test/testSuites/suite_statusLogin/shared/scripts/names.py index b3882d02b5..23c9d5eda2 100644 --- a/test/ui-test/testSuites/suite_statusLogin/shared/scripts/names.py +++ b/test/ui-test/testSuites/suite_statusLogin/shared/scripts/names.py @@ -11,3 +11,23 @@ loginView_main = {"container": statusDesktop_mainWindow, "type": "LoginView", "v loginView_errMsgLabel = {"container": statusDesktop_mainWindow, "id": "errMsg", "type": "StyledText", "visible": True} statusDesktop_mainWindow_overlay = {"container": statusDesktop_mainWindow, "type": "Overlay", "unnamed": 1, "visible": True} accountsView_accountListPanel = {"container": statusDesktop_mainWindow_overlay, "type": "AccountListPanel", "visible": True} +acknowledge_checkbox = {"checkable": True, "container": statusDesktop_mainWindow_overlay, "objectName": "acknowledgeCheckBox", "type": "StatusCheckBox", "visible": True} +termsOfUseCheckBox_StatusCheckBox = {"checkable": True, "container": statusDesktop_mainWindow_overlay, "id":"termsOfUse", "type": "StatusCheckBox", "visible": True} +getStartedStatusButton_StatusButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "getStartedStatusButton", "type": "StatusButton", "visible": True} +mainWindow_I_am_new_to_Status_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "I am new to Status", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Generate_new_keys_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Generate new keys", "type": "StatusBaseText", "unnamed": 1, "visible": True} +get_Started_StatusBaseText = {"container": statusDesktop_mainWindow_overlay, "text": "Get Started", "type": "StatusBaseText", "unnamed": 1, "visible": True} +i_accept_Status_StatusBaseText = {"container": statusDesktop_mainWindow_overlay, "text": "I accept Status", "type": "StatusBaseText", "unnamed": 1, "visible": True} +termsOfUseLink_StatusBaseText = {"container": statusDesktop_mainWindow_overlay, "objectName": "termsOfUseLink", "type": "StatusBaseText", "visible": True} +mainWindow_edit_TextEdit = {"container": statusDesktop_mainWindow, "id": "edit", "type": "TextEdit", "unnamed": 1, "visible": True} +mainWindow_Next_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Next", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Confirm_password_PlaceholderText = {"container": statusDesktop_mainWindow, "text": "Confirm password", "type": "PlaceholderText", "unnamed": 1, "visible": True} +mainWindow_Display_name_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Display name", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_nextBtn_StatusButton = {"container": statusDesktop_mainWindow, "id": "nextBtn", "type": "StatusButton", "unnamed": 1, "visible": True} +mainWindow_New_password_PlaceholderText = {"container": statusDesktop_mainWindow, "text": "New password", "type": "PlaceholderText", "unnamed": 1, "visible": True} +mainWindow_inputValue_StyledTextField = {"container": statusDesktop_mainWindow, "echoMode": 2, "id": "inputValue", "occurrence": 2, "passwordCharacter": "•", "type": "StyledTextField", "unnamed": 1, "visible": True} +mainWindow_Rectangle = {"container": statusDesktop_mainWindow, "occurrence": 11, "type": "Rectangle", "unnamed": 1, "visible": True} +mainWindow_Create_password_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Create password", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Confirm_you_password_again_PlaceholderText = {"container": statusDesktop_mainWindow, "text": "Confirm you password (again)", "type": "PlaceholderText", "unnamed": 1, "visible": True} +mainWindow_Finalise_Status_Password_Creation_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Finalise Status Password Creation", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_I_prefer_to_use_my_password_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "I prefer to use my password", "type": "StatusBaseText", "unnamed": 1, "visible": True} diff --git a/test/ui-test/testSuites/suite_statusLogin/shared/steps/steps.py b/test/ui-test/testSuites/suite_statusLogin/shared/steps/steps.py index 6387b5edfa..c1dc7c4c1a 100644 --- a/test/ui-test/testSuites/suite_statusLogin/shared/steps/steps.py +++ b/test/ui-test/testSuites/suite_statusLogin/shared/steps/steps.py @@ -3,7 +3,7 @@ #****************************************************************************** # Status.im #*****************************************************************************/ -#/** +# /** # * \file steps.py # * # * \test Status Desktop - Login @@ -14,10 +14,15 @@ # * with a pattern which is matched against the steps being executed. # ***************************************************************************** from data.StatusAccount import StatusAccount -from processes.StatusLoginProcess import StatusLoginProcess +from processes.StatusLoginProcess import StatusLoginProcess +from screens.StatusWelcomeScreen import StatusWelcomeScreen +from screens.StatusChatScreen import StatusChatScreen + +welcomeScreen = StatusWelcomeScreen() + @Given("A Status Desktop |any| and |word|") -def step(context,account,password): +def step(context, account, password): # Create new data domain: accountObj = StatusAccount(account, password) @@ -31,6 +36,7 @@ def step(context,account,password): # Verify process can be executed: test.verify(process.can_execute_process(), "Not possible to start login process. Check if expected Login Screen is available.") + @When("the user tries to login with valid credentials") def step(context): @@ -39,6 +45,7 @@ def step(context): # Check valid process behavior: loginProcess.execute_process(True) + @When("the user tries to login with invalid credentials") def step(context): loginProcess = context.userData['process'] @@ -46,16 +53,35 @@ def step(context): # Check invalid process behavior: loginProcess.execute_process(False) + @Then("the user is able to login to Status Desktop application") def step(context): get_process_result(context) + @Then("the user is NOT able to login to Status Desktop application") def step(context): get_process_result(context) - + + +@Given("A first time user lands on the status desktop and generates new key") +def step(context): + welcomeScreen.agree_terms_conditions_and_generate_new_key() + + +@When("user inputs username |any| and password |any|") +def step(context, username, password): + welcomeScreen.input_username_and_password_and_finalize_sign_up(username, password) + + +@Then("the user lands on the signed in app") +def step(context): + StatusChatScreen() + + # Common: def get_process_result(context): loginProcess = context.userData['process'] result, description = loginProcess.get_process_result() test.verify(result, description) + diff --git a/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.feature b/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.feature new file mode 100644 index 0000000000..a69ce67a56 --- /dev/null +++ b/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.feature @@ -0,0 +1,23 @@ +#****************************************************************************** +# Status.im +#*****************************************************************************/ +#/** +# * \file test.feature +# * +# * \test Status Sign up +# * \date May 2022 +# ** +# *****************************************************************************/ + +Feature: Status Desktop Sign Up + + As a user I want to Sign-up into the Status Desktop application. + + The following scenarios cover Sign up process. + + Scenario: User signs up with password + + Given A first time user lands on the status desktop and generates new key + When user inputs username tester123 and password TesTEr16843/!@00 + Then the user lands on the signed in app + diff --git a/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.py b/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.py new file mode 100644 index 0000000000..75e47d0b33 --- /dev/null +++ b/test/ui-test/testSuites/suite_statusLogin/tst_statusSignUp/test.py @@ -0,0 +1,8 @@ +source(findFile('scripts', 'python/bdd.py')) + +setupHooks('../shared/scripts/bdd_hooks.py') +collectStepDefinitions('./steps', '../shared/steps') + +def main(): + testSettings.throwOnFailure = True + runFeatureFile('test.feature')