e2e: wallet tests added

This commit is contained in:
Yevheniia Berdnyk 2024-04-02 17:59:56 +03:00
parent e1177d20b5
commit 5bff89a58f
No known key found for this signature in database
GPG Key ID: 0642C73C66214825
10 changed files with 792 additions and 419 deletions

View File

@ -1,59 +1,53 @@
import logging
import time
from decimal import Decimal
from json import JSONDecodeError
from os import environ
from typing import List
import pytest
import requests
import time
from json import JSONDecodeError
from decimal import Decimal
from os import environ
from selenium.common import TimeoutException
import tests
class NetworkApi(object):
class NetworkApi:
def __init__(self):
self.network_url = 'http://api-goerli.etherscan.io/api?'
self.headers = {
'User-Agent':"Mozilla\\5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit\\537.36 (KHTML, like Gecko) Chrome\\7"
"7.0.3865.90 Safari\\537.36", }
self.chat_bot_url = 'http://offsite.chat:8099'
self.network_url = 'http://api-sepolia.etherscan.io/api'
self.api_key = environ.get('ETHERSCAN_API_KEY')
def log(self, text: str):
tests.test_suite_data.current_test.testruns[-1].steps.append(text)
logging.info(text)
def send_etherscan_request(self, method, extracted_param: str):
for attempt in range(3):
try:
response = requests.request('GET', url=method, headers=self.headers).json()
if response:
return response[extracted_param]
except TypeError as e:
self.log("Check response from etherscan API. Returned values do not match expected. %s" % str(e))
except JSONDecodeError as e:
self.log("No valid JSON response from Etherscan: %s " % str(e))
pass
time.sleep(30)
def send_etherscan_request(self, params):
params['apikey'] = self.api_key
try:
response = requests.get(url=self.network_url, params=params).json()
if response:
return response['result']
except TypeError as e:
self.log("Check response from etherscan API. Returned values do not match expected. %s" % str(e))
except JSONDecodeError as e:
self.log("No valid JSON response from Etherscan: %s " % str(e))
pass
def get_token_transactions(self, address: str) -> List[dict]:
method = self.network_url + 'module=account&action=tokentx&address=0x%s&sort=desc&apikey=%s' % (
address, self.api_key)
return self.send_etherscan_request(method, 'result')
params = {'module': 'account', 'action': 'tokentx', 'address': address, 'sort': 'desc'}
return self.send_etherscan_request(params)
def get_transactions(self, address: str) -> List[dict]:
method = self.network_url + 'module=account&action=txlist&address=0x%s&sort=desc&apikey=%s' % (address, self.api_key)
return self.send_etherscan_request(method, 'result')
params = {'module': 'account', 'action': 'txlist', 'address': address, 'sort': 'desc'}
return self.send_etherscan_request(params)
def is_transaction_successful(self, transaction_hash: str) -> int:
method = self.network_url + 'module=transaction&action=getstatus&txhash=%s' % transaction_hash
return not int(requests.request('GET', url=method, headers=self.headers).json()['result']['isError'])
params = {'module': 'transaction', 'action': 'getstatus', 'txhash': transaction_hash}
return not int(self.send_etherscan_request(params)['isError'])
def get_balance(self, address):
address = '0x' + address
method = self.network_url + 'module=account&action=balance&address=%s&tag=latest&apikey=%s' % (
address, self.api_key)
balance = self.send_etherscan_request(method, 'result')
def get_balance(self, address: str):
params = {'module': 'account', 'action': 'balance', 'address': address, 'tag': 'latest'}
balance = self.send_etherscan_request(params)
if balance:
self.log('Balance is %s Gwei' % balance)
return int(balance)
@ -61,13 +55,12 @@ class NetworkApi(object):
self.log('Cannot extract balance!')
def get_latest_block_number(self) -> int:
method = self.network_url + 'module=proxy&action=eth_blockNumber'
return int(requests.request('GET', url=method).json()['result'], 0)
params = {'module': 'proxy', 'action': 'eth_blockNumber'}
return int(self.send_etherscan_request(params), 0)
def find_transaction_by_hash(self, transaction_hash: str):
method = self.network_url + 'module=transaction&action=gettxreceiptstatus&txhash=%s&apikey=%s' % (
transaction_hash, self.api_key)
result = self.send_etherscan_request(method, 'result')
params = {'module': 'transaction', 'action': 'gettxreceiptstatus', 'txhash': transaction_hash}
result = self.send_etherscan_request(params)
if result:
final_status = True
@ -86,13 +79,14 @@ class NetworkApi(object):
while True:
if counter >= wait_time:
for entry in range(0, 5):
self.log('Transaction #%s, amount is %s' %(entry+1, float(int(transactions[entry]['value']) / 10 ** decimals)))
self.log('Transaction #%s, amount is %s' % (
entry + 1, float(int(transactions[entry]['value']) / 10 ** decimals)))
self.log(str(transactions[entry]))
pytest.fail(
'Transaction with amount %s is not found in list of %s, address is %s during %ss' %
(amount, additional_info, address, wait_time))
else:
self.log("Finding tx in %s, attempt #%s" % (additional_info, str(int(counter / 30)+1)))
self.log("Finding tx in %s, attempt #%s" % (additional_info, str(int(counter / 30) + 1)))
try:
if token:
transactions = self.get_token_transactions(address)
@ -126,7 +120,8 @@ class NetworkApi(object):
if int(transaction['confirmations']) >= confirmations:
return
time.sleep(20)
pytest.fail('Transaction with amount %s was not confirmed, address is %s, still has %s confirmations' % (amount, address, int(transaction['confirmations'])))
pytest.fail('Transaction with amount %s was not confirmed, address is %s, still has %s confirmations' % (
amount, address, int(transaction['confirmations'])))
def verify_balance_is_updated(self, initial_balance, recipient_address, wait_time=360):
counter = 0
@ -141,10 +136,13 @@ class NetworkApi(object):
self.log('Balance is updated!')
return
def verify_balance_is(self, expected_balance: int, recipient_address: str, errors: list):
balance = self.get_balance(recipient_address)
if balance / 1000000000000000000 != expected_balance:
errors.append('Recipients balance is not updated on etherscan')
def wait_for_balance_to_be(self, address: str, expected_balance: int, less: bool = True):
for _ in range(5):
balance = self.get_balance(address) / 1000000000000000000
if (less and balance < expected_balance) or (not less and balance > expected_balance):
return
time.sleep(10)
raise TimeoutException('Balance is not updated on Etherscan')
# Do not use until web3 update
# def faucet(self, address):
@ -160,7 +158,6 @@ class NetworkApi(object):
# address = "0x" + address
# w3.donate_testnet_eth(address=address, amount=0.01, inscrease_default_gas_price=10)
# def get_donate(self, address, external_faucet=False, wait_time=300):
# initial_balance = self.get_balance(address)
# counter = 0
@ -180,11 +177,6 @@ class NetworkApi(object):
# self.log('Got %s Gwei for %s' % (self.get_balance(address), address))
# return
def start_chat_bot(self, chat_name: str, messages_number: int, interval: int = 1) -> list:
url = '%s/ping/%s?count=%s&interval=%s' % (self.chat_bot_url, chat_name, messages_number, interval)
text = requests.request('GET', url).text
return [i.split(maxsplit=5)[-1].strip('*') for i in text.splitlines()]
def get_rounded_balance(self, fetched_balance, actual_balance):
fetched_balance, actual_balance = str(fetched_balance), str(actual_balance)
# get actual number of decimals on account balance
@ -192,15 +184,14 @@ class NetworkApi(object):
rounded_balance = round(float(actual_balance), decimals)
return rounded_balance
def get_tx_param_by_hash(self, hash: str, param: str):
method = self.network_url + 'module=proxy&action=eth_getTransactionByHash&txhash=%s&apikey=%s' % (
hash, self.api_key)
res = self.send_etherscan_request(method, 'result')
def get_tx_param_by_hash(self, transaction_hash: str, param: str):
params = {'module': 'proxy', 'action': 'eth_getTransactionByHash', 'txhash': transaction_hash}
res = self.send_etherscan_request(params)
return int(res[param], 16)
def get_custom_fee_tx_params(self, hash: str):
return {
'fee_cap': str(self.get_tx_param_by_hash(hash, 'maxFeePerGas')/1000000000),
'tip_cap': str(self.get_tx_param_by_hash(hash, 'maxPriorityFeePerGas')/1000000000),
'fee_cap': str(self.get_tx_param_by_hash(hash, 'maxFeePerGas') / 1000000000),
'tip_cap': str(self.get_tx_param_by_hash(hash, 'maxPriorityFeePerGas') / 1000000000),
'gas_limit': str(self.get_tx_param_by_hash(hash, 'gas'))
}
}

View File

@ -129,6 +129,7 @@ class TestrailReport(BaseTestReport):
test_cases['pr']['community_multiple'] = 50982
test_cases['pr']['activity_centre_contact_request'] = 50984
test_cases['pr']['activity_centre_other'] = 51005
test_cases['pr']['wallet'] = 59443
## Nightly e2e
# test_cases['nightly']['activity_center'] = 736

View File

@ -0,0 +1,213 @@
import time
import pytest
from _pytest.outcomes import Failed
from selenium.common import TimeoutException
from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from support.api.network_api import NetworkApi
from tests import marks, run_in_parallel
from users import transaction_recipients
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="new_four_2")
@marks.new_ui_critical
class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.network_api = NetworkApi()
self.drivers, self.loop = create_shared_drivers(2)
self.sign_in_1, self.sign_in_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.sender, self.receiver = transaction_recipients['J'], transaction_recipients['K']
self.sender_username, self.receiver_username = 'sender', 'receiver'
self.loop.run_until_complete(
run_in_parallel(((self.sign_in_1.recover_access, {'passphrase': self.sender['passphrase'],
'username': self.sender_username}),
(self.sign_in_2.recover_access, {'passphrase': self.receiver['passphrase'],
'username': self.receiver_username}))))
self.home_1, self.home_2 = self.sign_in_1.get_home_view(), self.sign_in_2.get_home_view()
self.wallet_1, self.wallet_2 = self.sign_in_1.get_wallet_view(), self.sign_in_2.get_wallet_view()
# ToDo: Add verification of Activity tabs when the feature is ready in the next 2 tests:
def _get_balances_before_tx(self):
sender_balance = self.network_api.get_balance(self.sender['address'])
receiver_balance = self.network_api.get_balance(self.receiver['address'])
self.wallet_1.just_fyi("Getting ETH amount in the wallet of the sender before transaction")
self.wallet_1.wallet_tab.click()
self.wallet_1.get_account_element().click()
eth_amount_sender = self.wallet_1.get_asset(asset_name='Ether').get_amount()
self.wallet_2.just_fyi("Getting ETH amount in the wallet of the receiver before transaction")
self.wallet_2.wallet_tab.click()
self.wallet_2.get_account_element().click()
eth_amount_receiver = self.wallet_2.get_asset(asset_name='Ether').get_amount()
return sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver
def _check_balances_after_tx(self, amount_to_send, sender_balance, receiver_balance, eth_amount_sender,
eth_amount_receiver):
try:
self.network_api.wait_for_balance_to_be(address=self.sender['address'],
expected_balance=sender_balance - amount_to_send)
except TimeoutException:
self.errors.append("Sender balance was not updated")
try:
self.network_api.wait_for_balance_to_be(address=self.receiver['address'],
expected_balance=receiver_balance + amount_to_send)
except TimeoutException:
self.errors.append("Receiver balance was not updated")
def wait_for_wallet_balance_to_update(wallet_view, user_name, initial_eth_amount):
wallet_view.just_fyi("Getting ETH amount in the wallet of the %s after transaction" % user_name)
if user_name == 'sender':
exp_amount = round(initial_eth_amount - amount_to_send, 4)
else:
exp_amount = round(initial_eth_amount + amount_to_send, 4)
# for _ in range(12): # ToDo: 120 sec wait time, enable when autoupdate feature is ready
wallet_view.wallet_tab.click()
new_eth_amount = round(wallet_view.get_asset(asset_name='Ether').get_amount(), 4)
if user_name == 'sender' and new_eth_amount < exp_amount:
return
if user_name == 'receiver' and new_eth_amount >= exp_amount:
return
# wallet_view.chats_tab.click()
# time.sleep(10)
self.errors.append(
"Eth amount in the %ss wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
# ToDo: disable relogin when autoupdate feature ia ready
self.home_1.just_fyi("Relogin for getting an updated balance")
self.home_2.just_fyi("Relogin for getting an updated balance")
for _ in range(6): # just waiting 1 minute here to be sure that balances are updated
self.wallet_1.wallet_tab.click()
self.wallet_2.wallet_tab.click()
time.sleep(10)
self.loop.run_until_complete(
run_in_parallel(((self.home_1.reopen_app,),
(self.home_2.reopen_app,))))
self.loop.run_until_complete(
run_in_parallel(((wait_for_wallet_balance_to_update, {'wallet_view': self.wallet_1,
'user_name': self.sender_username,
'initial_eth_amount': eth_amount_sender}),
(wait_for_wallet_balance_to_update, {'wallet_view': self.wallet_2,
'user_name': self.receiver_username,
'initial_eth_amount': eth_amount_receiver}))))
self.errors.verify_no_errors()
@marks.testrail_id(727229)
def test_wallet_send_eth(self):
sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx()
self.wallet_2.close_account_button.click()
self.wallet_2.chats_tab.click()
self.wallet_1.just_fyi("Sending funds from wallet")
amount_to_send = 0.0001
self.wallet_1.send_asset(address=self.receiver['address'], asset_name='Ether', amount=amount_to_send)
self.wallet_1.close_account_button.click_until_presence_of_element(self.home_1.show_qr_code_button)
self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender,
eth_amount_receiver)
@marks.testrail_id(727230)
def test_wallet_send_asset_from_drawer(self):
sender_balance, receiver_balance, eth_amount_sender, eth_amount_receiver = self._get_balances_before_tx()
self.wallet_2.close_account_button.click()
self.wallet_2.chats_tab.click()
self.wallet_1.just_fyi("Sending asset from drawer")
amount_to_send = 0.0001
self.wallet_1.send_asset_from_drawer(address=self.receiver['address'], asset_name='Ether',
amount=amount_to_send)
self.wallet_1.close_account_button.click_until_presence_of_element(self.home_1.show_qr_code_button)
self._check_balances_after_tx(amount_to_send, sender_balance, receiver_balance, eth_amount_sender,
eth_amount_receiver)
@pytest.mark.xdist_group(name="new_one_2")
@marks.new_ui_critical
class TestWalletOneDevice(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.network_api = NetworkApi()
self.drivers, self.loop = create_shared_drivers(1)
self.sign_in_view = SignInView(self.drivers[0])
self.sign_in_view.create_user()
self.home_view = self.sign_in_view.get_home_view()
self.wallet_view = self.home_view.wallet_tab.click()
@marks.testrail_id(727231)
def test_wallet_add_remove_regular_account(self):
self.wallet_view.just_fyi("Adding new regular account")
new_account_name = "New Account"
self.wallet_view.add_regular_account(account_name=new_account_name)
if self.wallet_view.account_name_text.text != new_account_name:
pytest.fail("New account is not created")
self.wallet_view.account_emoji_button.click_until_presence_of_element(self.wallet_view.copy_address_button)
self.wallet_view.share_address_button.click()
new_wallet_address = self.wallet_view.sharing_text_native.text
self.wallet_view.click_system_back_button()
self.wallet_view.close_account_button.click_until_presence_of_element(self.home_view.show_qr_code_button)
self.wallet_view.just_fyi("Checking that the new wallet is added to the Sare QR Code menu")
self.home_view.show_qr_code_button.click()
self.home_view.share_wallet_tab_button.click()
if self.home_view.account_name_text.text != 'Account 1':
self.errors.append("Incorrect first account is shown on Share QR Code menu")
self.home_view.qr_code_image_element.swipe_left_on_element()
try:
self.home_view.account_name_text.wait_for_element_text(text=new_account_name, wait_time=3)
if self.home_view.copy_wallet_address() != new_wallet_address.split(':')[-1]:
self.home_view.driver.fail("Incorrect address")
except Failed:
self.errors.append("Can't swipe between accounts, newly added account is not shown")
self.home_view.click_system_back_button()
self.wallet_view.just_fyi("Removing newly added account")
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
self.wallet_view.remove_account(account_name=new_account_name)
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
self.errors.append("Account was not removed from wallet")
else:
self.errors.append("Newly added account is not shown in the accounts list")
self.errors.verify_no_errors()
@marks.testrail_id(727232)
def test_wallet_add_remove_watch_only_account(self):
self.wallet_view.just_fyi("Adding new watch only account")
new_account_name = "Account to watch"
address_to_watch = "0x8d2413447ff297d30bdc475f6d5cb00254685aae"
self.wallet_view.add_watch_only_account(address=address_to_watch, account_name=new_account_name)
if self.wallet_view.account_name_text.text != new_account_name:
pytest.fail("Account to watch was not added")
self.wallet_view.close_account_button.click_until_presence_of_element(self.home_view.show_qr_code_button)
self.wallet_view.just_fyi("Checking that the new wallet is added to the Sare QR Code menu")
self.home_view.show_qr_code_button.click()
self.home_view.share_wallet_tab_button.click()
if self.home_view.account_name_text.text != 'Account 1':
self.errors.append("Incorrect first account is shown on Share QR Code menu")
self.home_view.qr_code_image_element.swipe_left_on_element()
try:
self.home_view.account_name_text.wait_for_element_text(text=new_account_name, wait_time=3)
if self.home_view.copy_wallet_address() != address_to_watch:
self.home_view.driver.fail("Incorrect address")
except Failed:
self.errors.append("Can't swipe between accounts, account to watch is not shown")
self.home_view.click_system_back_button()
self.wallet_view.just_fyi("Removing account to watch")
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
self.wallet_view.remove_account(account_name=new_account_name, watch_only=True)
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
self.errors.append("Account was not removed from wallet")
else:
self.errors.append("Watch only account is not shown in the accounts list")
self.errors.verify_no_errors()

View File

@ -190,7 +190,7 @@ class BaseElement(object):
self.driver.fail(message if message else "`%s` is not equal to expected `%s` in %s sec" % (
element_text, text, wait_time))
def scroll_to_element(self, depth: int = 9, direction='down'):
def scroll_to_element(self, depth: int = 9, direction='down', down_start_y=0.4, down_end_y=0.05):
self.driver.info('Scrolling %s to %s' % (direction, self.name))
for _ in range(depth):
try:
@ -198,7 +198,7 @@ class BaseElement(object):
except NoSuchElementException:
size = self.driver.get_window_size()
if direction == 'down':
self.driver.swipe(500, size["height"] * 0.4, 500, size["height"] * 0.05)
self.driver.swipe(500, size["height"] * down_start_y, 500, size["height"] * down_end_y)
else:
self.driver.swipe(500, size["height"] * 0.25, 500, size["height"] * 0.8)
else:
@ -303,12 +303,13 @@ class BaseElement(object):
width, height = size['width'], size['height']
self.driver.swipe(start_x=x + width * 0.75, start_y=y + height / 2, end_x=x, end_y=y + height / 2)
def swipe_right_on_element(self, width_percentage=0.9):
def swipe_right_on_element(self, width_percentage=0.9, start_x=0):
self.driver.info("Swiping right on element %s" % self.name)
location, size = self.get_element_coordinates()
x, y = location['x'], location['y']
width, height = size['width'], size['height']
self.driver.swipe(start_x=x, start_y=y + height / 2, end_x=x + width * width_percentage, end_y=y + height / 2)
self.driver.swipe(start_x=x + start_x, start_y=y + height / 2, end_x=x + width * width_percentage,
end_y=y + height / 2)
def swipe_to_web_element(self, depth=700):
element = self.find_element()

View File

@ -94,6 +94,10 @@ class WalletTab(TabButton):
def __init__(self, driver):
super().__init__(driver, accessibility_id="wallet-stack-tab")
def navigate(self):
from views.wallet_view import WalletView
return WalletView(self.driver)
class BrowserTab(TabButton):
def __init__(self, driver):
@ -128,11 +132,11 @@ class WalletButton(TabButton):
super().__init__(driver, xpath="//*[contains(@content-desc,'tab, 3 out of 5')]")
def navigate(self):
from views.wallet_view import WalletView
from views.wallet_view_old_ui import WalletView
return WalletView(self.driver)
def click(self):
from views.wallet_view import WalletView
from views.wallet_view_old_ui import WalletView
self.click_until_presence_of_element(WalletView(self.driver).multiaccount_more_options)
return self.navigate()
@ -245,6 +249,14 @@ class SignInPhraseText(Text):
return self.text.split()
class SlideButton(Button):
def __init__(self, driver):
super().__init__(driver, xpath="//*[@resource-id='slide-button-track']")
def slide(self):
self.swipe_right_on_element(width_percentage=1.3, start_x=100)
class BaseView(object):
def __init__(self, driver):
self.driver = driver
@ -318,6 +330,7 @@ class BaseView(object):
# checkboxes and toggles
self.checkbox_button = CheckBox(self.driver, accessibility_id="checkbox-off")
self.slide_button_track = SlideButton(self.driver)
# external browser
self.open_in_status_button = OpenInStatusButton(self.driver)

View File

@ -225,6 +225,15 @@ class MuteButton(Button):
return self.find_element().find_element(by=MobileBy.XPATH, value="//android.widget.TextView[2]").text
class ShareQRCodeInfoText(Text):
def __init__(self, driver):
super().__init__(driver, accessibility_id="share-qr-code-info-text")
@property
def text(self):
return self.find_element().find_element(by=MobileBy.XPATH, value="/android.widget.TextView").text
class HomeView(BaseView):
def __init__(self, driver):
super().__init__(driver)
@ -329,10 +338,16 @@ class HomeView(BaseView):
self.mark_all_read_activity_button = Button(self.driver, translation_id="mark-all-notifications-as-read")
# Share tab
self.share_qr_code_info_text = ShareQRCodeInfoText(self.driver)
self.link_to_profile_button = Button(self.driver, accessibility_id="link-to-profile")
self.link_to_profile_text = Text(self.driver, accessibility_id="share-qr-code-info-text")
self.close_share_tab_button = Button(self.driver, accessibility_id="close-shell-share-tab")
self.qr_code_image_element = BaseElement(self.driver, accessibility_id='share-qr-code')
self.share_wallet_tab_button = Button(self.driver, accessibility_id="Wallet")
self.account_avatar = BaseElement(self.driver, accessibility_id="account-avatar")
self.account_name_text = Text(
self.driver, xpath="//*[@content-desc='link-to-profile']/preceding-sibling::android.widget.TextView")
self.share_link_to_profile_button = Button(self.driver, accessibility_id='link-to-profile')
# Discover communities
self.community_card_item = BaseElement(self.driver, accessibility_id="community-card-item")
@ -571,3 +586,17 @@ class HomeView(BaseView):
link_to_profile = self.get_link_to_profile()
self.click_system_back_button()
return link_to_profile.split("#")[-1]
def copy_wallet_address(self):
self.share_link_to_profile_button.click()
address = self.sharing_text_native.text
self.click_system_back_button()
return address
def get_wallet_address(self):
self.show_qr_code_button.click()
self.share_wallet_tab_button.click()
self.account_avatar.wait_for_visibility_of_element()
address = self.copy_wallet_address()
self.click_system_back_button()
return address

View File

@ -292,7 +292,6 @@ class ProfileView(BaseView):
self.syncing_button = Button(self.driver, accessibility_id="icon, Syncing, label-component, icon")
self.sync_plus_button = Button(self.driver,
xpath="//*[@text='Syncing']/following-sibling::android.view.ViewGroup[1]")
self.slide_button_track = Button(self.driver, xpath="//*[@resource-id='slide-button-track']")
# Keycard
self.keycard_button = Button(self.driver, accessibility_id="keycard-button")

View File

@ -1,378 +1,126 @@
import time
import pytest
from tests import common_password
from views.base_element import Button, Text, EditBox, SilentButton, CheckBox
from views.base_element import Button, EditBox, Text
from views.base_view import BaseView
from views.home_view import HomeView
from views.sign_in_view import SignInView
class TransactionHistoryButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="History-item-button")
class AssetElement(Button):
def navigate(self):
from views.transactions_view import TransactionsView
return TransactionsView(self.driver)
class AssetCheckBox(CheckBox):
def __init__(self, driver, asset_name):
super().__init__(driver, xpath="//*[@text='%s']" % asset_name)
self.asset_name = asset_name
self.locator = "//android.view.ViewGroup[@content-desc='container']/android.widget.TextView[@text='%s']" % \
self.asset_name
super().__init__(driver=driver, xpath=self.locator)
def enable(self):
self.scroll_to_element(12)
super().enable()
class BackupRecoveryPhrase(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="wallet-backup-recovery-title")
def navigate(self):
from views.profile_view import ProfileView
return ProfileView(self.driver)
class AccountElementButton(SilentButton):
def __init__(self, driver, account_name):
super().__init__(driver, xpath="//*[@content-desc='accountcard%s']" % account_name)
def color_matches(self, expected_color_image_name: str):
amount_text = Text(self.driver, xpath="%s//*[@content-desc='account-total-value']" % self.locator)
amount_text.wait_for_element_text('...', 60)
return not amount_text.is_element_differs_from_template(expected_color_image_name)
class SendTransactionButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="wallet-send")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class SendTransactionFromMainButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="send-transaction-button")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class ReceiveTransactionButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="receive")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class AddCustomTokenButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="add-custom-token")
def navigate(self):
from views.add_custom_token_view import AddCustomTokenView
return AddCustomTokenView(self.driver)
class AccountColorButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="account-color", suffix="/following-sibling::android.view.ViewGroup[1]")
def select_color_by_position(self, position: int):
self.click()
self.driver.find_element_by_xpath(
"((//android.widget.ScrollView)[1]/*/*)[%s]" % str(position + 1)).click()
def get_amount(self):
element = Text(self.driver, xpath=self.locator + "/../android.widget.TextView[3]")
element.scroll_to_element(down_start_y=0.89, down_end_y=0.8)
try:
amount = element.text.split()[0]
if '<' in amount:
return 0
else:
return float(amount)
except ValueError:
pytest.fail("Cannot get %s amount" % self.asset_name)
class WalletView(BaseView):
def __init__(self, driver):
super().__init__(driver)
# Wallet view
self.collectibles_tab = Button(self.driver, accessibility_id='Collectibles')
self.add_account_button = Button(self.driver, accessibility_id='add-account')
self.send_transaction_button = SendTransactionButton(self.driver)
self.send_transaction_from_main_screen = SendTransactionFromMainButton(self.driver)
self.transaction_history_button = TransactionHistoryButton(self.driver)
self.usd_total_value = Text(self.driver, accessibility_id="total-amount-value-text")
# Account adding
# ToDo: add unique accessibility ids for the next 2 elements:
self.create_account_button = HomeView(self.driver).start_a_new_chat_bottom_sheet_button
self.add_account_to_watch = HomeView(self.driver).add_a_contact_chat_bottom_sheet_button
self.address_to_watch_input = EditBox(self.driver, accessibility_id='add-address-to-watch')
self.account_has_activity_label = Text(self.driver, accessibility_id='account-has-activity')
self.add_account_continue_button = Button(self.driver, accessibility_id='Continue')
self.add_watched_address_button = Button(self.driver, accessibility_id='confirm-button-label')
self.receive_transaction_button = ReceiveTransactionButton(self.driver)
self.options_button = Button(self.driver, accessibility_id="options-menu-button")
self.manage_assets_button = Button(self.driver, accessibility_id="wallet-manage-assets")
self.manage_accounts_button = Button(self.driver, accessibility_id="wallet-manage-accounts")
self.scan_tokens_button = Button(self.driver, accessibility_id="wallet-scan-token")
self.all_assets_full_names = Text(self.driver,
xpath="//*[@content-desc='checkbox-off']/../android.widget.TextView[1]")
self.all_assets_symbols = Button(self.driver,
xpath="//*[@content-desc='checkbox-off']/../android.widget.TextView[2]")
self.currency_item_text = Text(self.driver, xpath="//*[@content-desc='currency-item']//android.widget.TextView")
# Account view
self.close_account_button = Button(self.driver, accessibility_id='top-bar')
self.account_name_text = Text(
self.driver, xpath="//*[@content-desc='account-avatar']/../following-sibling::android.widget.TextView[1]")
self.account_emoji_button = Button(self.driver, accessibility_id='account-emoji')
self.send_button = Button(self.driver, accessibility_id='send')
self.copy_address_button = Button(self.driver, accessibility_id='copy-address')
self.share_address_button = Button(self.driver, accessibility_id='share-account')
self.remove_account_button = Button(self.driver, accessibility_id='remove-account')
self.derivation_path_note_checkbox = Button(self.driver, accessibility_id='checkbox-off')
self.address_text = Text(self.driver, accessibility_id="address-text")
# Sending transaction
self.address_text_input = EditBox(self.driver, accessibility_id='address-text-input')
self.continue_button = Button(self.driver, accessibility_id='continue-button')
self.amount_input = EditBox(self.driver, xpath="//android.widget.EditText")
self.confirm_button = Button(self.driver, accessibility_id='button-one')
self.done_button = Button(self.driver, accessibility_id='done')
self.remind_me_later_button = Button(self.driver, translation_id="remind-me-later")
def get_account_element(self, account_name: str = 'Account 1'):
return Button(self.driver, xpath="//android.view.ViewGroup[contains(@content-desc,'%s')]" % account_name)
self.total_amount_text = Text(self.driver, accessibility_id="total-amount-value-text")
self.currency_text = Text(self.driver, accessibility_id="total-amount-currency-text")
self.backup_recovery_phrase = BackupRecoveryPhrase(self.driver)
self.backup_recovery_phrase_warning_text = Text(self.driver,
accessibility_id="back-up-your-seed-phrase-warning")
def get_asset(self, asset_name: str):
element = AssetElement(driver=self.driver, asset_name=asset_name)
element.scroll_to_element(down_start_y=0.89, down_end_y=0.8)
return element
self.add_custom_token_button = AddCustomTokenButton(self.driver)
def select_asset(self, asset_name: str):
return Button(driver=self.driver,
xpath="//*[@content-desc='token-network']/android.widget.TextView[@text='%s']" % asset_name)
# elements for multiaccount
self.multiaccount_more_options = Button(self.driver, accessibility_id="accounts-more-options")
self.accounts_status_account = AccountElementButton(self.driver, account_name=self.status_account_name)
self.set_currency_button = Button(self.driver, translation_id="set-currency")
self.add_account_button = Button(self.driver, accessibility_id="add-new-account")
self.generate_an_account_button = Button(self.driver, accessibility_id="add-account-sheet-generate")
self.add_watch_only_address_button = Button(self.driver, accessibility_id="add-account-sheet-watch")
self.enter_a_seed_phrase_button = Button(self.driver, accessibility_id="add-account-sheet-seed")
self.enter_a_private_key_button = Button(self.driver, accessibility_id="add-account-sheet-private-key")
self.enter_address_input = EditBox(self.driver, accessibility_id="add-account-enter-watch-address")
self.enter_seed_phrase_input = EditBox(self.driver, accessibility_id="add-account-enter-seed")
self.enter_a_private_key_input = EditBox(self.driver, accessibility_id="add-account-enter-private-key")
self.delete_account_button = Button(self.driver, translation_id="delete-account")
self.enter_your_password_input = EditBox(self.driver, accessibility_id="add-account-enter-password")
self.account_name_input = EditBox(self.driver, accessibility_id="enter-account-name")
self.account_color_button = AccountColorButton(self.driver)
self.add_account_generate_account_button = Button(self.driver,
accessibility_id="add-account-add-account-button")
self.status_account_total_usd_value = Text(self.driver, accessibility_id="account-total-value")
self.scan_qr_button = Button(self.driver, accessibility_id="accounts-qr-code")
self.close_send_transaction_view_button = Button(self.driver,
xpath="//androidx.appcompat.widget.LinearLayoutCompat")
self.hide_account_button = Button(self.driver, accessibility_id="hide-account-button")
def slide_and_confirm_with_password(self):
self.slide_button_track.slide()
self.password_input.send_keys(common_password)
self.login_button.click()
# collectibles
self.collectibles_button = Button(self.driver, translation_id="wallet-collectibles")
self.nft_asset_button = Button(self.driver, accessibility_id="nft-asset")
self.set_collectible_as_profile_photo_button = Button(self.driver, accessibility_id="set-nft-as-pfp")
self.view_collectible_on_opensea_button = Button(self.driver, translation_id="view-on-opensea")
def confirm_transaction(self):
self.confirm_button.click_until_presence_of_element(self.slide_button_track)
self.slide_and_confirm_with_password()
self.done_button.click()
# individual account settings
self.account_settings_button = Button(self.driver, translation_id="account-settings")
self.apply_settings_button = Button(self.driver, translation_id="apply")
self.password_delete_account_input = EditBox(self.driver,
xpath='//*[@text="Password"]/following-sibling::*/android.widget.EditText')
self.delete_account_confirm_button = Button(self.driver, accessibility_id="delete-account-confirm")
def send_asset(self, address: str, asset_name: str, amount: float):
self.send_button.click()
self.address_text_input.send_keys(address)
self.continue_button.click_until_presence_of_element(self.collectibles_tab)
self.select_asset(asset_name).click()
self.amount_input.send_keys('{:f}'.format(amount).rstrip('0'))
self.confirm_transaction()
def wait_balance_is_equal_expected_amount(self, asset='ETH', expected_balance=0.1, wait_time=300, main_screen=True):
counter = 0
while True:
if counter >= wait_time:
self.driver.fail('**Balance is not changed during %s seconds!**' % wait_time)
elif self.get_asset_amount_by_name(asset) != expected_balance:
counter += 10
time.sleep(10)
self.swipe_down()
self.driver.info('Waiting %s seconds for %s balance update to be equal to %s' % (
counter, asset, expected_balance))
else:
self.driver.info('Balance for %s is equal to %s' % (asset, expected_balance))
if main_screen:
if not self.accounts_status_account.is_element_displayed():
self.accounts_status_account.scroll_to_element(direction='up')
return
def send_asset_from_drawer(self, address: str, asset_name: str, amount: float):
asset_element = self.get_asset(asset_name)
asset_element.long_press_element()
self.send_button.wait_for_elements()
self.send_button.find_elements()[0].click()
self.address_text_input.send_keys(address)
self.continue_button.click_until_presence_of_element(self.confirm_button)
self.amount_input.send_keys('{:f}'.format(amount).rstrip('0'))
self.confirm_transaction()
def wait_balance_is_changed(self, asset='ETH', initial_balance=0, wait_time=180, scan_tokens=False, navigate_to_home=True):
self.driver.info('Waiting %ss for %s updated balance' % (wait_time, asset))
counter = 0
while True:
if counter >= wait_time:
self.driver.fail(
'Balance %s %s is not changed during %s seconds!' % (asset, initial_balance, wait_time))
elif self.asset_by_name(asset).is_element_displayed() and self.get_asset_amount_by_name(
asset) == initial_balance:
if scan_tokens:
self.scan_tokens()
if (counter / 60).is_integer():
self.pull_to_refresh()
counter += 20
counter += 10
time.sleep(10)
self.driver.info('Waiting %ss for %s updated balance' % (counter, asset))
elif not self.asset_by_name(asset).is_element_displayed(10):
if scan_tokens:
self.scan_tokens()
self.swipe_up()
counter += 10
time.sleep(10)
self.driver.info('Waiting %s seconds for %s to display asset' % (counter, asset))
else:
self.driver.info('Initial "%s" is not equal expected balance "%s", it is updated!' % (initial_balance,
self.get_asset_amount_by_name(asset)))
if navigate_to_home:
self.wallet_button.double_click()
self.element_by_translation_id("wallet-total-value").scroll_to_element(direction='up')
return self
def get_sign_in_phrase(self):
return ' '.join([element.text for element in self.sign_in_phrase.find_elements()])
def set_up_wallet_when_sending_tx(self):
self.driver.info("Setting up wallet")
phrase = self.sign_in_phrase.text
self.ok_got_it_button.click()
return phrase
def get_wallet_address(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting wallet address for '%s'" % account_name)
self.wallet_account_by_name(account_name).click()
self.receive_transaction_button.click_until_presence_of_element(self.qr_code_image)
address = self.address_text.text
self.close_share_popup()
return address
def wallet_account_by_name(self, account_name):
self.driver.info("Getting '%s' wallet account" % account_name)
return AccountElementButton(self.driver, account_name)
def get_asset_amount_by_name(self, asset: str):
self.driver.info("Getting %s amount" % asset)
asset_value = SilentButton(self.driver, xpath="//android.view.ViewGroup[@content-desc=':%s-asset-value']"
"//android.widget.TextView[1]" % asset)
for _ in range(2):
if not asset_value.is_element_displayed():
self.element = asset_value.scroll_to_element()
try:
value = float(asset_value.text.split()[0])
self.driver.info("%s value is %s" % (asset, value))
return value
except ValueError:
self.driver.info("No value for %s" % asset)
return 0.0
def asset_by_name(self, asset_name):
self.driver.info("Selecting %s asset" % asset_name)
return SilentButton(self.driver, xpath="//*[contains(@text,'%s')]" % asset_name)
def asset_checkbox_by_name(self, asset_name):
self.driver.info("Selecting %s asset checkbox by name" % asset_name)
return AssetCheckBox(self.driver, asset_name)
def get_account_options_by_name(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting '%s'account options" % account_name)
return SilentButton(self.driver, xpath="(//*[@text='%s']/../..//*[@content-desc='icon'])[2]" % account_name)
def get_account_options_from_main_screen(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting '%s'account options from main wallet screen" % account_name)
return SilentButton(self.driver,
xpath="//*[@content-desc='accountcard%s']//*[@content-desc='icon']" % account_name)
def hidden_account_by_name_button(self, account_name=''):
return SilentButton(self.driver,
xpath="//*[@text='%s']/following-sibling::*[@content-desc='hide-icon']" % account_name)
def show_account_by_name_button(self, account_name=''):
return SilentButton(self.driver,
xpath="//*[@text='%s']/following-sibling::*[@content-desc='show-icon']" % account_name)
def select_asset(self, *args):
self.driver.info("Selecting asset(s)")
self.multiaccount_more_options.click()
self.manage_assets_button.click()
for asset in args:
self.element_by_text(asset).scroll_to_element()
self.element_by_text(asset).scroll_and_click()
self.cross_icon.click()
def scan_tokens(self, *args):
self.driver.info("Scanning tokens")
self.multiaccount_more_options.click()
self.scan_tokens_button.click()
counter = 0
if args:
for asset in args:
while True:
if counter >= 20:
self.driver.fail('Balance of %s is not changed during 20 seconds!' % asset)
elif self.get_asset_amount_by_name(asset) == 0.0:
self.multiaccount_more_options.click()
self.scan_tokens_button.click()
self.driver.info('Trying to scan for tokens one more time and waiting %s seconds for %s '
'to update' % (counter, asset))
time.sleep(5)
counter += 5
else:
self.driver.info('Balance of %s is updated!' % asset)
return self
def send_transaction(self, **kwargs):
self.driver.info("## Sending transaction", device=False)
send_tx = self.send_transaction_from_main_screen.click() if kwargs.get('from_main_wallet',
True) else self.send_transaction_button.click()
send_tx.select_asset_button.click()
asset_name = kwargs.get('asset_name', 'ETH').upper()
asset_button = send_tx.asset_by_name(asset_name)
send_tx.select_asset_button.click_until_presence_of_element(
send_tx.eth_asset_in_select_asset_bottom_sheet_button)
asset_button.click()
send_tx.amount_edit_box.click()
transaction_amount = str(kwargs.get('amount', send_tx.get_unique_amount()))
send_tx.amount_edit_box.send_keys(transaction_amount)
if kwargs.get('account_name'):
send_tx.chose_recipient_button.click()
send_tx.accounts_button.click()
send_tx.element_by_text(kwargs.get('account_name')).click()
else:
send_tx.set_recipient_address(kwargs.get('recipient'))
if kwargs.get('sign_transaction', True):
send_tx.sign_transaction_button.click()
if self.sign_in_phrase.is_element_displayed():
self.set_up_wallet_when_sending_tx()
send_tx.sign_transaction(keycard=kwargs.get('keycard', False),
sender_password=kwargs.get('sender_password', common_password))
return send_tx
def find_transaction_in_history(self, amount, asset='ETH', account_name=None, return_hash=False):
if account_name is None:
account_name = self.status_account_name
self.driver.info("Finding '%s %s' transaction for '%s'" % (amount, asset, account_name))
if not self.transaction_history_button.is_element_displayed():
self.get_account_by_name(account_name).click()
self.transaction_history_button.wait_for_element()
transactions_view = self.transaction_history_button.click()
transaction_element = transactions_view.transactions_table.find_transaction(amount=amount, asset=asset)
result = transaction_element
if return_hash:
transaction_element.click()
from views.transactions_view import TransactionTable
result = TransactionTable.TransactionElement.TransactionDetailsView(self.driver).get_transaction_hash()
return result
def set_currency(self, desired_currency='EUR'):
self.driver.info("Setting '%s' currency" % desired_currency)
self.multiaccount_more_options.click_until_presence_of_element(self.set_currency_button)
self.set_currency_button.click()
desired_currency = self.element_by_text_part(desired_currency)
desired_currency.scroll_to_element()
desired_currency.click()
def get_account_by_name(self, account_name: str):
self.driver.info("Getting account: '%s'" % account_name)
return AccountElementButton(self.driver, account_name)
def add_account(self, account_name: str, password: str = common_password, keycard=False):
self.driver.info("## Add account: '%s'" % account_name, device=False)
def add_regular_account(self, account_name: str):
self.add_account_button.click()
self.generate_an_account_button.click()
self.account_name_input.send_keys(account_name)
if keycard:
from views.keycard_view import KeycardView
keycard_view = KeycardView(self.driver)
self.add_account_generate_account_button.click()
keycard_view.enter_default_pin()
else:
self.enter_your_password_input.send_keys(password)
self.add_account_generate_account_button.click_until_presence_of_element(self.accounts_status_account)
self.driver.info("## Account is added!", device=False)
self.create_account_button.click()
SignInView(self.driver).profile_title_input.send_keys(account_name)
self.slide_and_confirm_with_password()
def get_collectibles_amount(self, collectibles='CryptoKitties'):
self.driver.info("Getting '%s' Collectibles amount" % collectibles)
return Text(self.driver, xpath="//*[@text='%s']//following-sibling::android.widget.TextView" % collectibles)
def add_watch_only_account(self, address: str, account_name: str):
self.add_account_button.click()
self.add_account_to_watch.click()
self.address_to_watch_input.send_keys(address)
self.account_has_activity_label.wait_for_visibility_of_element()
self.add_account_continue_button.click()
SignInView(self.driver).profile_title_input.send_keys(account_name)
self.add_watched_address_button.click()
def remove_account(self, account_name: str, watch_only: bool = False):
self.get_account_element(account_name=account_name).click()
self.account_emoji_button.click()
self.remove_account_button.click()
if not watch_only:
self.derivation_path_note_checkbox.click()
self.confirm_button.click()

View File

@ -0,0 +1,378 @@
import time
from tests import common_password
from views.base_element import Button, Text, EditBox, SilentButton, CheckBox
from views.base_view import BaseView
class TransactionHistoryButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="History-item-button")
def navigate(self):
from views.transactions_view import TransactionsView
return TransactionsView(self.driver)
class AssetCheckBox(CheckBox):
def __init__(self, driver, asset_name):
super().__init__(driver, xpath="//*[@text='%s']" % asset_name)
def enable(self):
self.scroll_to_element(12)
super().enable()
class BackupRecoveryPhrase(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="wallet-backup-recovery-title")
def navigate(self):
from views.profile_view import ProfileView
return ProfileView(self.driver)
class AccountElementButton(SilentButton):
def __init__(self, driver, account_name):
super().__init__(driver, xpath="//*[@content-desc='accountcard%s']" % account_name)
def color_matches(self, expected_color_image_name: str):
amount_text = Text(self.driver, xpath="%s//*[@content-desc='account-total-value']" % self.locator)
amount_text.wait_for_element_text('...', 60)
return not amount_text.is_element_differs_from_template(expected_color_image_name)
class SendTransactionButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="wallet-send")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class SendTransactionFromMainButton(Button):
def __init__(self, driver):
super().__init__(driver, accessibility_id="send-transaction-button")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class ReceiveTransactionButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="receive")
def navigate(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
class AddCustomTokenButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="add-custom-token")
def navigate(self):
from views.add_custom_token_view import AddCustomTokenView
return AddCustomTokenView(self.driver)
class AccountColorButton(Button):
def __init__(self, driver):
super().__init__(driver, translation_id="account-color", suffix="/following-sibling::android.view.ViewGroup[1]")
def select_color_by_position(self, position: int):
self.click()
self.driver.find_element_by_xpath(
"((//android.widget.ScrollView)[1]/*/*)[%s]" % str(position + 1)).click()
class WalletView(BaseView):
def __init__(self, driver):
super().__init__(driver)
self.send_transaction_button = SendTransactionButton(self.driver)
self.send_transaction_from_main_screen = SendTransactionFromMainButton(self.driver)
self.transaction_history_button = TransactionHistoryButton(self.driver)
self.usd_total_value = Text(self.driver, accessibility_id="total-amount-value-text")
self.receive_transaction_button = ReceiveTransactionButton(self.driver)
self.options_button = Button(self.driver, accessibility_id="options-menu-button")
self.manage_assets_button = Button(self.driver, accessibility_id="wallet-manage-assets")
self.manage_accounts_button = Button(self.driver, accessibility_id="wallet-manage-accounts")
self.scan_tokens_button = Button(self.driver, accessibility_id="wallet-scan-token")
self.all_assets_full_names = Text(self.driver,
xpath="//*[@content-desc='checkbox-off']/../android.widget.TextView[1]")
self.all_assets_symbols = Button(self.driver,
xpath="//*[@content-desc='checkbox-off']/../android.widget.TextView[2]")
self.currency_item_text = Text(self.driver, xpath="//*[@content-desc='currency-item']//android.widget.TextView")
self.address_text = Text(self.driver, accessibility_id="address-text")
self.remind_me_later_button = Button(self.driver, translation_id="remind-me-later")
self.total_amount_text = Text(self.driver, accessibility_id="total-amount-value-text")
self.currency_text = Text(self.driver, accessibility_id="total-amount-currency-text")
self.backup_recovery_phrase = BackupRecoveryPhrase(self.driver)
self.backup_recovery_phrase_warning_text = Text(self.driver,
accessibility_id="back-up-your-seed-phrase-warning")
self.add_custom_token_button = AddCustomTokenButton(self.driver)
# elements for multiaccount
self.multiaccount_more_options = Button(self.driver, accessibility_id="accounts-more-options")
self.accounts_status_account = AccountElementButton(self.driver, account_name=self.status_account_name)
self.set_currency_button = Button(self.driver, translation_id="set-currency")
self.add_account_button = Button(self.driver, accessibility_id="add-new-account")
self.generate_an_account_button = Button(self.driver, accessibility_id="add-account-sheet-generate")
self.add_watch_only_address_button = Button(self.driver, accessibility_id="add-account-sheet-watch")
self.enter_a_seed_phrase_button = Button(self.driver, accessibility_id="add-account-sheet-seed")
self.enter_a_private_key_button = Button(self.driver, accessibility_id="add-account-sheet-private-key")
self.enter_address_input = EditBox(self.driver, accessibility_id="add-account-enter-watch-address")
self.enter_seed_phrase_input = EditBox(self.driver, accessibility_id="add-account-enter-seed")
self.enter_a_private_key_input = EditBox(self.driver, accessibility_id="add-account-enter-private-key")
self.delete_account_button = Button(self.driver, translation_id="delete-account")
self.enter_your_password_input = EditBox(self.driver, accessibility_id="add-account-enter-password")
self.account_name_input = EditBox(self.driver, accessibility_id="enter-account-name")
self.account_color_button = AccountColorButton(self.driver)
self.add_account_generate_account_button = Button(self.driver,
accessibility_id="add-account-add-account-button")
self.status_account_total_usd_value = Text(self.driver, accessibility_id="account-total-value")
self.scan_qr_button = Button(self.driver, accessibility_id="accounts-qr-code")
self.close_send_transaction_view_button = Button(self.driver,
xpath="//androidx.appcompat.widget.LinearLayoutCompat")
self.hide_account_button = Button(self.driver, accessibility_id="hide-account-button")
# collectibles
self.collectibles_button = Button(self.driver, translation_id="wallet-collectibles")
self.nft_asset_button = Button(self.driver, accessibility_id="nft-asset")
self.set_collectible_as_profile_photo_button = Button(self.driver, accessibility_id="set-nft-as-pfp")
self.view_collectible_on_opensea_button = Button(self.driver, translation_id="view-on-opensea")
# individual account settings
self.account_settings_button = Button(self.driver, translation_id="account-settings")
self.apply_settings_button = Button(self.driver, translation_id="apply")
self.password_delete_account_input = EditBox(self.driver,
xpath='//*[@text="Password"]/following-sibling::*/android.widget.EditText')
self.delete_account_confirm_button = Button(self.driver, accessibility_id="delete-account-confirm")
def wait_balance_is_equal_expected_amount(self, asset='ETH', expected_balance=0.1, wait_time=300, main_screen=True):
counter = 0
while True:
if counter >= wait_time:
self.driver.fail('**Balance is not changed during %s seconds!**' % wait_time)
elif self.get_asset_amount_by_name(asset) != expected_balance:
counter += 10
time.sleep(10)
self.swipe_down()
self.driver.info('Waiting %s seconds for %s balance update to be equal to %s' % (
counter, asset, expected_balance))
else:
self.driver.info('Balance for %s is equal to %s' % (asset, expected_balance))
if main_screen:
if not self.accounts_status_account.is_element_displayed():
self.accounts_status_account.scroll_to_element(direction='up')
return
def wait_balance_is_changed(self, asset='ETH', initial_balance=0, wait_time=180, scan_tokens=False, navigate_to_home=True):
self.driver.info('Waiting %ss for %s updated balance' % (wait_time, asset))
counter = 0
while True:
if counter >= wait_time:
self.driver.fail(
'Balance %s %s is not changed during %s seconds!' % (asset, initial_balance, wait_time))
elif self.asset_by_name(asset).is_element_displayed() and self.get_asset_amount_by_name(
asset) == initial_balance:
if scan_tokens:
self.scan_tokens()
if (counter / 60).is_integer():
self.pull_to_refresh()
counter += 20
counter += 10
time.sleep(10)
self.driver.info('Waiting %ss for %s updated balance' % (counter, asset))
elif not self.asset_by_name(asset).is_element_displayed(10):
if scan_tokens:
self.scan_tokens()
self.swipe_up()
counter += 10
time.sleep(10)
self.driver.info('Waiting %s seconds for %s to display asset' % (counter, asset))
else:
self.driver.info('Initial "%s" is not equal expected balance "%s", it is updated!' % (initial_balance,
self.get_asset_amount_by_name(asset)))
if navigate_to_home:
self.wallet_button.double_click()
self.element_by_translation_id("wallet-total-value").scroll_to_element(direction='up')
return self
def get_sign_in_phrase(self):
return ' '.join([element.text for element in self.sign_in_phrase.find_elements()])
def set_up_wallet_when_sending_tx(self):
self.driver.info("Setting up wallet")
phrase = self.sign_in_phrase.text
self.ok_got_it_button.click()
return phrase
def get_wallet_address(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting wallet address for '%s'" % account_name)
self.wallet_account_by_name(account_name).click()
self.receive_transaction_button.click_until_presence_of_element(self.qr_code_image)
address = self.address_text.text
self.close_share_popup()
return address
def wallet_account_by_name(self, account_name):
self.driver.info("Getting '%s' wallet account" % account_name)
return AccountElementButton(self.driver, account_name)
def get_asset_amount_by_name(self, asset: str):
self.driver.info("Getting %s amount" % asset)
asset_value = SilentButton(self.driver, xpath="//android.view.ViewGroup[@content-desc=':%s-asset-value']"
"//android.widget.TextView[1]" % asset)
for _ in range(2):
if not asset_value.is_element_displayed():
self.element = asset_value.scroll_to_element()
try:
value = float(asset_value.text.split()[0])
self.driver.info("%s value is %s" % (asset, value))
return value
except ValueError:
self.driver.info("No value for %s" % asset)
return 0.0
def asset_by_name(self, asset_name):
self.driver.info("Selecting %s asset" % asset_name)
return SilentButton(self.driver, xpath="//*[contains(@text,'%s')]" % asset_name)
def asset_checkbox_by_name(self, asset_name):
self.driver.info("Selecting %s asset checkbox by name" % asset_name)
return AssetCheckBox(self.driver, asset_name)
def get_account_options_by_name(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting '%s'account options" % account_name)
return SilentButton(self.driver, xpath="(//*[@text='%s']/../..//*[@content-desc='icon'])[2]" % account_name)
def get_account_options_from_main_screen(self, account_name=''):
account_name = self.status_account_name if not account_name else account_name
self.driver.info("Getting '%s'account options from main wallet screen" % account_name)
return SilentButton(self.driver,
xpath="//*[@content-desc='accountcard%s']//*[@content-desc='icon']" % account_name)
def hidden_account_by_name_button(self, account_name=''):
return SilentButton(self.driver,
xpath="//*[@text='%s']/following-sibling::*[@content-desc='hide-icon']" % account_name)
def show_account_by_name_button(self, account_name=''):
return SilentButton(self.driver,
xpath="//*[@text='%s']/following-sibling::*[@content-desc='show-icon']" % account_name)
def select_asset(self, *args):
self.driver.info("Selecting asset(s)")
self.multiaccount_more_options.click()
self.manage_assets_button.click()
for asset in args:
self.element_by_text(asset).scroll_to_element()
self.element_by_text(asset).scroll_and_click()
self.cross_icon.click()
def scan_tokens(self, *args):
self.driver.info("Scanning tokens")
self.multiaccount_more_options.click()
self.scan_tokens_button.click()
counter = 0
if args:
for asset in args:
while True:
if counter >= 20:
self.driver.fail('Balance of %s is not changed during 20 seconds!' % asset)
elif self.get_asset_amount_by_name(asset) == 0.0:
self.multiaccount_more_options.click()
self.scan_tokens_button.click()
self.driver.info('Trying to scan for tokens one more time and waiting %s seconds for %s '
'to update' % (counter, asset))
time.sleep(5)
counter += 5
else:
self.driver.info('Balance of %s is updated!' % asset)
return self
def send_transaction(self, **kwargs):
self.driver.info("## Sending transaction", device=False)
send_tx = self.send_transaction_from_main_screen.click() if kwargs.get('from_main_wallet',
True) else self.send_transaction_button.click()
send_tx.select_asset_button.click()
asset_name = kwargs.get('asset_name', 'ETH').upper()
asset_button = send_tx.asset_by_name(asset_name)
send_tx.select_asset_button.click_until_presence_of_element(
send_tx.eth_asset_in_select_asset_bottom_sheet_button)
asset_button.click()
send_tx.amount_edit_box.click()
transaction_amount = str(kwargs.get('amount', send_tx.get_unique_amount()))
send_tx.amount_edit_box.send_keys(transaction_amount)
if kwargs.get('account_name'):
send_tx.chose_recipient_button.click()
send_tx.accounts_button.click()
send_tx.element_by_text(kwargs.get('account_name')).click()
else:
send_tx.set_recipient_address(kwargs.get('recipient'))
if kwargs.get('sign_transaction', True):
send_tx.sign_transaction_button.click()
if self.sign_in_phrase.is_element_displayed():
self.set_up_wallet_when_sending_tx()
send_tx.sign_transaction(keycard=kwargs.get('keycard', False),
sender_password=kwargs.get('sender_password', common_password))
return send_tx
def find_transaction_in_history(self, amount, asset='ETH', account_name=None, return_hash=False):
if account_name is None:
account_name = self.status_account_name
self.driver.info("Finding '%s %s' transaction for '%s'" % (amount, asset, account_name))
if not self.transaction_history_button.is_element_displayed():
self.get_account_by_name(account_name).click()
self.transaction_history_button.wait_for_element()
transactions_view = self.transaction_history_button.click()
transaction_element = transactions_view.transactions_table.find_transaction(amount=amount, asset=asset)
result = transaction_element
if return_hash:
transaction_element.click()
from views.transactions_view import TransactionTable
result = TransactionTable.TransactionElement.TransactionDetailsView(self.driver).get_transaction_hash()
return result
def set_currency(self, desired_currency='EUR'):
self.driver.info("Setting '%s' currency" % desired_currency)
self.multiaccount_more_options.click_until_presence_of_element(self.set_currency_button)
self.set_currency_button.click()
desired_currency = self.element_by_text_part(desired_currency)
desired_currency.scroll_to_element()
desired_currency.click()
def get_account_by_name(self, account_name: str):
self.driver.info("Getting account: '%s'" % account_name)
return AccountElementButton(self.driver, account_name)
def add_account(self, account_name: str, password: str = common_password, keycard=False):
self.driver.info("## Add account: '%s'" % account_name, device=False)
self.add_account_button.click()
self.generate_an_account_button.click()
self.account_name_input.send_keys(account_name)
if keycard:
from views.keycard_view import KeycardView
keycard_view = KeycardView(self.driver)
self.add_account_generate_account_button.click()
keycard_view.enter_default_pin()
else:
self.enter_your_password_input.send_keys(password)
self.add_account_generate_account_button.click_until_presence_of_element(self.accounts_status_account)
self.driver.info("## Account is added!", device=False)
def get_collectibles_amount(self, collectibles='CryptoKitties'):
self.driver.info("Getting '%s' Collectibles amount" % collectibles)
return Text(self.driver, xpath="//*[@text='%s']//following-sibling::android.widget.TextView" % collectibles)