Added new desktop e2e tests
Signed-off-by: yevh-berdnyk <ie.berdnyk@gmail.com>
|
@ -2,6 +2,8 @@ import docker
|
|||
import pytest
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from urllib.request import urlretrieve
|
||||
from tests.report import TEST_REPORT_DIR_CONTAINER
|
||||
|
@ -12,10 +14,12 @@ def main(**kwargs):
|
|||
|
||||
if not os.path.exists(kwargs['test_results_path']):
|
||||
os.makedirs(kwargs['test_results_path'])
|
||||
app_version = None
|
||||
if kwargs['linux_app_url']:
|
||||
app_version = ([i for i in [i for i in kwargs['linux_app_url'].split('/') if '.AppImage' in i]])[0]
|
||||
urlretrieve(kwargs['linux_app_url'], 'nightly.AppImage')
|
||||
linux_app_url = kwargs['linux_app_url']
|
||||
else:
|
||||
linux_app_url = re.findall('https\S*AppImage', requests.get('https://status.im/nightly/').text)[0]
|
||||
app_version = ([i for i in [i for i in linux_app_url.split('/') if '.AppImage' in i]])[0]
|
||||
urlretrieve(linux_app_url, 'nightly.AppImage')
|
||||
client = docker.from_env()
|
||||
client.images.build(tag='status_desktop', path='.')
|
||||
pytest.main(['--collect-only', '-m %s' % kwargs['mark']])
|
||||
|
@ -55,7 +59,7 @@ if __name__ == '__main__':
|
|||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--test_results_path',
|
||||
action='store',
|
||||
default='/Users/adan/Desktop/desktop_e2e_results')
|
||||
default=os.path.dirname(os.path.abspath(__file__)))
|
||||
parser.add_argument('--linux_app_url',
|
||||
action='store',
|
||||
default=None)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import pytest
|
||||
|
||||
try:
|
||||
import org.sikuli.script.SikulixForJython
|
||||
from sikuli import *
|
||||
|
@ -6,6 +8,7 @@ except Exception:
|
|||
|
||||
|
||||
class BaseTestCase:
|
||||
errors = list()
|
||||
|
||||
try:
|
||||
Settings.ActionLogs = 0
|
||||
|
@ -18,3 +21,7 @@ class BaseTestCase:
|
|||
|
||||
def teardown_method(self, method):
|
||||
pass
|
||||
|
||||
def verify_no_errors(self):
|
||||
if self.errors:
|
||||
pytest.fail('. '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
|
||||
|
|
|
@ -64,3 +64,11 @@ class TestCreateAccount(BaseTestCase):
|
|||
sign_in.press_enter()
|
||||
sign_in.profile_button.click()
|
||||
profile.find_text('user_2')
|
||||
|
||||
@pytest.mark.testrail_id(5650)
|
||||
def test_status_log(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.create_account()
|
||||
with open('/root/.local/share/Status/Status.log') as f:
|
||||
if 'mnemonic' in f.read():
|
||||
pytest.fail("'mnemonic' is in Status.log!")
|
||||
|
|
|
@ -6,13 +6,15 @@ import pytest
|
|||
|
||||
class TestProfile(BaseTestCase):
|
||||
|
||||
@pytest.mark.testrail_id(5590)
|
||||
def test_copy_contact_code(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.recover_access(base_user['passphrase'])
|
||||
profile = sign_in.profile_button.click()
|
||||
profile.share_my_code_button.click()
|
||||
profile.copy_code_button.click()
|
||||
assert profile.get_clipboard() == base_user['public_key']
|
||||
if profile.get_clipboard() != base_user['public_key']:
|
||||
pytest.fail('Contact code was not copied to clipboard')
|
||||
|
||||
@pytest.mark.skip('Test cases is not ready yet')
|
||||
def test_change_mail_server(self):
|
||||
|
@ -23,3 +25,33 @@ class TestProfile(BaseTestCase):
|
|||
s_names = profile.get_mail_servers_list()
|
||||
profile.get_mail_server(s_names[0]).is_active()
|
||||
|
||||
@pytest.mark.testrail_id(5593)
|
||||
def test_log_out(self):
|
||||
sign_in = SignInView()
|
||||
username = 'test_log_out'
|
||||
sign_in.create_account(username=username)
|
||||
profile = sign_in.profile_button.click()
|
||||
profile.log_out_button.click()
|
||||
sign_in.password_input.find_element()
|
||||
for text in username, 'Sign in to Status', 'Other accounts':
|
||||
if not sign_in.element_by_text(text).is_visible():
|
||||
pytest.fail("Text '%s' is not shown" % text)
|
||||
|
||||
@pytest.mark.skip
|
||||
# @pytest.mark.testrail_id(5648)
|
||||
def test_back_up_recovery_phrase(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.create_account()
|
||||
profile = sign_in.profile_button.click()
|
||||
profile.back_up_recovery_phrase_button.click()
|
||||
profile.ok_continue_button.click()
|
||||
recovery_phrase = profile.get_recovery_phrase()
|
||||
profile.next_button.click()
|
||||
word_number = profile.get_recovery_phrase_word_number()
|
||||
profile.recovery_phrase_word_input.input_value(recovery_phrase[word_number])
|
||||
profile.next_button.click()
|
||||
word_number_1 = profile.get_recovery_phrase_word_number()
|
||||
profile.recovery_phrase_word_input.input_value(recovery_phrase[word_number_1])
|
||||
profile.done_button.click()
|
||||
profile.yes_button.click()
|
||||
profile.find_text("You're all set!")
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from utilities import passpharse_with_spaces
|
||||
from tests import base_user
|
||||
from tests.base_test_case import BaseTestCase
|
||||
from views.sign_in_view import SignInView
|
||||
|
@ -16,6 +19,7 @@ class TestRecoverAccess(BaseTestCase):
|
|||
profile.share_my_code_button.click()
|
||||
profile.find_text(base_user['public_key'])
|
||||
|
||||
@pytest.mark.testrail_id(5571)
|
||||
def test_recover_access_proceed_with_enter(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.i_have_account_button.click()
|
||||
|
@ -26,9 +30,55 @@ class TestRecoverAccess(BaseTestCase):
|
|||
sign_in.press_enter()
|
||||
sign_in.home_button.find_element()
|
||||
|
||||
@pytest.mark.testrail_id(5569)
|
||||
def test_recover_access_go_back(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.i_have_account_button.click()
|
||||
sign_in.recovery_phrase_input.find_element()
|
||||
sign_in.back_button.click()
|
||||
sign_in.create_account_button.find_element()
|
||||
|
||||
@pytest.mark.testrail_id(5649)
|
||||
def test_recovery_phrase_for_recovered_account(self):
|
||||
sign_in = SignInView()
|
||||
sign_in.recover_access(base_user['passphrase'])
|
||||
profile = sign_in.profile_button.click()
|
||||
if profile.share_my_code_button.is_visible():
|
||||
profile.element_by_text('Backup').verify_element_is_not_present()
|
||||
else:
|
||||
pytest.fail('Profile view was not opened')
|
||||
|
||||
@pytest.mark.testrail_id(5652)
|
||||
def test_recover_account_error_messages(self):
|
||||
errors = {'': 'Required field',
|
||||
' '.join(base_user['passphrase'].split()[::-1]): 'Some words might be misspelled',
|
||||
' '.join(base_user['passphrase'].split()[:-1]) + ' aaa': 'Some words might be misspelled',
|
||||
'robot seed robot seed robot seed robot seed robot seed robot seed.': 'Recovery phrase is invalid',
|
||||
'robot': 'Recovery phrase is invalid',
|
||||
'seed seed seed seed seed seed seed seed seed seed seed': 'Recovery phrase is invalid',
|
||||
'seed seed seed seed seed seed seed seed seed seed seed seed seed': 'Recovery phrase is invalid'
|
||||
}
|
||||
sign_in = SignInView()
|
||||
for i in errors:
|
||||
sign_in.i_have_account_button.click()
|
||||
sign_in.recovery_phrase_input.send_keys(i)
|
||||
sign_in.recover_password_input.click()
|
||||
error_message = errors[i]
|
||||
if not sign_in.element_by_text(error_message).is_visible():
|
||||
self.errors.append("Error message '%s' is not shown for passphrase '%s'" % (error_message, i))
|
||||
sign_in.back_button.click()
|
||||
sign_in.i_have_account_button.click()
|
||||
sign_in.recovery_phrase_input.send_keys(base_user['passphrase'])
|
||||
sign_in.recover_password_input.click()
|
||||
sign_in.sign_in_button.click()
|
||||
if not sign_in.element_by_text('Required field').is_visible():
|
||||
self.errors.append("Error message 'Required field' is not shown for empty password input")
|
||||
self.verify_no_errors()
|
||||
|
||||
@pytest.mark.testrail_id(5651)
|
||||
def test_recover_account_with_spaces(self):
|
||||
sign_in = SignInView()
|
||||
passphrase = passpharse_with_spaces(base_user['passphrase'])
|
||||
sign_in.recover_access(passphrase)
|
||||
profile = sign_in.profile_button.click()
|
||||
profile.find_text(base_user['username'])
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import itertools
|
||||
|
||||
|
||||
def passpharse_with_spaces(passphrase):
|
||||
phrase_list = passphrase.split()
|
||||
return ''.join(list(itertools.chain.from_iterable(zip(phrase_list, [' ' * i for i in range(1, 13)]))))
|
|
@ -2,6 +2,7 @@ import logging
|
|||
import time
|
||||
import pytest
|
||||
import re
|
||||
|
||||
try:
|
||||
import org.sikuli.script.SikulixForJython
|
||||
from sikuli import *
|
||||
|
@ -10,15 +11,16 @@ except Exception:
|
|||
|
||||
|
||||
class BaseElement(object):
|
||||
def __init__(self, screenshot):
|
||||
def __init__(self, screenshot, x=0, y=0, w=1024, h=768):
|
||||
self.screenshot = screenshot
|
||||
self.name = re.findall('([^\/]+)(?=.png)', self.screenshot)[0].replace('_', ' ').title()
|
||||
self.region = Region(x, y, w, h)
|
||||
|
||||
def find_element(self, log=True):
|
||||
if log:
|
||||
logging.info('Find %s' % self.name)
|
||||
try:
|
||||
wait(self.screenshot, 10)
|
||||
self.region.wait(self.screenshot, 10)
|
||||
except FindFailed:
|
||||
pytest.fail('%s was not found' % self.name)
|
||||
|
||||
|
@ -26,16 +28,27 @@ class BaseElement(object):
|
|||
if log:
|
||||
logging.info('Click %s' % self.name)
|
||||
self.find_element(log=False)
|
||||
click(self.screenshot)
|
||||
self.region.click(self.screenshot)
|
||||
|
||||
def is_visible(self):
|
||||
try:
|
||||
self.region.wait(self.screenshot, 10)
|
||||
return True
|
||||
except FindFailed:
|
||||
return False
|
||||
|
||||
def verify_element_is_not_present(self):
|
||||
logging.info('Verify: %s is not present' % self.name)
|
||||
try:
|
||||
wait(self.screenshot, 10)
|
||||
self.region.wait(self.screenshot, 10)
|
||||
pytest.fail('%s is displayed but not expected' % self.name)
|
||||
except FindFailed:
|
||||
pass
|
||||
|
||||
def get_target(self):
|
||||
self.find_element(log=False)
|
||||
return self.region.find(self.screenshot).getTarget()
|
||||
|
||||
|
||||
class InputField(BaseElement):
|
||||
|
||||
|
@ -53,7 +66,7 @@ class InputField(BaseElement):
|
|||
|
||||
def is_focused(self):
|
||||
self.find_element(log=False)
|
||||
return find(self.screenshot).getTarget() == Env.getMouseLocation()
|
||||
return self.get_target() == Env.getMouseLocation()
|
||||
|
||||
def verify_is_focused(self):
|
||||
logging.info('Verify %s is focused' % self.name)
|
||||
|
@ -63,14 +76,36 @@ class InputField(BaseElement):
|
|||
|
||||
class TextElement(object):
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.element_line = None
|
||||
|
||||
def find_element(self):
|
||||
for _ in range(3):
|
||||
lines = collectLines()
|
||||
for line in lines:
|
||||
if text in line.getText().encode('ascii', 'ignore'):
|
||||
if self.text in line.getText().encode('ascii', 'ignore'):
|
||||
self.element_line = line
|
||||
return
|
||||
time.sleep(3)
|
||||
pytest.fail("Element with text '%s' was not found" % self.text)
|
||||
|
||||
def click(self):
|
||||
logging.info("Click %s button" % self.text)
|
||||
self.find_element()
|
||||
self.element_line.click()
|
||||
|
||||
def get_whole_text(self):
|
||||
self.find_element()
|
||||
return self.element_line.getText().encode('ascii', 'ignore')
|
||||
|
||||
def is_visible(self):
|
||||
from _pytest.runner import Failed
|
||||
try:
|
||||
self.find_element()
|
||||
return True
|
||||
except Failed:
|
||||
return False
|
||||
|
||||
def verify_element_is_not_present(self):
|
||||
if self.is_visible():
|
||||
pytest.fail("'%s text is displayed but not expected'" % self.text)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
|
||||
try:
|
||||
import org.sikuli.script.SikulixForJython
|
||||
from sikuli import *
|
||||
|
@ -28,7 +29,11 @@ class BaseView(object):
|
|||
super(BaseView, self).__init__()
|
||||
self.home_button = BaseElement(IMAGES_PATH + '/home_button.png')
|
||||
self.profile_button = ProfileButton()
|
||||
self.back_button = BaseElement(IMAGES_PATH + '/back_button.png')
|
||||
self.back_button = BaseElement(IMAGES_PATH + '/back_button.png', x=10, y=20, w=50, h=50)
|
||||
self.ok_button = BaseElement(IMAGES_PATH + '/ok_button.png')
|
||||
self.next_button = BaseElement(IMAGES_PATH + '/next_button.png')
|
||||
self.done_button = BaseElement(IMAGES_PATH + '/done_button.png')
|
||||
self.yes_button = BaseElement(IMAGES_PATH + '/yes_button.png')
|
||||
|
||||
def find_text(self, expected_text):
|
||||
logging.info("Find text '%s'" % expected_text)
|
||||
|
|
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
|
@ -1,4 +1,8 @@
|
|||
import os
|
||||
# import pytesseract
|
||||
import re
|
||||
# from PIL import Image
|
||||
from subprocess import check_output
|
||||
|
||||
try:
|
||||
import org.sikuli.script.SikulixForJython
|
||||
|
@ -6,7 +10,7 @@ try:
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
from views.base_element import BaseElement, TextElement
|
||||
from views.base_element import BaseElement, TextElement, InputField
|
||||
from views.base_view import BaseView
|
||||
|
||||
IMAGES_PATH = os.path.join(os.path.dirname(__file__), 'images/profile_view')
|
||||
|
@ -27,9 +31,12 @@ class MailServerElement(TextElement):
|
|||
class ProfileView(BaseView):
|
||||
def __init__(self):
|
||||
super(ProfileView, self).__init__()
|
||||
self.share_my_code_button = BaseElement(IMAGES_PATH + '/share_my_code_button.png')
|
||||
self.share_my_code_button = TextElement('Share my contact code')
|
||||
self.copy_code_button = BaseElement(IMAGES_PATH + '/copy_code_button.png')
|
||||
self.log_out_button = BaseElement(IMAGES_PATH + '/log_out_button.png')
|
||||
self.back_up_recovery_phrase_button = TextElement('Backup your recovery')
|
||||
self.ok_continue_button = BaseElement(IMAGES_PATH + '/ok_continue_button.png')
|
||||
self.recovery_phrase_word_input = InputField(IMAGES_PATH + '/recovery_phrase_word_input.png')
|
||||
|
||||
def get_mail_servers_list(self):
|
||||
server_names = []
|
||||
|
@ -40,3 +47,21 @@ class ProfileView(BaseView):
|
|||
|
||||
def get_mail_server(self, name):
|
||||
return MailServerElement(name)
|
||||
|
||||
def get_recovery_phrase(self):
|
||||
self.share_my_code_button.find_element()
|
||||
reg = Region(370, 130, 600, 240)
|
||||
current_text = reg.text().encode('ascii', 'ignore')
|
||||
phrase_list = re.findall(r"[\w']+", current_text.replace('1O', '10'))
|
||||
phrase_dict = dict()
|
||||
for i in range(len(phrase_list) - 1):
|
||||
if phrase_list[i].isdigit():
|
||||
phrase_dict[phrase_list[i]] = phrase_list[i + 1]
|
||||
return phrase_dict
|
||||
|
||||
def get_recovery_phrase_word_number(self):
|
||||
image_name = 'recovery.png'
|
||||
# check_output(['import', '-window', 'root', image_name])
|
||||
# text = pytesseract.image_to_string(Image.open(image_name))
|
||||
# os.remove(image_name)
|
||||
# return re.findall('#(.*)\n', text)[0]
|
||||
|
|
|
@ -4,8 +4,8 @@ try:
|
|||
except Exception:
|
||||
pass
|
||||
import os
|
||||
import pytest
|
||||
from views.base_element import BaseElement, InputField
|
||||
import logging
|
||||
from views.base_element import BaseElement, InputField, TextElement
|
||||
from views.base_view import BaseView
|
||||
from views.home_view import HomeView
|
||||
|
||||
|
@ -25,17 +25,27 @@ class CreateAccountButton(BaseElement):
|
|||
super(CreateAccountButton, self).find_element(log=log)
|
||||
|
||||
|
||||
class UserNameInput(InputField):
|
||||
def __init__(self):
|
||||
super(UserNameInput, self).__init__(IMAGES_PATH + '/username_input.png')
|
||||
|
||||
def input_value(self, value):
|
||||
logging.info("%s field: set value '%s'" % (self.name, value))
|
||||
import time
|
||||
time.sleep(10)
|
||||
type(value)
|
||||
|
||||
|
||||
class SignInView(BaseView):
|
||||
def __init__(self):
|
||||
super(SignInView, self).__init__()
|
||||
self.create_account_button = CreateAccountButton()
|
||||
self.i_have_account_button = BaseElement(IMAGES_PATH + '/i_have_account.png')
|
||||
self.i_have_account_button = TextElement('I already have an account')
|
||||
self.other_accounts_button = BaseElement(IMAGES_PATH + '/other_accounts.png')
|
||||
self.privacy_policy_button = BaseElement(IMAGES_PATH + 'privacy_policy_button.png')
|
||||
self.privacy_policy_button = TextElement('Privacy Policy')
|
||||
self.create_password_input = InputField(IMAGES_PATH + '/create_password_input.png')
|
||||
self.confirm_password_input = InputField(IMAGES_PATH + '/confirm_password_input.png')
|
||||
self.username_input = InputField(IMAGES_PATH + '/username_input.png')
|
||||
self.next_button = BaseElement(IMAGES_PATH + '/next_button.png')
|
||||
self.username_input = UserNameInput()
|
||||
self.recovery_phrase_input = InputField(IMAGES_PATH + '/recovery_phrase_input.png')
|
||||
self.recover_password_input = InputField(IMAGES_PATH + '/recover_password_input.png')
|
||||
self.sign_in_button = BaseElement(IMAGES_PATH + '/sign_in_button.png')
|
||||
|
@ -50,12 +60,14 @@ class SignInView(BaseView):
|
|||
self.username_input.input_value(username)
|
||||
self.next_button.click()
|
||||
self.home_button.find_element()
|
||||
self.ok_button.click()
|
||||
return HomeView()
|
||||
|
||||
def recover_access(self, passphrase):
|
||||
def recover_access(self, passphrase, password='qwerty'):
|
||||
self.i_have_account_button.click()
|
||||
self.recovery_phrase_input.send_keys(passphrase)
|
||||
self.recover_password_input.send_keys('123456')
|
||||
self.recover_password_input.send_keys(password)
|
||||
self.sign_in_button.click()
|
||||
self.home_button.find_element()
|
||||
self.ok_button.click()
|
||||
return HomeView()
|
||||
|
|