diff --git a/test/e2e/constants/onboarding.py b/test/e2e/constants/onboarding.py new file mode 100644 index 0000000000..c2580f38db --- /dev/null +++ b/test/e2e/constants/onboarding.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class OnboardingMessages(Enum): + WRONG_LOGIN_LESS_LETTERS = 'Username must be at least 5 character(s)' + WRONG_LOGIN_SYMBOLS_NOT_ALLOWED = 'Only letters, numbers, underscores, whitespaces and hyphens allowed' + WRONG_PASSWORD = 'Password must be at least 10 characters long' + PASSWORDS_DONT_MATCH = "Passwords don't match" + PASSWORD_INCORRECT = 'Password incorrect' diff --git a/test/e2e/gui/objects_map/onboarding_names.py b/test/e2e/gui/objects_map/onboarding_names.py index f42fb07642..ea0f1e6ddc 100755 --- a/test/e2e/gui/objects_map/onboarding_names.py +++ b/test/e2e/gui/objects_map/onboarding_names.py @@ -65,10 +65,11 @@ mainWindow_Plug_in_Keycard_reader_StatusBaseText = {"container": mainWindow_Keyc mainWindow_InsertDetailsView = {"container": statusDesktop_mainWindow, "type": "InsertDetailsView", "unnamed": 1, "visible": True} updatePicButton_StatusRoundButton = {"container": mainWindow_InsertDetailsView, "id": "updatePicButton", "type": "StatusRoundButton", "unnamed": 1, "visible": True} mainWindow_CanvasItem = {"container": mainWindow_InsertDetailsView, "type": "CanvasItem", "unnamed": 1, "visible": True} -mainWindow_Next_StatusButton = {"container": statusDesktop_mainWindow, "objectName": "onboardingDetailsViewNextButton", "type": "StatusButton", "visible": True, "enabled": True} +mainWindow_Next_StatusButton = {"container": statusDesktop_mainWindow, "objectName": "onboardingDetailsViewNextButton", "type": "StatusButton", "visible": True} mainWindow_inputLayout_ColumnLayout = {"container": statusDesktop_mainWindow, "id": "inputLayout", "type": "ColumnLayout", "unnamed": 1, "visible": True} mainWindow_statusBaseInput_StatusBaseInput = {"container": mainWindow_inputLayout_ColumnLayout, "objectName": "onboardingDisplayNameInput", "type": "TextEdit", "visible": True} mainWindow_errorMessage_StatusBaseText = {"container": mainWindow_inputLayout_ColumnLayout, "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_nameInput_StatusInput = {"container": statusDesktop_mainWindow, "id": "nameInput", "type": "StatusInput", "unnamed": 1, "visible": True} # Your emojihash and identicon ring mainWindow_welcomeScreenUserProfileImage_StatusSmartIdenticon = {"container": mainWindow_InsertDetailsView, "objectName": "welcomeScreenUserProfileImage", "type": "StatusSmartIdenticon", "visible": True} @@ -81,12 +82,14 @@ mainWindow_userImageCopy_StatusSmartIdenticon = {"container": mainWindow_InsertD mainWindow_CreatePasswordView = {"container": statusDesktop_mainWindow, "type": "CreatePasswordView", "unnamed": 1, "visible": True} mainWindow_passwordViewNewPassword = {"container": mainWindow_CreatePasswordView, "echoMode": 2, "objectName": "passwordViewNewPassword", "type": "StatusPasswordInput", "visible": True} mainWindow_passwordViewNewPasswordConfirm = {"container": mainWindow_CreatePasswordView, "echoMode": 2, "objectName": "passwordViewNewPasswordConfirm", "type": "StatusPasswordInput", "visible": True} -mainWindow_Create_password_StatusButton = {"checkable": False, "container": mainWindow_CreatePasswordView, "objectName": "onboardingCreatePasswordButton", "type": "StatusButton", "visible": True, "enabled": True} +mainWindow_Create_password_StatusButton = {"checkable": False, "container": mainWindow_CreatePasswordView, "objectName": "onboardingCreatePasswordButton", "type": "StatusButton", "visible": True} +mainWindow_view_PasswordView = {"container": statusDesktop_mainWindow, "id": "view", "type": "PasswordView", "unnamed": 1, "visible": True} # Confirm Password View mainWindow_ConfirmPasswordView = {"container": statusDesktop_mainWindow, "type": "ConfirmPasswordView", "unnamed": 1,"visible": True} mainWindow_confirmAgainPasswordInput = {"container": mainWindow_ConfirmPasswordView, "objectName": "confirmAgainPasswordInput", "type": "StatusPasswordInput", "visible": True} mainWindow_Finalise_Status_Password_Creation_StatusButton = {"checkable": False, "container": mainWindow_ConfirmPasswordView, "objectName": "confirmPswSubmitBtn", "type": "StatusButton", "visible": True} +mainWindow_passwordView_PasswordConfirmationView = {"container": statusDesktop_mainWindow, "id": "passwordView", "type": "PasswordConfirmationView", "unnamed": 1, "visible": True} # Login View mainWindow_LoginView = {"container": statusDesktop_mainWindow, "type": "LoginView", "unnamed": 1, "visible": True} @@ -95,7 +98,7 @@ loginView_passwordInput = {"container": mainWindow_LoginView, "objectName": "log loginView_currentUserNameLabel = {"container": mainWindow_LoginView, "objectName": "currentUserNameLabel", "type": "StatusBaseText"} loginView_changeAccountBtn = {"container": mainWindow_LoginView, "objectName": "loginChangeAccountButton", "type": "StatusFlatRoundButton"} accountsView_accountListPanel = {"container": statusDesktop_mainWindow, "objectName": "LoginView_AccountsRepeater", "type": "Repeater", "visible": True} - +mainWindow_txtPassword_Input = {"container": statusDesktop_mainWindow, "id": "txtPassword", "type": "Input", "unnamed": 1, "visible": True} # Touch ID Auth View mainWindow_TouchIDAuthView = {"container": statusDesktop_mainWindow, "type": "TouchIDAuthView", "unnamed": 1, "visible": True} diff --git a/test/e2e/gui/screens/onboarding.py b/test/e2e/gui/screens/onboarding.py index b3871aeab3..23a33e8edb 100755 --- a/test/e2e/gui/screens/onboarding.py +++ b/test/e2e/gui/screens/onboarding.py @@ -8,6 +8,7 @@ import allure import configs import constants.tesseract import driver +from driver.objects_access import walk_children from gui.components.os.open_file_dialogs import OpenFileDialog from gui.components.picture_edit_popup import PictureEditPopup from gui.elements.button import Button @@ -195,6 +196,12 @@ class SeedPhraseInputView(OnboardingView): self._seed_phrase_input_text_edit = TextEdit('mainWindow_statusSeedPhraseInputField_TextEdit') self._import_button = Button('mainWindow_Import_StatusButton') + @property + @allure.step('Get import button enabled state') + def is_import_button_enabled(self) -> bool: + return driver.waitForObjectExists(self._import_button.real_name, + configs.timeouts.UI_LOAD_TIMEOUT_MSEC).enabled + @allure.step('Input seed phrase') def input_seed_phrase(self, seed_phrase: typing.List[str], autocomplete: bool): if len(seed_phrase) == 12: @@ -218,6 +225,8 @@ class SeedPhraseInputView(OnboardingView): else: self._seed_phrase_input_text_edit.text = word + @allure.step('Click import button') + def import_seed_phrase(self): self._import_button.click() return YourProfileView().wait_until_appears() @@ -246,6 +255,12 @@ class YourProfileView(OnboardingView): self._display_name_text_field = TextEdit('mainWindow_statusBaseInput_StatusBaseInput') self._erros_text_label = TextLabel('mainWindow_errorMessage_StatusBaseText') self._next_button = Button('mainWindow_Next_StatusButton') + self._login_input_object = QObject('mainWindow_nameInput_StatusInput') + + @property + @allure.step('Get next button enabled state') + def is_next_button_enabled(self) -> bool: + return driver.waitForObjectExists(self._next_button.real_name, configs.timeouts.UI_LOAD_TIMEOUT_MSEC).enabled @property @allure.step('Get profile image') @@ -360,18 +375,31 @@ class CreatePasswordView(OnboardingView): self._new_password_text_field = TextEdit('mainWindow_passwordViewNewPassword') self._confirm_password_text_field = TextEdit('mainWindow_passwordViewNewPasswordConfirm') self._create_button = Button('mainWindow_Create_password_StatusButton') + self._password_view_object = QObject('mainWindow_view_PasswordView') @property @allure.step('Verify: Create password button enabled') def is_create_password_button_enabled(self) -> bool: - # Verification is_enable can not be used - # LookupError, because of "Enable: True" in object real name, if button disabled - return self._create_button.is_visible + return driver.waitForObjectExists(self._create_button.real_name, + configs.timeouts.UI_LOAD_TIMEOUT_MSEC).enabled + + @property + @allure.step('Get password error message') + def password_error_message(self) -> str: + return self._password_view_object.object.errorMsgText + + @allure.step('Set password in first field') + def set_password_in_first_field(self, value: str): + self._new_password_text_field.clear().text = value + + @allure.step('Set password in confirmation field') + def set_password_in_confirmation_field(self, value: str): + self._confirm_password_text_field.clear().text = value @allure.step('Set password and open Confirmation password view') def create_password(self, value: str) -> 'ConfirmPasswordView': - self._new_password_text_field.clear().text = value - self._confirm_password_text_field.clear().text = value + self.set_password_in_first_field(value) + self.set_password_in_confirmation_field(value) self._create_button.click() time.sleep(1) return ConfirmPasswordView().wait_until_appears() @@ -388,10 +416,28 @@ class ConfirmPasswordView(OnboardingView): super(ConfirmPasswordView, self).__init__('mainWindow_ConfirmPasswordView') self._confirm_password_text_field = TextEdit('mainWindow_confirmAgainPasswordInput') self._confirm_button = Button('mainWindow_Finalise_Status_Password_Creation_StatusButton') + self._confirmation_password_view_object = QObject('mainWindow_passwordView_PasswordConfirmationView') + + @property + @allure.step('Get finalise password creation button enabled state') + def is_confirm_password_button_enabled(self) -> bool: + return driver.waitForObjectExists(self._confirm_button.real_name, + configs.timeouts.UI_LOAD_TIMEOUT_MSEC).enabled + + @property + @allure.step('Get confirmation error message') + def confirmation_error_message(self) -> str: + for child in walk_children(self._confirmation_password_view_object.object): + if getattr(child, 'id', '') == 'errorTxt': + return str(child.text) + + @allure.step('Set password') + def set_password(self, value: str): + self._confirm_password_text_field.text = value @allure.step('Confirm password') def confirm_password(self, value: str): - self._confirm_password_text_field.text = value + self.set_password(value) self._confirm_button.click() @allure.step('Go back') @@ -426,6 +472,12 @@ class LoginView(QObject): self._current_user_name_label = TextLabel('loginView_currentUserNameLabel') self._change_account_button = Button('loginView_changeAccountBtn') self._accounts_combobox = QObject('accountsView_accountListPanel') + self._password_object = QObject('mainWindow_txtPassword_Input') + + @property + @allure.step('Get login error message') + def login_error_message(self) -> str: + return str(self._password_object.object.validationError) @allure.step('Log in user') def log_in(self, account): diff --git a/test/e2e/tests/onboarding/test_onboarding_import_seed.py b/test/e2e/tests/onboarding/test_onboarding_import_seed.py index 176685c3d5..3e8a1ed473 100644 --- a/test/e2e/tests/onboarding/test_onboarding_import_seed.py +++ b/test/e2e/tests/onboarding/test_onboarding_import_seed.py @@ -31,6 +31,7 @@ def keys_screen(main_window) -> KeysView: def test_import_seed_phrase(aut: AUT, keys_screen, main_window, user_account, autocomplete: bool): with step('Open import seed phrase view and enter seed phrase'): input_view = keys_screen.open_import_seed_phrase_view().open_seed_phrase_input_view() + input_view.input_seed_phrase(user_account.seed_phrase) profile_view = input_view.input_seed_phrase(user_account.seed_phrase, autocomplete) profile_view.set_display_name(user_account.name) diff --git a/test/e2e/tests/onboarding/test_onboarding_negative_scenarios.py b/test/e2e/tests/onboarding/test_onboarding_negative_scenarios.py new file mode 100644 index 0000000000..ca2f0b1d70 --- /dev/null +++ b/test/e2e/tests/onboarding/test_onboarding_negative_scenarios.py @@ -0,0 +1,167 @@ +import time + +import allure +import pytest +from allure_commons._allure import step + +import configs.system +import constants +from constants import UserAccount +from constants.onboarding import OnboardingMessages +from driver.aut import AUT +from gui.components.onboarding.before_started_popup import BeforeStartedPopUp +from gui.components.onboarding.beta_consent_popup import BetaConsentPopup +from gui.components.splash_screen import SplashScreen +from gui.screens.onboarding import AllowNotificationsView, WelcomeToStatusView, KeysView, BiometricsView, LoginView + + +@pytest.fixture +def keys_screen(main_window) -> KeysView: + with step('Open Generate new keys view'): + if configs.system.IS_MAC: + AllowNotificationsView().wait_until_appears().allow() + BeforeStartedPopUp().get_started() + wellcome_screen = WelcomeToStatusView().wait_until_appears() + return wellcome_screen.get_keys() + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702991', 'Login with an invalid password') +@pytest.mark.case(702991) +@pytest.mark.parametrize('error', [OnboardingMessages.PASSWORD_INCORRECT.value + ]) +def test_login_with_wrong_password(aut: AUT, keys_screen, main_window, error: str): + user_one: UserAccount = constants.user_account_one + user_one_wrong_password: UserAccount = constants.user_account_one_changed_password + + with step('Open generate keys view and set user name'): + profile_view = keys_screen.generate_new_keys() + profile_view.set_display_name(user_one.name) + + with step('Finalize onboarding and open main screen'): + details_view = profile_view.next() + create_password_view = details_view.next() + confirm_password_view = create_password_view.create_password(user_one.password) + confirm_password_view.confirm_password(user_one.password) + if configs.system.IS_MAC: + BiometricsView().wait_until_appears().prefer_password() + SplashScreen().wait_until_appears().wait_until_hidden() + if not configs.DEV_BUILD: + BetaConsentPopup().confirm() + + with step('Verify that the user logged in correctly'): + user_canvas = main_window.left_panel.open_user_canvas() + profile_popup = user_canvas.open_profile_popup() + assert profile_popup.user_name == user_one.name + + with step('Restart application and input wrong password'): + aut.restart() + login_view = LoginView() + login_view.log_in(user_one_wrong_password) + time.sleep(2) + + with step ('Verify that user cannot log in and the error appears'): + assert login_view.login_error_message == error + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702992', 'Sign up with wrong username format') +@pytest.mark.case(702992) +@pytest.mark.parametrize('user_name, error', [ + pytest.param('Athl', OnboardingMessages.WRONG_LOGIN_LESS_LETTERS.value), + pytest.param('Gra', OnboardingMessages.WRONG_LOGIN_LESS_LETTERS.value), + pytest.param('tester3@', OnboardingMessages.WRONG_LOGIN_SYMBOLS_NOT_ALLOWED.value) +]) +def test_sign_up_with_wrong_name(keys_screen, user_name: str, error: str): + with step(f'Input name {user_name}'): + profile_view = keys_screen.generate_new_keys() + profile_view.set_display_name(user_name) + + with step('Verify that button Next is disabled and correct error appears'): + assert profile_view.is_next_button_enabled is False + assert profile_view.error_message == error + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702993', + 'Sign up with wrong password format in both new password and confirmation input') +@pytest.mark.case(702993) +@pytest.mark.parametrize('user_account', [constants.user.user_account_one]) +@pytest.mark.parametrize('password, error', [ + pytest.param('badP', OnboardingMessages.WRONG_PASSWORD.value), +]) +def test_sign_up_with_wrong_password_in_both_fields(keys_screen, user_account, password: str, error: str): + with step('Input correct user name'): + profile_view = keys_screen.generate_new_keys() + profile_view.set_display_name(user_account.name) + + with step('Input wrong password in both first and confirmation fields'): + details_view = profile_view.next() + create_password_view = details_view.next() + create_password_view.set_password_in_first_field(password) + create_password_view.set_password_in_confirmation_field(password) + + with step('Verify that button Create password is disabled and correct error appears'): + assert create_password_view.is_create_password_button_enabled is False + assert create_password_view.password_error_message == error + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702994', + 'Sign up with right password format in new password input but incorrect in confirmation password input') +@pytest.mark.case(702994) +@pytest.mark.parametrize('user_account', [constants.user.user_account_one]) +@pytest.mark.parametrize('first_password, confirmation_password', [ + pytest.param('TesTEr16843/!@01', 'bad2!s'), +]) +def test_sign_up_with_wrong_password_in_confirmation_field(keys_screen, user_account, first_password: str, + confirmation_password: str): + with step('Input correct user name'): + profile_view = keys_screen.generate_new_keys() + profile_view.set_display_name(user_account.name) + + with step('Input correct password in first field and wrong password in confirmation field'): + details_view = profile_view.next() + create_password_view = details_view.next() + create_password_view.set_password_in_first_field(first_password) + create_password_view.set_password_in_confirmation_field(confirmation_password) + + with step('Verify that button Create password is disabled'): + assert create_password_view.is_create_password_button_enabled is False + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702995', + 'Sign up with incorrect confirmation-again password') +@pytest.mark.case(702995) +@pytest.mark.parametrize('user_account', [constants.user.user_account_one]) +@pytest.mark.parametrize('password, confirmation_again_password, error', [ + pytest.param('TesTEr16843/!@01', 'TesTEr16843/!@)', OnboardingMessages.PASSWORDS_DONT_MATCH.value), +]) +def test_sign_up_with_wrong_password_in_confirmation_again_field(keys_screen, user_account, password: str, + confirmation_again_password: str, error: str): + with step('Input correct user name'): + profile_view = keys_screen.generate_new_keys() + profile_view.set_display_name(user_account.name) + + with step('Input correct password in both first and confirmation fields'): + details_view = profile_view.next() + create_password_view = details_view.next() + confirm_password_view = create_password_view.create_password(password) + + with step('Input wrong password in confirmation again field'): + confirm_password_view.set_password(confirmation_again_password) + + with step('Verify that button Finalise Status Password Creation is disabled and correct error appears'): + assert confirm_password_view.is_confirm_password_button_enabled is False + assert confirm_password_view.confirmation_error_message == error + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/702999', + 'Sign up with wrong imported seed phrase') +@pytest.mark.case(702999) +@pytest.mark.parametrize('seed_phrase', [ + pytest.param('pelican chief sudden oval media rare swamp elephant lawsuit wheal knife initial'), +]) +def test_sign_up_with_wrong_seed_phrase(keys_screen, seed_phrase: str): + with step('Open import seed phrase view and enter seed phrase'): + input_view = keys_screen.open_import_seed_phrase_view().open_seed_phrase_input_view() + input_view.input_seed_phrase(seed_phrase.split()) + + with step('Verify that import button is disabled'): + assert input_view.is_import_button_enabled is False