From 0cb31f89b5a1a8b26b5a14b3459353b95879d741 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 23 Oct 2019 11:38:14 +0100 Subject: [PATCH 01/27] Changed get_json to use the requests library for the ability to add new API headers --- pytest_appium/_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pytest_appium/_utils.py b/pytest_appium/_utils.py index af059cf..5404dd0 100644 --- a/pytest_appium/_utils.py +++ b/pytest_appium/_utils.py @@ -1,6 +1,7 @@ import json import urllib #.request import time +import requests def _decode_response(response): @@ -12,8 +13,9 @@ def _decode_response(response): return json.loads(data.decode(encoding)) -def get_json(url): - return _decode_response(urllib.request.urlopen(url)) +def get_json(url, headers: dict=None): + r = requests.get(url, headers=headers) + return r.json() def post_json(url, data): From 857f30a6e0b65b559027fdebdf12af3484039cea Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Fri, 7 Aug 2020 18:21:00 +0100 Subject: [PATCH 02/27] Deprected MarkInfo resolution --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 618ab49..0f15cdd 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -213,7 +213,7 @@ def test_example(): # Filter tests that are not targeted for this platform current_platform = config._variables.get('capabilities',{}).get('platformName','').lower() def select_test(item): - platform_marker = item.get_marker("platform") + platform_marker = item.get_closest_marker("platform") if platform_marker and platform_marker.args and current_platform: test_platform_specified = platform_marker.args[0].lower() if test_platform_specified != current_platform: From 3a9e54afeacf4b1f1252cd20094f0fb33b8ad2e8 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Fri, 7 Aug 2020 19:51:46 +0100 Subject: [PATCH 03/27] attempting to fix driver_class and kwargs errors --- pytest_appium/conftest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 0f15cdd..c0fd6c3 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -138,16 +138,16 @@ def _appium_is_device_available(appium_wd_api_endpoint, desiredCapabilities={}, } @pytest.yield_fixture(scope='session') -def driver_session_(request, session_capabilities): +def driver_session_(driver_class, driver_kwargs, request, session_capabilities): """ Appium Session Created from --capabilities (do not use this fixture directly as report screenshots will not function) """ - _driver_class = driver_class(request) - _driver_kwargs = driver_kwargs(request, session_capabilities) + driver_class(request) + driver_kwargs(request, session_capabilities) - appium_url = _driver_kwargs['command_executor'] + appium_url = driver_kwargs['command_executor'] # Wait for Appium def wait_for_appium(): @@ -171,7 +171,7 @@ def wait_for_appium(): wait_for_appium() try: - yield from driver(request, _driver_class, _driver_kwargs) + yield from driver(request, driver_class, driver_kwargs) except urllib.error.URLError: raise Exception(f"""Unable to connect to Appium server {appium_url}""") From 2c2ee8d41788fe0497bed64a370c7db3ea06e4ba Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 10 Aug 2020 13:53:30 +0100 Subject: [PATCH 04/27] Revert "Deprected MarkInfo resolution" This reverts commit 857f30a6e0b65b559027fdebdf12af3484039cea. --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 0f15cdd..618ab49 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -213,7 +213,7 @@ def test_example(): # Filter tests that are not targeted for this platform current_platform = config._variables.get('capabilities',{}).get('platformName','').lower() def select_test(item): - platform_marker = item.get_closest_marker("platform") + platform_marker = item.get_marker("platform") if platform_marker and platform_marker.args and current_platform: test_platform_specified = platform_marker.args[0].lower() if test_platform_specified != current_platform: From 61515e0bdb64edd1a45e5d2eff653dbba6d0939a Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 10 Aug 2020 14:25:36 +0100 Subject: [PATCH 05/27] trying to revert my mistakes --- pytest_appium/conftest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 49d65ea..618ab49 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -138,16 +138,16 @@ def _appium_is_device_available(appium_wd_api_endpoint, desiredCapabilities={}, } @pytest.yield_fixture(scope='session') -def driver_session_(driver_class, driver_kwargs, request, session_capabilities): +def driver_session_(request, session_capabilities): """ Appium Session Created from --capabilities (do not use this fixture directly as report screenshots will not function) """ - driver_class(request) - driver_kwargs(request, session_capabilities) + _driver_class = driver_class(request) + _driver_kwargs = driver_kwargs(request, session_capabilities) - appium_url = driver_kwargs['command_executor'] + appium_url = _driver_kwargs['command_executor'] # Wait for Appium def wait_for_appium(): @@ -171,7 +171,7 @@ def wait_for_appium(): wait_for_appium() try: - yield from driver(request, driver_class, driver_kwargs) + yield from driver(request, _driver_class, _driver_kwargs) except urllib.error.URLError: raise Exception(f"""Unable to connect to Appium server {appium_url}""") From 00af69712d5dbbe7b77d75266b80251236642a49 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 10 Aug 2020 16:54:05 +0100 Subject: [PATCH 06/27] removed warning by making driver_class and driver_kwargs not fixtures --- pytest_appium.egg-info/PKG-INFO | 220 ++++++++++++++++++++ pytest_appium.egg-info/SOURCES.txt | 22 ++ pytest_appium.egg-info/dependency_links.txt | 1 + pytest_appium.egg-info/requires.txt | 4 + pytest_appium.egg-info/top_level.txt | 1 + pytest_appium/conftest.py | 7 +- 6 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 pytest_appium.egg-info/PKG-INFO create mode 100644 pytest_appium.egg-info/SOURCES.txt create mode 100644 pytest_appium.egg-info/dependency_links.txt create mode 100644 pytest_appium.egg-info/requires.txt create mode 100644 pytest_appium.egg-info/top_level.txt diff --git a/pytest_appium.egg-info/PKG-INFO b/pytest_appium.egg-info/PKG-INFO new file mode 100644 index 0000000..16a2a16 --- /dev/null +++ b/pytest_appium.egg-info/PKG-INFO @@ -0,0 +1,220 @@ +Metadata-Version: 1.1 +Name: pytest-appium +Version: 0.0.2 +Summary: Plugin for running Appium with pytest +Home-page: http://git.int.thisisglobal.com/interactive/pytest-appium +Author: Global +Author-email: leicestersquare-interactive-developers@global.com +License: MIT +Description: pytest-appium + ============= + + `pytest-appium` is a plugin for [pytest](https://docs.pytest.org/en/latest/) that provides support for running [Appium](http://appium.io/) based tests. + + It is inspired by [pytest-selenium](https://github.com/pytest-dev/pytest-selenium) + + This package has a suite of additional utilities + + * HTML Reports + * Augment the base Appium `driver` with additional modular functionality with python mixins. + * Wait for Appium to be ready + * `pytest.mark.platform` + * Light python builders for Android [UiSelector](https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html) + + + Setup + ----- + + pip requirements file + ``` + git+http://GIT.SERVER.LOCATION/pytest-appium.git@master#egg=pytest-appium + ``` + + pytest.ini + ``` + [pytest] + addopts = -p pytest_appium + ``` + + python test example + ```python + from pytest_appium.android.UIAutomator2 import UiSelector, UiScrollable + from pytest_appium.driver.proxy._enums import Direction + + @pytest.mark.platform('ios') + def test_example(appium_extended, platform): + el = appium_extended.find_element_on_page( + UiSelector().resourceIdMatches('.*awesome_item'), + direction=Direction.LEFT, + ) + assert el.text == 'Example' + ``` + + commandline example + ```bash + $(PYTHON_VENV)/bin/py.test \ + $(TEST_PATH) \ + --html=$(REPORT_PATH)/report.html \ + --junitxml=$(REPORT_PATH)/report.xml \ + --variables variables/pytest/android_emulator_local.json \ + --capability app $(APPIUM_APK_PATH) + ``` + for more commandline details use `pytest --help` under the heading `appium` + + + Features + -------- + + ### HTML reports + + [pytest-html](https://pypi.python.org/pypi/pytest-html/) for Appium tests. + + Includes screenshot, page `XML` and full `logcat` dumps. + + + ### Wait for startup conditions + + Orchestration of service startup order is sometimes problematic. + On startup we can wait for a varity of conditions. + `pytest --help` for details + + ``` + --appium_wait_for_condition={appium,android_device_available} + Type of appium condition to wait for before beginning + first test + --appium_wait_for_seconds=APPIUM_WAIT_FOR_SECONDS + Seconds to wait for an Appium server to become + available before raising an error. + ``` + + * `appium` - Waits for the Appium port to become active + * `android_device_available` - Trys to send a low level `wd` api call to launch an Android packagename "NOT-REAL". We know an android device is connected and available if the error message explicitly contains "NOT-REAL". + + Example of use in a `docker-compose.yml` waiting for android device. + ```yaml + command: + - pytest + ... + - --appium_host=android-container + - --appium_wait_for_seconds=90 + - --appium_wait_for_condition=android_device_available + ... + ``` + + Exampe of use in a `bash` script waiting for appium service to become active. + ```bash + ... + (nohup node $(APPIUM_PATH) $(APPIUM_ARGS) > $(REPORT_FOLDER)/appium.log &) + ... + + _env/bin/py.test \ + tests \ + ... + --appium_host=localhost \ + --appium_wait_for_condition appium \ + --appium_wait_for_seconds 30 \ + ... + + ``` + + ### pytest Markers for platforms + + ```python + @pytest.mark.platform('ios') + def test_ios(appium_extended): + pass + + @pytest.mark.platform('android') + def test_android(appium_extended): + pass + + def test_both_ios_and_android(appium_extended): + pass + ``` + + ### Python wrapper for expressing UiSelector syntax in python + + Handling long android strings to compose UiSelectors is inflexible. A lightweight UiSelector python builder is provided + + ```python + from pytest_appium.android.UIAutomator2 import UiSelector, UiScrollable + + # Create a UiSelector python builder + selector = UiSelector().resourceIdMatches('.*filmstrip_list').childSelector(UiSelector().index(1)) + assert str(selector) == 'new UiSelector().resourceIdMatches(".*filmstrip_list").childSelector(new UiSelector().index(1))' + + # UiSelector objects can be used directly + el = self.driver.find_element_by_android_uiautomator(selector) + + # UiSelectors can have segments modified/appended after creation + selector.ui_objects[-1].childSelector(UiSelector().className('my_class')) + assert str(selector) == 'new UiSelector().resourceIdMatches(".*filmstrip_list").childSelector(new UiSelector().index(1).childSelector(new UiSelector().className("my_class")))' + self.driver.find_element_by_android_uiautomator(selector) + ``` + + ### Appium Driver Extension Framework + + The base Appium [python-client](https://github.com/appium/python-client) `driver` supports base functions. + We sometimes want to add extra functionality to this `driver` for individual platforms. + + We can transparently overlay extra Mixin's over the base `driver` object. This is available as the pytest fixture `appium_extended`. + + ```python + from pytest_appium.driver.proxy.proxy_mixin import register_proxy_mixin + + @register_proxy_mixin(name='android') + class MyAndroidDriverMixin(): + def new_thing(self, text): + log.debug('my mixin method for android') + # modify the selector in some cool way + return self.find_element(*my_cool_selector_with_text) + + @register_proxy_mixin(name='ios') + class MyIOSDriverMixin(): + def new_thing(self, text): + log.debug('my mixin method for ios') + # modify the selector in some cool way + return self.find_element(*my_cool_selector_with_text) + + def test_my_mixin(appium_extended): + el = appium_extended.new_thing('text of awesome') + + # The `appium` fixture can be used to get the base `driver` without mixin augmentation. + @pytest.mark.xfail(strict=True) + def test_my_mixin_without_extension(appium): + el = appium.new_thing('text of awesome') + + ``` + + Omit the `name='platform'` argument to allow the mixin to augment all platforms. + + Note: `dir(appium_extended)` will *NOT* reveal your additional mixin methods. They are invisible. (This could be improved in a future version) + + + ### `appium_extended` Driver Extensions Summary + + | platform | method | description | + |----------|--------|-------------| + | all | .platform | return a string of the platform name (android, ios) | + | all | .wait_for() | wait for element to become visible | + | all | .find_element_safe | same as find_element but returns None rather than throw exception | + | all | .get_element_bounds | return dict of derived location information of element | + | all | .swipe_element | swipe in a direction | + | all | .find_element_on_page | swipe up/down left/right looking for an element. Similar to android UiScrollable but platform dependent | + | android | .find_element_by_android_uiautomator | accepts UiSelector python objects | + | android | .scroll_to_element_by_android_uiautomator | similar to find_element_on_page | + | android | .back, .home, .app_switcher, .background_app | send android keycodes | + | android | .wait_for_webview | wait for a webview to become active and populated | + | ios | | in progress | + +Keywords: appium,pytest,py.test,webqa,qa +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Framework :: Pytest +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/pytest_appium.egg-info/SOURCES.txt b/pytest_appium.egg-info/SOURCES.txt new file mode 100644 index 0000000..680ba82 --- /dev/null +++ b/pytest_appium.egg-info/SOURCES.txt @@ -0,0 +1,22 @@ +README.md +setup.py +pytest_appium/__init__.py +pytest_appium/_utils.py +pytest_appium/conftest.py +pytest_appium/exceptions.py +pytest_appium/hooks.py +pytest_appium/html_reporting.py +pytest_appium.egg-info/PKG-INFO +pytest_appium.egg-info/SOURCES.txt +pytest_appium.egg-info/dependency_links.txt +pytest_appium.egg-info/requires.txt +pytest_appium.egg-info/top_level.txt +pytest_appium/android/UIAutomator2.py +pytest_appium/android/__init__.py +pytest_appium/driver/__init__.py +pytest_appium/driver/proxy/__init__.py +pytest_appium/driver/proxy/_enums.py +pytest_appium/driver/proxy/android_extensions.py +pytest_appium/driver/proxy/appium_extensions.py +pytest_appium/driver/proxy/ios_extensions.py +pytest_appium/driver/proxy/proxy_mixin.py \ No newline at end of file diff --git a/pytest_appium.egg-info/dependency_links.txt b/pytest_appium.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pytest_appium.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pytest_appium.egg-info/requires.txt b/pytest_appium.egg-info/requires.txt new file mode 100644 index 0000000..fb6369f --- /dev/null +++ b/pytest_appium.egg-info/requires.txt @@ -0,0 +1,4 @@ +pytest +pytest-html +Appium-Python-Client +wrapt diff --git a/pytest_appium.egg-info/top_level.txt b/pytest_appium.egg-info/top_level.txt new file mode 100644 index 0000000..9c720bc --- /dev/null +++ b/pytest_appium.egg-info/top_level.txt @@ -0,0 +1 @@ +pytest_appium diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 618ab49..2e1b5d4 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -49,7 +49,6 @@ def session_capabilities(request, variables): return capabilities -@pytest.fixture def driver_kwargs(request, capabilities): """ """ # Assertions of capabilitys should go here @@ -64,11 +63,13 @@ def driver_kwargs(request, capabilities): return kwargs -@pytest.fixture def driver_class(request): """Appium driver class""" return webdriver.Remote +@pytest.fixture +def driver_class_fixture(request): + return driver_class(request) @pytest.yield_fixture def driver(request, driver_class, driver_kwargs): @@ -213,7 +214,7 @@ def test_example(): # Filter tests that are not targeted for this platform current_platform = config._variables.get('capabilities',{}).get('platformName','').lower() def select_test(item): - platform_marker = item.get_marker("platform") + platform_marker = item.get_closest_marker("platform") if platform_marker and platform_marker.args and current_platform: test_platform_specified = platform_marker.args[0].lower() if test_platform_specified != current_platform: From d8bac1f63c37fbe58fb548a67722b05dbf76c840 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 10 Aug 2020 17:21:29 +0100 Subject: [PATCH 07/27] removed pytest.yield_fixture from driver func --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 2e1b5d4..cdbdd7f 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -71,7 +71,7 @@ def driver_class(request): def driver_class_fixture(request): return driver_class(request) -@pytest.yield_fixture + def driver(request, driver_class, driver_kwargs): """Returns a AppiumDriver instance based on options and capabilities""" driver = driver_class(**driver_kwargs) From dcb475b438862bb3f58196c8cb71912923acf73d Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 10 Aug 2020 19:04:20 +0100 Subject: [PATCH 08/27] replacing old pytest.yield_fixutres --- .gitignore | 4 +++- pytest_appium/conftest.py | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 92fab75..9c4f314 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ **/.cache **/__pycache__ -**/.vscode \ No newline at end of file +**/.vscode + +.pytest_appium.egg-info \ No newline at end of file diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index cdbdd7f..237cd2d 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -48,7 +48,7 @@ def session_capabilities(request, variables): capabilities[capability[0]] = capability[1] return capabilities - +@pytest.fixture(scope='session') def driver_kwargs(request, capabilities): """ """ # Assertions of capabilitys should go here @@ -62,7 +62,7 @@ def driver_kwargs(request, capabilities): ) return kwargs - +@pytest.fixture(scope='session') def driver_class(request): """Appium driver class""" return webdriver.Remote @@ -71,7 +71,7 @@ def driver_class(request): def driver_class_fixture(request): return driver_class(request) - +@pytest.fixture(scope='session') def driver(request, driver_class, driver_kwargs): """Returns a AppiumDriver instance based on options and capabilities""" driver = driver_class(**driver_kwargs) @@ -138,8 +138,8 @@ def _appium_is_device_available(appium_wd_api_endpoint, desiredCapabilities={}, #'ios_device_available': appium_is_device_available_ios, } -@pytest.yield_fixture(scope='session') -def driver_session_(request, session_capabilities): +@pytest.fixture(scope='session') +def driver_session_(driver, request, session_capabilities): """ Appium Session Created from --capabilities @@ -177,7 +177,7 @@ def wait_for_appium(): raise Exception(f"""Unable to connect to Appium server {appium_url}""") -@pytest.yield_fixture +@pytest.fixture def driver_session(request, driver_session_): """ Appium Session @@ -187,7 +187,7 @@ def driver_session(request, driver_session_): #driver_session_.reset() -@pytest.yield_fixture +@pytest.fixture def appium(driver_session): """Alias for driver_session""" yield driver_session From 2ad6933fae47df1a2043fa9082a9178daebaa8fa Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Tue, 11 Aug 2020 15:29:33 +0100 Subject: [PATCH 09/27] replacing old pytest.yield_fixutres --- pytest_appium/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index cdbdd7f..f796585 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -138,7 +138,7 @@ def _appium_is_device_available(appium_wd_api_endpoint, desiredCapabilities={}, #'ios_device_available': appium_is_device_available_ios, } -@pytest.yield_fixture(scope='session') +@pytest.fixture(scope='session') def driver_session_(request, session_capabilities): """ Appium Session @@ -177,7 +177,7 @@ def wait_for_appium(): raise Exception(f"""Unable to connect to Appium server {appium_url}""") -@pytest.yield_fixture +@pytest.fixture def driver_session(request, driver_session_): """ Appium Session @@ -187,7 +187,7 @@ def driver_session(request, driver_session_): #driver_session_.reset() -@pytest.yield_fixture +@pytest.fixture def appium(driver_session): """Alias for driver_session""" yield driver_session From e8bd328e4464fa4be06e0afc36434a502f74133b Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Tue, 11 Aug 2020 16:09:53 +0100 Subject: [PATCH 10/27] removing egg files which should be ignored --- pytest_appium.egg-info/PKG-INFO | 220 -------------------- pytest_appium.egg-info/SOURCES.txt | 22 -- pytest_appium.egg-info/dependency_links.txt | 1 - pytest_appium.egg-info/requires.txt | 4 - pytest_appium.egg-info/top_level.txt | 1 - 5 files changed, 248 deletions(-) delete mode 100644 pytest_appium.egg-info/PKG-INFO delete mode 100644 pytest_appium.egg-info/SOURCES.txt delete mode 100644 pytest_appium.egg-info/dependency_links.txt delete mode 100644 pytest_appium.egg-info/requires.txt delete mode 100644 pytest_appium.egg-info/top_level.txt diff --git a/pytest_appium.egg-info/PKG-INFO b/pytest_appium.egg-info/PKG-INFO deleted file mode 100644 index 16a2a16..0000000 --- a/pytest_appium.egg-info/PKG-INFO +++ /dev/null @@ -1,220 +0,0 @@ -Metadata-Version: 1.1 -Name: pytest-appium -Version: 0.0.2 -Summary: Plugin for running Appium with pytest -Home-page: http://git.int.thisisglobal.com/interactive/pytest-appium -Author: Global -Author-email: leicestersquare-interactive-developers@global.com -License: MIT -Description: pytest-appium - ============= - - `pytest-appium` is a plugin for [pytest](https://docs.pytest.org/en/latest/) that provides support for running [Appium](http://appium.io/) based tests. - - It is inspired by [pytest-selenium](https://github.com/pytest-dev/pytest-selenium) - - This package has a suite of additional utilities - - * HTML Reports - * Augment the base Appium `driver` with additional modular functionality with python mixins. - * Wait for Appium to be ready - * `pytest.mark.platform` - * Light python builders for Android [UiSelector](https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html) - - - Setup - ----- - - pip requirements file - ``` - git+http://GIT.SERVER.LOCATION/pytest-appium.git@master#egg=pytest-appium - ``` - - pytest.ini - ``` - [pytest] - addopts = -p pytest_appium - ``` - - python test example - ```python - from pytest_appium.android.UIAutomator2 import UiSelector, UiScrollable - from pytest_appium.driver.proxy._enums import Direction - - @pytest.mark.platform('ios') - def test_example(appium_extended, platform): - el = appium_extended.find_element_on_page( - UiSelector().resourceIdMatches('.*awesome_item'), - direction=Direction.LEFT, - ) - assert el.text == 'Example' - ``` - - commandline example - ```bash - $(PYTHON_VENV)/bin/py.test \ - $(TEST_PATH) \ - --html=$(REPORT_PATH)/report.html \ - --junitxml=$(REPORT_PATH)/report.xml \ - --variables variables/pytest/android_emulator_local.json \ - --capability app $(APPIUM_APK_PATH) - ``` - for more commandline details use `pytest --help` under the heading `appium` - - - Features - -------- - - ### HTML reports - - [pytest-html](https://pypi.python.org/pypi/pytest-html/) for Appium tests. - - Includes screenshot, page `XML` and full `logcat` dumps. - - - ### Wait for startup conditions - - Orchestration of service startup order is sometimes problematic. - On startup we can wait for a varity of conditions. - `pytest --help` for details - - ``` - --appium_wait_for_condition={appium,android_device_available} - Type of appium condition to wait for before beginning - first test - --appium_wait_for_seconds=APPIUM_WAIT_FOR_SECONDS - Seconds to wait for an Appium server to become - available before raising an error. - ``` - - * `appium` - Waits for the Appium port to become active - * `android_device_available` - Trys to send a low level `wd` api call to launch an Android packagename "NOT-REAL". We know an android device is connected and available if the error message explicitly contains "NOT-REAL". - - Example of use in a `docker-compose.yml` waiting for android device. - ```yaml - command: - - pytest - ... - - --appium_host=android-container - - --appium_wait_for_seconds=90 - - --appium_wait_for_condition=android_device_available - ... - ``` - - Exampe of use in a `bash` script waiting for appium service to become active. - ```bash - ... - (nohup node $(APPIUM_PATH) $(APPIUM_ARGS) > $(REPORT_FOLDER)/appium.log &) - ... - - _env/bin/py.test \ - tests \ - ... - --appium_host=localhost \ - --appium_wait_for_condition appium \ - --appium_wait_for_seconds 30 \ - ... - - ``` - - ### pytest Markers for platforms - - ```python - @pytest.mark.platform('ios') - def test_ios(appium_extended): - pass - - @pytest.mark.platform('android') - def test_android(appium_extended): - pass - - def test_both_ios_and_android(appium_extended): - pass - ``` - - ### Python wrapper for expressing UiSelector syntax in python - - Handling long android strings to compose UiSelectors is inflexible. A lightweight UiSelector python builder is provided - - ```python - from pytest_appium.android.UIAutomator2 import UiSelector, UiScrollable - - # Create a UiSelector python builder - selector = UiSelector().resourceIdMatches('.*filmstrip_list').childSelector(UiSelector().index(1)) - assert str(selector) == 'new UiSelector().resourceIdMatches(".*filmstrip_list").childSelector(new UiSelector().index(1))' - - # UiSelector objects can be used directly - el = self.driver.find_element_by_android_uiautomator(selector) - - # UiSelectors can have segments modified/appended after creation - selector.ui_objects[-1].childSelector(UiSelector().className('my_class')) - assert str(selector) == 'new UiSelector().resourceIdMatches(".*filmstrip_list").childSelector(new UiSelector().index(1).childSelector(new UiSelector().className("my_class")))' - self.driver.find_element_by_android_uiautomator(selector) - ``` - - ### Appium Driver Extension Framework - - The base Appium [python-client](https://github.com/appium/python-client) `driver` supports base functions. - We sometimes want to add extra functionality to this `driver` for individual platforms. - - We can transparently overlay extra Mixin's over the base `driver` object. This is available as the pytest fixture `appium_extended`. - - ```python - from pytest_appium.driver.proxy.proxy_mixin import register_proxy_mixin - - @register_proxy_mixin(name='android') - class MyAndroidDriverMixin(): - def new_thing(self, text): - log.debug('my mixin method for android') - # modify the selector in some cool way - return self.find_element(*my_cool_selector_with_text) - - @register_proxy_mixin(name='ios') - class MyIOSDriverMixin(): - def new_thing(self, text): - log.debug('my mixin method for ios') - # modify the selector in some cool way - return self.find_element(*my_cool_selector_with_text) - - def test_my_mixin(appium_extended): - el = appium_extended.new_thing('text of awesome') - - # The `appium` fixture can be used to get the base `driver` without mixin augmentation. - @pytest.mark.xfail(strict=True) - def test_my_mixin_without_extension(appium): - el = appium.new_thing('text of awesome') - - ``` - - Omit the `name='platform'` argument to allow the mixin to augment all platforms. - - Note: `dir(appium_extended)` will *NOT* reveal your additional mixin methods. They are invisible. (This could be improved in a future version) - - - ### `appium_extended` Driver Extensions Summary - - | platform | method | description | - |----------|--------|-------------| - | all | .platform | return a string of the platform name (android, ios) | - | all | .wait_for() | wait for element to become visible | - | all | .find_element_safe | same as find_element but returns None rather than throw exception | - | all | .get_element_bounds | return dict of derived location information of element | - | all | .swipe_element | swipe in a direction | - | all | .find_element_on_page | swipe up/down left/right looking for an element. Similar to android UiScrollable but platform dependent | - | android | .find_element_by_android_uiautomator | accepts UiSelector python objects | - | android | .scroll_to_element_by_android_uiautomator | similar to find_element_on_page | - | android | .back, .home, .app_switcher, .background_app | send android keycodes | - | android | .wait_for_webview | wait for a webview to become active and populated | - | ios | | in progress | - -Keywords: appium,pytest,py.test,webqa,qa -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: Framework :: Pytest -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/pytest_appium.egg-info/SOURCES.txt b/pytest_appium.egg-info/SOURCES.txt deleted file mode 100644 index 680ba82..0000000 --- a/pytest_appium.egg-info/SOURCES.txt +++ /dev/null @@ -1,22 +0,0 @@ -README.md -setup.py -pytest_appium/__init__.py -pytest_appium/_utils.py -pytest_appium/conftest.py -pytest_appium/exceptions.py -pytest_appium/hooks.py -pytest_appium/html_reporting.py -pytest_appium.egg-info/PKG-INFO -pytest_appium.egg-info/SOURCES.txt -pytest_appium.egg-info/dependency_links.txt -pytest_appium.egg-info/requires.txt -pytest_appium.egg-info/top_level.txt -pytest_appium/android/UIAutomator2.py -pytest_appium/android/__init__.py -pytest_appium/driver/__init__.py -pytest_appium/driver/proxy/__init__.py -pytest_appium/driver/proxy/_enums.py -pytest_appium/driver/proxy/android_extensions.py -pytest_appium/driver/proxy/appium_extensions.py -pytest_appium/driver/proxy/ios_extensions.py -pytest_appium/driver/proxy/proxy_mixin.py \ No newline at end of file diff --git a/pytest_appium.egg-info/dependency_links.txt b/pytest_appium.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/pytest_appium.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pytest_appium.egg-info/requires.txt b/pytest_appium.egg-info/requires.txt deleted file mode 100644 index fb6369f..0000000 --- a/pytest_appium.egg-info/requires.txt +++ /dev/null @@ -1,4 +0,0 @@ -pytest -pytest-html -Appium-Python-Client -wrapt diff --git a/pytest_appium.egg-info/top_level.txt b/pytest_appium.egg-info/top_level.txt deleted file mode 100644 index 9c720bc..0000000 --- a/pytest_appium.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pytest_appium From 6e17bdb6e46c29c2398e6016ffb406eda148c453 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Thu, 1 Apr 2021 08:18:34 +0100 Subject: [PATCH 11/27] attempt to disable Android Logcat gathering --- pytest_appium/html_reporting.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index ec5b66c..ada9afb 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -120,7 +120,9 @@ def pytest_runtest_makereport(self, item, call): if 'page_source' not in exclude: _gather_page_source(item, report, driver, summary, extra) if 'logs' not in exclude: - _gather_logs(item, report, driver, summary, extra) + pass # log gathering on Android is very time-consuming, + # and seems to fail on Jenkins anyway + # _gather_logs(item, report, driver, summary, extra) item.config.hook.pytest_appium_capture_debug(item=item, report=report, extra=extra) item.config.hook.pytest_appium_runtest_makereport(item=item, report=report, summary=summary, extra=extra) if summary: From fbb0b2cffdd4760ae1ebd4b59bcc1362d48dde51 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Fri, 9 Jun 2023 09:13:23 +0100 Subject: [PATCH 12/27] fixing TypeError for deprecated desired_capabilities Kwarg --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index f796585..0ff510e 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -55,7 +55,7 @@ def driver_kwargs(request, capabilities): #appium_user = f'{0.appium_username}:{0.appium_access_key}@' kwargs = dict( command_executor='http://{0.appium_host}:{0.appium_port}/wd/hub'.format(request.config.option), - desired_capabilities=capabilities, + capabilities=capabilities, browser_profile=None, proxy=None, keep_alive=False, From b5fb37c111264ae32bd43b0cea1e8b803510305e Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Fri, 9 Jun 2023 09:29:46 +0100 Subject: [PATCH 13/27] reverting changes --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index 0ff510e..f796585 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -55,7 +55,7 @@ def driver_kwargs(request, capabilities): #appium_user = f'{0.appium_username}:{0.appium_access_key}@' kwargs = dict( command_executor='http://{0.appium_host}:{0.appium_port}/wd/hub'.format(request.config.option), - capabilities=capabilities, + desired_capabilities=capabilities, browser_profile=None, proxy=None, keep_alive=False, From 36fe4b4f069abcef5022bd4cfb2a8b240ec7efe1 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 11 Sep 2023 09:45:25 +0100 Subject: [PATCH 14/27] Replacing Deprecated MobileBy with AppiumBy --- pytest_appium/driver/proxy/ios_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/driver/proxy/ios_extensions.py b/pytest_appium/driver/proxy/ios_extensions.py index 7b8e8c3..514e349 100644 --- a/pytest_appium/driver/proxy/ios_extensions.py +++ b/pytest_appium/driver/proxy/ios_extensions.py @@ -1,7 +1,7 @@ import logging from contextlib import contextmanager -from appium.webdriver.common.mobileby import MobileBy as By +from appium.webdriver.common.appiumby import AppiumBy as By from pytest_appium._utils import wait_for from pytest_appium.driver.proxy.proxy_mixin import register_proxy_mixin From 22304cee4fffe0d31c74cfae4f0aeece03077fc2 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 11 Sep 2023 10:03:56 +0100 Subject: [PATCH 15/27] Replacing Deprecated MobileBy with AppiumBy --- pytest_appium/android/UIAutomator2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest_appium/android/UIAutomator2.py b/pytest_appium/android/UIAutomator2.py index b0cfd8a..e8ecb36 100644 --- a/pytest_appium/android/UIAutomator2.py +++ b/pytest_appium/android/UIAutomator2.py @@ -2,9 +2,9 @@ from functools import reduce try: - from appium.webdriver.common.mobileby import MobileBy + from appium.webdriver.common.appiumby import AppiumBy except ImportError: - class MobileBy(): + class AppiumBy(): ANDROID_UIAUTOMATOR = '-android uiautomator' """ @@ -104,7 +104,7 @@ def _add_segment(*args): return _add_segment def build(self): - return (MobileBy.ANDROID_UIAUTOMATOR, self.__str__()) + return (AppiumBy.ANDROID_UIAUTOMATOR, self.__str__()) class UiSelector(_PythonUIAutomatorBuilderMixin): From 18b5f08942de7dd0030f0bb4693616d565813e28 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 11 Sep 2023 17:22:29 +0100 Subject: [PATCH 16/27] Revert "Replacing Deprecated MobileBy with AppiumBy" This reverts commit 22304cee4fffe0d31c74cfae4f0aeece03077fc2. --- pytest_appium/android/UIAutomator2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest_appium/android/UIAutomator2.py b/pytest_appium/android/UIAutomator2.py index e8ecb36..b0cfd8a 100644 --- a/pytest_appium/android/UIAutomator2.py +++ b/pytest_appium/android/UIAutomator2.py @@ -2,9 +2,9 @@ from functools import reduce try: - from appium.webdriver.common.appiumby import AppiumBy + from appium.webdriver.common.mobileby import MobileBy except ImportError: - class AppiumBy(): + class MobileBy(): ANDROID_UIAUTOMATOR = '-android uiautomator' """ @@ -104,7 +104,7 @@ def _add_segment(*args): return _add_segment def build(self): - return (AppiumBy.ANDROID_UIAUTOMATOR, self.__str__()) + return (MobileBy.ANDROID_UIAUTOMATOR, self.__str__()) class UiSelector(_PythonUIAutomatorBuilderMixin): From 90be9f2f74379ac280ca0d1d22f003b954c3886c Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Mon, 11 Sep 2023 17:22:34 +0100 Subject: [PATCH 17/27] Revert "Replacing Deprecated MobileBy with AppiumBy" This reverts commit 36fe4b4f069abcef5022bd4cfb2a8b240ec7efe1. --- pytest_appium/driver/proxy/ios_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/driver/proxy/ios_extensions.py b/pytest_appium/driver/proxy/ios_extensions.py index 514e349..7b8e8c3 100644 --- a/pytest_appium/driver/proxy/ios_extensions.py +++ b/pytest_appium/driver/proxy/ios_extensions.py @@ -1,7 +1,7 @@ import logging from contextlib import contextmanager -from appium.webdriver.common.appiumby import AppiumBy as By +from appium.webdriver.common.mobileby import MobileBy as By from pytest_appium._utils import wait_for from pytest_appium.driver.proxy.proxy_mixin import register_proxy_mixin From 32b0b5e1aa90ae57f108610db9cc063dde052c00 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Thu, 7 Dec 2023 18:51:35 +0000 Subject: [PATCH 18/27] Since Appium 2, is no longer needed, so removing it from the driver keyword arguments function --- pytest_appium/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/conftest.py b/pytest_appium/conftest.py index f796585..5132c65 100644 --- a/pytest_appium/conftest.py +++ b/pytest_appium/conftest.py @@ -54,7 +54,7 @@ def driver_kwargs(request, capabilities): # Assertions of capabilitys should go here #appium_user = f'{0.appium_username}:{0.appium_access_key}@' kwargs = dict( - command_executor='http://{0.appium_host}:{0.appium_port}/wd/hub'.format(request.config.option), + command_executor='http://{0.appium_host}:{0.appium_port}'.format(request.config.option), desired_capabilities=capabilities, browser_profile=None, proxy=None, From 2831e0dcca848da25163d988bcfb8d41b8298758 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Tue, 20 Feb 2024 14:03:40 +0000 Subject: [PATCH 19/27] Added videos to pytest-html report --- pytest_appium/html_reporting.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index ada9afb..13ca7c8 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -32,6 +32,17 @@ def _gather_screenshot(item, report, driver, summary, extra): # add screenshot to the html report extra.append(pytest_html.extras.image(screenshot, 'Screenshot')) +def _gather_video(item, report, driver, summary, extra): + try: + video = driver.stop_recording_screen() + except Exception as e: + summary.append('WARNING: Failed to gather video: {0}'.format(e)) + return + pytest_html = item.config.pluginmanager.getplugin('html') + if pytest_html is not None: + # add screenshot to the html report + extra.append(pytest_html.extras.mp4(video, 'Video')) + def _gather_page_source(item, report, driver, summary, extra): try: @@ -117,6 +128,8 @@ def pytest_runtest_makereport(self, item, call): _gather_app_strings(item, report, driver, summary, extra) if 'screenshot' not in exclude: _gather_screenshot(item, report, driver, summary, extra) + if 'video' not in exclude: + _gather_video(item, report, driver, summary, extra) if 'page_source' not in exclude: _gather_page_source(item, report, driver, summary, extra) if 'logs' not in exclude: From 1434fa807d4f7d52af86253dd9381586e8fda823 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 10 Apr 2024 12:47:06 +0100 Subject: [PATCH 20/27] Attempting to add failsafe for 'incorrect Padding' Base64 error --- pytest_appium/html_reporting.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 13ca7c8..a51e4eb 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -41,7 +41,11 @@ def _gather_video(item, report, driver, summary, extra): pytest_html = item.config.pluginmanager.getplugin('html') if pytest_html is not None: # add screenshot to the html report - extra.append(pytest_html.extras.mp4(video, 'Video')) + try: + extra.append(pytest_html.extras.mp4(video, 'Video')) + except Exception as e: + summary.append('Something went wrogn attaching video: {0}'.format(e)) + return def _gather_page_source(item, report, driver, summary, extra): From f2d4909b1bf690a2f7781a91d84e4c7e8abed7e7 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 10 Apr 2024 15:44:40 +0100 Subject: [PATCH 21/27] Adding Failsafe for _gather_screenshot too --- pytest_appium/html_reporting.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index a51e4eb..19b6f32 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -30,7 +30,11 @@ def _gather_screenshot(item, report, driver, summary, extra): pytest_html = item.config.pluginmanager.getplugin('html') if pytest_html is not None: # add screenshot to the html report - extra.append(pytest_html.extras.image(screenshot, 'Screenshot')) + try: + extra.append(pytest_html.extras.image(screenshot, 'Screenshot')) + except Exception as e: + summary.append('Something went wrong attaching Screenshot: {0}'.format(e)) + return def _gather_video(item, report, driver, summary, extra): try: @@ -40,11 +44,11 @@ def _gather_video(item, report, driver, summary, extra): return pytest_html = item.config.pluginmanager.getplugin('html') if pytest_html is not None: - # add screenshot to the html report + # add recording to the html report try: extra.append(pytest_html.extras.mp4(video, 'Video')) except Exception as e: - summary.append('Something went wrogn attaching video: {0}'.format(e)) + summary.append('Something went wrong attaching video: {0}'.format(e)) return From 7e5e8a80c7fbe63acda0ea4b13dcc58be1d0dc08 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 10 Apr 2024 16:11:27 +0100 Subject: [PATCH 22/27] Reverting changes --- pytest_appium/html_reporting.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 19b6f32..13ca7c8 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -30,11 +30,7 @@ def _gather_screenshot(item, report, driver, summary, extra): pytest_html = item.config.pluginmanager.getplugin('html') if pytest_html is not None: # add screenshot to the html report - try: - extra.append(pytest_html.extras.image(screenshot, 'Screenshot')) - except Exception as e: - summary.append('Something went wrong attaching Screenshot: {0}'.format(e)) - return + extra.append(pytest_html.extras.image(screenshot, 'Screenshot')) def _gather_video(item, report, driver, summary, extra): try: @@ -44,12 +40,8 @@ def _gather_video(item, report, driver, summary, extra): return pytest_html = item.config.pluginmanager.getplugin('html') if pytest_html is not None: - # add recording to the html report - try: - extra.append(pytest_html.extras.mp4(video, 'Video')) - except Exception as e: - summary.append('Something went wrong attaching video: {0}'.format(e)) - return + # add screenshot to the html report + extra.append(pytest_html.extras.mp4(video, 'Video')) def _gather_page_source(item, report, driver, summary, extra): From ecaa5b157e14ba9c390f4d5a278b23ff9518608f Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Thu, 11 Apr 2024 17:29:44 +0100 Subject: [PATCH 23/27] Ensuring null videos aren't attached to screenshot --- pytest_appium/html_reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 13ca7c8..55e951a 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -39,7 +39,7 @@ def _gather_video(item, report, driver, summary, extra): summary.append('WARNING: Failed to gather video: {0}'.format(e)) return pytest_html = item.config.pluginmanager.getplugin('html') - if pytest_html is not None: + if video and pytest_html is not None: # add screenshot to the html report extra.append(pytest_html.extras.mp4(video, 'Video')) From f2b5290c184dcd373f002f1effbe1db91ab55aa5 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Tue, 4 Jun 2024 17:58:25 +0100 Subject: [PATCH 24/27] Using pass instead of return for when video fails so actual error if any can still be displayed in report --- pytest_appium/html_reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 55e951a..7c8de81 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -37,7 +37,7 @@ def _gather_video(item, report, driver, summary, extra): video = driver.stop_recording_screen() except Exception as e: summary.append('WARNING: Failed to gather video: {0}'.format(e)) - return + pass pytest_html = item.config.pluginmanager.getplugin('html') if video and pytest_html is not None: # add screenshot to the html report From 299ef1483e9acde20889c4ffab30fa539e68870a Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Tue, 4 Jun 2024 18:24:23 +0100 Subject: [PATCH 25/27] Making sure video is definately none --- pytest_appium/html_reporting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 7c8de81..25a5506 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -37,9 +37,10 @@ def _gather_video(item, report, driver, summary, extra): video = driver.stop_recording_screen() except Exception as e: summary.append('WARNING: Failed to gather video: {0}'.format(e)) - pass + video = None + return pytest_html = item.config.pluginmanager.getplugin('html') - if video and pytest_html is not None: + if video is not None and pytest_html is not None: # add screenshot to the html report extra.append(pytest_html.extras.mp4(video, 'Video')) From 937a42c0d446d6bfb3948d0da56897c3468a07b7 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 5 Jun 2024 11:16:25 +0100 Subject: [PATCH 26/27] Allowing report to carry on if video can't be uploaded --- pytest_appium/html_reporting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 25a5506..204244f 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -38,7 +38,7 @@ def _gather_video(item, report, driver, summary, extra): except Exception as e: summary.append('WARNING: Failed to gather video: {0}'.format(e)) video = None - return + pass pytest_html = item.config.pluginmanager.getplugin('html') if video is not None and pytest_html is not None: # add screenshot to the html report From dce58cfc8b3200112140044c825d67e197e6bcf5 Mon Sep 17 00:00:00 2001 From: "theo.king" Date: Wed, 5 Jun 2024 12:33:16 +0100 Subject: [PATCH 27/27] Reverting changes --- pytest_appium/html_reporting.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pytest_appium/html_reporting.py b/pytest_appium/html_reporting.py index 204244f..55e951a 100644 --- a/pytest_appium/html_reporting.py +++ b/pytest_appium/html_reporting.py @@ -37,10 +37,9 @@ def _gather_video(item, report, driver, summary, extra): video = driver.stop_recording_screen() except Exception as e: summary.append('WARNING: Failed to gather video: {0}'.format(e)) - video = None - pass + return pytest_html = item.config.pluginmanager.getplugin('html') - if video is not None and pytest_html is not None: + if video and pytest_html is not None: # add screenshot to the html report extra.append(pytest_html.extras.mp4(video, 'Video'))