Skip to content

Commit

Permalink
e2e: added verifications to fallback test
Browse files Browse the repository at this point in the history
  • Loading branch information
yevh-berdnyk committed Jan 21, 2025
1 parent f0e0c95 commit 9782ba2
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 35 deletions.
4 changes: 3 additions & 1 deletion test/appium/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ Pillow~=10.0.0
pytest-xdist==3.2.0
pytz~=2020.4
PyGithub==1.55
typing-extensions==4.12.2
typing-extensions==4.12.2
mnemonic==0.21
bip-utils==2.9.3
15 changes: 15 additions & 0 deletions test/appium/support/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins, Bip44Changes


def generate_wallet_address(passphrase: str, number: int = 1):
# Derive accounts using the standard MetaMask path
seed_bytes = Bip39SeedGenerator(passphrase).Generate()
bip44_mst_ctx = Bip44.FromSeed(seed_bytes, Bip44Coins.ETHEREUM)

# Generate first n addresses
expected_addresses = list()
for i in range(number):
bip44_acc_ctx = bip44_mst_ctx.Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(i)
expected_addresses.append(bip44_acc_ctx.PublicKey().ToAddress().lower())

return expected_addresses
122 changes: 101 additions & 21 deletions test/appium/tests/critical/test_fallback.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from selenium.common import TimeoutException

from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from support.helpers import generate_wallet_address
from tests import marks, run_in_parallel, transl
from users import transaction_senders
from views.sign_in_view import SignInView
Expand Down Expand Up @@ -162,34 +163,90 @@ def _check_message(home_view, index):

@marks.testrail_id(741054)
def test_fallback_add_key_pair(self):
expected_addresses = generate_wallet_address(passphrase=self.recovery_phrase, number=4)
account_to_add = transaction_senders['ETH_1']
self.home_1.navigate_back_to_home_view()
self.home_2.navigate_back_to_home_view()
wallet_1 = self.home_1.wallet_tab.click()
wallet_2 = self.home_2.wallet_tab.click()
regular_account_name = "New regular account"
key_pair_account_name = "Key pair account"
key_pair_name = "New key pair"
key_pair_account_address = '0x' + account_to_add['address'].lower()

wallet_1.just_fyi("Device 1: add a new regular account")
regular_account_name = "New regular account"
regular_derivation_path = wallet_1.add_regular_account(account_name=regular_account_name)
regular_account_wallet_address = wallet_1.get_account_address().split(':')[-1]
regular_account_address = wallet_1.get_account_address().split(':')[-1]
account_element = wallet_1.get_account_element(account_name=regular_account_name)
wallet_1.close_account_button.click_until_presence_of_element(account_element)

wallet_1.just_fyi("Device 1: add a new key pair account")
if regular_account_address != expected_addresses[1]:
self.errors.append("Newly added regular account address %s doesn't match expected %s" % (
regular_account_address, expected_addresses[1]))
if regular_account_address not in expected_addresses:
self.errors.append("Newly added regular account address %s is not in the list of expected addresses %s" % (
regular_account_address, expected_addresses))

wallet_1.just_fyi("Device 1: add a new key pair account by importing recovery phrase")
account_element.swipe_left_on_element()
imported_key_pair_account_name = "Imported account"
imported_key_pair_name = "Imported key pair"
imported_key_pair_account_address = '0x' + account_to_add['address'].lower()
imported_key_pair_derivation_path = wallet_1.import_key_pair_using_recovery_phrase(
account_name=imported_key_pair_account_name,
passphrase=account_to_add['passphrase'],
key_pair_name=imported_key_pair_name)

wallet_1.close_account_button.click_until_presence_of_element(account_element)

wallet_1.just_fyi("Device 1: verify default and added key pairs details")
account_element.swipe_left_on_element()
key_pair_derivation_path = wallet_1.add_key_pair_account(account_name=key_pair_account_name,
passphrase=account_to_add['passphrase'],
key_pair_name=key_pair_name)
wallet_1.get_account_element(account_name=imported_key_pair_account_name).swipe_left_on_element()
if not wallet_1.add_account_button.is_element_displayed():
wallet_1.get_account_element(account_name=imported_key_pair_account_name).swipe_left_on_element()
wallet_1.add_account_button.click()
wallet_1.create_account_button.click()
wallet_1.edit_key_pair_button.click()
expected_texts_regular = [
regular_account_name,
"%s...%s" % (regular_account_address[:5], regular_account_address[-3:])
]
for text in expected_texts_regular:
if not wallet_1.default_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
self.errors.append("Newly added regular account is not shown in default key pair list")
break
expected_texts_key_pair = [
imported_key_pair_account_name, imported_key_pair_name,
"%s...%s" % (imported_key_pair_account_address[:5], imported_key_pair_account_address[-3:])
]
for text in expected_texts_key_pair:
if not wallet_1.added_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
self.errors.append("Newly added regular account is not shown in default key pair list")
break

wallet_1.just_fyi("Device 1: add a new key pair account by generating a new key pair")
generated_key_pair_account_name = "Generated account"
generated_key_pair_name = "Generated key pair"
generated_key_pair_derivation_path, generated_passphrase = wallet_1.generate_new_key_pair(
account_name=generated_key_pair_account_name,
key_pair_name=generated_key_pair_name)
generated_key_pair_account_address = wallet_1.get_account_address().split(':')[-1]
wallet_1.close_account_button.click_until_presence_of_element(account_element)

expected_addresses = generate_wallet_address(passphrase=generated_passphrase, number=4)
if generated_key_pair_account_address != expected_addresses[0]:
self.errors.append("Generated key pair account address %s doesn't match expected %s" % (
generated_key_pair_account_address, expected_addresses[0]))
if generated_key_pair_account_address not in expected_addresses:
self.errors.append("Generated key pair account address %s is not in the list of expected addresses %s" % (
generated_key_pair_account_address, expected_addresses))

self.home_2.just_fyi("Device 2: check imported accounts are shown before importing key pair")
self.home_2.profile_button.click()
self.profile_2.profile_wallet_button.click()
self.profile_2.key_pairs_and_accounts_button.click()
if not self.profile_2.get_missing_key_pair_by_name(key_pair_name=key_pair_name).is_element_displayed():
self.errors.append("Key pair is not shown in profile as missing before importing")
if not self.profile_2.get_missing_key_pair_by_name(key_pair_name=imported_key_pair_name).is_element_displayed():
self.errors.append("New imported key pair is not shown in profile as missing before importing")
if not self.profile_2.get_missing_key_pair_by_name(
key_pair_name=generated_key_pair_name).is_element_displayed():
self.errors.append("Generated key pair is not shown in profile as missing before importing")
if not self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).is_element_displayed():
self.errors.append(
"Newly added regular account is not shown in profile as on device before importing key pair")
Expand All @@ -200,7 +257,7 @@ def test_fallback_add_key_pair(self):

wallet_2.just_fyi("Device 2: import key pair")
wallet_2.get_account_element(account_name=regular_account_name).swipe_left_on_element()
wallet_2.get_account_element(account_name=key_pair_account_name).click()
wallet_2.get_account_element(account_name=imported_key_pair_account_name).click()
wallet_2.element_by_translation_id("import-key-pair").click()
self.sign_in_2.passphrase_edit_box.send_keys(account_to_add['passphrase'])
wallet_2.slide_and_confirm_with_password()
Expand All @@ -211,19 +268,28 @@ def test_fallback_add_key_pair(self):
self.profile_2.key_pairs_and_accounts_button.click()
if self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).is_element_displayed():
address_text = self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).address.text
if address_text != '...'.join((regular_account_wallet_address[:5], regular_account_wallet_address[-3:])):
if address_text != '...'.join((regular_account_address[:5], regular_account_address[-3:])):
self.errors.append(
"Incorrect wallet address if shown for regular account after importing: " + address_text)
else:
self.errors.append("Newly added regular account is not shown in profile after importing key pair")

if self.profile_2.get_key_pair_account_by_name(account_name=key_pair_account_name).is_element_displayed():
address_text = self.profile_2.get_key_pair_account_by_name(account_name=key_pair_account_name).address.text
if address_text != '...'.join((key_pair_account_address[:5], key_pair_account_address[-3:])):
account_element = self.profile_2.get_key_pair_account_by_name(
account_name=imported_key_pair_account_name)
if account_element.is_element_displayed():
address_text = account_element.address.text
if address_text != '...'.join(
(imported_key_pair_account_address[:5], imported_key_pair_account_address[-3:])):
self.errors.append(
"Incorrect wallet address if shown for key pair account after importing: " + address_text)
"Incorrect wallet address if shown for imported key pair account after importing: " + address_text)
else:
self.errors.append("Key pair account is not shown in profile as on device after importing key pair")
self.errors.append(
"Imported key pair account is not shown in profile as on device after importing key pair")

if not self.profile_2.get_missing_key_pair_by_name(
key_pair_name=generated_key_pair_name).is_element_displayed():
self.errors.append(
"Generated key pair account is not shown in profile as missing after importing the first key pair")
self.profile_2.click_system_back_button(times=3)

# ToDo: Arbiscan API is down, looking for analogue
Expand All @@ -243,11 +309,25 @@ def test_fallback_add_key_pair(self):
self.errors.append("Incorrect derivation path %s is shown for the regular account" % der_path)
wallet_2.close_account_button.click_until_presence_of_element(account_element)
account_element.swipe_left_on_element()
wallet_2.get_account_element(account_name=key_pair_account_name).click()
wallet_2.get_account_element(account_name=imported_key_pair_account_name).click()
wallet_2.about_tab.click()
der_path = wallet_2.account_about_derivation_path_text.text
if der_path != key_pair_derivation_path:
self.errors.append("Incorrect derivation path %s is shown for the key pair account" % der_path)
if der_path != imported_key_pair_derivation_path:
self.errors.append("Incorrect derivation path %s is shown for the imported key pair account" % der_path)
wallet_2.close_account_button.click_until_presence_of_element(account_element)
account_element.swipe_left_on_element()
wallet_2.get_account_element(account_name=generated_key_pair_account_name).click()
wallet_2.element_by_translation_id("import-key-pair").click()
self.sign_in_2.passphrase_edit_box.send_keys(generated_passphrase)
wallet_2.slide_and_confirm_with_password()
wallet_2.get_account_element(account_name=generated_key_pair_account_name).click()
wallet_2.about_tab.click()
der_path = wallet_2.account_about_derivation_path_text.text
if der_path != generated_key_pair_derivation_path:
self.errors.append("Incorrect derivation path %s is shown for the generated key pair account" % der_path)
if not wallet_2.element_by_text_part(generated_key_pair_account_address).is_element_displayed():
self.errors.append(
"Generated key pair address %s is absent in About tab" % generated_key_pair_account_address)
self.errors.verify_no_errors()

@marks.testrail_id(740222)
Expand Down
3 changes: 3 additions & 0 deletions test/appium/views/base_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ def exclude_emoji(value):
def get_child_element_by_text(self, text: str):
return BaseElement(self.driver, prefix=self.locator, xpath="//*[@text='%s']" % text)

def get_child_element_by_text_part(self, text: str):
return BaseElement(self.driver, prefix=self.locator, xpath="//*[contains(@text,'%s')]" % text)


class EditBox(BaseElement):

Expand Down
49 changes: 36 additions & 13 deletions test/appium/views/wallet_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,19 @@ def __init__(self, driver):
# Edit key pair
self.edit_key_pair_button = Button(self.driver, accessibility_id="Edit")
self.key_pairs_plus_button = Button(self.driver, accessibility_id="standard-title-action")
self.default_key_pair_container = BaseElement(self.driver,
xpath="//*[@content-desc='user-avatar, title, details']")
self.added_key_pair_container = BaseElement(self.driver,
xpath="//*[@content-desc='icon, title, details']")
self.generate_new_keypair_button = Button(self.driver, accessibility_id="generate-new-keypair")
self.import_using_recovery_phrase_button = Button(self.driver, accessibility_id="import-using-phrase")
self.key_pair_continue_button = Button(self.driver, accessibility_id="Continue")
self.key_pair_name_input = EditBox(
self.driver, xpath="//*[@text='Key pair name']/..//following-sibling::*/*[@content-desc='input']")
self.passphrase_text_element = Text(
self.driver, xpath="//*[@resource-id='counter-component']/following-sibling::android.widget.TextView")
self.passphrase_word_number_container = Text(
self.driver, xpath="//*[@content-desc='number-container']/android.widget.TextView")

def set_network_in_wallet(self, network_name: str):
self.network_drop_down.click()
Expand Down Expand Up @@ -198,25 +206,40 @@ def remove_account(self, account_name: str, watch_only: bool = False):
def get_activity_element(self, index=1):
return ActivityElement(self.driver, index=index)

def add_key_pair_account(self, account_name, passphrase=None, key_pair_name=None):
def generate_new_key_pair(self, account_name: str, key_pair_name: str):
self.key_pairs_plus_button.click()
self.generate_new_keypair_button.click()
for checkbox in self.checkbox_button.find_elements():
checkbox.click()
self.element_by_translation_id("reveal-phrase").click()
passphrase = [i.text for i in self.passphrase_text_element.find_elements()]
self.element_by_translation_id("i-have-written").click()
for _ in range(4):
element = self.passphrase_word_number_container.find_element()
number = int(element.text)
Button(self.driver, accessibility_id=passphrase[number - 1]).click()
self.wait_for_staleness_of_element(element)
self.checkbox_button.click()
self.element_by_translation_id("done").click()
self.key_pair_name_input.send_keys(key_pair_name)
self.key_pair_continue_button.click()
derivation_path = self.add_account_derivation_path_text.text
SignInView(self.driver).profile_title_input.send_keys(account_name)
self.slide_and_confirm_with_password()
return derivation_path.replace(' ', ''), ' '.join(passphrase)

def import_key_pair_using_recovery_phrase(self, account_name: str, passphrase: str, key_pair_name: str):
self.add_account_button.click()
self.create_account_button.click()
signin_view = SignInView(self.driver)
signin_view.profile_title_input.send_keys(account_name)
self.edit_key_pair_button.click()
self.key_pairs_plus_button.click()
if passphrase:
self.import_using_recovery_phrase_button.click()
signin_view.passphrase_edit_box.send_keys(passphrase)
self.key_pair_continue_button.click()
self.key_pair_name_input.send_keys(key_pair_name)
self.key_pair_continue_button.click()
else:
self.generate_new_keypair_button.click()
for checkbox in self.checkbox_button.find_elements():
checkbox.click()
self.element_by_translation_id("reveal-phrase").click()
# ToDo: can't be done in current small size emulators, add when moved to LambdaTest
self.import_using_recovery_phrase_button.click()
signin_view.passphrase_edit_box.send_keys(passphrase)
self.key_pair_continue_button.click()
self.key_pair_name_input.send_keys(key_pair_name)
self.key_pair_continue_button.click()
derivation_path = self.add_account_derivation_path_text.text
self.slide_and_confirm_with_password()
return derivation_path.replace(' ', '')
Expand Down

0 comments on commit 9782ba2

Please sign in to comment.