From 52fed9d5c2cb4af1acea9be13ae10b2402486c15 Mon Sep 17 00:00:00 2001 From: Vladimir Druzhinin Date: Thu, 10 Aug 2023 13:43:17 +0200 Subject: [PATCH] test(Onboarding) Test on Import: 12 word seed phrase added #86 --- test/ui-pytest/configs/_local.py.ci | 6 +- test/ui-pytest/configs/_local.py.default | 5 ++ test/ui-pytest/configs/testpath.py | 4 +- test/ui-pytest/conftest.py | 2 + test/ui-pytest/constants/user.py | 12 +-- test/ui-pytest/driver/aut.py | 4 +- test/ui-pytest/driver/server.py | 10 +-- .../gui/objects_map/onboarding_names.py | 30 +++++++ test/ui-pytest/gui/screens/onboarding.py | 87 +++++++++++++++++-- test/ui-pytest/pytest.ini | 1 - test/ui-pytest/scripts/utils/local_system.py | 2 +- test/ui-pytest/tests/fixtures/aut.py | 7 +- test/ui-pytest/tests/test_onboarding.py | 52 ++++++++--- 13 files changed, 184 insertions(+), 38 deletions(-) diff --git a/test/ui-pytest/configs/_local.py.ci b/test/ui-pytest/configs/_local.py.ci index af3374a68e..d4d0f1e7dd 100644 --- a/test/ui-pytest/configs/_local.py.ci +++ b/test/ui-pytest/configs/_local.py.ci @@ -1,4 +1,8 @@ +import logging import os -LOCAL_RUN = False +LOG_LEVEL = logging.DEBUG +LOCAL_RUN = True +DEV_BUILD = False + APP_DIR = os.getenv('APP_DIR') diff --git a/test/ui-pytest/configs/_local.py.default b/test/ui-pytest/configs/_local.py.default index 13b3a3ec2b..330ed57992 100644 --- a/test/ui-pytest/configs/_local.py.default +++ b/test/ui-pytest/configs/_local.py.default @@ -1,2 +1,7 @@ +import logging + +LOG_LEVEL = logging.DEBUG LOCAL_RUN = True +DEV_BUILD = False + APP_DIR = None diff --git a/test/ui-pytest/configs/testpath.py b/test/ui-pytest/configs/testpath.py index bbcabbb896..109bce3137 100644 --- a/test/ui-pytest/configs/testpath.py +++ b/test/ui-pytest/configs/testpath.py @@ -1,7 +1,6 @@ import os -from datetime import datetime - import typing +from datetime import datetime from scripts.utils.system_path import SystemPath @@ -19,6 +18,7 @@ RESULTS: SystemPath = TEMP / 'results' RUN: SystemPath = RESULTS / RUN_ID VP: SystemPath = ROOT / 'ext' / 'vp' TEST_FILES: SystemPath = ROOT / 'ext' / 'test_files' +TEST_USER_DATA: SystemPath = ROOT / 'ext' / 'user_data' # Driver Directories SQUISH_DIR = SystemPath(os.getenv('SQUISH_DIR')) diff --git a/test/ui-pytest/conftest.py b/test/ui-pytest/conftest.py index 14fa7af634..bc9ee87b1f 100644 --- a/test/ui-pytest/conftest.py +++ b/test/ui-pytest/conftest.py @@ -32,9 +32,11 @@ def setup_session_scope( @pytest.fixture(autouse=True) def setup_function_scope( + caplog, generate_test_data, check_result ): + caplog.set_level(configs.LOG_LEVEL) yield diff --git a/test/ui-pytest/constants/user.py b/test/ui-pytest/constants/user.py index fc6d8c5ee1..5943929624 100644 --- a/test/ui-pytest/constants/user.py +++ b/test/ui-pytest/constants/user.py @@ -1,7 +1,9 @@ from collections import namedtuple -UserAccount = namedtuple('User', ['name', 'password']) -user_account = UserAccount('squisher', '*P@ssw0rd*') -user_account_one = UserAccount('tester123', 'TesTEr16843/!@00') -user_account_two = UserAccount('Athletic', 'TesTEr16843/!@00') -user_account_three = UserAccount('Nervous', 'TesTEr16843/!@00') +UserAccount = namedtuple('User', ['name', 'password', 'seed_phrase']) +user_account = UserAccount('squisher', '*P@ssw0rd*', [ + 'rail', 'witness', 'era', 'asthma', 'empty', 'cheap', 'shed', 'pond', 'skate', 'amount', 'invite', 'year' +]) +user_account_one = UserAccount('tester123', 'TesTEr16843/!@00', []) +user_account_two = UserAccount('Athletic', 'TesTEr16843/!@00', []) +user_account_three = UserAccount('Nervous', 'TesTEr16843/!@00', []) diff --git a/test/ui-pytest/driver/aut.py b/test/ui-pytest/driver/aut.py index 521d58b67d..40a480f907 100644 --- a/test/ui-pytest/driver/aut.py +++ b/test/ui-pytest/driver/aut.py @@ -21,6 +21,7 @@ class AUT: self.host = host self.port = int(port) self.ctx = None + self.pid = None self.aut_id = self.path.name if IS_LIN else self.path.stem self.process_name = 'Status' if IS_WIN else 'nim_status_client' driver.testSettings.setWrappersForApplication(self.aut_id, ['Qt']) @@ -51,7 +52,7 @@ class AUT: @allure.step('Close application by process name') def stop(self): if configs.LOCAL_RUN: - local_system.kill_process_by_port(self.port) + local_system.kill_process_by_pid(self.pid) else: local_system.kill_process_by_name(self.process_name) @@ -77,5 +78,6 @@ class AUT: ' '.join(command), configs.timeouts.PROCESS_TIMEOUT_SEC) self.attach() + self.pid = self.ctx.pid assert squish.waitFor(lambda: self.ctx.isRunning, configs.timeouts.PROCESS_TIMEOUT_SEC) return self diff --git a/test/ui-pytest/driver/server.py b/test/ui-pytest/driver/server.py index a5eb84cdec..d5ebc2f8b4 100644 --- a/test/ui-pytest/driver/server.py +++ b/test/ui-pytest/driver/server.py @@ -1,5 +1,4 @@ import logging -import time import typing import configs.testpath @@ -36,17 +35,12 @@ class SquishServer: _logger.info(err) local_system.execute(cmd, check=True) - def stop(self, attempt: int = 2): - local_system.run([self.path, '--stop']) + def stop(self): + local_system.kill_process_by_name(_PROCESS_NAME, verify=False) try: local_system.wait_for_close(_PROCESS_NAME, 2) except AssertionError as err: _logger.debug(err) - if attempt: - time.sleep(1) - self.stop(attempt-1) - else: - raise err # https://doc-snapshots.qt.io/squish/cli-squishserver.html def configuring(self, action: str, options: typing.Union[int, str, list]): diff --git a/test/ui-pytest/gui/objects_map/onboarding_names.py b/test/ui-pytest/gui/objects_map/onboarding_names.py index 33c869f8d4..17c32a489d 100755 --- a/test/ui-pytest/gui/objects_map/onboarding_names.py +++ b/test/ui-pytest/gui/objects_map/onboarding_names.py @@ -14,6 +14,36 @@ mainWindow_I_already_use_Status_StatusBaseText = {"container": mainWindow_Welcom # Get Keys View mainWindow_KeysMainView = {"container": statusDesktop_mainWindow, "type": "KeysMainView", "unnamed": 1, "visible": True} mainWindow_Generate_new_keys_StatusButton = {"checkable": False, "container": mainWindow_KeysMainView, "objectName": "keysMainViewPrimaryActionButton", "type": "StatusButton", "visible": True} +mainWindow_Generate_keys_for_new_Keycard_StatusBaseText = {"container": mainWindow_KeysMainView, "id": "button2", + "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Import_seed_phrase = {"container": mainWindow_KeysMainView, "id": "button3", "type": "Row", "unnamed": 1, + "visible": True} + +# Import Seed Phrase View +keysMainView_PrimaryAction_Button = {"container": statusDesktop_mainWindow, + "objectName": "keysMainViewPrimaryActionButton", "type": "StatusButton"} + +# Seed Phrase Input View +mainWindow_SeedPhraseInputView = {"container": statusDesktop_mainWindow, "type": "SeedPhraseInputView", "unnamed": 1, + "visible": True} +switchTabBar_12_words_Button = {"container": mainWindow_SeedPhraseInputView, "objectName": "12SeedButton", + "type": "StatusSwitchTabButton"} +switchTabBar_18_words_Button = {"container": mainWindow_SeedPhraseInputView, "objectName": "18SeedButton", + "type": "StatusSwitchTabButton"} +switchTabBar_24_words_Button = {"container": mainWindow_SeedPhraseInputView, "objectName": "24SeedButton", + "type": "StatusSwitchTabButton"} +mainWindow_statusSeedPhraseInputField_TextEdit = {"container": mainWindow_SeedPhraseInputView, + "objectName": "statusSeedPhraseInputField", "type": "TextEdit", + "visible": True} +mainWindow_Import_StatusButton = {"checkable": False, "container": mainWindow_SeedPhraseInputView, + "objectName": "seedPhraseViewSubmitButton", "text": "Import", "type": "StatusButton", + "visible": True} + +# Keycard Init View +mainWindow_KeycardInitView = {"container": statusDesktop_mainWindow, "type": "KeycardInitView", "unnamed": 1, + "visible": True} +mainWindow_Plug_in_Keycard_reader_StatusBaseText = {"container": mainWindow_KeycardInitView, "type": "StatusBaseText", + "unnamed": 1, "visible": True} # Your Profile View mainWindow_InsertDetailsView = {"container": statusDesktop_mainWindow, "type": "InsertDetailsView", "unnamed": 1, "visible": True} diff --git a/test/ui-pytest/gui/screens/onboarding.py b/test/ui-pytest/gui/screens/onboarding.py index e3b4366df8..4c2021e064 100755 --- a/test/ui-pytest/gui/screens/onboarding.py +++ b/test/ui-pytest/gui/screens/onboarding.py @@ -1,11 +1,10 @@ import logging import time +import typing from abc import abstractmethod import allure -import cv2 -import configs.testpath import constants.tesseract import driver from gui.components.os.open_file_dialogs import OpenFileDialog @@ -62,18 +61,94 @@ class KeysView(OnboardingScreen): def __init__(self): super(KeysView, self).__init__('mainWindow_KeysMainView') self._generate_key_button = Button('mainWindow_Generate_new_keys_StatusButton') + self._generate_key_for_new_keycard_button = Button('mainWindow_Generate_keys_for_new_Keycard_StatusBaseText') + self._import_seed_phrase_button = Button('mainWindow_Import_seed_phrase') @allure.step('Open Profile view') def generate_new_keys(self) -> 'YourProfileView': self._generate_key_button.click() return YourProfileView().wait_until_appears() + @allure.step('Open Keycard Init view') + def generate_key_for_new_keycard(self) -> 'KeycardInitView': + self._generate_key_for_new_keycard_button.click() + return KeycardInitView().wait_until_appears() + + @allure.step('Open Import Seed Phrase view') + def open_import_seed_phrase_view(self) -> 'ImportSeedPhraseView': + self._import_seed_phrase_button.click() + return ImportSeedPhraseView().wait_until_appears() + @allure.step('Go back') def back(self) -> WelcomeScreen: self._back_button.click() return WelcomeScreen().wait_until_appears() +class ImportSeedPhraseView(OnboardingScreen): + + def __init__(self): + super(ImportSeedPhraseView, self).__init__('mainWindow_KeysMainView') + self._import_seed_phrase_button = Button('keysMainView_PrimaryAction_Button') + + @allure.step('Open seed phrase input view') + def open_seed_phrase_input_view(self): + self._import_seed_phrase_button.click() + return SeedPhraseInputView().wait_until_appears() + + @allure.step('Go back') + def back(self) -> KeysView: + self._back_button.click() + return KeysView().wait_until_appears() + + +class SeedPhraseInputView(OnboardingScreen): + + def __init__(self): + super(SeedPhraseInputView, self).__init__('mainWindow_SeedPhraseInputView') + self._12_words_tab_button = Button('switchTabBar_12_words_Button') + self._18_words_tab_button = Button('switchTabBar_18_words_Button') + self._24_words_tab_button = Button('switchTabBar_24_words_Button') + self._seed_phrase_input_text_edit = TextEdit('mainWindow_statusSeedPhraseInputField_TextEdit') + self._import_button = Button('mainWindow_Import_StatusButton') + + @allure.step('Input seed phrase') + def input_seed_phrase(self, seed_phrase: typing.List[str]): + if len(seed_phrase) == 12: + if not self._12_words_tab_button.is_checked: + self._12_words_tab_button.click() + elif len(seed_phrase) == 18: + if not self._18_words_tab_button.is_checked: + self._18_words_tab_button.click() + elif len(seed_phrase) == 24: + if not self._24_words_tab_button.is_checked: + self._24_words_tab_button.click() + else: + raise RuntimeError("Wrong amount of seed words", len(seed_phrase)) + + for index, word in enumerate(seed_phrase, start=1): + self._seed_phrase_input_text_edit.real_name['objectName'] = f'statusSeedPhraseInputField{index}' + self._seed_phrase_input_text_edit.text = word + + self._import_button.click() + return YourProfileView().wait_until_appears() + + +class KeycardInitView(OnboardingScreen): + + def __init__(self): + super(KeycardInitView, self).__init__('mainWindow_KeycardInitView') + self._message = TextLabel('mainWindow_Plug_in_Keycard_reader_StatusBaseText') + + @property + def message(self) -> str: + return self._message.text + + def back(self) -> KeysView: + self._back_button.click() + return KeysView().wait_until_appears() + + class YourProfileView(OnboardingScreen): def __init__(self): @@ -177,16 +252,16 @@ class EmojiAndIconView(OnboardingScreen): @allure.step('Verify: User image contains text') def is_user_image_contains(self, text: str): crop = driver.UiTypes.ScreenRectangle( - 20, 20, self._profile_image.image.width - 40, self._profile_image.image.height - 40 - ) + 20, 20, self._profile_image.image.width - 40, self._profile_image.image.height - 40 + ) return self.profile_image.has_text(text, constants.tesseract.text_on_profile_image, crop=crop) @allure.step @allure.step('Verify: User image background color') def is_user_image_background_white(self): crop = driver.UiTypes.ScreenRectangle( - 20, 20, self._profile_image.image.width - 40, self._profile_image.image.height - 40 - ) + 20, 20, self._profile_image.image.width - 40, self._profile_image.image.height - 40 + ) return self.profile_image.has_color(constants.Color.WHITE, crop=crop) diff --git a/test/ui-pytest/pytest.ini b/test/ui-pytest/pytest.ini index 29aa9918e9..eea75aed46 100644 --- a/test/ui-pytest/pytest.ini +++ b/test/ui-pytest/pytest.ini @@ -1,7 +1,6 @@ [pytest] log_format = %(asctime)s.%(msecs)03d %(levelname)7s %(name)s %(message).5000s log_cli = true -log_cli_level = INFO addopts = --disable-warnings diff --git a/test/ui-pytest/scripts/utils/local_system.py b/test/ui-pytest/scripts/utils/local_system.py index 3b50efa560..6ae5c60cd2 100644 --- a/test/ui-pytest/scripts/utils/local_system.py +++ b/test/ui-pytest/scripts/utils/local_system.py @@ -117,7 +117,7 @@ def wait_for_close(process_name: str = None, timeout_sec: int = configs.timeouts else: raise RuntimeError('Set process name or PID to find process') time.sleep(1) - assert time.monotonic() - started_at < timeout_sec, f'Close process error: {process_name}' + assert time.monotonic() - started_at < timeout_sec, f'Close process error: {process_name or pid}' _logger.info(f'Process closed: {process_name}') diff --git a/test/ui-pytest/tests/fixtures/aut.py b/test/ui-pytest/tests/fixtures/aut.py index 326afe291e..8b53f2ff0e 100644 --- a/test/ui-pytest/tests/fixtures/aut.py +++ b/test/ui-pytest/tests/fixtures/aut.py @@ -1,6 +1,5 @@ from datetime import datetime -import allure import pytest import configs @@ -21,7 +20,11 @@ def aut() -> AUT: def user_data(request) -> system_path.SystemPath: user_data = configs.testpath.STATUS_DATA / f'app_{datetime.now():%H%M%S_%f}' / 'data' if hasattr(request, 'param'): - system_path.SystemPath(request.param).copy_to(user_data) + fp = request.param + if isinstance(fp, str): + fp = configs.testpath.TEST_USER_DATA / fp / 'data' + assert fp.is_dir() + fp.copy_to(user_data) yield user_data diff --git a/test/ui-pytest/tests/test_onboarding.py b/test/ui-pytest/tests/test_onboarding.py index 6850efa188..37def91ae3 100755 --- a/test/ui-pytest/tests/test_onboarding.py +++ b/test/ui-pytest/tests/test_onboarding.py @@ -5,18 +5,29 @@ import pytest from allure import step import configs.timeouts +import constants import driver from gui.components.before_started_popup import BeforeStartedPopUp from gui.components.profile_picture_popup import shift_image from gui.components.splash_screen import SplashScreen from gui.components.welcome_status_popup import WelcomeStatusPopup -from gui.screens.onboarding import AllowNotificationsView, WelcomeScreen, TouchIDAuthView +from gui.screens.onboarding import AllowNotificationsView, WelcomeScreen, TouchIDAuthView, KeysView from scripts.tools import image _logger = logging.getLogger(__name__) pytestmark = allure.suite("Onboarding") +@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 = WelcomeScreen().wait_until_appears() + return wellcome_screen.get_keys() + + @allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703421', 'Generate new keys') @pytest.mark.case(703421) @pytest.mark.parametrize('user_name, password, user_image, zoom, shift', [ @@ -25,15 +36,7 @@ pytestmark = allure.suite("Onboarding") pytest.param('_1Test-User', '*P@ssw0rd*', 'tv_signal.jpeg', 5, shift_image(0, 1000, 1000, 0), marks=pytest.mark.smoke), ]) -def test_generate_new_keys(main_window, user_name, password, user_image: str, zoom, shift): - with step('Open Generate new keys view'): - - if configs.system.IS_MAC: - AllowNotificationsView().wait_until_appears().allow() - BeforeStartedPopUp().get_started() - wellcome_screen = WelcomeScreen().wait_until_appears() - keys_screen = wellcome_screen.get_keys() - +def test_generate_new_keys(main_window, keys_screen, user_name: str, password, user_image: str, zoom: int, shift): with step(f'Setup profile with name: {user_name} and image: {user_image}'): profile_view = keys_screen.generate_new_keys() @@ -71,7 +74,8 @@ def test_generate_new_keys(main_window, user_name, password, user_image: str, zo if configs.system.IS_MAC: TouchIDAuthView().wait_until_appears().prefer_password() SplashScreen().wait_until_appears().wait_until_hidden() - WelcomeStatusPopup().confirm() + if not configs.DEV_BUILD: + WelcomeStatusPopup().confirm() with step('Open User Canvas and verify user info'): @@ -100,3 +104,29 @@ def test_generate_new_keys(main_window, user_name, password, user_image: str, zo f'{user_image.split(".")[1]}_profile.png', threshold=0.9 ) + + +@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703039', 'Import: 12 word seed phrase') +@pytest.mark.case(703039) +@pytest.mark.parametrize('user_account', [constants.user.user_account]) +def test_import_seed_phrase(keys_screen, main_window, user_account): + 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() + profile_view = input_view.input_seed_phrase(user_account.seed_phrase) + profile_view.set_display_name(user_account.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_account.password) + confirm_password_view.confirm_password(user_account.password) + if configs.system.IS_MAC: + TouchIDAuthView().wait_until_appears().prefer_password() + SplashScreen().wait_until_appears().wait_until_hidden() + if not configs.DEV_BUILD: + WelcomeStatusPopup().confirm() + + with step('Verify that the user logged in via seed phrase correctly'): + user_canvas = main_window.left_panel.open_user_canvas() + profile_popup = user_canvas.open_profile_popup() + assert profile_popup.user_name == user_account.name