e2e: LambdaTest

This commit is contained in:
Yevheniia Berdnyk 2024-10-24 18:59:53 +03:00
parent 735ab61d4a
commit c38512512a
No known key found for this signature in database
68 changed files with 205 additions and 345 deletions

View File

@ -73,9 +73,9 @@ pipeline {
passwordVariable: 'TESTRAIL_PASS'
),
usernamePassword(
credentialsId: 'sauce-labs-api',
usernameVariable: 'SAUCE_USERNAME',
passwordVariable: 'SAUCE_ACCESS_KEY'
credentialsId: 'lambda-test-api',
usernameVariable: 'LAMBDA_TEST_USERNAME',
passwordVariable: 'LAMBDA_TEST_ACCESS_KEY'
),
string(
credentialsId: 'etherscan-api-key',
@ -96,7 +96,6 @@ pipeline {
sh """
python3 -m pytest \
--numprocesses 8 \
--rerun_count=2 \
--testrail_report=True \
-m testrail_id \
-m \"nightly\" \
@ -110,21 +109,6 @@ pipeline {
}
post {
always {
script {
sauce('sauce-labs-cred') {
saucePublisher()
}
}
}
success {
script {
junit(
testDataPublishers: [[$class: 'SauceOnDemandReportPublisher', jobVisibility: 'public']],
testResults: 'test/appium/tests/*.xml'
)
}
}
cleanup {
sh 'make purge'
}

View File

@ -110,11 +110,6 @@ pipeline {
usernameVariable: 'TESTRAIL_USER',
passwordVariable: 'TESTRAIL_PASS'
),
usernamePassword(
credentialsId: 'sauce-labs-api',
usernameVariable: 'SAUCE_USERNAME',
passwordVariable: 'SAUCE_ACCESS_KEY'
),
usernamePassword(
credentialsId: 'lambda-test-api',
usernameVariable: 'LAMBDA_TEST_USERNAME',
@ -139,7 +134,6 @@ pipeline {
sh """
python3 -m pytest \
--numprocesses 8 \
--rerun_count=2 \
--testrail_report=True \
-k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_URL ?: apk_path} \

View File

@ -17,6 +17,7 @@ eth-account==0.7.0
eth-hash==0.3.2
eth-keys
execnet==1.7.1
filelock==3.16.1
flaky==3.7.0
future==0.18.2
hexbytes==0.2.2

View File

@ -1,10 +1,9 @@
import hmac
import json
import os
import re
import urllib
from hashlib import md5
from support.lambda_test import get_session_info
from support.test_data import SingleTestData
@ -12,8 +11,6 @@ class BaseTestReport:
TEST_REPORT_DIR = "%s/../report" % os.path.dirname(os.path.abspath(__file__))
def __init__(self):
self.sauce_username = os.environ.get('SAUCE_USERNAME')
self.sauce_access_key = os.environ.get('SAUCE_ACCESS_KEY')
self.init_report()
def init_report(self):
@ -97,17 +94,8 @@ class BaseTestReport:
failed.append(test)
return passed, failed, xfailed
def get_sauce_token(self, job_id):
return hmac.new(bytes(self.sauce_username + ":" + self.sauce_access_key, 'latin-1'),
bytes(job_id, 'latin-1'), md5).hexdigest()
def get_sauce_job_url(self, job_id, first_command=0):
token = self.get_sauce_token(job_id)
from tests.conftest import apibase
url = 'https://%s/jobs/%s?auth=%s' % (apibase, job_id, token)
if first_command > 0:
url += "#%s" % first_command
return url
def get_lambda_test_job_url(self, job_id, first_command=0):
return "https://appautomation.lambdatest.com/test?testID=" + get_session_info(job_id)['test_id']
@staticmethod
def get_jenkins_link_to_rerun_e2e(branch_name="develop", pr_id="", tr_case_ids=""):
@ -115,19 +103,6 @@ class BaseTestReport:
return 'https://ci.status.im/job/status-mobile/job/e2e/job/status-app-prs-rerun/parambuild/' \
'?BRANCH_NAME=%s&PR_ID=%s&APK_NAME=%s.apk&TR_CASE_IDS=%s' % (branch_name, pr_id, pr_id, tr_case_ids)
def get_sauce_final_screenshot_url(self, job_id):
return 'https://media.giphy.com/media/9M5jK4GXmD5o1irGrF/giphy.gif'
# temp blocked, no sense with groups
# from tests.conftest import sauce, apibase
# token = self.get_sauce_token(job_id)
# username = sauce.accounts.account_user.get_active_user().username
# for _ in range(10):
# try:
# scr_number = sauce.jobs.get_job_assets(username=username, job_id=job_id)['screenshots'][-1]
# return 'https://assets.%s/jobs/%s/%s?auth=%s' % (apibase, job_id, scr_number, token)
# except SauceException:
# time.sleep(3)
@staticmethod
def is_test_successful(test):
# Test passed if last testrun has passed

View File

@ -166,7 +166,7 @@ class GithubHtmlReport(BaseTestReport):
first_command = 0
else:
first_command = 0
html += "<li><a href=\"%s\">Steps, video, logs</a></li>" % self.get_sauce_job_url(job_id, first_command)
html += "<li><a href=\"%s\">Steps, video, logs</a></li>" % self.get_lambda_test_job_url(job_id, first_command)
# if test_run.error:
# html += "<li><a href=\"%s\">Failure screenshot</a></li>" % self.get_sauce_final_screenshot_url(job_id)
html += "</ul></p>"

View File

@ -9,7 +9,6 @@ session.auth = (lambda_test_username, lambda_test_access_key)
def upload_apk(apk_file_path):
resp = session.post(
# url="https://manual-api.lambdatest.com/app/upload/realDevice",
url="https://manual-api.lambdatest.com/app/upload/virtualDevice",
files={'appFile': open(apk_file_path, 'rb')},
data={'name': test_suite_data.apk_name}
@ -22,7 +21,18 @@ def update_session(session_id, session_name, status):
resp = session.get(
url="https://mobile-api.lambdatest.com/mobile-automation/api/v1/sessions/%s" % session_id,
data={
"name": session_name #, "status_ind": status
"name": session_name # , "status_ind": status
}
)
assert resp.status_code == 200
def get_session_info(session_id):
resp = session.get(url="https://mobile-api.lambdatest.com/mobile-automation/api/v1/sessions/%s" % session_id)
assert resp.status_code == 200
return resp.json()['data']
def upload_image():
'curl -u "yevheniia:fZaXHEAFEWOVCZLnSVrwHY11eJGsWAknibtG572PiZsvT1h57V" -X POST https://mobile-mgm.lambdatest.com/mfs/v1.0/media/upload -F media_file=@/Users/yberdnyk/Downloads/aaa.png -F type=image -F custom_id=SampleImage'
pass

View File

@ -167,10 +167,10 @@ class TestrailReport(BaseTestReport):
else:
first_command = 0
try:
devices += "# [Device %d](%s) \n" % (i + 1, self.get_sauce_job_url(job_id=device,
first_command=first_command))
devices += "# [Device %d](%s) \n" % (i + 1, self.get_lambda_test_job_url(job_id=device,
first_command=first_command))
except KeyError:
devices += "# Device %s: SauceLabs session was not found \n" % (i + 1)
devices += "# Device %s: LambdaTest session was not found \n" % (i + 1)
comment = str()
if test.group_name:
comment += "# Class: %s \n" % test.group_name
@ -274,9 +274,8 @@ class TestrailReport(BaseTestReport):
first_command = 0
else:
first_command = 0
job_url = self.get_sauce_job_url(job_id=job_id, first_command=first_command)
case_info = "Logs for device %d: [steps](%s), [failure screenshot](%s)" \
% (f, job_url, self.get_sauce_final_screenshot_url(job_id))
job_url = self.get_lambda_test_job_url(job_id=job_id, first_command=first_command)
case_info = "Logs for device %d: [steps](%s)" % (f, job_url)
if test.group_name:
group_blocks[test.group_name] += case_title + error + case_info

View File

@ -12,17 +12,14 @@ import requests
from appium import webdriver
from appium.options.common import AppiumOptions
from appium.webdriver.common.mobileby import MobileBy
from sauceclient import SauceException
from selenium.common.exceptions import NoSuchElementException, TimeoutException, WebDriverException
from selenium.webdriver.support.wait import WebDriverWait
from appium.webdriver.connectiontype import ConnectionType
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from urllib3.exceptions import MaxRetryError, ProtocolError
from support.api.network_api import NetworkApi
from tests import test_suite_data, start_threads, appium_container, pytest_config_global, transl
from tests.conftest import sauce_username, sauce_access_key, apibase, github_report, run_name, option, \
lambda_test_username, lambda_test_access_key
from tests.conftest import github_report, run_name, lambda_test_username, lambda_test_access_key
executor_sauce_lab = 'https://%s:%s@ondemand.%s:443/wd/hub' % (sauce_username, sauce_access_key, apibase)
executor_lambda_test = 'https://%s:%s@mobile-hub.lambdatest.com/wd/hub' % (lambda_test_username, lambda_test_access_key)
executor_local = 'http://localhost:4723/wd/hub'
@ -62,41 +59,6 @@ def add_local_devices_to_capabilities():
return updated_capabilities
def get_capabilities_sauce_lab():
caps = dict()
caps['platformName'] = 'Android'
caps['idleTimeout'] = 1000
caps['appium:app'] = 'storage:filename=' + test_suite_data.apk_name
caps['appium:deviceName'] = 'Android GoogleAPI Emulator'
caps['appium:deviceOrientation'] = 'portrait'
caps['appium:platformVersion'] = '14.0'
caps['appium:automationName'] = 'UiAutomator2'
caps['appium:newCommandTimeout'] = 600
caps['appium:idleTimeout'] = 1000
caps['appium:hideKeyboard'] = True
caps['appium:automationName'] = 'UiAutomator2'
caps['appium:setWebContentDebuggingEnabled'] = True
caps['appium:ignoreUnimportantViews'] = False
caps['ignoreUnimportantViews'] = False
caps['appium:enableNotificationListener'] = True
caps['enableNotificationListener'] = True
caps['appium:enforceXPath1'] = True
caps['enforceXPath1'] = True
caps['sauce:options'] = dict()
caps['sauce:options']['appiumVersion'] = '2.11.0'
caps['sauce:options']['username'] = sauce_username
caps['sauce:options']['accessKey'] = sauce_access_key
caps['sauce:options']['build'] = run_name
caps['sauce:options']['name'] = test_suite_data.current_test.name
caps['sauce:options']['maxDuration'] = 3600
caps['sauce:options']['idleTimeout'] = 1000
options = AppiumOptions()
options.load_capabilities(caps)
return options
def get_lambda_test_capabilities_real_device():
capabilities = {
"lt:options": {
@ -104,10 +66,9 @@ def get_lambda_test_capabilities_real_device():
"platformName": "android",
"deviceName": "Pixel 8",
"platformVersion": "14",
"app": "lt://APP10160471311729636675434695", # lambda_test_apk_url,
"app": pytest_config_global['lt_apk_url'],
"devicelog": True,
"visual": True,
# "network": True,
"video": True,
"build": run_name,
"name": test_suite_data.current_test.group_name,
@ -126,16 +87,21 @@ def get_lambda_test_capabilities_emulator():
"w3c": True,
"platformName": "android",
"deviceName": "Pixel 6",
"appiumVersion": "2.11.0",
"appiumVersion": "2.1.3",
"platformVersion": "14",
"app": "lt://APP10160522181729681886587724", #option.lambda_test_apk_url,
"app": pytest_config_global['lt_apk_url'],
"devicelog": True,
"visual": True,
# "network": True,
"video": True,
"build": run_name,
"name": test_suite_data.current_test.group_name,
"idleTimeout": 1000
"idleTimeout": 1000,
# "enableImageInjection": True,
# "uploadMedia": ["lt://MEDIA2b3e34e2b0ee4928b9fc38c603f98191",], # "lt://MEDIAcfc1b4f1af0740759254404186bbe4f1"]
},
"appium:options": {
"automationName": "UiAutomator2",
"hideKeyboard": True
}
}
options = AppiumOptions()
@ -165,9 +131,9 @@ def pull_requests_log(driver):
class AbstractTestCase:
__metaclass__ = ABCMeta
def print_sauce_lab_info(self, driver):
def print_lt_session_info(self, driver):
sys.stdout = sys.stderr
print("SauceOnDemandSessionID=%s job-name=%s" % (driver.session_id, run_name))
print("LambdaTestSessionID=%s job-name=%s" % (driver.session_id, run_name))
def get_translation_by_key(self, key):
return transl[key]
@ -220,6 +186,16 @@ class Driver(webdriver.Remote):
def fail(self, text: str):
pytest.fail('Device %s: %s' % (self.number, text))
def update_lt_session_status(self, index, status):
data = {
"action": "setTestStatus",
"arguments": {
"status": status,
"remark": "Device %s" % index
}
}
self.execute_script("lambda-hook: %s" % str(data).replace("'", "\""))
class Errors(object):
def __init__(self):
@ -240,11 +216,11 @@ class SingleDeviceTestCase(AbstractTestCase):
appium_container.start_appium_container(pytest_config_global['docker_shared_volume'])
appium_container.connect_device(pytest_config_global['device_ip'])
(executor, capabilities) = (executor_sauce_lab, get_capabilities_sauce_lab()) if \
self.environment == 'sauce' else (executor_local, get_capabilities_local())
for key, value in kwargs.items():
capabilities[key] = value
self.driver = Driver(executor, capabilities)
# (executor, capabilities) = (executor_sauce_lab, get_capabilities_sauce_lab()) if \
# self.environment == 'sauce' else (executor_local, get_capabilities_local())
# for key, value in kwargs.items():
# capabilities[key] = value
# self.driver = Driver(executor, capabilities)
test_suite_data.current_test.testruns[-1].jobs[self.driver.session_id] = 1
self.driver.implicitly_wait(implicit_wait)
self.errors = Errors()
@ -254,7 +230,7 @@ class SingleDeviceTestCase(AbstractTestCase):
def teardown_method(self, method):
if self.environment == 'sauce':
self.print_sauce_lab_info(self.driver)
self.print_lt_session_info(self.driver)
try:
self.add_alert_text_to_report(self.driver)
geth_content = pull_geth(self.driver)
@ -290,48 +266,6 @@ class LocalMultipleDeviceTestCase(AbstractTestCase):
pass
class SauceMultipleDeviceTestCase(AbstractTestCase):
@classmethod
def setup_class(cls):
cls.loop = asyncio.new_event_loop()
asyncio.set_event_loop(cls.loop)
def setup_method(self, method):
self.drivers = dict()
self.errors = Errors()
def create_drivers(self, quantity=2, max_duration=1800, custom_implicitly_wait=None):
self.drivers = self.loop.run_until_complete(start_threads(quantity,
Driver,
self.drivers,
executor_sauce_lab,
get_capabilities_sauce_lab()))
for driver in range(quantity):
test_suite_data.current_test.testruns[-1].jobs[self.drivers[driver].session_id] = driver + 1
self.drivers[driver].implicitly_wait(
custom_implicitly_wait if custom_implicitly_wait else implicit_wait)
def teardown_method(self, method):
geth_names, geth_contents = [], []
for driver in self.drivers:
try:
self.print_sauce_lab_info(self.drivers[driver])
self.add_alert_text_to_report(self.drivers[driver])
geth_names.append(
'%s_geth%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
geth_contents.append(pull_geth(self.drivers[driver]))
self.drivers[driver].quit()
except (WebDriverException, AttributeError):
pass
geth = {geth_names[i]: geth_contents[i] for i in range(len(geth_names))}
github_report.save_test(test_suite_data.current_test, geth)
@classmethod
def teardown_class(cls):
cls.loop.close()
def create_shared_drivers(quantity):
drivers = dict()
if pytest_config_global['env'] == 'local':
@ -354,18 +288,20 @@ def create_shared_drivers(quantity):
drivers,
command_executor=executor_lambda_test,
options=get_lambda_test_capabilities_emulator()))
# options=get_lambda_test_capabilities_real_device()))
if len(drivers) < quantity:
test_suite_data.current_test.testruns[-1].error = "Not all %s drivers are created" % quantity
for i in range(quantity):
test_suite_data.current_test.testruns[-1].jobs[drivers[i].session_id] = i + 1
drivers[i].implicitly_wait(implicit_wait)
drivers[i].update_settings({"enforceXPath1": True})
drivers[i].set_network_connection(ConnectionType.WIFI_ONLY)
return drivers, loop
except (MaxRetryError, AttributeError) as e:
test_suite_data.current_test.testruns[-1].error = str(e)
for _, driver in drivers.items():
for i, driver in drivers.items():
try:
driver.update_lt_session_status(i + 1, "failed")
driver.quit()
except (WebDriverException, AttributeError):
pass
@ -405,13 +341,14 @@ class LocalSharedMultipleDeviceTestCase(AbstractTestCase):
pass
class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
class LambdaTestSharedMultipleDeviceTestCase(AbstractTestCase):
def setup_method(self, method):
if not self.drivers:
pytest.fail(test_suite_data.current_test.testruns[-1].error)
# for _, driver in self.drivers.items():
# driver.execute_script("sauce:context=Started %s" % method.__name__)
for _, driver in self.drivers.items():
driver.execute_script("lambda-testCase-start=%s" % method.__name__)
driver.log_event("appium", "Started %s" % method.__name__)
jobs = test_suite_data.current_test.testruns[-1].jobs
if not jobs:
for index, driver in self.drivers.items():
@ -423,7 +360,7 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
log_names, log_contents = [], []
for driver in self.drivers:
try:
self.print_sauce_lab_info(self.drivers[driver])
self.print_lt_session_info(self.drivers[driver])
self.add_alert_text_to_report(self.drivers[driver])
log_names.append(
'%s_geth%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
@ -451,7 +388,6 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
@classmethod
def teardown_class(cls):
from tests.conftest import sauce
requests_session = requests.Session()
requests_session.auth = (lambda_test_username, lambda_test_access_key)
if test_suite_data.tests[0].testruns[-1].error and 'setup failed' in test_suite_data.tests[0].testruns[
@ -467,20 +403,13 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
log_names.append('%s_geth%s.log' % (cls.__name__, i))
log_contents.append(pull_requests_log(driver=driver))
log_names.append('%s_requests%s.log' % (cls.__name__, i))
session_id = driver.session_id
from support.lambda_test import update_session
try:
# sauce.jobs.update_job(username=sauce_username, job_id=session_id, name=cls.__name__)
update_session(
session_id=session_id,
session_name=cls.__name__,
status="failed" if group_setup_failed else "passed"
)
except (RemoteDisconnected, SauceException, requests.exceptions.ConnectionError):
pass
lt_session_status = "failed"
else:
lt_session_status = "passed"
try:
driver.update_lt_session_status(i + 1, lt_session_status)
driver.quit()
except WebDriverException:
except (WebDriverException, RemoteDisconnected):
pass
# url = 'https://api.%s/rest/v1/%s/jobs/%s/assets/%s' % (apibase, sauce_username, session_id, "log.json")
# try:
@ -514,11 +443,9 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
if pytest_config_global['env'] == 'local':
MultipleDeviceTestCase = LocalMultipleDeviceTestCase
MultipleSharedDeviceTestCase = LocalSharedMultipleDeviceTestCase
else:
MultipleDeviceTestCase = SauceMultipleDeviceTestCase
MultipleSharedDeviceTestCase = SauceSharedMultipleDeviceTestCase
MultipleSharedDeviceTestCase = LambdaTestSharedMultipleDeviceTestCase
class NoDeviceTestCase(AbstractTestCase):

View File

@ -1,3 +1,4 @@
import json
import os
import re
import signal
@ -11,6 +12,7 @@ from os import environ
import pytest
import requests
from _pytest.runner import runtestprotocol
from filelock import FileLock
from requests.exceptions import ConnectionError as c_er
import tests
@ -18,9 +20,6 @@ from support.device_stats_db import DeviceStatsDB
from support.test_rerun import should_rerun_test
from tests import test_suite_data, appium_container
sauce_username = environ.get('SAUCE_USERNAME')
sauce_access_key = environ.get('SAUCE_ACCESS_KEY')
lambda_test_username = environ.get('LAMBDA_TEST_USERNAME')
lambda_test_access_key = environ.get('LAMBDA_TEST_ACCESS_KEY')
@ -38,12 +37,8 @@ def pytest_addoption(parser):
help='Url or local path to apk')
parser.addoption('--env',
action='store',
default='sauce',
help='Specify environment: local/sauce/api')
parser.addoption('--datacenter',
action='store',
default='eu-central-1',
help='For sauce only: us-west-1, eu-central-1')
default='lt',
help='Specify environment: local/lt/api')
parser.addoption('--platform_version',
action='store',
default='8.0',
@ -60,10 +55,6 @@ def pytest_addoption(parser):
action='store',
default=False,
help='boolean; For creating testrail report per run')
parser.addoption('--network',
action='store',
default='ropsten',
help='string; ropsten or rinkeby')
parser.addoption('--rerun_count',
action='store',
default=0,
@ -145,32 +136,18 @@ def pytest_addoption(parser):
@dataclass
class Option:
datacenter: str = None
lambda_test_apk_url: str = None
option = Option()
testrail_report = None
github_report = None
apibase = None
sauce = None
run_name = None
# lambda_test_apk_url = None
def is_master(config):
return not hasattr(config, 'workerinput')
def is_uploaded():
return False # ToDo: add verification
# stored_files = sauce.storage.files()
# for i in range(len(stored_files)):
# if stored_files[i].name == test_suite_data.apk_name:
# return True
@contextmanager
def _upload_time_limit(seconds):
def signal_handler(signum, frame):
@ -193,20 +170,13 @@ class UploadApkException(Exception):
def _upload_and_check_response(apk_file_path):
from support.lambda_test import upload_apk
with _upload_time_limit(1000):
# # resp = sauce.storage.upload(apk_file_path)
return upload_apk(apk_file_path)
# try:
# if resp.name != test_suite_data.apk_name:
# raise UploadApkException("Incorrect apk was uploaded to Sauce storage, response:\n%s" % resp)
# except AttributeError:
# raise UploadApkException("Error when uploading apk to Sauce storage, response:\n%s" % resp)
def _upload_and_check_response_with_retries(apk_file_path, retries=3):
for _ in range(retries):
try:
return _upload_and_check_response(apk_file_path)
# break
except (ConnectionError, RemoteDisconnected, c_er):
time.sleep(10)
@ -252,20 +222,10 @@ def pytest_configure(config):
testrail_report = TestrailReport()
from support.github_report import GithubHtmlReport
global github_report
from saucelab_api_client.saucelab_api_client import SauceLab
github_report = GithubHtmlReport()
tests.pytest_config_global = vars(config.option)
config.addinivalue_line("markers", "testrail_id(name): empty")
global apibase
if config.getoption('datacenter') == 'us-west-1':
apibase = 'us-west-1.saucelabs.com'
elif config.getoption('datacenter') == 'eu-central-1':
apibase = 'eu-central-1.saucelabs.com'
else:
raise NotImplementedError("Unknown SauceLabs datacenter")
# global sauce
# sauce = SauceLab('https://api.' + apibase + '/', sauce_username, sauce_access_key)
if config.getoption('log_steps'):
import logging
logging.basicConfig(level=logging.INFO)
@ -281,18 +241,6 @@ def pytest_configure(config):
else:
run_name = get_run_name(config, new_one=False)
if is_master(config):
apk_src = config.getoption('apk')
if apk_src.startswith('http'):
apk_path = _download_apk(apk_src)
else:
apk_path = apk_src
# global lambda_test_apk_url
option.lambda_test_apk_url = _upload_and_check_response(apk_path)
if apk_src.startswith('http'):
os.remove(apk_path)
if not is_master(config):
return
@ -308,8 +256,23 @@ def pytest_configure(config):
)
def pytest_configure_node(node):
node.workerinput['lambda_test_apk_url'] = node.config.option.lambda_test_apk_url
@pytest.fixture(scope='session', autouse=True)
def upload_apk(tmp_path_factory):
fn = tmp_path_factory.getbasetemp().parent / "lt_apk.json"
with FileLock(str(fn) + ".lock"):
if fn.is_file():
data = json.loads(fn.read_text())
tests.pytest_config_global['lt_apk_url'] = data['lambda_test_apk_url']
else:
apk_src = tests.pytest_config_global['apk']
if apk_src.startswith('http'):
apk_path = _download_apk(apk_src)
else:
apk_path = apk_src
tests.pytest_config_global['lt_apk_url'] = _upload_and_check_response(apk_path)
fn.write_text(json.dumps({'lambda_test_apk_url': tests.pytest_config_global['lt_apk_url']}))
if apk_src.startswith('http'):
os.remove(apk_path)
def pytest_unconfigure(config):
@ -342,7 +305,6 @@ def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
is_sauce_env = item.config.getoption('env') == 'sauce'
case_ids_set = item.config.getoption("run_testrail_ids")
def catch_error():
@ -381,10 +343,6 @@ def pytest_runtest_makereport(item, call):
test_suite_data.current_test.group_name = item.instance.__class__.__name__
error = catch_error()
final_error = '%s %s' % (error_intro, error)
# if is_sauce_env:
# update_sauce_jobs(test_suite_data.current_test.group_name,
# test_suite_data.current_test.testruns[-1].jobs,
# report.passed)
if error:
test_suite_data.current_test.testruns[-1].error = final_error
github_report.save_test(test_suite_data.current_test)
@ -401,8 +359,6 @@ def pytest_runtest_makereport(item, call):
current_test.testruns[-1].run = False
if error:
current_test.testruns[-1].error = '%s [[%s]]' % (error, report.wasxfail)
# if is_sauce_env:
# update_sauce_jobs(current_test.name, current_test.testruns[-1].jobs, report.passed)
if item.config.getoption('docker'):
device_stats = appium_container.get_device_stats()
if item.config.getoption('bugreport'):
@ -426,15 +382,6 @@ def pytest_runtest_makereport(item, call):
device_stats_db.save_stats(build_name, item.name, test_group, not report.failed, device_stats)
def update_sauce_jobs(test_name, job_ids, passed):
from sauceclient import SauceException
for job_id in job_ids.keys():
try:
sauce.jobs.update_job(username=sauce_username, job_id=job_id, name=test_name, passed=passed)
except (RemoteDisconnected, SauceException, c_er):
pass
def get_testrail_case_id(item):
testrail_id = item.get_closest_marker('testrail_id')
if testrail_id:

View File

@ -14,7 +14,6 @@ from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="new_one_2")
@marks.nightly
@marks.lt
class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
def prepare_devices(self):
@ -61,13 +60,13 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
"Receiver also sets 'thumbs-up' emoji and verifies counter on received message in 1-1 chat")
message_receiver = self.chat_2.chat_element_by_text(message_from_sender)
message_receiver.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1, 90)
self.chat_2.add_remove_same_reaction(message_from_sender)
self.chat_2.add_remove_same_reaction()
message_receiver.emojis_below_message(emoji="thumbs-up").wait_for_element_text(2)
message_sender.emojis_below_message(emoji="thumbs-up").wait_for_element_text(2, 90)
self.device_2.just_fyi(
"Receiver removes 'thumbs-up' emoji and verify that counter will decrease for both users")
self.chat_2.add_remove_same_reaction(message_from_sender)
self.chat_2.add_remove_same_reaction()
message_receiver.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1)
message_sender.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1, 90)
@ -79,21 +78,20 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
message_sender.emojis_below_message(emoji="love").wait_for_element_text(1, 90)
self.device_1.just_fyi("Sender votes for 'love' reaction. Check reactions counters")
self.chat_1.add_remove_same_reaction(message_from_sender, emoji="love")
self.chat_1.add_remove_same_reaction(emoji="love")
message_receiver.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1)
message_sender.emojis_below_message(emoji="thumbs-up").wait_for_element_text(1)
message_receiver.emojis_below_message(emoji="love").wait_for_element_text(2, 90)
message_sender.emojis_below_message(emoji="love").wait_for_element_text(2)
self.device_1.just_fyi("Check emojis info")
message_sender.emojis_below_message(emoji="love").long_press_until_element_is_shown(
self.chat_1.authors_for_reaction(emoji="love"))
message_sender.emojis_below_message(emoji="love").long_press_without_release()
if not self.chat_1.user_list_element_by_name(
self.username_1).is_element_displayed() or not self.chat_1.user_list_element_by_name(
self.username_2).is_element_displayed():
self.errors.append("Incorrect users are shown for 'love' reaction.")
self.chat_1.authors_for_reaction(emoji="thumbs-up").click()
self.chat_1.authors_for_reaction(emoji="thumbs-up").double_click()
if not self.chat_1.user_list_element_by_name(
self.username_1).is_element_displayed() or self.chat_1.user_list_element_by_name(
self.username_2).is_element_displayed():
@ -232,8 +230,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.errors.append("Can pin more than 3 messages in chat")
else:
unpin_element = self.chat_1.element_by_translation_id('unpin-from-chat')
self.chat_1.pinned_messages_list.message_element_by_text(self.message_2).long_press_element(
element_to_release_on=unpin_element)
self.chat_1.pinned_messages_list.message_element_by_text(self.message_2).long_press_without_release()
self.home_1.just_fyi("Unpin one message so that another could be pinned")
unpin_element.click_until_absense_of_element(desired_element=unpin_element)
self.chat_1.pin_message(self.message_4, 'pin-to-chat')
@ -254,7 +251,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
pinned_message = self.chat_1.pinned_messages_list.message_element_by_text(self.message_4)
unpin_element = self.chat_1.element_by_translation_id("unpin-from-chat")
pinned_message.long_press_element(element_to_release_on=unpin_element)
pinned_message.long_press_without_release()
unpin_element.click_until_absense_of_element(unpin_element)
# try:
# self.chat_2.chat_element_by_text(self.message_4).pinned_by_label.wait_for_invisibility_of_element()
@ -276,7 +273,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
def test_1_1_chat_non_latin_messages_stack_update_profile_photo(self):
self.home_1.navigate_back_to_home_view()
self.home_1.profile_button.click()
self.profile_1.edit_profile_picture(image_index=2)
self.profile_1.edit_profile_picture(image_index=0)
self.chat_2.just_fyi("Send messages with non-latin symbols")
self.home_1.click_system_back_button()
@ -315,8 +312,8 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.chat_1.just_fyi("Go back to chat view and checking that profile photo is updated")
if not self.chat_2.chat_message_input.is_element_displayed():
self.home_2.get_chat(self.username_1).click()
if self.chat_2.chat_element_by_text(message).member_photo.is_element_differs_from_template("member3.png",
diff=7):
if self.chat_2.chat_element_by_text(message).member_photo.is_element_differs_from_template(
"profile_image_in_1_1_chat.png", diff=7):
self.errors.append("Image of user in 1-1 chat is too different from template!")
self.errors.verify_no_errors()
@ -415,14 +412,14 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.chat_1.just_fyi("Device 1 sends an image")
image_description = "test image"
self.chat_1.send_images_with_description(description=image_description, indexes=[2])
self.chat_1.send_images_with_description(description=image_description, indexes=[0])
self.chat_2.just_fyi("Device 2 checks image message")
if not self.chat_2.chat_element_by_text(image_description).is_element_displayed(30):
self.chat_2.hide_keyboard_if_shown()
self.chat_2.chat_element_by_text(image_description).wait_for_visibility_of_element(30)
if not self.chat_2.chat_element_by_text(
image_description).image_in_message.is_element_image_similar_to_template('saucelabs_sauce_chat.png'):
image_description).image_in_message.is_element_image_similar_to_template('image_1_chat_view.png'):
self.errors.append("Not expected image is shown to the receiver.")
for chat in self.chat_1, self.chat_2:
@ -460,7 +457,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
chat.just_fyi("Check that image is saved in gallery")
chat.show_images_button.click()
chat.allow_all_button.click_if_shown()
if not chat.get_image_by_index(0).is_element_image_similar_to_template("saucelabs_sauce_gallery.png"):
if not chat.get_image_by_index(0).is_element_image_similar_to_template("image_1_gallery_view.png"):
self.errors.append(
"Image is not saved to gallery for %s." % ("sender" if chat is self.chat_1 else "receiver"))
chat.click_system_back_button()
@ -485,7 +482,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.chat_2.send_message(message_after_edit_1_1)
self.chat_2.chat_element_by_text(message_after_edit_1_1).wait_for_status_to_be("Delivered")
chat_1_element = self.chat_1.chat_element_by_text(message_after_edit_1_1)
chat_1_element.long_press_element()
chat_1_element.long_press_without_release()
for action in ("edit", "delete-for-everyone"):
if self.chat_1.element_by_translation_id(action).is_element_displayed():
self.errors.append('Option to %s someone else message available!' % action)
@ -643,13 +640,13 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
self.chat_1.just_fyi("Unmute chat")
self.chat_1.navigate_back_to_home_view()
chat.long_press_element()
chat.long_press_without_release()
if self.home_1.mute_chat_button.text != transl["unmute-chat"]:
self.errors.append("Chat is not muted")
expected_text = "Muted until you turn it back on"
if not self.home_1.element_by_text(expected_text).is_element_displayed():
self.errors.append("Text '%s' is not shown for muted chat" % expected_text)
self.home_1.mute_chat_button.click()
self.home_1.mute_chat_button.double_click()
unmuted_message = "after unmute"
self.chat_2.send_message(unmuted_message)

View File

@ -13,7 +13,6 @@ from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="new_one_3")
@marks.nightly
@marks.lt
class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
def prepare_devices(self):
@ -119,7 +118,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chats[1].set_reaction(message=message, emoji="love")
self.chats[2].just_fyi("Member_2 sets 2 reactions on the message: 'thumbs-up' and 'laugh'")
self.chats[2].add_remove_same_reaction(message=message, emoji="thumbs-up")
self.chats[2].add_remove_same_reaction(emoji="thumbs-up")
self.chats[2].set_reaction(message=message, emoji="laugh")
def _check_reactions_count(chat_view_index):
@ -136,14 +135,13 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
)))
self.chats[0].just_fyi("Admin checks info about voted users")
self.chats[0].chat_element_by_text(message).emojis_below_message(
emoji="thumbs-up").long_press_until_element_is_shown(self.chats[0].authors_for_reaction(emoji="thumbs-up"))
self.chats[0].chat_element_by_text(message).emojis_below_message(emoji="thumbs-up").long_press_without_release()
if not self.chats[0].user_list_element_by_name(
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
self.usernames[2]).is_element_displayed():
self.errors.append("Incorrect users are shown for 'thumbs-up' reaction.")
self.chats[0].authors_for_reaction(emoji="love").click()
self.chats[0].authors_for_reaction(emoji="love").double_click()
if not self.chats[0].user_list_element_by_name(
self.usernames[1]).is_element_displayed() or self.chats[0].user_list_element_by_name(
self.usernames[2]).is_element_displayed():
@ -169,12 +167,12 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chats[0].navigate_back_to_chat_view()
self.chats[1].just_fyi("Member_1 removes 'thumbs-up' reaction and adds 'sad' one")
self.chats[1].add_remove_same_reaction(message=message, emoji="thumbs-up")
self.chats[1].add_remove_same_reaction(emoji="thumbs-up")
self.chats[1].set_reaction(message=message, emoji="sad")
self.chats[2].just_fyi("Member_2 removes 'laugh' reaction and adds 'sad' one")
self.chats[2].add_remove_same_reaction(message=message, emoji="laugh")
self.chats[2].add_remove_same_reaction(message=message, emoji="sad")
self.chats[2].add_remove_same_reaction(emoji="laugh")
self.chats[2].add_remove_same_reaction(emoji="sad")
def _check_reactions_count_after_change(chat_view_index):
self.chats[chat_view_index].just_fyi(
@ -212,14 +210,13 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
chat.navigate_back_to_home_view()
self.chats[0].just_fyi("Admin checks info about voted users after relogin")
message_element.emojis_below_message(
emoji="thumbs-up").long_press_until_element_is_shown(self.chats[0].authors_for_reaction(emoji="thumbs-up"))
message_element.emojis_below_message(emoji="thumbs-up").long_press_without_release()
if self.chats[0].user_list_element_by_name(
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
self.usernames[2]).is_element_displayed():
self.errors.append("Incorrect users are shown for 'thumbs-up' reaction after relogin.")
self.chats[0].authors_for_reaction(emoji="love").click()
self.chats[0].authors_for_reaction(emoji="love").double_click()
if not self.chats[0].user_list_element_by_name(
self.usernames[1]).is_element_displayed() or self.chats[0].user_list_element_by_name(
self.usernames[2]).is_element_displayed():
@ -241,18 +238,18 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chats[1].just_fyi("Member_1 sends an image")
image_description = "test image"
self.chats[1].send_images_with_description(description=image_description, indexes=[2])
self.chats[1].send_images_with_description(description=image_description, indexes=[1])
self.chats[0].just_fyi("Admin checks image message")
chat_element = self.chats[0].chat_element_by_text(image_description)
chat_element.wait_for_visibility_of_element(60)
if not chat_element.image_in_message.is_element_image_similar_to_template('saucelabs_sauce_group_chat.png'):
if not chat_element.image_in_message.is_element_image_similar_to_template('image_2_chat_view.png'):
self.errors.append("Not expected image is shown to the admin.")
self.chats[2].just_fyi("Member_2 checks image message")
chat_element = self.chats[2].chat_element_by_text(image_description)
chat_element.wait_for_visibility_of_element(60)
if not chat_element.image_in_message.is_element_image_similar_to_template('saucelabs_sauce_group_chat.png'):
if not chat_element.image_in_message.is_element_image_similar_to_template('image_2_chat_view.png'):
self.errors.append("Not expected image is shown to the member_2.")
self.chats[0].just_fyi("Admin opens the image and shares it")
@ -293,7 +290,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chats[2].just_fyi("Member_2 checks that image was saved in gallery")
self.chats[2].show_images_button.click()
self.chats[2].allow_all_button.click_if_shown()
if not self.chats[2].get_image_by_index(0).is_element_image_similar_to_template("saucelabs_sauce_gallery.png"):
if not self.chats[2].get_image_by_index(0).is_element_image_similar_to_template("image_2_gallery_view.png"):
self.errors.append("Image is not saved to gallery for member_2.")
self.chats[2].navigate_back_to_home_view()
@ -374,10 +371,11 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.errors.append("Message 1 is not pinned in group chat!")
self.chats[0].just_fyi("Check that non admin user can not unpin messages")
self.chats[1].chat_element_by_text(self.message_1).long_press_element()
self.chats[1].chat_element_by_text(self.message_1).long_press_without_release()
if self.chats[1].element_by_translation_id("unpin-from-chat").is_element_displayed():
self.errors.append("Unpin option is available for non-admin user")
self.chats[1].tap_by_coordinates(500, 100)
self.chats[1].tap_by_coordinates(500, 100)
# not implemented yet :
@ -406,8 +404,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.chats[0].pin_message(self.message_4, 'pin-to-chat')
self.chats[0].view_pinned_messages_button.click_until_presence_of_element(self.chats[0].pinned_messages_list)
unpin_element = self.chats[0].element_by_translation_id('unpin-from-chat')
self.chats[0].pinned_messages_list.message_element_by_text(self.message_2).long_press_element(
element_to_release_on=unpin_element)
self.chats[0].pinned_messages_list.message_element_by_text(self.message_2).long_press_without_release()
unpin_element.click_until_absense_of_element(desired_element=unpin_element)
self.chats[0].chat_element_by_text(self.message_4).click()
self.chats[0].pin_message(self.message_4, 'pin-to-chat')
@ -457,7 +454,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
"Muted until %s %s" % (exp_time.strftime('%H:%M'), "today" if current_time.hour < 16 else "tomorrow") for
exp_time in expected_times]
chat = self.homes[1].get_chat(self.chat_name)
chat.long_press_element()
chat.long_press_without_release()
if self.homes[1].mute_chat_button.text != transl["unmute-chat"]:
pytest.fail("Chat is not muted")
current_text = self.homes[1].mute_chat_button.unmute_caption_text
@ -487,15 +484,16 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message[:25])):
self.errors.append("Message text '%s' is not shown in chat preview after mute" % muted_message)
chat.click()
chat.click()
if not self.chats[1].chat_element_by_text(muted_message).is_element_displayed(30):
self.errors.append(
"Message '%s' is not shown in chat for %s after mute" % (muted_message, self.usernames[1]))
"Message '%s' is not shown in chat for %s (Member 1) after mute" % (muted_message, self.usernames[1]))
self.chats[1].navigate_back_to_home_view()
self.chats[1].just_fyi("Member 1 unmutes the chat")
chat.long_press_element()
self.homes[1].mute_chat_button.click()
chat.long_press_element()
chat.long_press_without_release()
self.homes[1].mute_chat_button.double_click()
chat.long_press_without_release()
if self.homes[1].element_starts_with_text("Muted until").is_element_displayed():
self.errors.append("Chat is still muted after being unmuted")
self.errors.verify_no_errors()
@ -523,8 +521,10 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[2], unmuted_message)):
self.errors.append("Message text '%s' is not shown in chat preview after unmute" % unmuted_message)
chat.click()
chat.click()
if not self.chats[1].chat_element_by_text(unmuted_message).is_element_displayed(30):
self.errors.append(
"Message '%s' is not shown in chat for %s after unmute" % (self.usernames[1], unmuted_message))
"Message '%s' is not shown in chat for %s (Member 1) after unmute" % (
unmuted_message, self.usernames[1]))
self.errors.verify_no_errors()

View File

@ -281,11 +281,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
# if community_name == 'Status':
self.home.just_fyi("Check Status community screen")
card.click()
self.community_view.join_button.save_new_screenshot_of_element('status_community_join_button_aaa.png')
if self.community_view.join_button.is_element_differs_from_template(
'status_community_join_button.png'):
self.errors.append("Status community Join button is different from expected template.")
self.community_view.community_logo.save_new_screenshot_of_element('status_community_logo_aaa.png')
if self.community_view.community_logo.is_element_differs_from_template('status_community_logo.png'):
self.errors.append("Status community logo is different from expected template.")
@ -412,7 +410,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(703194)
def test_community_several_images_send_reply(self):
self.home_1.just_fyi('Send several images in 1-1 chat from Gallery')
image_description, file_name = 'gallery', 'gallery_1.png'
image_description = 'gallery'
self.channel_1.send_images_with_description(image_description, [0, 1])
self.channel_2.just_fyi("Check gallery on second device")
@ -423,7 +421,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
try:
chat_element.wait_for_visibility_of_element(120)
received = True
if chat_element.image_container_in_message.is_element_differs_from_template(file_name, 5):
if chat_element.image_container_in_message.is_element_differs_from_template("images_gallery.png", 5):
self.errors.append("Gallery message do not match the template!")
except TimeoutException:
self.errors.append("Gallery message was not received")
@ -465,7 +463,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.channel_2.hide_keyboard_if_shown()
self.channel_2.chat_element_by_text(image_description).wait_for_visibility_of_element(10)
if not self.channel_2.chat_element_by_text(
image_description).image_in_message.is_element_image_similar_to_template('image_sent_in_community.png'):
image_description).image_in_message.is_element_image_similar_to_template('image_1_chat_view.png'):
self.errors.append("Not expected image is shown to the receiver")
if not self.channel_1.chat_element_by_text(image_description).is_element_displayed(60):
@ -489,7 +487,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.channel_1.show_images_button.click()
self.channel_1.allow_all_button.click_if_shown()
if not self.channel_1.get_image_by_index(0).is_element_image_similar_to_template(
"sauce_dark_image_gallery.png"):
"image_1_gallery_view.png"):
self.errors.append('Saved image is not shown in Recent')
self.channel_1.click_system_back_button()

View File

@ -271,7 +271,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
self.sign_in_2.continue_button.click()
if not self.sign_in_2.password_input.is_element_displayed():
self.errors.append("Can't recover an access with a valid passphrase")
self.sign_in_2.click_system_back_button()
self.sign_in_2.click_system_back_button(times=2)
self.sign_in_2.just_fyi("Device 2: try recovering an account which is already synced")
self.sign_in_2.passphrase_edit_box.clear()

View File

@ -13,5 +13,3 @@ upgrade = pytest.mark.upgrade
skip = pytest.mark.skip
xfail = pytest.mark.xfail
secured = pytest.mark.secured
lt = pytest.mark.lt # temp

View File

@ -1,5 +1,5 @@
from tests import marks, pytest_config_global, test_dapp_name
from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase
from tests.base_test_case import SingleDeviceTestCase, MultipleSharedDeviceTestCase
from tests.users import upgrade_users, transaction_recipients, basic_user, ens_user, transaction_senders
from views.sign_in_view import SignInView
import views.dbs.chats.data as chat_data
@ -245,7 +245,7 @@ class TestUpgradeApplication(SingleDeviceTestCase):
@marks.upgrade
class TestUpgradeMultipleApplication(MultipleDeviceTestCase):
class TestUpgradeMultipleApplication(MultipleSharedDeviceTestCase):
@marks.testrail_id(695783)
def test_commands_audio_backward_compatibility_upgrade(self):

View File

@ -10,6 +10,9 @@ from PIL import Image, ImageChops, ImageStat
from appium.webdriver.common.mobileby import MobileBy
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
@ -324,9 +327,21 @@ class BaseElement(object):
action.click_and_hold(element).perform()
time.sleep(2)
if element_to_release_on:
action.release(element_to_release_on.find_element()).perform()
action.release(element_to_release_on.find_element())
action.perform()
else:
action.release(element).perform()
action.release(element)
action.perform()
# actions = ActionChains(self.driver)
# actions.w3c_actions = ActionBuilder(self, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
# actions.w3c_actions.pointer_action.click_and_hold(element)
# actions.w3c_actions.pointer_action.release()
# actions.perform()
def long_press_without_release(self):
action = ActionChains(self.driver)
action.click_and_hold(self.find_element()).perform()
def long_press_until_element_is_shown(self, expected_element):
element = self.find_element()

View File

@ -411,6 +411,7 @@ class BaseView(object):
def just_fyi(self, some_str):
self.driver.info('# STEP: %s' % some_str, device=False)
# self.driver.execute_script("sauce:context=STEP: %s" % some_str)
self.driver.log_event("appium", "STEP: %s" % some_str)
def hide_keyboard_if_shown(self):
if self.driver.is_keyboard_shown():

View File

@ -4,6 +4,8 @@ from datetime import datetime, timedelta
from time import sleep
import dateutil.parser
import pytest
from appium.webdriver.common.appiumby import AppiumBy
from selenium.common.exceptions import NoSuchElementException, TimeoutException, StaleElementReferenceException, \
InvalidElementStateException
from selenium.webdriver import ActionChains
@ -232,11 +234,14 @@ class ChatElementByText(Text):
def replied_message_text(self):
class RepliedMessageText(Text):
def __init__(self, driver, parent_locator: str):
super().__init__(driver, prefix=parent_locator,
xpath="/preceding::android.widget.TextView[@content-desc='quoted-message']")
super().__init__(driver,
# prefix=parent_locator,
# xpath="/preceding::android.widget.TextView[@content-desc='quoted-message']"
accessibility_id='quoted-message')
try:
return RepliedMessageText(self.driver, self.message_locator).text
# return RepliedMessageText(self.driver, self.message_locator).text
return self.find_element().find_element(by=AppiumBy.ACCESSIBILITY_ID, value='quoted-message').text
except NoSuchElementException:
return ''
@ -1011,13 +1016,13 @@ class ChatView(BaseView):
def pin_message(self, message, action="pin"):
self.driver.info("Looking for message '%s' pin" % message)
element = self.element_by_translation_id(action)
self.chat_element_by_text(message).long_press_until_element_is_shown(element)
self.chat_element_by_text(message).long_press_without_release()
element.click_until_absense_of_element(element)
def edit_message_in_chat(self, message_to_edit, message_to_update):
self.driver.info("Looking for message '%s' to edit it" % message_to_edit)
self.chat_element_by_text(message_to_edit).message_body.long_press_element()
self.element_by_translation_id("edit-message").click()
self.chat_element_by_text(message_to_edit).message_body.long_press_without_release()
self.element_by_translation_id("edit-message").double_click()
self.chat_message_input.clear()
self.chat_message_input.send_keys(message_to_update)
self.send_message_button.click()
@ -1028,40 +1033,34 @@ class ChatView(BaseView):
delete_button = self.element_by_translation_id("delete-for-everyone")
else:
delete_button = self.element_by_translation_id("delete-for-me")
self.chat_element_by_text(message).message_body.long_press_element()
delete_button.click()
self.chat_element_by_text(message).message_body.long_press_without_release()
delete_button.double_click()
def copy_message_text(self, message_text):
self.driver.info("Copying '%s' message via long press" % message_text)
self.chat_element_by_text(message_text).wait_for_visibility_of_element()
self.chat_element_by_text(message_text).long_press_element()
self.element_by_translation_id("copy-text").click()
self.chat_element_by_text(message_text).long_press_without_release()
self.element_by_translation_id("copy-text").double_click()
def quote_message(self, message: str):
self.driver.info("Quoting '%s' message" % message)
element = self.chat_element_by_text(message)
element.wait_for_sent_state()
element.long_press_until_element_is_shown(self.reply_message_button)
self.reply_message_button.click()
element.long_press_without_release()
self.reply_message_button.double_click()
def set_reaction(self, message: str, emoji: str = 'thumbs-up', emoji_message=False):
self.driver.info("Setting '%s' reaction" % emoji)
# Audio message is obvious should be tapped not on audio-scroll-line
# so we tap on its below element as exception here (not the case for link/tag message!)
element = Button(self.driver, accessibility_id='reaction-%s' % emoji)
if message == 'audio':
self.audio_message_in_chat_timer.long_press_element()
if emoji_message:
self.element_by_text_part(message).long_press_without_release()
else:
if not emoji_message:
self.chat_element_by_text(message).long_press_until_element_is_shown(element)
else:
self.element_by_text_part(message).long_press_until_element_is_shown(element)
# old UI
# element = Button(self.driver, accessibility_id='pick-emoji-%s' % key)
element.click()
self.chat_element_by_text(message).long_press_without_release()
element.wait_for_element()
element.double_click()
element.wait_for_invisibility_of_element()
def add_remove_same_reaction(self, message: str, emoji: str = 'thumbs-up'):
def add_remove_same_reaction(self, emoji: str = 'thumbs-up'):
self.driver.info("Adding one more '%s' reaction or removing an added one" % emoji)
key = emojis[emoji]
element = Button(self.driver, accessibility_id='emoji-reaction-%s' % key)
@ -1212,7 +1211,11 @@ class ChatView(BaseView):
self.show_images_button.click()
self.allow_button.click_if_shown()
self.allow_all_button.click_if_shown()
[self.get_image_by_index(i).click() for i in indexes]
try:
[self.get_image_by_index(i).click() for i in indexes]
except NoSuchElementException:
self.click_system_back_button()
pytest.fail("Can't send image(s) with index(es) %s" % indexes)
self.images_confirm_selection_button.click()
self.chat_message_input.send_keys(description)
self.send_message_button.click()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

View File

@ -545,8 +545,8 @@ class HomeView(BaseView):
def delete_chat_long_press(self, username):
self.driver.info("Deleting chat '%s' by long press" % username)
self.get_chat(username).long_press_element()
self.close_chat_button.click()
self.get_chat(username).long_press_without_release()
self.close_chat_button.double_click()
self.confirm_closing_chat_button.click()
def leave_chat_long_press(self, username):
@ -565,13 +565,15 @@ class HomeView(BaseView):
def mute_chat_long_press(self, chat_name, mute_period="mute-till-unmute", community=False, community_channel=False):
self.driver.info("Muting chat with %s" % chat_name)
self.get_chat(username=chat_name, community=community, community_channel=community_channel).long_press_element()
self.get_chat(username=chat_name, community=community,
community_channel=community_channel).long_press_without_release()
if community:
self.mute_community_button.click()
element = self.mute_community_button
elif community_channel:
self.mute_channel_button.click()
element = self.mute_channel_button
else:
self.mute_chat_button.click()
element = self.mute_chat_button
element.double_click()
self.element_by_translation_id(mute_period).click()
def get_pn(self, pn_text: str):
@ -587,7 +589,14 @@ class HomeView(BaseView):
def get_link_to_profile(self):
self.show_qr_code_button.click()
try:
element = self.link_to_profile_button.find_element()
except NoSuchElementException:
element = None
pass
self.share_profile_tab_button.click()
if element:
self.wait_for_staleness_of_element(element)
self.link_to_profile_button.click()
link_to_profile = self.sharing_text_native.text
self.click_system_back_button()

View File

@ -438,7 +438,7 @@ class ProfileView(BaseView):
def edit_profile_picture(self, image_index: int, update_by="Gallery"):
self.driver.info("## Setting custom profile image", device=False)
if not AbstractTestCase().environment == 'sauce':
if not AbstractTestCase().environment == 'lt':
raise NotImplementedError('Test case is implemented to run on SauceLabs only')
self.edit_profile_button.click()
self.change_profile_photo_button.click()
@ -473,6 +473,7 @@ class ProfileView(BaseView):
try:
image_element.find_elements()[image_index].click()
except IndexError:
self.click_system_back_button(times=2)
raise NoSuchElementException("Image with index %s was not found" % image_index) from None
def logout(self):

View File

@ -163,8 +163,8 @@ class WalletView(BaseView):
def send_asset_from_drawer(self, address: str, asset_name: str, amount: float):
asset_element = self.get_asset(asset_name)
asset_element.long_press_element()
self.send_from_drawer_button.click()
asset_element.long_press_without_release()
self.send_from_drawer_button.double_click()
self.address_text_input.send_keys(address)
self.continue_button.click()
self.set_amount(amount)
@ -218,6 +218,7 @@ class WalletView(BaseView):
self.element_by_translation_id("reveal-phrase").click()
# ToDo: can't be done in current small size emulators, add when moved to LambdaTest
self.slide_and_confirm_with_password()
self.add_account_derivation_path_text.wait_for_element()
derivation_path = self.add_account_derivation_path_text.text
return derivation_path.replace(' ', '')