diff --git a/test/appium/tests/preconditions.py b/test/appium/tests/preconditions.py index 131dd1b96d..3632ae345c 100644 --- a/test/appium/tests/preconditions.py +++ b/test/appium/tests/preconditions.py @@ -1,5 +1,3 @@ - - def set_password_as_new_user(*args): for view in args: view.request_password_icon.click() @@ -7,7 +5,8 @@ def set_password_as_new_user(*args): view.confirm() view.chat_request_input.send_keys("qwerty1234") view.confirm() - view.find_full_text("Tap here to validate your phone number & I\'ll find your friends.") + view.find_full_text( + "Here is your signing phrase. You will use it to verify your transactions. Write it down and keep it safe!") def recover_access(home, passphrase, password, username): @@ -21,4 +20,3 @@ def recover_access(home, passphrase, password, username): login.password_input.send_keys(password) login.sign_in_button.click() login.find_full_text('Chats', 60) - diff --git a/test/appium/tests/test_wallet.py b/test/appium/tests/test_wallet.py index 757e44df9b..0d46fa8193 100644 --- a/test/appium/tests/test_wallet.py +++ b/test/appium/tests/test_wallet.py @@ -1,5 +1,8 @@ +from datetime import datetime + import pytest from tests.basetestcase import SingleDeviceTestCase +from views.base_view import get_ethereum_price_in_usd, verify_transaction_in_ropsten from views.home import HomeView from tests.preconditions import set_password_as_new_user, recover_access from tests import transaction_users @@ -50,7 +53,8 @@ class TestWallet(SingleDeviceTestCase): wallet = chats.wallet_button.click() wallet.send_button.click() wallet.amount_edit_box.click() - wallet.send_as_keyevent('0,1') + amount = '0,00%s' % datetime.now().strftime('%f')[:3] + wallet.send_as_keyevent(amount) wallet.confirm() wallet.chose_recipient_button.click() wallet.deny_button.click() @@ -62,13 +66,40 @@ class TestWallet(SingleDeviceTestCase): chats.sign_later_button.click() wallet.yes_button.click() wallet.ok_button_apk.click() - wallet.transactions_icon.click() - wallet.unsigned_tab.click() - wallet.sign_button.click() + tr_view = wallet.transactions_button.click() + tr_view.unsigned_tab.click() + tr_view.sign_button.click() chats.sign_transaction_button.click() chats.enter_password_input.send_keys(transaction_users[sender]['password']) chats.sign_transaction_button.click() chats.got_it_button.click() chats.verify_balance_is_updated(initial_balance_recipient, recipient_address) + if test == 'sign_later': + tr_view.history_tab.click() + else: + chats.wallet_button.click() + tr_view = wallet.transactions_button.click() + transaction = tr_view.transactions_table.find_transaction(amount=amount.replace(',', '.')) + details_view = transaction.click() + transaction_hash = details_view.get_transaction_hash() + verify_transaction_in_ropsten(address=transaction_users[sender]['address'], transaction_hash=transaction_hash) + @pytest.mark.wallet + def test_balance_and_eth_rate(self): + errors = list() + home = HomeView(self.driver) + recover_access(home, + passphrase=transaction_users['A_USER']['passphrase'], + password=transaction_users['A_USER']['password'], + username=transaction_users['A_USER']['username']) + chats = home.get_chats() + address = transaction_users['A_USER']['address'] + balance = chats.get_balance(address) / 1000000000000000000 + eth_rate = get_ethereum_price_in_usd() + wallet = chats.wallet_button.click() + wallet_balance = wallet.get_eth_value() + if wallet_balance != balance: + errors.append('Balance %s is not equal to the expected %s' % (wallet_balance, balance)) + wallet.verify_eth_rate(eth_rate, errors) + assert not errors, 'errors occurred:\n{}'.format('\n'.join(errors)) diff --git a/test/appium/views/base_view.py b/test/appium/views/base_view.py index a1ff5ad400..b6cdbc63cd 100644 --- a/test/appium/views/base_view.py +++ b/test/appium/views/base_view.py @@ -6,7 +6,6 @@ import requests class BackButton(BaseButton): - def __init__(self, driver): super(BackButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@content-desc='toolbar-back-button']") @@ -19,14 +18,12 @@ class BackButton(BaseButton): class DenyButton(BaseButton): - def __init__(self, driver): super(DenyButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Deny']") class ContactsButton(BaseButton): - def __init__(self, driver): super(ContactsButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Contacts']") @@ -37,7 +34,6 @@ class ContactsButton(BaseButton): class WalletButton(BaseButton): - def __init__(self, driver): super(WalletButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Wallet']") @@ -48,35 +44,56 @@ class WalletButton(BaseButton): class YesButton(BaseButton): - def __init__(self, driver): super(YesButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Yes']") class NoButton(BaseButton): - def __init__(self, driver): super(NoButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='No']") class OkButtonAPK(BaseButton): - def __init__(self, driver): super(OkButtonAPK, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='OK']") class ContinueButtonAPK(BaseButton): - def __init__(self, driver): super(ContinueButtonAPK, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Continue']") -class BaseViewObject(object): +def get_ethereum_price_in_usd() -> float: + url = 'https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD' + return float(requests.request('GET', url).json()['USD']) + +def get_transactions(address: str) -> dict: + url = 'http://ropsten.etherscan.io/api?module=account&action=txlist&address=0x%s&sort=desc' % address + return requests.request('GET', url=url).json()['result'] + + +def is_transaction_successful(transaction_hash: str) -> int: + url = "https://ropsten.etherscan.io/api?module=transaction&action=getstatus&txhash=%s" % transaction_hash + return not int(requests.request('GET', url=url).json()['result']['isError']) + + +def verify_transaction_in_ropsten(address: str, transaction_hash: str): + transactions = get_transactions(address=address) + for transaction in transactions: + if transaction['hash'] == transaction_hash: + logging.info('Transaction is found in Ropsten network') + if not is_transaction_successful(transaction_hash=transaction_hash): + pytest.fail('Transaction is not successful') + return + pytest.fail('Transaction was not found via Ropsten API') + + +class BaseViewObject(object): def __init__(self, driver): self.driver = driver diff --git a/test/appium/views/transactions.py b/test/appium/views/transactions.py new file mode 100644 index 0000000000..8766e1e107 --- /dev/null +++ b/test/appium/views/transactions.py @@ -0,0 +1,80 @@ +import time + +import pytest +from selenium.common.exceptions import NoSuchElementException + +from views.base_element import BaseElement, BaseButton, BaseText +from views.base_view import BaseViewObject + + +class TransactionTable(BaseElement): + def __init__(self, driver): + super(TransactionTable, self).__init__(driver) + self.driver = driver + self.locator = self.Locator.xpath_selector("//android.support.v4.view.ViewPager") + + class TransactionElement(BaseButton): + def __init__(self, driver, amount): + super(TransactionTable.TransactionElement, self).__init__(driver) + self.driver = driver + self.locator = self.Locator.xpath_selector( + "(//android.widget.TextView[contains(@text,'%s ETH')])" % amount) + + class TransactionDetailsViewObject(BaseViewObject): + def __init__(self, driver): + super(TransactionTable.TransactionElement.TransactionDetailsViewObject, self).__init__(driver) + self.driver = driver + self.locators = dict(transaction_hash="//android.widget.TextView[@text='Hash']/following-sibling::*[1]") + + class DetailsTextElement(BaseText): + def __init__(self, driver, locator): + super(TransactionTable.TransactionElement.TransactionDetailsViewObject.DetailsTextElement, + self).__init__(driver) + self.locator = self.Locator.xpath_selector(locator) + + def get_transaction_hash(self) -> str: + return self.DetailsTextElement(driver=self.driver, locator=self.locators['transaction_hash']).text + + def navigate(self): + return self.TransactionDetailsViewObject(self.driver) + + def get_transaction_element(self, amount: str): + return self.TransactionElement(self.driver, amount=amount) + + def find_transaction(self, amount: str) -> TransactionElement: + for i in range(18): + try: + element = self.get_transaction_element(amount=amount) + element.find_element() + return element + except NoSuchElementException: + time.sleep(10) + self.driver.swipe(500, 500, 500, 1000) + pytest.fail('Transaction was not found on Wallet/Transaction screen') + + +class HistoryTab(BaseButton): + def __init__(self, driver): + super(HistoryTab, self).__init__(driver) + self.locator = self.Locator.xpath_selector("//*[@text='HISTORY']") + + +class UnsignedTab(BaseButton): + def __init__(self, driver): + super(UnsignedTab, self).__init__(driver) + self.locator = self.Locator.xpath_selector("//*[@text='UNSIGNED']") + + class SignButton(BaseButton): + def __init__(self, driver): + super(UnsignedTab.SignButton, self).__init__(driver) + self.locator = self.Locator.xpath_selector("//*[@text='SIGN']") + + +class TransactionsViewObject(BaseViewObject): + def __init__(self, driver): + super(TransactionsViewObject, self).__init__(driver) + self.driver = driver + self.history_tab = HistoryTab(self.driver) + self.unsigned_tab = UnsignedTab(self.driver) + self.sign_button = UnsignedTab.SignButton(self.driver) + self.transactions_table = TransactionTable(self.driver) diff --git a/test/appium/views/wallet.py b/test/appium/views/wallet.py index 7a09dac311..69b9b6c9f1 100644 --- a/test/appium/views/wallet.py +++ b/test/appium/views/wallet.py @@ -1,6 +1,7 @@ +import logging + from views.base_view import BaseViewObject -import pytest -from views.base_element import * +from views.base_element import BaseButton, BaseEditBox, BaseText class SendButton(BaseButton): @@ -14,7 +15,7 @@ class AmountEditBox(BaseEditBox, BaseButton): def __init__(self, driver): super(AmountEditBox, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='0.000']") + self.locator = self.Locator.xpath_selector("//*[@text='Amount']/..//android.widget.EditText") class ChooseRecipientButton(BaseButton): @@ -24,35 +25,36 @@ class ChooseRecipientButton(BaseButton): self.locator = self.Locator.xpath_selector("//*[@text='Choose recipient...']") -class TransactionsIcon(BaseButton): +class TransactionsButton(BaseButton): def __init__(self, driver): - super(TransactionsIcon, self).__init__(driver) + super(TransactionsButton, self).__init__(driver) self.locator = self.Locator.xpath_selector('(//android.view.ViewGroup[@content-desc="icon"])[4]') - -class UnsignedTab(BaseButton): - - def __init__(self, driver): - super(UnsignedTab, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='UNSIGNED']") - - class SignButton(BaseButton): - - def __init__(self, driver): - super(UnsignedTab.SignButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='SIGN']") + def navigate(self): + from views.transactions import TransactionsViewObject + return TransactionsViewObject(self.driver) class ChooseFromContactsButton(BaseButton): - def __init__(self, driver): super(ChooseFromContactsButton, self).__init__(driver) self.locator = self.Locator.xpath_selector("//*[@text='Choose From Contacts']") -class WalletViewObject(BaseViewObject): +class EthAssetText(BaseText): + def __init__(self, driver): + super(EthAssetText, self).__init__(driver) + self.locator = self.Locator.xpath_selector("//*[@text='ETH']/../android.widget.TextView[1]") + +class UsdTotalValueText(BaseText): + def __init__(self, driver): + super(UsdTotalValueText, self).__init__(driver) + self.locator = self.Locator.xpath_selector("//*[@text='USD']/../android.widget.TextView[1]") + + +class WalletViewObject(BaseViewObject): def __init__(self, driver): super(WalletViewObject, self).__init__(driver) self.driver = driver @@ -61,6 +63,20 @@ class WalletViewObject(BaseViewObject): self.amount_edit_box = AmountEditBox(self.driver) self.chose_recipient_button = ChooseRecipientButton(self.driver) self.chose_from_contacts_button = ChooseFromContactsButton(self.driver) - self.unsigned_tab = UnsignedTab(self.driver) - self.sign_button = UnsignedTab.SignButton(self.driver) - self.transactions_icon = TransactionsIcon(self.driver) + self.transactions_button = TransactionsButton(self.driver) + self.eth_asset = EthAssetText(self.driver) + self.usd_total_value = UsdTotalValueText(self.driver) + + def get_usd_total_value(self): + return float(self.usd_total_value.text) + + def get_eth_value(self): + return float(self.eth_asset.text) + + def verify_eth_rate(self, expected_rate: int, errors: list): + usd = self.get_usd_total_value() + eth = self.get_eth_value() + current_rate = usd / eth + if round(current_rate, 2) != expected_rate: + errors.append('Current ETH rate %s is not equal to the expected %s' % (current_rate, expected_rate)) + logging.info('Current ETH rate %s is ok' % current_rate)