From ad68f46c5b94dd25f30aa75871f07982bd7ddcb2 Mon Sep 17 00:00:00 2001 From: Anastasiya Semenkevich Date: Thu, 22 Aug 2024 17:36:10 +0300 Subject: [PATCH] tests: use randomly generated seed where possible --- test/e2e/constants/user.py | 6 +-- test/e2e/constants/wallet.py | 11 ++++ test/e2e/gui/components/context_menu.py | 5 ++ test/e2e/gui/objects_map/names.py | 13 ++--- test/e2e/gui/screens/wallet.py | 6 +++ test/e2e/requirements.txt | 3 ++ test/e2e/scripts/utils/generators.py | 16 ++++++ ..._button_manage_account_from_seed_phrase.py | 54 +++++-------------- ...enerated_account_custom_derivation_path.py | 24 +++++---- 9 files changed, 80 insertions(+), 58 deletions(-) diff --git a/test/e2e/constants/user.py b/test/e2e/constants/user.py index 5f61911925..14233c6862 100644 --- a/test/e2e/constants/user.py +++ b/test/e2e/constants/user.py @@ -32,15 +32,15 @@ class ReturningUser(UserAccount): class ReturningUsersData(Enum): - RETURNING_USER_ONE = ( [ 'rail', 'witness', 'era', 'asthma', 'empty', 'cheap', 'shed', 'pond', 'skate', 'amount', 'invite', 'year' ], '0x3286c371ef648fe6232324b27ee0515f4ded24d9') RETURNING_USER_TWO = ( [ - 'measure', 'cube', 'cousin', 'debris', 'slam', 'ignore', 'seven', 'hat', 'satisfy', 'frown', 'casino', 'inflict' -], '0x99C096bB5F12bDe37DE9dbee8257Ebe2a5667C46') + 'measure', 'cube', 'cousin', 'debris', 'slam', 'ignore', 'seven', 'hat', 'satisfy', 'frown', 'casino', + 'inflict' + ], '0x99C096bB5F12bDe37DE9dbee8257Ebe2a5667C46') WALLET_USER = ( [ 'vocal', 'fruit', 'ordinary', 'meadow', 'south', 'athlete', 'inherit', 'since', 'version', 'pitch', diff --git a/test/e2e/constants/wallet.py b/test/e2e/constants/wallet.py index 8621bd519e..9b7f905036 100644 --- a/test/e2e/constants/wallet.py +++ b/test/e2e/constants/wallet.py @@ -1,3 +1,4 @@ +import random from enum import Enum @@ -81,3 +82,13 @@ class WalletAccountPopup(Enum): WALLET_ACCOUNT_NAME_MIN = 'Account name must be at least 5 characters' WALLET_KEYPAIR_NAME_MIN = 'Key pair name must be at least 5 character(s)' WALLET_KEYPAIR_MIN = 'Key pair must be at least 5 character(s)' + + +class SeedPhrases(Enum): + TWELVE_WORDS_SEED = 'pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial' + EIGHTEEN_WORDS_SEED = 'kitten tiny cup admit cactus shrug shuffle accident century faith roof plastic beach police barely vacant sign blossom' + TWENTY_FOUR_WORDS_SEED = 'elite dinosaur flavor canoe garbage palace antique dolphin virtual mixed sand impact solution inmate hair pipe affair cage vote estate gloom lamp robust like' + + @classmethod + def select_random_seed(cls): + return random.choice(list(SeedPhrases)) \ No newline at end of file diff --git a/test/e2e/gui/components/context_menu.py b/test/e2e/gui/components/context_menu.py index 98b42387c5..754a32f4e1 100644 --- a/test/e2e/gui/components/context_menu.py +++ b/test/e2e/gui/components/context_menu.py @@ -13,6 +13,7 @@ class ContextMenu(QObject): self._context_add_watched_address_option = QObject(names.contextMenuItem_AddWatchOnly) self._context_delete_account_option = QObject(names.contextMenuItem_Delete) self._context_edit_account_option = QObject(names.contextMenuItem_Edit) + self._context_copy_address_option = QObject(names.contextMenuItem_Copy_Address) self._context_hide_include_in_total_balance = QObject(names.contextMenuItem_HideInclude) self._context_edit_saved_address_option = QObject(names.contextSavedAddressEdit) self._context_delete_saved_address_option = QObject(names.contextSavedAddressDelete) @@ -58,6 +59,10 @@ class ContextMenu(QObject): def select_edit_account_from_context_menu(self): self._context_edit_account_option.click() + @allure.step('Select copy address from context menu') + def select_copy_address_from_context_menu(self): + self._context_copy_address_option.click() + @allure.step('Check delete option visibility in context menu') def is_delete_account_option_present(self): return self._context_delete_account_option.is_visible diff --git a/test/e2e/gui/objects_map/names.py b/test/e2e/gui/objects_map/names.py index fdff5e5284..7d84389312 100644 --- a/test/e2e/gui/objects_map/names.py +++ b/test/e2e/gui/objects_map/names.py @@ -291,12 +291,13 @@ mainWallet_Saved_Addresses_Popup_Network_Selector_Arbitrum_network_tag = {"conta # Context Menu contextMenu_PopupItem = {"container": statusDesktop_mainWindow_overlay, "type": "PopupItem", "unnamed": 1, "visible": True} contextMenuItem = {"container": statusDesktop_mainWindow_overlay, "type": "StatusBaseText", "unnamed": 1, "visible": True} -contextMenuItem_AddWatchOnly = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-AddWatchOnlyAccountAction*"), "type": "StatusMenuItem"} -contextMenuItem_Delete = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-DeleteAction*"), "type": "StatusMenuItem"} -contextMenuItem_Edit = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-EditAction*"), "type": "StatusMenuItem"} -contextMenuItem_HideInclude = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-HideFromTotalBalance*"), "type": "StatusMenuItem"} -contextSavedAddressEdit = {"container": statusDesktop_mainWindow, "objectName": "editSavedAddress", "type": "StatusMenuItem"} -contextSavedAddressDelete = {"container": statusDesktop_mainWindow, "objectName": "deleteSavedAddress", "type": "StatusMenuItem"} +contextMenuItem_AddWatchOnly = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-AddWatchOnlyAccountAction*"), "type": "StatusMenuItem", "visible": True} +contextMenuItem_Delete = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-DeleteAction*"), "type": "StatusMenuItem", "visible": True} +contextMenuItem_Edit = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-EditAction*"), "type": "StatusMenuItem", "visible": True} +contextMenuItem_Copy_Address = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-CopyAddressAction*"), "type": "StatusSuccessAction", "visible": True} +contextMenuItem_HideInclude = {"container": statusDesktop_mainWindow_overlay, "enabled": True, "objectName": RegularExpression("AccountMenu-HideFromTotalBalance*"), "type": "StatusMenuItem", "visible": True} +contextSavedAddressEdit = {"container": statusDesktop_mainWindow, "objectName": "editSavedAddress", "type": "StatusMenuItem", "visible": True} +contextSavedAddressDelete = {"container": statusDesktop_mainWindow, "objectName": "deleteSavedAddress", "type": "StatusMenuItem", "visible": True} # Confirmation Popup confirmButton = {"container": statusDesktop_mainWindow_overlay, "objectName": RegularExpression("confirm*"), "type": "StatusButton"} diff --git a/test/e2e/gui/screens/wallet.py b/test/e2e/gui/screens/wallet.py index 864baa0bb6..9456951f4a 100644 --- a/test/e2e/gui/screens/wallet.py +++ b/test/e2e/gui/screens/wallet.py @@ -2,6 +2,7 @@ import time import typing import allure +import pyperclip import configs import constants.user @@ -134,6 +135,11 @@ class LeftPanel(QObject): else: raise ex + @allure.step('Copy address for the account in the context menu') + def copy_account_address_in_context_menu(self, account_name: str): + self._open_context_menu_for_account(account_name).select_copy_address_from_context_menu() + return str(pyperclip.paste()) + class SavedAddressesView(QObject): diff --git a/test/e2e/requirements.txt b/test/e2e/requirements.txt index f13e9ef081..7b32e51169 100644 --- a/test/e2e/requirements.txt +++ b/test/e2e/requirements.txt @@ -14,3 +14,6 @@ pytest-timeout==2.2.0 shortuuid==1.0.12 pluggy==1.2.0 beautifulsoup4==4.12.3 +requests==2.31.0 +mnemonic==0.21 +zpywallet==0.6.2 \ No newline at end of file diff --git a/test/e2e/scripts/utils/generators.py b/test/e2e/scripts/utils/generators.py index 26fa8b6aec..d7e97eb853 100644 --- a/test/e2e/scripts/utils/generators.py +++ b/test/e2e/scripts/utils/generators.py @@ -1,5 +1,8 @@ import random import string +from mnemonic import Mnemonic +from zpywallet import HDWallet +from zpywallet.network import EthereumMainNet def random_name_string(): @@ -19,3 +22,16 @@ def random_password_string(): def random_ens_string(): return ''.join( random.choices(string.digits + string.ascii_lowercase, k=8)) + + +def random_mnemonic(): + mnemo = Mnemonic("english") + words = mnemo.generate(strength=random.choice([128, 192, 256])) + return words + + +def get_wallet_address_from_mnemonic(mnemonic_data) -> str: + w = HDWallet.from_mnemonic(mnemonic=mnemonic_data, passphrase='', network=EthereumMainNet) + child_w = w.get_child_for_path("m/44'/60'/0'/0/0") + address_from_mnemonic = child_w.address() + return address_from_mnemonic diff --git a/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_account_from_seed_phrase.py b/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_account_from_seed_phrase.py index 45f98f3f36..64ce51fe0f 100644 --- a/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_account_from_seed_phrase.py +++ b/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_account_from_seed_phrase.py @@ -4,16 +4,16 @@ import allure import pytest from allure_commons._allure import step -from constants import UserAccount, RandomUser -from scripts.utils.generators import random_name_string, random_password_string +from constants import RandomUser from constants.wallet import WalletSeedPhrase +from scripts.utils.generators import random_mnemonic from tests.wallet_main_screen import marks import constants -import driver from gui.components.signing_phrase_popup import SigningPhrasePopup from gui.components.authenticate_popup import AuthenticatePopup from gui.main_window import MainWindow +from scripts.utils.generators import get_wallet_address_from_mnemonic pytestmark = marks @@ -22,30 +22,23 @@ pytestmark = marks @pytest.mark.case(703030) @pytest.mark.parametrize('user_account', [RandomUser()]) @pytest.mark.parametrize('name, color, emoji, emoji_unicode, ' - 'new_name, new_color, new_emoji, new_emoji_unicode, seed_phrase', [ + 'new_name, new_color, new_emoji, new_emoji_unicode, mnemonic_data', [ pytest.param('SPAcc24', '#2a4af5', 'sunglasses', '1f60e', 'SPAcc24edited', '#216266', 'thumbsup', '1f44d', - 'elite dinosaur flavor canoe garbage palace antique dolphin virtual mixed sand ' - 'impact solution inmate hair pipe affair cage vote estate gloom lamp robust like'), - pytest.param('SPAcc18', '#2a4af5', 'sunglasses', '1f60e', - 'SPAcc18edited', '#216266', 'thumbsup', '1f44d', - 'kitten tiny cup admit cactus shrug shuffle accident century faith roof plastic ' - 'beach police barely vacant sign blossom'), - pytest.param('SPAcc12', '#2a4af5', 'sunglasses', '1f60e', - 'SPAcc12edited', '#216266', 'thumbsup', '1f44d', - 'pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial') + random_mnemonic() + ) ]) def test_plus_button_manage_account_from_seed_phrase(main_screen: MainWindow, user_account, name: str, color: str, emoji: str, emoji_unicode: str, new_name: str, new_color: str, new_emoji: str, new_emoji_unicode: str, - seed_phrase: str): + mnemonic_data: str): with step('Create imported seed phrase wallet account'): wallet = main_screen.left_panel.open_wallet() SigningPhrasePopup().wait_until_appears().confirm_phrase() account_popup = wallet.left_panel.open_add_account_popup() account_popup.set_name(name).set_emoji(emoji).set_color( - color).open_add_new_account_popup().import_new_seed_phrase(seed_phrase.split()) + color).open_add_new_account_popup().import_new_seed_phrase(mnemonic_data.split()) account_popup.save_changes() AuthenticatePopup().wait_until_appears().authenticate(user_account.password) account_popup.wait_until_hidden() @@ -64,29 +57,11 @@ def test_plus_button_manage_account_from_seed_phrase(main_screen: MainWindow, us if time.monotonic() - started_at > 15: raise LookupError(f'Account {expected_account} not found in {wallet.left_panel.accounts}') - with step('Edit wallet account'): - account_popup = wallet.left_panel.open_edit_account_popup_from_context_menu(name) - account_popup.set_name(new_name).set_emoji(new_emoji).set_color(new_color).save_changes() - - with step('Verify that the account is correctly displayed in accounts list'): - expected_account = constants.user.account_list_item(new_name, new_color.lower(), new_emoji_unicode) - started_at = time.monotonic() - while expected_account not in wallet.left_panel.accounts: - time.sleep(1) - if time.monotonic() - started_at > 15: - raise LookupError(f'Account {expected_account} not found in {wallet.left_panel.accounts}') - - with step('Delete wallet account with agreement'): - wallet.left_panel.delete_account_from_context_menu(new_name).agree_and_confirm() - - with step('Verify toast message notification when removing account'): - messages = main_screen.wait_for_notification() - assert f'"{new_name}" successfully removed' in messages, \ - f"Toast message about account removal is not correct or not present. Current list of messages: {messages}" - - with step('Verify that the account is not displayed in accounts list'): - assert driver.waitFor(lambda: new_name not in [account.name for account in wallet.left_panel.accounts], 10000), \ - f'Account with {new_name} is still displayed even it should not be' + with step('Verify account address from UI is correct for derived account '): + address_in_ui = wallet.left_panel.copy_account_address_in_context_menu(name) + address_from_mnemonic = get_wallet_address_from_mnemonic(mnemonic_data) + assert address_in_ui == address_from_mnemonic, \ + f'Expected to recover {address_from_mnemonic} but got {address_in_ui}' @allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/736371', @@ -97,8 +72,7 @@ def test_plus_button_manage_account_from_seed_phrase(main_screen: MainWindow, us 'new_name, new_color, new_emoji, new_emoji_unicode, seed_phrase', [ pytest.param('SPAcc24', '#2a4af5', 'sunglasses', '1f60e', 'SPAcc24edited', '#216266', 'thumbsup', '1f44d', - 'elite dinosaur flavor canoe garbage palace antique dolphin virtual mixed sand ' - 'impact solution inmate hair pipe affair cage vote estate gloom lamp robust like'), + random_mnemonic()), ]) def test_plus_button_re_importing_seed_phrase(main_screen: MainWindow, user_account, name: str, color: str, emoji: str, emoji_unicode: str, diff --git a/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_generated_account_custom_derivation_path.py b/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_generated_account_custom_derivation_path.py index 75d4b89c61..35b87c57ba 100644 --- a/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_generated_account_custom_derivation_path.py +++ b/test/e2e/tests/wallet_main_screen/wallet - plus button/test_plus_button_manage_generated_account_custom_derivation_path.py @@ -18,14 +18,21 @@ pytestmark = marks @allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703028', 'Manage a custom generated account') @pytest.mark.case(703028) @pytest.mark.parametrize('user_account', [RandomUser()]) -@pytest.mark.parametrize('derivation_path, generated_address_index, name, color, emoji, emoji_unicode, new_name, new_color, new_emoji, new_emoji_unicode', - [ - pytest.param('Ethereum', '5', 'Ethereum', '#216266', 'sunglasses', '1f60e', 'EthEdited', '#216266', 'thumbsup', '1f44d'), - pytest.param('Ethereum Testnet (Ropsten)', '10', 'Ethereum Testnet ', '#7140fd', 'sunglasses', '1f60e', 'RopstenEdited', '#216266', 'thumbsup', '1f44d'), - pytest.param('Ethereum (Ledger)', '15', 'Ethereum Ledger', '#2a799b', 'sunglasses', '1f60e', 'LedgerEdited', '#216266', 'thumbsup', '1f44d'), - pytest.param('Ethereum (Ledger Live/KeepKey)', '20', 'Ethereum Ledger Live', '#7140fd', 'sunglasses', '1f60e', 'LiveEdited', '#216266', 'thumbsup', '1f44d'), - pytest.param('N/A', '95', 'Custom path', '#216266', 'sunglasses', '1f60e', 'CustomEdited', '#216266', 'thumbsup', '1f44d') -]) +@pytest.mark.parametrize( + 'derivation_path, generated_address_index, name, color, emoji, emoji_unicode, new_name, new_color, new_emoji, ' + 'new_emoji_unicode', + [ + pytest.param('Ethereum', '5', 'Ethereum', '#216266', 'sunglasses', '1f60e', 'EthEdited', '#216266', 'thumbsup', + '1f44d'), + pytest.param('Ethereum Testnet (Ropsten)', '10', 'Ethereum Testnet ', '#7140fd', 'sunglasses', '1f60e', + 'RopstenEdited', '#216266', 'thumbsup', '1f44d'), + pytest.param('Ethereum (Ledger)', '15', 'Ethereum Ledger', '#2a799b', 'sunglasses', '1f60e', 'LedgerEdited', + '#216266', 'thumbsup', '1f44d'), + pytest.param('Ethereum (Ledger Live/KeepKey)', '20', 'Ethereum Ledger Live', '#7140fd', 'sunglasses', '1f60e', + 'LiveEdited', '#216266', 'thumbsup', '1f44d'), + pytest.param('N/A', '95', 'Custom path', '#216266', 'sunglasses', '1f60e', 'CustomEdited', '#216266', + 'thumbsup', '1f44d') + ]) def test_plus_button_manage_generated_account_custom_derivation_path(main_screen: MainWindow, user_account, derivation_path: str, generated_address_index: int, name: str, color: str, emoji: str, @@ -40,7 +47,6 @@ def test_plus_button_manage_generated_account_custom_derivation_path(main_screen generated_address_index, user_account.password).save_changes() - with step('Verify that the account is correctly displayed in accounts list'): expected_account = constants.user.account_list_item(name, color.lower(), emoji_unicode) started_at = time.monotonic()