status-mobile/test/appium/views/base_view.py

653 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import base64
import pytest
import random
import re
import string
import zbarlight
from PIL import Image
from appium.webdriver.common.touch_action import TouchAction
from datetime import datetime
from eth_keys import datatypes
from io import BytesIO
from selenium.common.exceptions import NoSuchElementException, TimeoutException, StaleElementReferenceException
from support.device_apps import start_web_browser
from tests import common_password
from views.base_element import BaseButton, BaseElement, BaseEditBox, BaseText
class BackButton(BaseButton):
def __init__(self, driver):
super(BackButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id('back-button')
def click(self, times_to_click: int = 1):
for _ in range(times_to_click):
self.find_element().click()
self.driver.info('Tap on %s' % self.name)
return self.navigate()
class AllowButton(BaseButton):
def __init__(self, driver):
super(AllowButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='Allow' or @text='ALLOW']")
def click(self, times_to_click=3):
try:
for _ in range(times_to_click):
self.find_element().click()
self.driver.info('Tap on %s' % self.name)
except NoSuchElementException:
pass
class DenyButton(BaseButton):
def __init__(self, driver):
super(DenyButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='Deny' or @text='DENY']")
class DeleteButton(BaseButton):
def __init__(self, driver):
super(DeleteButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='DELETE']")
class YesButton(BaseButton):
def __init__(self, driver):
super(YesButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='YES' or @text='GOT IT']")
class NoButton(BaseButton):
def __init__(self, driver):
super(NoButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='No']")
class OkButton(BaseButton):
def __init__(self, driver):
super(OkButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='OK']")
class ContinueButton(BaseButton):
def __init__(self, driver):
super(ContinueButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='CONTINUE' or @text='Continue']")
class TabButton(BaseButton):
@property
def counter(self):
class Counter(BaseText):
def __init__(self, driver, parent_locator):
super(Counter, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//*[@content-desc='%s']//android.view.ViewGroup[2]/android.widget.TextView" % parent_locator)
return Counter(self.driver, self.locator.value)
class HomeButton(TabButton):
def __init__(self, driver):
super(HomeButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id('home-tab-button')
def navigate(self):
from views.home_view import HomeView
return HomeView(self.driver)
def click(self):
from views.home_view import PlusButton
self.click_until_presence_of_element(PlusButton(self.driver))
return self.navigate()
class DappTabButton(TabButton):
def __init__(self, driver):
super(DappTabButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id('dapp-tab-button')
def navigate(self):
from views.dapps_view import DappsView
return DappsView(self.driver)
def click(self):
from views.dapps_view import EnterUrlEditbox
self.click_until_presence_of_element(EnterUrlEditbox(self.driver))
return self.navigate()
class WalletButton(TabButton):
def __init__(self, driver):
super(WalletButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id('wallet-tab-button')
def navigate(self):
from views.wallet_view import WalletView
return WalletView(self.driver)
def click(self):
self.driver.info('Tap on %s' % self.name)
from views.wallet_view import MultiaccountMoreOptions
self.click_until_presence_of_element(MultiaccountMoreOptions(self.driver))
return self.navigate()
class ProfileButton(TabButton):
def __init__(self, driver):
super(ProfileButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id('profile-tab-button')
def navigate(self):
from views.profile_view import ProfileView
return ProfileView(self.driver)
def click(self):
from views.profile_view import DefaultUserNameText
self.click_until_presence_of_element(DefaultUserNameText(self.driver))
return self.navigate()
class SaveButton(BaseButton):
def __init__(self, driver):
super(SaveButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//android.widget.TextView[@text='Save']")
class NextButton(BaseButton):
def __init__(self, driver):
super(NextButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//android.widget.TextView[@text='Next']")
class AddButton(BaseButton):
def __init__(self, driver):
super(AddButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//android.widget.TextView[@text='Add']")
class DoneButton(BaseButton):
def __init__(self, driver):
super(DoneButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@content-desc='done-button' or contains(@text, 'Done')]")
class AppsButton(BaseButton):
def __init__(self, driver):
super(AppsButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id("Apps")
class StatusAppIcon(BaseButton):
def __init__(self, driver):
super(StatusAppIcon, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//*[@text='Status']")
class SendMessageButton(BaseButton):
def __init__(self, driver):
super(SendMessageButton, self).__init__(driver)
self.locator = self.Locator.accessibility_id("send-message-button")
def click(self):
self.find_element().click()
self.driver.info('Tap on %s' % self.name)
class ConnectionStatusText(BaseText):
def __init__(self, driver):
super(ConnectionStatusText, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//*[@content-desc='connection-status-text']/android.widget.TextView")
class OkContinueButton(BaseButton):
def __init__(self, driver):
super(OkContinueButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='OK, CONTINUE']")
class DiscardButton(BaseButton):
def __init__(self, driver):
super(DiscardButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='DISCARD']")
class ConfirmButton(BaseButton):
def __init__(self, driver):
super(ConfirmButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='CONFIRM']")
class ProgressBar(BaseElement):
def __init__(self, driver, parent_locator: str = ''):
super(ProgressBar, self).__init__(driver)
self.locator = self.Locator.xpath_selector(parent_locator + '//android.widget.ProgressBar')
class CrossIcon(BaseButton):
def __init__(self, driver):
super(CrossIcon, self).__init__(driver)
self.locator = self.Locator.xpath_selector('(//android.view.ViewGroup[@content-desc="icon"])[1]')
class CrossIconInWelcomeScreen(BaseButton):
def __init__(self, driver):
super(CrossIconInWelcomeScreen, self).__init__(driver)
self.locator = self.Locator.accessibility_id('hide-home-button')
class ShowRoots(BaseButton):
def __init__(self, driver):
super(ShowRoots, self).__init__(driver)
self.locator = self.Locator.accessibility_id('Show roots')
class GetStartedButton(BaseButton):
def __init__(self, driver):
super(GetStartedButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='Get started']")
class AssetButton(BaseButton):
def __init__(self, driver, asset_name):
super(AssetButton, self).__init__(driver)
self.asset_name = asset_name
self.locator = self.Locator.xpath_selector('(//*[@content-desc=":' + self.asset_name + '-asset-value"])[2]')
@property
def name(self):
return self.asset_name + self.__class__.__name__
def click(self):
self.wait_for_element().click()
self.driver.info('Tap on %s' % self.name)
class OpenInStatusButton(BaseButton):
def __init__(self, driver):
super(OpenInStatusButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector('//*[@text="Open in Status"]')
def click(self):
self.wait_for_visibility_of_element()
# using sleep is wrong, but implicit wait for element can't help in particular case
time.sleep(3)
self.swipe_to_web_element()
self.wait_for_element().click()
class OkGotItButton(BaseButton):
def __init__(self,driver):
super(OkGotItButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@text='OK, got it']")
def click(self):
self.wait_for_element().click()
self.wait_for_invisibility_of_element()
class AirplaneModeButton(BaseButton):
def __init__(self, driver):
super(AirplaneModeButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//*[@content-desc='Airplane mode']")
def click(self):
action = TouchAction(self.driver)
action.press(None, 50, 0).move_to(None, 50, 300).perform()
super(AirplaneModeButton, self).click()
action.press(None, 50, 600).move_to(None, 50, 0).perform()
class BaseView(object):
def __init__(self, driver):
self.driver = driver
self.send_message_button = SendMessageButton(self.driver)
self.home_button = HomeButton(self.driver)
self.wallet_button = WalletButton(self.driver)
self.profile_button = ProfileButton(self.driver)
self.dapp_tab_button = DappTabButton(self.driver)
self.yes_button = YesButton(self.driver)
self.no_button = NoButton(self.driver)
self.back_button = BackButton(self.driver)
self.allow_button = AllowButton(self.driver)
self.deny_button = DenyButton(self.driver)
self.continue_button = ContinueButton(self.driver)
self.ok_button = OkButton(self.driver)
self.next_button = NextButton(self.driver)
self.add_button = AddButton(self.driver)
self.save_button = SaveButton(self.driver)
self.done_button = DoneButton(self.driver)
self.delete_button = DeleteButton(self.driver)
self.ok_continue_button = OkContinueButton(self.driver)
self.discard_button = DiscardButton(self.driver)
self.confirm_button = ConfirmButton(self.driver)
self.connection_status = ConnectionStatusText(self.driver)
self.cross_icon = CrossIcon(self.driver)
self.show_roots_button = ShowRoots(self.driver)
self.get_started_button = GetStartedButton(self.driver)
self.ok_got_it_button = OkGotItButton(self.driver)
self.progress_bar = ProgressBar(self.driver)
self.cross_icon_iside_welcome_screen_button = CrossIconInWelcomeScreen(self.driver)
# external browser
self.open_in_status_button = OpenInStatusButton(self.driver)
self.apps_button = AppsButton(self.driver)
self.status_app_icon = StatusAppIcon(self.driver)
self.airplane_mode_button = AirplaneModeButton(self.driver)
self.element_types = {
'base': BaseElement,
'button': BaseButton,
'edit_box': BaseEditBox,
'text': BaseText
}
def accept_agreements(self):
iterations = int()
self.close_native_device_dialog("Messages")
self.close_native_device_dialog("Youtube")
while iterations <= 1 and (self.ok_button.is_element_displayed(2) or
self.continue_button.is_element_displayed(2)):
for button in self.ok_button, self.continue_button:
try:
button.wait_for_element(3)
button.click()
except (NoSuchElementException, TimeoutException):
pass
iterations += 1
def close_native_device_dialog(self, alert_text_part):
element = self.element_by_text_part(alert_text_part)
if element.is_element_present(1):
self.driver.info("Dismissing %s alert" % alert_text_part)
self.dismiss_alert()
def dismiss_alert(self):
self.driver.info("Dismiss alert")
self.driver.switch_to.alert().dismiss()
@property
def logcat(self):
logcat = self.driver.get_log("logcat")
if len(logcat) > 1000:
return str([i for i in logcat if 'appium' not in str(i).lower()])
raise TimeoutError('Logcat is empty')
def confirm(self):
self.driver.info("Tap 'Confirm' on native keyboard")
self.driver.press_keycode(66)
def confirm_until_presence_of_element(self, desired_element, attempts=3):
counter = 0
while not desired_element.is_element_present(1) and counter <= attempts:
try:
self.confirm()
self.driver.info('Wait for %s' % desired_element.name)
desired_element.wait_for_element(5)
return
except TimeoutException:
counter += 1
def just_fyi(self, string):
self.driver.info('=========================================================================')
self.driver.info(string)
def click_system_back_button(self, times=1):
self.driver.info('Click system back button')
for _ in range(times):
self.driver.press_keycode(4)
def cut_text(self):
self.driver.info('Cut text')
self.driver.press_keycode(277)
def copy_text(self):
self.driver.info('Copy text')
self.driver.press_keycode(278)
def paste_text(self):
self.driver.info('Paste text')
self.driver.press_keycode(279)
def send_as_keyevent(self, string):
keys = {'0': 7, '1': 8, '2': 9, '3': 10, '4': 11, '5': 12, '6': 13, '7': 14, '8': 15, '9': 16,
',': 55, '-': 69, '+': 81, '.': 56, '/': 76, '\\': 73, ';': 74, ' ': 62,
'[': 71, ']': 72, '=': 70, '\n': 66, '_': [69, 5], ':': [74, 5],
'a': 29, 'b': 30, 'c': 31, 'd': 32, 'e': 33, 'f': 34, 'g': 35, 'h': 36, 'i': 37, 'j': 38,
'k': 39, 'l': 40, 'm': 41, 'n': 42, 'o': 43, 'p': 44, 'q': 45, 'r': 46, 's': 47, 't': 48,
'u': 49, 'v': 50, 'w': 51, 'x': 52, 'y': 53, 'z': 54}
time.sleep(3)
self.driver.info("Enter '%s' using native keyboard" % string)
for i in string:
if i.isalpha() and i.isupper():
keycode, metastate = keys[i.lower()], 64 # META_SHIFT_LEFT_ON Constant Value: 64. Example: i='n' -> 'N'
elif type(keys[i]) is list:
keycode, metastate = keys[i][0], keys[i][1]
else:
keycode, metastate = keys[i], None
self.driver.press_keycode(keycode=keycode, metastate=metastate)
def find_full_text(self, text, wait_time=60):
self.driver.info("Looking for full text: '%s'" % text)
element = BaseElement(self.driver)
element.locator = element.Locator.text_selector(text)
return element.wait_for_element(wait_time)
def find_text_part(self, text, wait_time=60):
self.driver.info("Looking for a text part: '%s'" % text)
element = BaseElement(self.driver)
element.locator = element.Locator.text_part_selector(text)
return element.wait_for_element(wait_time)
def element_by_text(self, text, element_type='button'):
self.driver.info("Looking for an element by text: '%s'" % text)
element = self.element_types[element_type](self.driver)
element.locator = element.Locator.text_selector(text)
return element
def element_by_text_part(self, text, element_type='button'):
self.driver.info("Looking for an element by text part: '%s'" % text)
element = self.element_types[element_type](self.driver)
element.locator = element.Locator.text_part_selector(text)
return element
def element_starts_with_text(self, text, element_type='base'):
self.driver.info("Looking for full text: '%s'" % text)
element = self.element_types[element_type](self.driver)
element.locator = element.Locator.xpath_selector("//*[starts-with(@text,'%s')]" % text)
return element
def wait_for_element_starts_with_text(self, text, wait_time=60):
self.driver.info("Looking for full text: '%s'" % text)
element = BaseElement(self.driver)
element.locator = element.Locator.xpath_selector("//*[starts-with(@text,'%s')]" % text)
return element.wait_for_element(wait_time)
def element_by_accessibility_id(self, accessibility_id, element_type='button'):
self.driver.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'):
self.driver.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_up(self):
size = self.driver.get_window_size()
self.driver.swipe(size["width"]*0.5, size["height"]*0.8, size["width"]*0.5, size["height"]*0.2)
def swipe_down(self):
size = self.driver.get_window_size()
self.driver.swipe(size["width"]*0.5, size["height"]*0.2, size["width"]*0.5, size["height"]*0.8)
def swipe_left(self):
size = self.driver.get_window_size()
self.driver.swipe(size["width"]*0.8, size["height"]*0.8, size["width"]*0.2, size["height"]*0.8)
def swipe_right(self):
size = self.driver.get_window_size()
self.driver.swipe(size["width"]*0.2, size["height"]*0.8, size["width"]*0.8, size["height"]*0.8)
def get_status_test_dapp_view(self):
from views.web_views.status_test_dapp import StatusTestDAppView
return StatusTestDAppView(self.driver)
def get_home_view(self):
from views.home_view import HomeView
return HomeView(self.driver)
def get_chat_view(self):
from views.chat_view import ChatView
return ChatView(self.driver)
def get_sign_in_view(self):
from views.sign_in_view import SignInView
return SignInView(self.driver)
def get_send_transaction_view(self):
from views.send_transaction_view import SendTransactionView
return SendTransactionView(self.driver)
def get_base_web_view(self):
from views.web_views.base_web_view import BaseWebView
return BaseWebView(self.driver)
def get_profile_view(self):
from views.profile_view import ProfileView
return ProfileView(self.driver)
def get_wallet_view(self):
from views.wallet_view import WalletView
return WalletView(self.driver)
@staticmethod
def get_unique_amount():
return '0.00%s' % datetime.now().strftime('%-d%-H%-M%-S').strip('0')
@staticmethod
def get_public_chat_name():
return ''.join(random.choice(string.ascii_lowercase) for _ in range(7))
def get_text_from_qr(self):
image = Image.open(BytesIO(base64.b64decode(self.driver.get_screenshot_as_base64())))
image.load()
try:
return str(zbarlight.scan_codes('qrcode', image)[0])[2:][:132]
except IndexError:
raise BaseException('No data in QR code')
def public_key_to_address(self, public_key):
raw_public_key = bytearray.fromhex(public_key.replace('0x04', ''))
return datatypes.PublicKey(raw_public_key).to_address()[2:]
def get_back_to_home_view(self, times_to_click_on_back_btn=5):
counter = 0
from views.home_view import PlusButton
while not PlusButton(self.driver).is_element_displayed(2):
try:
if counter >= times_to_click_on_back_btn:
break
self.back_button.click()
except (NoSuchElementException, TimeoutException):
counter += 1
return self.home_button.click()
def relogin(self, password=common_password):
try:
profile_view = self.profile_button.click()
except (NoSuchElementException, TimeoutException):
self.get_back_to_home_view()
profile_view = self.profile_button.click()
profile_view.logout()
sign_in_view = self.get_sign_in_view()
sign_in_view.sign_in(password)
def close_share_chat_key_popup(self):
TouchAction(self.driver).tap(None, 255, 104, 1).perform()
def get_public_key(self):
profile_view = self.profile_button.click()
profile_view.share_my_profile_button.click()
profile_view.public_key_text.wait_for_visibility_of_element()
public_key = profile_view.public_key_text.text
self.close_share_chat_key_popup()
return public_key
def share_via_messenger(self):
self.element_by_text('Messages').click()
self.element_by_text('NEW MESSAGE').click()
self.send_as_keyevent('+0100100101')
self.confirm()
def reconnect(self):
connect_status = self.connection_status
for i in range(3):
if connect_status.is_element_displayed(5, ignored_exceptions=StaleElementReferenceException):
if 'Tap to reconnect' in connect_status.text:
try:
connect_status.click()
except AttributeError:
pass
try:
connect_status.wait_for_invisibility_of_element()
except TimeoutException as e:
if i == 2:
e.msg = "Device %s: Can't reconnect to mail server after 3 attempts" % self.driver.number
raise e
def find_values_in_logcat(self, **kwargs):
logcat = self.logcat
items_in_logcat = list()
for key, value in kwargs.items():
if re.findall(r'\W%s$|\W%s\W' % (value, value), logcat):
items_in_logcat.append('%s in logcat!!!' % key.capitalize())
return items_in_logcat
def asset_by_name(self, asset_name):
return AssetButton(self.driver, asset_name)
def toggle_airplane_mode(self):
self.airplane_mode_button.click()
self.close_native_device_dialog("MmsService")
def toggle_mobile_data(self):
self.driver.start_activity(app_package='com.android.settings', app_activity='.Settings')
network_and_internet = self.element_by_text('Network & Internet')
network_and_internet.wait_for_visibility_of_element()
network_and_internet.click()
toggle = self.element_by_accessibility_id('WiFi')
toggle.wait_for_visibility_of_element()
toggle.click()
self.driver.back()
self.driver.back()
def open_universal_web_link(self, deep_link):
start_web_browser(self.driver)
self.send_as_keyevent(deep_link)
self.confirm()
self.open_in_status_button.click()