Added new desktop e2e tests

Signed-off-by: yevh-berdnyk <ie.berdnyk@gmail.com>
This commit is contained in:
yevh-berdnyk 2018-11-16 10:53:05 +01:00
parent 8f0bfde759
commit d299713037
No known key found for this signature in database
GPG Key ID: E9B425FDFC4DEA9C
20 changed files with 206 additions and 22 deletions

View File

@ -2,6 +2,8 @@ import docker
import pytest import pytest
import argparse import argparse
import os import os
import re
import requests
from datetime import datetime from datetime import datetime
from urllib.request import urlretrieve from urllib.request import urlretrieve
from tests.report import TEST_REPORT_DIR_CONTAINER from tests.report import TEST_REPORT_DIR_CONTAINER
@ -12,10 +14,12 @@ def main(**kwargs):
if not os.path.exists(kwargs['test_results_path']): if not os.path.exists(kwargs['test_results_path']):
os.makedirs(kwargs['test_results_path']) os.makedirs(kwargs['test_results_path'])
app_version = None
if kwargs['linux_app_url']: 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] linux_app_url = kwargs['linux_app_url']
urlretrieve(kwargs['linux_app_url'], 'nightly.AppImage') 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 = docker.from_env()
client.images.build(tag='status_desktop', path='.') client.images.build(tag='status_desktop', path='.')
pytest.main(['--collect-only', '-m %s' % kwargs['mark']]) pytest.main(['--collect-only', '-m %s' % kwargs['mark']])
@ -55,7 +59,7 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--test_results_path', parser.add_argument('--test_results_path',
action='store', action='store',
default='/Users/adan/Desktop/desktop_e2e_results') default=os.path.dirname(os.path.abspath(__file__)))
parser.add_argument('--linux_app_url', parser.add_argument('--linux_app_url',
action='store', action='store',
default=None) default=None)

View File

@ -1,3 +1,5 @@
import pytest
try: try:
import org.sikuli.script.SikulixForJython import org.sikuli.script.SikulixForJython
from sikuli import * from sikuli import *
@ -6,6 +8,7 @@ except Exception:
class BaseTestCase: class BaseTestCase:
errors = list()
try: try:
Settings.ActionLogs = 0 Settings.ActionLogs = 0
@ -18,3 +21,7 @@ class BaseTestCase:
def teardown_method(self, method): def teardown_method(self, method):
pass pass
def verify_no_errors(self):
if self.errors:
pytest.fail('. '.join([self.errors.pop(0) for _ in range(len(self.errors))]))

View File

@ -64,3 +64,11 @@ class TestCreateAccount(BaseTestCase):
sign_in.press_enter() sign_in.press_enter()
sign_in.profile_button.click() sign_in.profile_button.click()
profile.find_text('user_2') 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!")

View File

@ -6,13 +6,15 @@ import pytest
class TestProfile(BaseTestCase): class TestProfile(BaseTestCase):
@pytest.mark.testrail_id(5590)
def test_copy_contact_code(self): def test_copy_contact_code(self):
sign_in = SignInView() sign_in = SignInView()
sign_in.recover_access(base_user['passphrase']) sign_in.recover_access(base_user['passphrase'])
profile = sign_in.profile_button.click() profile = sign_in.profile_button.click()
profile.share_my_code_button.click() profile.share_my_code_button.click()
profile.copy_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') @pytest.mark.skip('Test cases is not ready yet')
def test_change_mail_server(self): def test_change_mail_server(self):
@ -23,3 +25,33 @@ class TestProfile(BaseTestCase):
s_names = profile.get_mail_servers_list() s_names = profile.get_mail_servers_list()
profile.get_mail_server(s_names[0]).is_active() 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!")

View File

@ -1,3 +1,6 @@
import pytest
from utilities import passpharse_with_spaces
from tests import base_user from tests import base_user
from tests.base_test_case import BaseTestCase from tests.base_test_case import BaseTestCase
from views.sign_in_view import SignInView from views.sign_in_view import SignInView
@ -16,6 +19,7 @@ class TestRecoverAccess(BaseTestCase):
profile.share_my_code_button.click() profile.share_my_code_button.click()
profile.find_text(base_user['public_key']) profile.find_text(base_user['public_key'])
@pytest.mark.testrail_id(5571)
def test_recover_access_proceed_with_enter(self): def test_recover_access_proceed_with_enter(self):
sign_in = SignInView() sign_in = SignInView()
sign_in.i_have_account_button.click() sign_in.i_have_account_button.click()
@ -26,9 +30,55 @@ class TestRecoverAccess(BaseTestCase):
sign_in.press_enter() sign_in.press_enter()
sign_in.home_button.find_element() sign_in.home_button.find_element()
@pytest.mark.testrail_id(5569)
def test_recover_access_go_back(self): def test_recover_access_go_back(self):
sign_in = SignInView() sign_in = SignInView()
sign_in.i_have_account_button.click() sign_in.i_have_account_button.click()
sign_in.recovery_phrase_input.find_element() sign_in.recovery_phrase_input.find_element()
sign_in.back_button.click() sign_in.back_button.click()
sign_in.create_account_button.find_element() 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'])

View File

@ -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)]))))

View File

@ -2,6 +2,7 @@ import logging
import time import time
import pytest import pytest
import re import re
try: try:
import org.sikuli.script.SikulixForJython import org.sikuli.script.SikulixForJython
from sikuli import * from sikuli import *
@ -10,15 +11,16 @@ except Exception:
class BaseElement(object): class BaseElement(object):
def __init__(self, screenshot): def __init__(self, screenshot, x=0, y=0, w=1024, h=768):
self.screenshot = screenshot self.screenshot = screenshot
self.name = re.findall('([^\/]+)(?=.png)', self.screenshot)[0].replace('_', ' ').title() self.name = re.findall('([^\/]+)(?=.png)', self.screenshot)[0].replace('_', ' ').title()
self.region = Region(x, y, w, h)
def find_element(self, log=True): def find_element(self, log=True):
if log: if log:
logging.info('Find %s' % self.name) logging.info('Find %s' % self.name)
try: try:
wait(self.screenshot, 10) self.region.wait(self.screenshot, 10)
except FindFailed: except FindFailed:
pytest.fail('%s was not found' % self.name) pytest.fail('%s was not found' % self.name)
@ -26,16 +28,27 @@ class BaseElement(object):
if log: if log:
logging.info('Click %s' % self.name) logging.info('Click %s' % self.name)
self.find_element(log=False) 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): def verify_element_is_not_present(self):
logging.info('Verify: %s is not present' % self.name) logging.info('Verify: %s is not present' % self.name)
try: try:
wait(self.screenshot, 10) self.region.wait(self.screenshot, 10)
pytest.fail('%s is displayed but not expected' % self.name) pytest.fail('%s is displayed but not expected' % self.name)
except FindFailed: except FindFailed:
pass pass
def get_target(self):
self.find_element(log=False)
return self.region.find(self.screenshot).getTarget()
class InputField(BaseElement): class InputField(BaseElement):
@ -53,7 +66,7 @@ class InputField(BaseElement):
def is_focused(self): def is_focused(self):
self.find_element(log=False) self.find_element(log=False)
return find(self.screenshot).getTarget() == Env.getMouseLocation() return self.get_target() == Env.getMouseLocation()
def verify_is_focused(self): def verify_is_focused(self):
logging.info('Verify %s is focused' % self.name) logging.info('Verify %s is focused' % self.name)
@ -63,14 +76,36 @@ class InputField(BaseElement):
class TextElement(object): class TextElement(object):
def __init__(self, text): def __init__(self, text):
self.text = text
self.element_line = None self.element_line = None
def find_element(self):
for _ in range(3): for _ in range(3):
lines = collectLines() lines = collectLines()
for line in lines: 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 self.element_line = line
return return
time.sleep(3) time.sleep(3)
pytest.fail("Element with text '%s' was not found" % self.text)
def click(self): def click(self):
logging.info("Click %s button" % self.text)
self.find_element()
self.element_line.click() 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)

View File

@ -1,4 +1,5 @@
import logging import logging
try: try:
import org.sikuli.script.SikulixForJython import org.sikuli.script.SikulixForJython
from sikuli import * from sikuli import *
@ -28,7 +29,11 @@ class BaseView(object):
super(BaseView, self).__init__() super(BaseView, self).__init__()
self.home_button = BaseElement(IMAGES_PATH + '/home_button.png') self.home_button = BaseElement(IMAGES_PATH + '/home_button.png')
self.profile_button = ProfileButton() 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): def find_text(self, expected_text):
logging.info("Find text '%s'" % expected_text) logging.info("Find text '%s'" % expected_text)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,4 +1,8 @@
import os import os
# import pytesseract
import re
# from PIL import Image
from subprocess import check_output
try: try:
import org.sikuli.script.SikulixForJython import org.sikuli.script.SikulixForJython
@ -6,7 +10,7 @@ try:
except Exception: except Exception:
pass pass
from views.base_element import BaseElement, TextElement from views.base_element import BaseElement, TextElement, InputField
from views.base_view import BaseView from views.base_view import BaseView
IMAGES_PATH = os.path.join(os.path.dirname(__file__), 'images/profile_view') IMAGES_PATH = os.path.join(os.path.dirname(__file__), 'images/profile_view')
@ -27,9 +31,12 @@ class MailServerElement(TextElement):
class ProfileView(BaseView): class ProfileView(BaseView):
def __init__(self): def __init__(self):
super(ProfileView, self).__init__() 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.copy_code_button = BaseElement(IMAGES_PATH + '/copy_code_button.png')
self.log_out_button = BaseElement(IMAGES_PATH + '/log_out_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): def get_mail_servers_list(self):
server_names = [] server_names = []
@ -40,3 +47,21 @@ class ProfileView(BaseView):
def get_mail_server(self, name): def get_mail_server(self, name):
return MailServerElement(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]

View File

@ -4,8 +4,8 @@ try:
except Exception: except Exception:
pass pass
import os import os
import pytest import logging
from views.base_element import BaseElement, InputField from views.base_element import BaseElement, InputField, TextElement
from views.base_view import BaseView from views.base_view import BaseView
from views.home_view import HomeView from views.home_view import HomeView
@ -25,17 +25,27 @@ class CreateAccountButton(BaseElement):
super(CreateAccountButton, self).find_element(log=log) 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): class SignInView(BaseView):
def __init__(self): def __init__(self):
super(SignInView, self).__init__() super(SignInView, self).__init__()
self.create_account_button = CreateAccountButton() 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.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.create_password_input = InputField(IMAGES_PATH + '/create_password_input.png')
self.confirm_password_input = InputField(IMAGES_PATH + '/confirm_password_input.png') self.confirm_password_input = InputField(IMAGES_PATH + '/confirm_password_input.png')
self.username_input = InputField(IMAGES_PATH + '/username_input.png') self.username_input = UserNameInput()
self.next_button = BaseElement(IMAGES_PATH + '/next_button.png')
self.recovery_phrase_input = InputField(IMAGES_PATH + '/recovery_phrase_input.png') self.recovery_phrase_input = InputField(IMAGES_PATH + '/recovery_phrase_input.png')
self.recover_password_input = InputField(IMAGES_PATH + '/recover_password_input.png') self.recover_password_input = InputField(IMAGES_PATH + '/recover_password_input.png')
self.sign_in_button = BaseElement(IMAGES_PATH + '/sign_in_button.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.username_input.input_value(username)
self.next_button.click() self.next_button.click()
self.home_button.find_element() self.home_button.find_element()
self.ok_button.click()
return HomeView() return HomeView()
def recover_access(self, passphrase): def recover_access(self, passphrase, password='qwerty'):
self.i_have_account_button.click() self.i_have_account_button.click()
self.recovery_phrase_input.send_keys(passphrase) 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.sign_in_button.click()
self.home_button.find_element() self.home_button.find_element()
self.ok_button.click()
return HomeView() return HomeView()