diff --git a/test/appium/tests/__init__.py b/test/appium/tests/__init__.py index a796509652..54cff83c17 100644 --- a/test/appium/tests/__init__.py +++ b/test/appium/tests/__init__.py @@ -166,3 +166,6 @@ bootnode_address = "enode://a8a97f126f5e3a340cb4db28a1187c325290ec08b2c9a6b1f198 "fd3de3acb09cc38b5a05272e583a2365ad1fa67f66c55b34@167.99.210.203:30404" mailserver_address = "enode://531e252ec966b7e83f5538c19bf1cde7381cc7949026a6e499b6e998e695751aadf26d4c98d5a4eab" \ "fb7cefd31c3c88d600a775f14ed5781520a88ecd25da3c6:status-offline-inbox@35.225.227.79:30504" + +camera_access_error_text = "To grant the required camera permission, please go to your system settings " \ + "and make sure that Status > Camera is selected." diff --git a/test/appium/tests/atomic/account_management/test_profile.py b/test/appium/tests/atomic/account_management/test_profile.py index 7f3f3da215..36c26242c1 100644 --- a/test/appium/tests/atomic/account_management/test_profile.py +++ b/test/appium/tests/atomic/account_management/test_profile.py @@ -1,6 +1,6 @@ import pytest -from tests import marks, group_chat_users, basic_user, bootnode_address, mailserver_address +from tests import marks, group_chat_users, basic_user, bootnode_address, mailserver_address, camera_access_error_text from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase from views.sign_in_view import SignInView @@ -192,6 +192,38 @@ class TestProfileSingleDevice(SingleDeviceTestCase): for text in basic_user['username'], 'In contacts', 'Send transaction', 'Send message', 'Contact code': chat_view.find_full_text(text) + @marks.testrail_id(2177) + def test_deny_camera_access_changing_profile_photo(self): + sign_in = SignInView(self.driver) + sign_in.create_user() + profile = sign_in.profile_button.click() + profile.edit_button.click() + profile.edit_picture_button.click() + profile.capture_button.click() + for _ in range(2): + profile.deny_button.click() + profile.element_by_text(camera_access_error_text).wait_for_visibility_of_element(3) + profile.ok_button.click() + profile.edit_picture_button.click() + profile.capture_button.click() + profile.deny_button.wait_for_visibility_of_element(2) + + @marks.testrail_id(2178) + def test_deny_device_storage_access_changing_profile_photo(self): + sign_in = SignInView(self.driver) + sign_in.create_user() + profile = sign_in.profile_button.click() + profile.edit_button.click() + profile.edit_picture_button.click() + profile.select_from_gallery_button.click() + for _ in range(2): + profile.deny_button.click() + profile.element_by_text(camera_access_error_text).wait_for_visibility_of_element(3) + profile.ok_button.click() + profile.edit_picture_button.click() + profile.select_from_gallery_button.click() + profile.deny_button.wait_for_visibility_of_element(2) + @marks.all @marks.account diff --git a/test/appium/tests/atomic/account_management/test_wallet_management.py b/test/appium/tests/atomic/account_management/test_wallet_management.py index f4666eab30..fe1d4e5d64 100644 --- a/test/appium/tests/atomic/account_management/test_wallet_management.py +++ b/test/appium/tests/atomic/account_management/test_wallet_management.py @@ -1,6 +1,6 @@ import pytest -from tests import marks, transaction_users +from tests import marks, transaction_users, camera_access_error_text from tests.base_test_case import SingleDeviceTestCase from views.sign_in_view import SignInView @@ -130,3 +130,19 @@ class TestWallet(SingleDeviceTestCase): send_transaction.select_asset_button.click() if send_transaction.asset_by_name(asset_name).is_element_displayed(): pytest.fail('Collectibles can be sent from wallet') + + @marks.testrail_id(2176) + def test_deny_camera_access_scanning_wallet_adders(self): + sign_in = SignInView(self.driver) + sign_in.create_user() + wallet = sign_in.wallet_button.click() + wallet.set_up_wallet() + send_transaction = wallet.send_transaction_button.click() + send_transaction.chose_recipient_button.click() + send_transaction.scan_qr_code_button.click() + send_transaction.deny_button.click() + send_transaction.element_by_text(camera_access_error_text).wait_for_visibility_of_element(3) + send_transaction.ok_button.click() + send_transaction.chose_recipient_button.click() + send_transaction.scan_qr_code_button.click() + send_transaction.deny_button.wait_for_visibility_of_element(2) diff --git a/test/appium/tests/atomic/browsing/test_browsing.py b/test/appium/tests/atomic/browsing/test_browsing.py index 76ff95254e..7a3298b361 100644 --- a/test/appium/tests/atomic/browsing/test_browsing.py +++ b/test/appium/tests/atomic/browsing/test_browsing.py @@ -10,8 +10,7 @@ class TestBrowsing(SingleDeviceTestCase): @marks.testrail_id(1411) def test_browse_page_with_non_english_text(self): sign_in = SignInView(self.driver) - sign_in.create_user() - home_view = sign_in.get_home_view() + home_view = sign_in.create_user() start_new_chat = home_view.plus_button.click() start_new_chat.open_d_app_button.click() start_new_chat.enter_url_editbox.set_value('www.wikipedia.org') @@ -25,20 +24,21 @@ class TestBrowsing(SingleDeviceTestCase): @marks.testrail_id(1412) def test_open_invalid_link(self): sign_in = SignInView(self.driver) - sign_in.create_user() - home_view = sign_in.get_home_view() + home_view = sign_in.create_user() start_new_chat = home_view.plus_button.click() start_new_chat.open_d_app_button.click() start_new_chat.enter_url_editbox.set_value('invalid.takoe') start_new_chat.confirm() browsing_view = home_view.get_base_web_view() browsing_view.find_text_part('Unable to load page') + browsing_view.browser_cross_icon.click() + if home_view.element_by_text('Browser').is_element_displayed(): + pytest.fail('Browser entity is shown for an invalid link') @marks.testrail_id(3705) def test_connection_is_not_secure(self): sign_in = SignInView(self.driver) - sign_in.create_user() - home_view = sign_in.get_home_view() + home_view = sign_in.create_user() start_new_chat = home_view.plus_button.click() start_new_chat.open_d_app_button.click() start_new_chat.enter_url_editbox.set_value('google.com') diff --git a/test/appium/tests/atomic/chats/test_chats_management.py b/test/appium/tests/atomic/chats/test_chats_management.py index 19cd9d5f3f..f967c15d16 100644 --- a/test/appium/tests/atomic/chats/test_chats_management.py +++ b/test/appium/tests/atomic/chats/test_chats_management.py @@ -1,6 +1,6 @@ import pytest -from tests import marks, group_chat_users, basic_user +from tests import marks, group_chat_users, basic_user, camera_access_error_text from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase from views.sign_in_view import SignInView @@ -121,6 +121,30 @@ class TestChatManagement(SingleDeviceTestCase): self.errors.append("Public chat '%s' is shown after re-login, but the chat has been deleted" % chat_name) self.verify_no_errors() + @marks.testrail_id(2172) + def test_incorrect_contact_code_start_new_chat(self): + sign_in = SignInView(self.driver) + home = sign_in.create_user() + start_new_chat = home.plus_button.click() + start_new_chat.start_new_chat_button.click() + start_new_chat.public_key_edit_box.set_value(group_chat_users['B_USER']['public_key'][:-1]) + start_new_chat.confirm() + if not start_new_chat.element_by_text('Please scan a valid contact code').is_element_displayed(): + pytest.fail('Error is not shown for invalid public key') + + @marks.testrail_id(2175) + def test_deny_camera_access_scanning_contact_code(self): + sign_in = SignInView(self.driver) + home = sign_in.create_user() + start_new_chat = home.plus_button.click() + start_new_chat.start_new_chat_button.click() + start_new_chat.scan_contact_code_button.click() + start_new_chat.deny_button.click() + start_new_chat.element_by_text(camera_access_error_text).wait_for_visibility_of_element(3) + start_new_chat.ok_button.click() + start_new_chat.scan_contact_code_button.click() + start_new_chat.deny_button.wait_for_visibility_of_element(2) + @marks.chat class TestChatManagementMultipleDevice(MultipleDeviceTestCase): diff --git a/test/appium/tests/atomic/chats/test_commands.py b/test/appium/tests/atomic/chats/test_commands.py index e4e27c96fa..b34a98dbe1 100644 --- a/test/appium/tests/atomic/chats/test_commands.py +++ b/test/appium/tests/atomic/chats/test_commands.py @@ -3,7 +3,7 @@ from _pytest.outcomes import Failed from decimal import Decimal as d from selenium.common.exceptions import TimeoutException -from tests import marks, transaction_users, common_password, group_chat_users +from tests import marks, transaction_users, common_password, group_chat_users, transaction_users_wallet from tests.base_test_case import MultipleDeviceTestCase, SingleDeviceTestCase from views.sign_in_view import SignInView @@ -408,3 +408,66 @@ class TestCommandsSingleDevices(SingleDeviceTestCase): self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount) if not chat.chat_element_by_text(amount).contains_text('Confirmed', wait_time=90): pytest.fail('Transaction state is not updated on the sender side') + + @marks.testrail_id(3790) + def test_insufficient_funds_1_1_chat_0_balance(self): + sign_in_view = SignInView(self.driver) + sign_in_view.create_user() + wallet_view = sign_in_view.wallet_button.click() + wallet_view.set_up_wallet() + home_view = wallet_view.home_button.click() + chat_view = home_view.add_contact(transaction_users['H_USER']['public_key']) + chat_view.commands_button.click() + chat_view.send_command.click() + chat_view.asset_by_name('ETH').click() + chat_view.send_as_keyevent('1') + chat_view.send_message_button.click() + send_transaction = chat_view.get_send_transaction_view() + error_text = send_transaction.element_by_text('Insufficient funds') + if not error_text.is_element_displayed(): + self.errors.append("'Insufficient funds' error is now shown when sending 1 ETH from chat with balance 0") + send_transaction.back_button.click() + chat_view.commands_button.click() + chat_view.send_command.click() + chat_view.asset_by_name('STT').click() + chat_view.send_as_keyevent('1') + chat_view.send_message_button.click() + if not error_text.is_element_displayed(): + self.errors.append("'Insufficient funds' error is now shown when sending 1 STT from chat with balance 0") + self.verify_no_errors() + + @marks.testrail_id(3793) + def test_insufficient_funds_1_1_chat_positive_balance(self): + sender = transaction_users_wallet['A_USER'] + sign_in_view = SignInView(self.driver) + sign_in_view.recover_access(sender['passphrase'], sender['password']) + wallet_view = sign_in_view.wallet_button.click() + wallet_view.set_up_wallet() + eth_value = wallet_view.get_eth_value() + stt_value = wallet_view.get_stt_value() + if eth_value == 0 or stt_value == 0: + pytest.fail('No funds!') + home_view = wallet_view.home_button.click() + chat_view = home_view.add_contact(transaction_users['H_USER']['public_key']) + chat_view.commands_button.click() + chat_view.send_command.click() + chat_view.asset_by_name('ETH').click() + chat_view.send_as_keyevent(str(round(eth_value + 1))) + chat_view.send_message_button.click() + send_transaction = chat_view.get_send_transaction_view() + error_text = send_transaction.element_by_text('Insufficient funds') + if not error_text.is_element_displayed(): + self.errors.append( + "'Insufficient funds' error is now shown when sending %s ETH from chat with balance %s" % ( + round(eth_value + 1), eth_value)) + send_transaction.back_button.click() + chat_view.commands_button.click() + chat_view.send_command.click() + chat_view.asset_by_name('STT').click() + chat_view.send_as_keyevent(str(round(stt_value + 1))) + chat_view.send_message_button.click() + if not error_text.is_element_displayed(): + self.errors.append( + "'Insufficient funds' error is now shown when sending %s STT from chat with balance %s" % ( + round(stt_value + 1), stt_value)) + self.verify_no_errors() diff --git a/test/appium/tests/atomic/transactions/test_wallet.py b/test/appium/tests/atomic/transactions/test_wallet.py index 1336a54706..6c6fd2461c 100644 --- a/test/appium/tests/atomic/transactions/test_wallet.py +++ b/test/appium/tests/atomic/transactions/test_wallet.py @@ -1,4 +1,7 @@ import random + +import pytest + from tests import transaction_users, transaction_users_wallet, marks, common_password from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase from views.sign_in_view import SignInView @@ -260,7 +263,7 @@ class TestTransactionWalletSingleDevice(SingleDeviceTestCase): self.verify_no_errors() @marks.testrail_id(1405) - def test_insufficient_funds_error_wallet(self): + def test_send_valid_amount_after_insufficient_funds_error(self): sender = transaction_users['H_USER'] sign_in_view = SignInView(self.driver) sign_in_view.recover_access(sender['passphrase'], sender['password']) @@ -287,6 +290,51 @@ class TestTransactionWalletSingleDevice(SingleDeviceTestCase): send_transaction.got_it_button.click() self.network_api.find_transaction_by_unique_amount(sender['address'], valid_amount) + @marks.testrail_id(3764) + def test_insufficient_funds_wallet_0_balance(self): + sign_in_view = SignInView(self.driver) + sign_in_view.create_user() + wallet_view = sign_in_view.wallet_button.click() + wallet_view.set_up_wallet() + send_transaction = wallet_view.send_transaction_button.click() + send_transaction.amount_edit_box.set_value(1) + error_text = send_transaction.element_by_text('Insufficient funds') + if not error_text.is_element_displayed(): + self.errors.append("'Insufficient funds' error is now shown when sending 1 ETH from wallet with balance 0") + send_transaction.select_asset_button.click() + send_transaction.asset_by_name('STT').click() + send_transaction.amount_edit_box.set_value(1) + if not error_text.is_element_displayed(): + self.errors.append("'Insufficient funds' error is now shown when sending 1 STT from wallet with balance 0") + self.verify_no_errors() + + @marks.testrail_id(3792) + def test_insufficient_funds_wallet_positive_balance(self): + sender = transaction_users_wallet['A_USER'] + sign_in_view = SignInView(self.driver) + sign_in_view.recover_access(sender['passphrase'], sender['password']) + wallet_view = sign_in_view.wallet_button.click() + wallet_view.set_up_wallet() + eth_value = wallet_view.get_eth_value() + stt_value = wallet_view.get_stt_value() + if eth_value == 0 or stt_value == 0: + pytest.fail('No funds!') + send_transaction = wallet_view.send_transaction_button.click() + send_transaction.amount_edit_box.set_value(round(eth_value + 1)) + error_text = send_transaction.element_by_text('Insufficient funds') + if not error_text.is_element_displayed(): + self.errors.append( + "'Insufficient funds' error is now shown when sending %s ETH from wallet with balance %s" % ( + round(eth_value + 1), eth_value)) + send_transaction.select_asset_button.click() + send_transaction.asset_by_name('STT').click() + send_transaction.amount_edit_box.set_value(round(stt_value + 1)) + if not error_text.is_element_displayed(): + self.errors.append( + "'Insufficient funds' error is now shown when sending %s STT from wallet with balance %s" % ( + round(stt_value + 1), stt_value)) + self.verify_no_errors() + @marks.testrail_id(3728) def test_modify_transaction_fee_values(self): sender = transaction_users['H_USER'] diff --git a/test/appium/views/base_view.py b/test/appium/views/base_view.py index 0b382764b1..be66fa5e0f 100644 --- a/test/appium/views/base_view.py +++ b/test/appium/views/base_view.py @@ -43,7 +43,7 @@ class AllowButton(BaseButton): class DenyButton(BaseButton): def __init__(self, driver): super(DenyButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='Deny']") + self.locator = self.Locator.xpath_selector("//*[@text='DENY']") class DeleteButton(BaseButton): @@ -337,11 +337,17 @@ class BaseView(object): return element.wait_for_element(wait_time) def element_by_accessibility_id(self, accessibility_id, element_type='button'): - info("Looking for an element by text: '%s'" % accessibility_id) + info("Looking for an element by accessibility id: '%s'" % accessibility_id) element = self.element_types[element_type](self.driver) element.locator = element.Locator.accessibility_id(accessibility_id) return element + def element_by_xpath(self, xpath, element_type='button'): + info("Looking for an element by xpath: '%s'" % xpath) + element = self.element_types[element_type](self.driver) + element.locator = element.Locator.xpath_selector(xpath) + return element + def swipe_down(self): self.driver.swipe(500, 500, 500, 1000) diff --git a/test/appium/views/contacts_view.py b/test/appium/views/contacts_view.py index 87b6191998..a1d436681f 100644 --- a/test/appium/views/contacts_view.py +++ b/test/appium/views/contacts_view.py @@ -26,6 +26,12 @@ class PublicKeyEditBox(BaseEditBox): self.locator = self.Locator.accessibility_id('enter-contact-code-input') +class ScanContactCodeButton(BaseEditBox): + def __init__(self, driver): + super(ScanContactCodeButton, self).__init__(driver) + self.locator = self.Locator.accessibility_id('scan-contact-code-button') + + class ConfirmPublicKeyButton(BaseButton): def __init__(self, driver): super(ConfirmPublicKeyButton, self).__init__(driver) @@ -41,6 +47,7 @@ class ContactsView(BaseView): self.plus_button = PlusButton(self.driver) self.public_key_edit_box = PublicKeyEditBox(self.driver) + self.scan_contact_code_button = ScanContactCodeButton(self.driver) self.confirm_public_key_button = ConfirmPublicKeyButton(self.driver) self.status_test_dapp_button = StatusTestDAppButton(self.driver) diff --git a/test/appium/views/home_view.py b/test/appium/views/home_view.py index 288ffd4ce5..26a86da794 100644 --- a/test/appium/views/home_view.py +++ b/test/appium/views/home_view.py @@ -149,7 +149,7 @@ class HomeView(BaseView): def join_public_chat(self, chat_name: str): start_new_chat = self.plus_button.click() start_new_chat.join_public_chat_button.click() - start_new_chat.chat_name_editbox.send_keys(chat_name) + start_new_chat.chat_name_editbox.set_value(chat_name) time.sleep(2) start_new_chat.confirm() from views.chat_view import ChatView diff --git a/test/appium/views/profile_view.py b/test/appium/views/profile_view.py index 04b045e9cc..d113dd9c47 100644 --- a/test/appium/views/profile_view.py +++ b/test/appium/views/profile_view.py @@ -60,7 +60,7 @@ class NetworkSettingsButton(BaseButton): class NetworkButton(BaseButton): def __init__(self, driver, network): super(NetworkSettingsButton.NetworkButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector('//*[@text="' + network + '"]') + self.locator = self.Locator.text_selector(network) class ConnectButton(BaseButton): @@ -95,7 +95,7 @@ class ConfirmLogoutButton(BaseButton): def __init__(self, driver): super(ConfirmLogoutButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='LOG OUT']") + self.locator = self.Locator.text_selector('LOG OUT') class UserNameText(BaseText): @@ -157,7 +157,7 @@ class AdvancedButton(BaseButton): def __init__(self, driver): super(AdvancedButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector('//*[@text="Advanced"]') + self.locator = self.Locator.text_selector('Advanced') def click(self): self.scroll_to_element().click() @@ -191,7 +191,7 @@ class RecoveryPhraseWordNumberText(BaseText): def __init__(self, driver): super(RecoveryPhraseWordNumberText, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[contains(@text,'#')]") + self.locator = self.Locator.text_part_selector('#') @property def number(self): @@ -210,7 +210,7 @@ class OkGotItButton(BaseButton): def __init__(self, driver): super(OkGotItButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='OK, GOT IT']") + self.locator = self.Locator.text_selector('OK, GOT IT') class DebugModeToggle(BaseButton): @@ -228,7 +228,14 @@ class SelectFromGalleryButton(BaseButton): def __init__(self, driver): super(SelectFromGalleryButton, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='Select from gallery']") + self.locator = self.Locator.text_selector('Select from gallery') + + +class CaptureButton(BaseButton): + + def __init__(self, driver): + super(CaptureButton, self).__init__(driver) + self.locator = self.Locator.text_selector('Capture') class MainCurrencyButton(BaseButton): @@ -406,7 +413,9 @@ class ProfileView(BaseView): self.recovery_phrase_word_number = RecoveryPhraseWordNumberText(self.driver) self.recovery_phrase_word_input = RecoveryPhraseWordInput(self.driver) self.ok_got_it_button = OkGotItButton(self.driver) + self.select_from_gallery_button = SelectFromGalleryButton(self.driver) + self.capture_button = CaptureButton(self.driver) self.help_button = HelpButton(self.driver) self.request_feature_button = RequestFeatureButton(self.driver) diff --git a/test/appium/views/send_transaction_view.py b/test/appium/views/send_transaction_view.py index 223e5544a8..bdf1e86a3a 100644 --- a/test/appium/views/send_transaction_view.py +++ b/test/appium/views/send_transaction_view.py @@ -65,6 +65,12 @@ class EnterRecipientAddressButton(BaseButton): self.locator = self.Locator.xpath_selector("//*[@text='Enter recipient address']") +class ScanQRCodeButton(BaseButton): + def __init__(self, driver): + super(ScanQRCodeButton, self).__init__(driver) + self.locator = self.Locator.text_selector('Scan QR code') + + class EnterRecipientAddressInput(BaseEditBox): def __init__(self, driver): super(EnterRecipientAddressInput, self).__init__(driver) @@ -142,6 +148,7 @@ class SendTransactionView(BaseView): self.chose_recipient_button = ChooseRecipientButton(self.driver) self.enter_recipient_address_button = EnterRecipientAddressButton(self.driver) + self.scan_qr_code_button = ScanQRCodeButton(self.driver) self.enter_recipient_address_input = EnterRecipientAddressInput(self.driver) self.first_recipient_button = FirstRecipient(self.driver) self.recent_recipients_button = RecentRecipientsButton(self.driver) diff --git a/test/appium/views/wallet_view.py b/test/appium/views/wallet_view.py index 8661be03c1..cd44320a01 100644 --- a/test/appium/views/wallet_view.py +++ b/test/appium/views/wallet_view.py @@ -60,7 +60,13 @@ class ChooseFromContactsButton(BaseButton): class EthAssetText(BaseText): def __init__(self, driver): super(EthAssetText, self).__init__(driver) - self.locator = self.Locator.xpath_selector("//*[@text='ETH']/../android.widget.TextView[1]") + self.locator = self.Locator.accessibility_id('eth-asset-value-text') + + +class STTAssetText(BaseText): + def __init__(self, driver): + super(STTAssetText, self).__init__(driver) + self.locator = self.Locator.accessibility_id('stt-asset-value-text') class UsdTotalValueText(BaseText): @@ -180,7 +186,8 @@ class WalletView(BaseView): self.send_transaction_button = SendTransactionButton(self.driver) self.transaction_history_button = TransactionHistoryButton(self.driver) - self.eth_asset = EthAssetText(self.driver) + self.eth_asset_value = EthAssetText(self.driver) + self.stt_asset_value = STTAssetText(self.driver) self.usd_total_value = UsdTotalValueText(self.driver) self.send_transaction_request = SendTransactionRequestButton(self.driver) @@ -207,7 +214,10 @@ class WalletView(BaseView): return float(re.sub('[$,]', '', self.usd_total_value.text)) def get_eth_value(self): - return float(self.eth_asset.text) + return float(self.eth_asset_value.text) + + def get_stt_value(self): + return float(self.stt_asset_value.text) def verify_currency_balance(self, expected_rate: int, errors: list): usd = self.get_usd_total_value()