diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a8af654b..a4f7c00a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,5 @@ rev: 'v0.761' hooks: - id: mypy - files: ^appium/ - entry: mypy appium/ + entry: mypy appium/ test/ pass_filenames: false diff --git a/appium/webdriver/extensions/action_helpers.py b/appium/webdriver/extensions/action_helpers.py index 98ddbf67..d03d36ee 100644 --- a/appium/webdriver/extensions/action_helpers.py +++ b/appium/webdriver/extensions/action_helpers.py @@ -66,7 +66,7 @@ def drag_and_drop(self, origin_el: WebElement, destination_el: WebElement) -> T: action.long_press(origin_el).move_to(destination_el).release().perform() return self - def tap(self, positions: List[Tuple], duration: Optional[int] = None) -> T: + def tap(self, positions: List[Tuple[int, int]], duration: Optional[int] = None) -> T: """Taps on an particular place with up to five fingers, holding for a certain time diff --git a/appium/webdriver/extensions/applications.py b/appium/webdriver/extensions/applications.py index 9ab8a295..3e1939cf 100644 --- a/appium/webdriver/extensions/applications.py +++ b/appium/webdriver/extensions/applications.py @@ -172,13 +172,16 @@ class for more details. } return self.execute(Command.QUERY_APP_STATE, data)['value'] - def app_strings(self, language: str = None, string_file: str = None) -> str: + def app_strings(self, language: str = None, string_file: str = None) -> Dict[str, str]: """Returns the application strings from the device for the specified language. Args: language (str): strings language code string_file (str): the name of the string file to query + + Returns: + Dict[str, str]: The key is string id and the value is the content. """ data = {} if language is not None: diff --git a/ci.sh b/ci.sh index a0b1d8fc..1303ff84 100755 --- a/ci.sh +++ b/ci.sh @@ -35,7 +35,7 @@ if [[ $? -ne 0 ]] ; then fi ( - python -m mypy appium + python -m mypy appium test ) if [[ $? -ne 0 ]] ; then EXIT_STATUS=1 diff --git a/test/functional/android/activities_tests.py b/test/functional/android/activities_tests.py index 7b1894ff..d13f2d52 100644 --- a/test/functional/android/activities_tests.py +++ b/test/functional/android/activities_tests.py @@ -19,25 +19,25 @@ class ActivitiesTests(BaseTestCase): - def test_current_activity(self): + def test_current_activity(self) -> None: activity = self.driver.current_activity self.assertEqual('.ApiDemos', activity) - def test_start_activity_this_app(self): + def test_start_activity_this_app(self) -> None: self.driver.start_activity(APIDEMO_PKG_NAME, ".ApiDemos") self._assert_activity_contains('Demos') self.driver.start_activity(APIDEMO_PKG_NAME, ".accessibility.AccessibilityNodeProviderActivity") self._assert_activity_contains('Node') - def test_start_activity_other_app(self): + def test_start_activity_other_app(self) -> None: self.driver.start_activity(APIDEMO_PKG_NAME, ".ApiDemos") self._assert_activity_contains('Demos') self.driver.start_activity("com.android.calculator2", ".Calculator") self._assert_activity_contains('Calculator') - def _assert_activity_contains(self, activity): + def _assert_activity_contains(self, activity: str) -> None: current = self.driver.current_activity self.assertTrue(activity in current) diff --git a/test/functional/android/applications_tests.py b/test/functional/android/applications_tests.py index 45ea52ca..b8b98ffb 100644 --- a/test/functional/android/applications_tests.py +++ b/test/functional/android/applications_tests.py @@ -23,33 +23,33 @@ class ApplicationsTests(BaseTestCase): - def test_background_app(self): + def test_background_app(self) -> None: self.driver.background_app(1) sleep(3) self.driver.launch_app() - def test_is_app_installed(self): + def test_is_app_installed(self) -> None: self.assertFalse(self.driver.is_app_installed('sdfsdf')) self.assertTrue(self.driver.is_app_installed(APIDEMO_PKG_NAME)) - def test_install_app(self): + def test_install_app(self) -> None: self.skipTest('This causes the server to crash. no idea why') self.assertFalse(self.driver.is_app_installed('io.selendroid.testapp')) self.driver.install_app('/Users/isaac/code/python-client/test/apps/selendroid-test-app.apk') self.assertTrue(self.driver.is_app_installed('io.selendroid.testapp')) - def test_remove_app(self): + def test_remove_app(self) -> None: self.assertTrue(self.driver.is_app_installed(APIDEMO_PKG_NAME)) self.driver.remove_app(APIDEMO_PKG_NAME) self.assertFalse(self.driver.is_app_installed(APIDEMO_PKG_NAME)) - def test_close_and_launch_app(self): + def test_close_and_launch_app(self) -> None: self.driver.close_app() self.driver.launch_app() activity = self.driver.current_activity self.assertEqual('.ApiDemos', activity) - def test_app_management(self): + def test_app_management(self) -> None: app_id = self.driver.current_package self.assertEqual(self.driver.query_app_state(app_id), ApplicationState.RUNNING_IN_FOREGROUND) @@ -60,19 +60,19 @@ def test_app_management(self): self.assertEqual(self.driver.query_app_state(app_id), ApplicationState.RUNNING_IN_FOREGROUND) - def test_app_strings(self): + def test_app_strings(self) -> None: strings = self.driver.app_strings() self.assertEqual(u'You can\'t wipe my data, you are a monkey!', strings[u'monkey_wipe_data']) - def test_app_strings_with_language(self): + def test_app_strings_with_language(self) -> None: strings = self.driver.app_strings('en') self.assertEqual(u'You can\'t wipe my data, you are a monkey!', strings[u'monkey_wipe_data']) - def test_app_strings_with_language_and_file(self): + def test_app_strings_with_language_and_file(self) -> None: strings = self.driver.app_strings('en', 'some_file') self.assertEqual(u'You can\'t wipe my data, you are a monkey!', strings[u'monkey_wipe_data']) - def test_reset(self): + def test_reset(self) -> None: self.driver.reset() self.assertTrue(self.driver.is_app_installed(APIDEMO_PKG_NAME)) diff --git a/test/functional/android/chrome_tests.py b/test/functional/android/chrome_tests.py index 32f74216..971e4ebf 100644 --- a/test/functional/android/chrome_tests.py +++ b/test/functional/android/chrome_tests.py @@ -20,15 +20,15 @@ class ChromeTests(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: caps = get_desired_capabilities() caps['browserName'] = 'Chrome' self.driver = webdriver.Remote('http://localhost:4723/wd/hub', caps) - def tearDown(self): + def tearDown(self) -> None: self.driver.quit() - def test_find_single_element(self): + def test_find_single_element(self) -> None: self.driver.get('http://10.0.2.2:4723/test/guinea-pig') self.driver.find_element_by_link_text('i am a link').click() diff --git a/test/functional/android/common_tests.py b/test/functional/android/common_tests.py index 04fb63e8..4da8f793 100644 --- a/test/functional/android/common_tests.py +++ b/test/functional/android/common_tests.py @@ -30,15 +30,15 @@ class CommonTests(BaseTestCase): - def test_current_package(self): + def test_current_package(self) -> None: self.assertEqual(APIDEMO_PKG_NAME, self.driver.current_package) - def test_end_test_coverage(self): + def test_end_test_coverage(self) -> None: self.skipTest('Not sure how to set this up to run') self.driver.end_test_coverage(intent='android.intent.action.MAIN', path='') sleep(5) - def test_open_notifications(self): + def test_open_notifications(self) -> None: if is_ci(): # TODO Due to unexpected dialog, "System UI isn't responding" self.skipTest('Need to fix flaky test during running on CI.') diff --git a/test/functional/android/context_switching_tests.py b/test/functional/android/context_switching_tests.py index ed4dcef9..2b42e55d 100644 --- a/test/functional/android/context_switching_tests.py +++ b/test/functional/android/context_switching_tests.py @@ -24,37 +24,37 @@ @pytest.mark.skip(reason="Need to fix broken test") class ContextSwitchingTests(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: desired_caps = desired_capabilities.get_desired_capabilities('selendroid-test-app.apk') self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) - def test_contexts_list(self): + def tearDown(self) -> None: + self.driver.quit() + + def test_contexts_list(self) -> None: self._enter_webview() contexts = self.driver.contexts self.assertEqual(2, len(contexts)) - def test_move_to_correct_context(self): + def test_move_to_correct_context(self) -> None: self._enter_webview() self.assertEqual('WEBVIEW_io.selendroid.testapp', self.driver.current_context) - def test_actually_in_webview(self): + def test_actually_in_webview(self) -> None: self._enter_webview() self.driver.find_element_by_css_selector('input[type=submit]').click() el = self.driver.find_element_by_xpath("//h1[contains(., 'This is my way')]") self.assertIsNot(None, el) - def test_move_back_to_native_context(self): + def test_move_back_to_native_context(self) -> None: self._enter_webview() self.driver.switch_to.context(None) self.assertEqual('NATIVE_APP', self.driver.current_context) - def test_set_invalid_context(self): + def test_set_invalid_context(self) -> None: self.assertRaises(NoSuchContextException, self.driver.switch_to.context, 'invalid name') - def tearDown(self): - self.driver.quit() - - def _enter_webview(self): + def _enter_webview(self) -> None: btn = self.driver.find_element_by_name('buttonStartWebviewCD') btn.click() self.driver.switch_to.context('WEBVIEW') diff --git a/test/functional/android/device_time_tests.py b/test/functional/android/device_time_tests.py index deefdd36..736bf7c6 100644 --- a/test/functional/android/device_time_tests.py +++ b/test/functional/android/device_time_tests.py @@ -21,7 +21,7 @@ class DeviceTimeTests(BaseTestCase): - def test_device_time(self): + def test_device_time(self) -> None: date_time = self.driver.device_time # convert to date ought to work parse(date_time) diff --git a/test/functional/android/finger_print_tests.py b/test/functional/android/finger_print_tests.py index e77e72a4..cc0457c2 100644 --- a/test/functional/android/finger_print_tests.py +++ b/test/functional/android/finger_print_tests.py @@ -19,7 +19,7 @@ class FingerPrintTests(BaseTestCase): - def test_finger_print(self): + def test_finger_print(self) -> None: result = self.driver.finger_print(1) self.assertEqual(None, result) diff --git a/test/functional/android/helper/desired_capabilities.py b/test/functional/android/helper/desired_capabilities.py index eccb091a..7ddcd80a 100644 --- a/test/functional/android/helper/desired_capabilities.py +++ b/test/functional/android/helper/desired_capabilities.py @@ -13,17 +13,19 @@ # limitations under the License. import os - +from typing import Any, Dict, Optional # Returns abs path relative to this file and not cwd -def PATH(p): + + +def PATH(p: str) -> str: return os.path.abspath( os.path.join(os.path.dirname(__file__), '..', p) ) -def get_desired_capabilities(app=None): - desired_caps = { +def get_desired_capabilities(app: Optional[str] = None) -> Dict[str, Any]: + desired_caps: Dict[str, Any] = { 'platformName': 'Android', 'deviceName': 'Android Emulator', 'newCommandTimeout': 240, diff --git a/test/functional/android/helper/test_helper.py b/test/functional/android/helper/test_helper.py index 5813abc6..c8b4af27 100644 --- a/test/functional/android/helper/test_helper.py +++ b/test/functional/android/helper/test_helper.py @@ -16,6 +16,7 @@ import base64 import os import unittest +from typing import TYPE_CHECKING from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -25,6 +26,10 @@ from . import desired_capabilities +if TYPE_CHECKING: + from appium.webdriver.webelement import WebElement + from appium.webdriver.webdriver import WebDriver + # the emulator is sometimes slow and needs time to think SLEEPY_TIME = 10 @@ -32,7 +37,7 @@ APIDEMO_PKG_NAME = 'io.appium.android.apis' -def wait_for_element(driver, locator, value, timeout=SLEEPY_TIME): +def wait_for_element(driver: 'WebDriver', locator: str, value: str, timeout: int = SLEEPY_TIME) -> 'WebElement': """Wait until the element located Args: @@ -55,13 +60,13 @@ def wait_for_element(driver, locator, value, timeout=SLEEPY_TIME): class BaseTestCase(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: desired_caps = desired_capabilities.get_desired_capabilities('ApiDemos-debug.apk.zip') self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) if is_ci(): self.driver.start_recording_screen() - def tearDown(self): + def tearDown(self) -> None: if is_ci(): payload = self.driver.stop_recording_screen() video_path = os.path.join(os.getcwd(), self._testMethodName + '.mp4') diff --git a/test/functional/android/hw_actions_tests.py b/test/functional/android/hw_actions_tests.py index 3bb022f4..2a6b14e8 100644 --- a/test/functional/android/hw_actions_tests.py +++ b/test/functional/android/hw_actions_tests.py @@ -20,7 +20,7 @@ class HwActionsTests(BaseTestCase): - def test_lock(self): + def test_lock(self) -> None: self.driver.lock(-1) sleep(10) try: diff --git a/test/functional/android/ime_tests.py b/test/functional/android/ime_tests.py index 6cac0e73..ade988c6 100644 --- a/test/functional/android/ime_tests.py +++ b/test/functional/android/ime_tests.py @@ -23,25 +23,25 @@ class IMETests(BaseTestCase): - def test_available_ime_engines(self): + def test_available_ime_engines(self) -> None: engines = self.driver.available_ime_engines self.assertIsInstance(engines, list) self.assertTrue(ANDROID_LATIN in engines or GOOGLE_LATIN in engines) - def test_is_ime_active(self): + def test_is_ime_active(self) -> None: self.assertTrue(self.driver.is_ime_active()) - def test_active_ime_engine(self): + def test_active_ime_engine(self) -> None: engines = self.driver.available_ime_engines self.assertTrue(self.driver.active_ime_engine in engines) - def test_activate_ime_engine(self): + def test_activate_ime_engine(self) -> None: engines = self.driver.available_ime_engines self.driver.activate_ime_engine(engines[-1]) self.assertEqual(self.driver.active_ime_engine, engines[-1]) - def test_deactivate_ime_engine(self): + def test_deactivate_ime_engine(self) -> None: engines = self.driver.available_ime_engines self.driver.activate_ime_engine(engines[-1]) diff --git a/test/functional/android/keyboard_tests.py b/test/functional/android/keyboard_tests.py index 6c634da3..53a5d48c 100644 --- a/test/functional/android/keyboard_tests.py +++ b/test/functional/android/keyboard_tests.py @@ -19,12 +19,12 @@ class KeyboardTests(BaseTestCase): - def test_press_keycode(self): - # not sure how to test this. + def test_press_keycode(self) -> None: + # TODO not sure how to test this. self.driver.press_keycode(176) - def test_long_press_keycode(self): - # not sure how to test this. + def test_long_press_keycode(self) -> None: + # TODO not sure how to test this. self.driver.long_press_keycode(176) diff --git a/test/functional/android/location_tests.py b/test/functional/android/location_tests.py index 1584fd5a..68603385 100644 --- a/test/functional/android/location_tests.py +++ b/test/functional/android/location_tests.py @@ -19,8 +19,8 @@ class LocationTests(BaseTestCase): - def test_toggle_location_services(self): - self.driver.toggle_location_services() + def test_toggle_location_services(self) -> None: + self.driver.toggle_location_services() # TODO Add assert if __name__ == '__main__': diff --git a/test/functional/android/log_event_tests.py b/test/functional/android/log_event_tests.py index a64ff9a0..cc3c2b62 100644 --- a/test/functional/android/log_event_tests.py +++ b/test/functional/android/log_event_tests.py @@ -19,7 +19,7 @@ class LogEventTests(BaseTestCase): - def test_log_event(self): + def test_log_event(self) -> None: vendor = 'appium' event = 'funEvent' self.driver.log_event(vendor, event) diff --git a/test/functional/android/multi_action_tests.py b/test/functional/android/multi_action_tests.py index 3d0be2b0..9904ccbf 100644 --- a/test/functional/android/multi_action_tests.py +++ b/test/functional/android/multi_action_tests.py @@ -23,7 +23,7 @@ class MultiActionTests(BaseTestCase): - def test_parallel_actions(self): + def test_parallel_actions(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') self.driver.scroll(el1, el2) @@ -55,7 +55,7 @@ def test_parallel_actions(self): ma.add(a1, a2) ma.perform() - def test_actions_with_waits(self): + def test_actions_with_waits(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') self.driver.scroll(el1, el2) @@ -95,7 +95,7 @@ def test_actions_with_waits(self): ma.add(a1, a2) ma.perform() - def test_driver_multi_tap(self): + def test_driver_multi_tap(self) -> None: el = self.driver.find_element_by_accessibility_id('Graphics') action = TouchAction(self.driver) action.tap(el).perform() diff --git a/test/functional/android/network_connection_tests.py b/test/functional/android/network_connection_tests.py index 5727e1d6..73d3816d 100644 --- a/test/functional/android/network_connection_tests.py +++ b/test/functional/android/network_connection_tests.py @@ -22,11 +22,11 @@ class NetworkConnectionTests(BaseTestCase): - def test_get_network_connection(self): + def test_get_network_connection(self) -> None: nc = self.driver.network_connection self.assertIsInstance(nc, int) - def test_set_network_connection(self): + def test_set_network_connection(self) -> None: if is_ci(): self.skipTest('Need to fix flaky test during running on CI') nc = self.driver.set_network_connection(ConnectionType.DATA_ONLY) diff --git a/test/functional/android/remote_fs_tests.py b/test/functional/android/remote_fs_tests.py index 1a7a0092..db6f3f1e 100644 --- a/test/functional/android/remote_fs_tests.py +++ b/test/functional/android/remote_fs_tests.py @@ -23,7 +23,7 @@ class RemoteFsTests(BaseTestCase): - def test_push_pull_file(self): + def test_push_pull_file(self) -> None: dest_path = '/data/local/tmp/test_push_file.txt' data = bytes('This is the contents of the file to push to the device.', 'utf-8') @@ -32,7 +32,7 @@ def test_push_pull_file(self): self.assertEqual(data, data_ret) - def test_pull_folder(self): + def test_pull_folder(self) -> None: data = bytes('random string data {}'.format(random.randint(0, 1000)), 'utf-8') dest_dir = '/data/local/tmp/' @@ -45,7 +45,7 @@ def test_pull_folder(self): for filename in ['1.txt', '2.txt']: self.assertTrue(filename in fzip.namelist()) - def test_push_file_with_src_path(self): + def test_push_file_with_src_path(self) -> None: test_files = ['test_image.jpg', 'test_file.txt'] for file_name in test_files: src_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', file_name) diff --git a/test/functional/android/screen_record_tests.py b/test/functional/android/screen_record_tests.py index 26f5f764..cad3b72b 100644 --- a/test/functional/android/screen_record_tests.py +++ b/test/functional/android/screen_record_tests.py @@ -20,7 +20,7 @@ class ScreenRecordTests(BaseTestCase): - def test_screen_record(self): + def test_screen_record(self) -> None: self.driver.start_recording_screen(timeLimit=10, forcedRestart=True) sleep(10) result = self.driver.stop_recording_screen() diff --git a/test/functional/android/search_context/find_by_accessibility_id_tests.py b/test/functional/android/search_context/find_by_accessibility_id_tests.py index 508edc21..b3a64507 100644 --- a/test/functional/android/search_context/find_by_accessibility_id_tests.py +++ b/test/functional/android/search_context/find_by_accessibility_id_tests.py @@ -23,18 +23,18 @@ class FindByAccessibilityIDTests(BaseTestCase): - def test_find_single_element(self): + def test_find_single_element(self) -> None: wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Accessibility")').click() wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Accessibility Node Querying")').click() el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Task Take out Trash') self.assertIsNotNone(el) - def test_find_multiple_elements(self): + def test_find_multiple_elements(self) -> None: els = self.driver.find_elements_by_accessibility_id('Accessibility') self.assertIsInstance(els, list) - def test_element_find_single_element(self): + def test_element_find_single_element(self) -> None: if is_ci(): self.skipTest('Need to fix flaky test during running on CI') wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Accessibility")').click() @@ -45,7 +45,7 @@ def test_element_find_single_element(self): sub_el = el.find_element_by_accessibility_id('Task Take out Trash') self.assertIsNotNone(sub_el) - def test_element_find_multiple_elements(self): + def test_element_find_multiple_elements(self) -> None: wait_for_element(self.driver, MobileBy.CLASS_NAME, 'android.widget.ListView') el = self.driver.find_element_by_class_name('android.widget.ListView') diff --git a/test/functional/android/search_context/find_by_image_tests.py b/test/functional/android/search_context/find_by_image_tests.py index 9d628c28..8d3440f5 100644 --- a/test/functional/android/search_context/find_by_image_tests.py +++ b/test/functional/android/search_context/find_by_image_tests.py @@ -28,7 +28,7 @@ @pytest.mark.skip(reason="Need to fix broken test") class FindByImageTests(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: desired_caps = desired_capabilities.get_desired_capabilities('ApiDemos-debug.apk') self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) @@ -37,10 +37,10 @@ def setUp(self): "fixImageTemplateSize": True, "autoUpdateImageElementPosition": True}) - def tearDown(self): + def tearDown(self) -> None: self.driver.quit() - def test_find_based_on_image_template(self): + def test_find_based_on_image_template(self) -> None: image_path = desired_capabilities.PATH('file/find_by_image_success.png') print(image_path) with open(image_path, 'rb') as png_file: @@ -64,7 +64,7 @@ def test_find_based_on_image_template(self): el.click() self.driver.find_element_by_accessibility_id("Alarm") - def test_find_multiple_elements_by_image_just_returns_one(self): + def test_find_multiple_elements_by_image_just_returns_one(self) -> None: WebDriverWait(self.driver, 3).until( EC.presence_of_element_located((By.ACCESSIBILITY_ID, "App")) ) @@ -73,7 +73,7 @@ def test_find_multiple_elements_by_image_just_returns_one(self): els[0].click() self.driver.find_element_by_accessibility_id("Alarm") - def test_find_throws_no_such_element(self): + def test_find_throws_no_such_element(self) -> None: image_path = desired_capabilities.PATH('file/find_by_image_failure.png') with open(image_path, 'rb') as png_file: b64_data = base64.b64encode(png_file.read()).decode('UTF-8') diff --git a/test/functional/android/search_context/find_by_uiautomator_tests.py b/test/functional/android/search_context/find_by_uiautomator_tests.py index 47430356..1e197e8e 100644 --- a/test/functional/android/search_context/find_by_uiautomator_tests.py +++ b/test/functional/android/search_context/find_by_uiautomator_tests.py @@ -21,27 +21,27 @@ @pytest.mark.skip(reason="Need to fix flaky test") class FindByUIAutomatorTests(BaseTestCase): - def test_find_single_element(self): + def test_find_single_element(self) -> None: el = self.driver.find_element_by_android_uiautomator('new UiSelector().text("Animation")') self.assertIsNotNone(el) - def test_find_multiple_elements(self): + def test_find_multiple_elements(self) -> None: els = self.driver.find_elements_by_android_uiautomator('new UiSelector().clickable(true)') self.assertIsInstance(els, list) - def test_element_find_single_element(self): + def test_element_find_single_element(self) -> None: el = self.driver.find_element_by_class_name('android.widget.ListView') sub_el = el.find_element_by_android_uiautomator('new UiSelector().description("Animation")') self.assertIsNotNone(sub_el) - def test_element_find_multiple_elements(self): + def test_element_find_multiple_elements(self) -> None: el = self.driver.find_element_by_class_name('android.widget.ListView') sub_els = el.find_elements_by_android_uiautomator('new UiSelector().clickable(true)') self.assertIsInstance(sub_els, list) - def test_scroll_into_view(self): + def test_scroll_into_view(self) -> None: el = self.driver.find_element_by_android_uiautomator( 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("Views").instance(0));') el.click() diff --git a/test/functional/android/settings_tests.py b/test/functional/android/settings_tests.py index a1ffe10b..98f3d667 100644 --- a/test/functional/android/settings_tests.py +++ b/test/functional/android/settings_tests.py @@ -19,11 +19,11 @@ class SettingsTests(BaseTestCase): - def test_get_settings(self): + def test_get_settings(self) -> None: settings = self.driver.get_settings() self.assertIsNotNone(settings) - def test_update_settings(self): + def test_update_settings(self) -> None: self.driver.update_settings({"waitForIdleTimeout": 10001}) settings = self.driver.get_settings() self.assertEqual(settings["waitForIdleTimeout"], 10001) diff --git a/test/functional/android/touch_action_tests.py b/test/functional/android/touch_action_tests.py index 7bf7e30f..22c11bba 100644 --- a/test/functional/android/touch_action_tests.py +++ b/test/functional/android/touch_action_tests.py @@ -27,14 +27,14 @@ class TouchActionTests(BaseTestCase): - def test_tap(self): + def test_tap(self) -> None: el = self.driver.find_element_by_accessibility_id('Animation') action = TouchAction(self.driver) action.tap(el).perform() el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Bouncing Balls') self.assertIsNotNone(el) - def test_tap_x_y(self): + def test_tap_x_y(self) -> None: el = self.driver.find_element_by_accessibility_id('Animation') action = TouchAction(self.driver) action.tap(el, 100, 10).perform() @@ -42,7 +42,7 @@ def test_tap_x_y(self): el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Bouncing Balls') self.assertIsNotNone(el) - def test_tap_twice(self): + def test_tap_twice(self) -> None: el = self.driver.find_element_by_accessibility_id('Text') action = TouchAction(self.driver) action.tap(el).perform() @@ -56,7 +56,7 @@ def test_tap_twice(self): els = self.driver.find_elements_by_class_name('android.widget.TextView') self.assertEqual('This is a test\nThis is a test\n', els[1].get_attribute("text")) - def test_press_and_immediately_release(self): + def test_press_and_immediately_release(self) -> None: el = self.driver.find_element_by_accessibility_id('Animation') action = TouchAction(self.driver) action.press(el).release().perform() @@ -64,7 +64,7 @@ def test_press_and_immediately_release(self): el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Bouncing Balls') self.assertIsNotNone(el) - def test_press_and_immediately_release_x_y(self): + def test_press_and_immediately_release_x_y(self) -> None: el = self.driver.find_element_by_accessibility_id('Animation') action = TouchAction(self.driver) action.press(el, 100, 10).release().perform() @@ -72,7 +72,7 @@ def test_press_and_immediately_release_x_y(self): el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Bouncing Balls') self.assertIsNotNone(el) - def test_press_and_wait(self): + def test_press_and_wait(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') @@ -97,7 +97,7 @@ def test_press_and_wait(self): 'new UiSelector().text("Sample menu")') self.assertIsNotNone(el) - def test_press_and_moveto(self): + def test_press_and_moveto(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') @@ -107,7 +107,7 @@ def test_press_and_moveto(self): el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views') self.assertIsNotNone(el) - def test_press_and_moveto_x_y(self): + def test_press_and_moveto_x_y(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('App') @@ -117,7 +117,7 @@ def test_press_and_moveto_x_y(self): el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views') self.assertIsNotNone(el) - def test_long_press(self): + def test_long_press(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') @@ -142,7 +142,7 @@ def test_long_press(self): 'new UiSelector().text("Sample menu")') self.assertIsNotNone(el) - def test_long_press_x_y(self): + def test_long_press_x_y(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') @@ -167,7 +167,7 @@ def test_long_press_x_y(self): 'new UiSelector().text("Sample menu")') self.assertIsNotNone(el) - def test_drag_and_drop(self): + def test_drag_and_drop(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') self.driver.scroll(el1, el2) @@ -188,7 +188,7 @@ def test_drag_and_drop(self): el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_text'.format(APIDEMO_PKG_NAME)) self.assertTrue('drag_dot_3' in el.text) - def test_driver_drag_and_drop(self): + def test_driver_drag_and_drop(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Content') el2 = self.driver.find_element_by_accessibility_id('Animation') self.driver.scroll(el1, el2) @@ -208,7 +208,7 @@ def test_driver_drag_and_drop(self): el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_text'.format(APIDEMO_PKG_NAME)) self.assertTrue('drag_dot_3' in el.text) - def test_driver_swipe(self): + def test_driver_swipe(self) -> None: el = self.driver.find_element_by_accessibility_id('Views') action = TouchAction(self.driver) action.tap(el).perform() diff --git a/test/functional/android/webelement_tests.py b/test/functional/android/webelement_tests.py index b936ffc4..bb28782f 100644 --- a/test/functional/android/webelement_tests.py +++ b/test/functional/android/webelement_tests.py @@ -25,13 +25,13 @@ class WebelementTests(BaseTestCase): - def test_element_location_in_view(self): + def test_element_location_in_view(self) -> None: el = self.driver.find_element_by_accessibility_id('Content') loc = el.location_in_view self.assertIsNotNone(loc['x']) self.assertIsNotNone(loc['y']) - def test_set_text(self): + def test_set_text(self) -> None: self.driver.find_element_by_android_uiautomator( 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("Views").instance(0));').click() @@ -44,7 +44,7 @@ def test_set_text(self): self.assertEqual('new text', el.text) - def test_send_keys(self): + def test_send_keys(self) -> None: for text in ['App', 'Activity', 'Custom Title']: wait_for_element(self.driver, MobileBy.XPATH, f"//android.widget.TextView[@text='{text}']").click() diff --git a/test/functional/ios/applications_tests.py b/test/functional/ios/applications_tests.py index 067aec18..362ab42e 100644 --- a/test/functional/ios/applications_tests.py +++ b/test/functional/ios/applications_tests.py @@ -22,7 +22,7 @@ class WebDriverTests(BaseTestCase): - def test_app_management(self): + def test_app_management(self) -> None: # this only works in Xcode9+ if float(desired_capabilities.get_desired_capabilities( desired_capabilities.BUNDLE_ID)['platformVersion']) < 11: diff --git a/test/functional/ios/execute_driver_tests.py b/test/functional/ios/execute_driver_tests.py index 4f2251ec..cf696675 100644 --- a/test/functional/ios/execute_driver_tests.py +++ b/test/functional/ios/execute_driver_tests.py @@ -19,7 +19,7 @@ class ExecuteDriverTests(BaseTestCase): - def test_batch(self): + def test_batch(self) -> None: script = """ const status = await driver.status(); console.warn('warning message'); @@ -30,7 +30,7 @@ def test_batch(self): assert(response.result['build']) assert(response.logs['warn'] == ['warning message']) - def test_batch_combination_python_script(self): + def test_batch_combination_python_script(self) -> None: script = """ console.warn('warning message'); const element = await driver.findElement('accessibility id', 'Buttons'); diff --git a/test/functional/ios/helper/desired_capabilities.py b/test/functional/ios/helper/desired_capabilities.py index 12dc982a..633b8e2c 100644 --- a/test/functional/ios/helper/desired_capabilities.py +++ b/test/functional/ios/helper/desired_capabilities.py @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. import os +from typing import Any, Dict, Optional # Returns abs path relative to this file and not cwd -def PATH(p): return os.path.abspath( +def PATH(p: str) -> str: return os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) @@ -24,8 +25,8 @@ def PATH(p): return os.path.abspath( BUNDLE_ID = 'com.example.apple-samplecode.UICatalog' -def get_desired_capabilities(app=None): - desired_caps = { +def get_desired_capabilities(app: Optional[str] = None) -> Dict[str, Any]: + desired_caps: Dict[str, Any] = { 'deviceName': iphone_device_name(), 'platformName': 'iOS', 'platformVersion': '13.3', @@ -42,15 +43,15 @@ def get_desired_capabilities(app=None): class PytestXdistWorker: - NUMBER = os.getenv('PYTEST_XDIST_WORKER') - COUNT = os.getenv('PYTEST_XDIST_WORKER_COUNT') # Return 2 if `-n 2` is passed + NUMBER: Optional[str] = os.getenv('PYTEST_XDIST_WORKER') + COUNT: Optional[str] = os.getenv('PYTEST_XDIST_WORKER_COUNT') # Return 2 if `-n 2` is passed @staticmethod - def gw(number): + def gw(number: int) -> str: if PytestXdistWorker.COUNT is None: return '0' - if number >= PytestXdistWorker.COUNT: + if number >= int(PytestXdistWorker.COUNT): return 'gw0' return f'gw{number}' @@ -58,7 +59,7 @@ def gw(number): # If you run tests with pytest-xdist, you can run tests in parallel. -def wda_port(): +def wda_port() -> int: if PytestXdistWorker.NUMBER == PytestXdistWorker.gw(1): return 8101 @@ -68,7 +69,7 @@ def wda_port(): # Before running tests, you must have iOS simulators named 'iPhone 6s - 8100' and 'iPhone 6s - 8101' -def iphone_device_name(port=None): +def iphone_device_name() -> str: if PytestXdistWorker.NUMBER == PytestXdistWorker.gw(0): return 'iPhone 8 - 8100' elif PytestXdistWorker.NUMBER == PytestXdistWorker.gw(1): diff --git a/test/functional/ios/helper/test_helper.py b/test/functional/ios/helper/test_helper.py index 3329bbd6..1e66e46d 100644 --- a/test/functional/ios/helper/test_helper.py +++ b/test/functional/ios/helper/test_helper.py @@ -25,13 +25,13 @@ class BaseTestCase(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: desired_caps = desired_capabilities.get_desired_capabilities('UICatalog.app.zip') self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) if is_ci(): self.driver.start_recording_screen() - def tearDown(self): + def tearDown(self) -> None: if is_ci(): payload = self.driver.stop_recording_screen() video_path = os.path.join(os.getcwd(), self._testMethodName + '.mp4') diff --git a/test/functional/ios/hw_actions_tests.py b/test/functional/ios/hw_actions_tests.py index f37d268d..9f43392f 100644 --- a/test/functional/ios/hw_actions_tests.py +++ b/test/functional/ios/hw_actions_tests.py @@ -18,7 +18,7 @@ class HwActionsTests(BaseTestCase): - def test_lock(self): + def test_lock(self) -> None: self.driver.lock(-1) try: self.assertTrue(self.driver.is_locked()) @@ -26,16 +26,16 @@ def test_lock(self): self.driver.unlock() self.assertFalse(self.driver.is_locked()) - def test_shake(self): - # what can we assert about this? + def test_shake(self) -> None: + # TODO what can we assert about this? self.driver.shake() - def test_touch_id(self): + def test_touch_id(self) -> None: # nothing to assert, just verify that it doesn't blow up self.driver.touch_id(True) self.driver.touch_id(False) - def test_toggle_touch_id_enrollment(self): + def test_toggle_touch_id_enrollment(self) -> None: # nothing to assert, just verify that it doesn't blow up self.driver.toggle_touch_id_enrollment() diff --git a/test/functional/ios/keyboard_tests.py b/test/functional/ios/keyboard_tests.py index 7ae62347..08ecfdfa 100644 --- a/test/functional/ios/keyboard_tests.py +++ b/test/functional/ios/keyboard_tests.py @@ -19,7 +19,7 @@ class KeyboardTests(BaseTestCase): - def test_hide_keyboard(self): + def test_hide_keyboard(self) -> None: self._move_to_textbox() el = self.driver.find_elements_by_class_name('XCUIElementTypeTextField')[0] @@ -33,7 +33,7 @@ def test_hide_keyboard(self): self.assertFalse(el.is_displayed()) - def test_hide_keyboard_presskey_strategy(self): + def test_hide_keyboard_presskey_strategy(self) -> None: self._move_to_textbox() el = self.driver.find_elements_by_class_name('XCUIElementTypeTextField')[0] @@ -47,7 +47,7 @@ def test_hide_keyboard_presskey_strategy(self): self.assertFalse(el.is_displayed()) - def test_hide_keyboard_no_key_name(self): + def test_hide_keyboard_no_key_name(self) -> None: self._move_to_textbox() el = self.driver.find_elements_by_class_name('XCUIElementTypeTextField')[0] @@ -63,7 +63,7 @@ def test_hide_keyboard_no_key_name(self): # currently fails. self.assertFalse(el.is_displayed()) - def test_is_keyboard_shown(self): + def test_is_keyboard_shown(self) -> None: self._move_to_textbox() el = self.driver.find_elements_by_class_name('XCUIElementTypeTextField')[0] @@ -71,7 +71,7 @@ def test_is_keyboard_shown(self): el.set_value('Testing') self.assertTrue(self.driver.is_keyboard_shown()) - def _move_to_textbox(self): + def _move_to_textbox(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Sliders') el2 = self.driver.find_element_by_accessibility_id('Buttons') self.driver.scroll(el1, el2) diff --git a/test/functional/ios/remote_fs_tests.py b/test/functional/ios/remote_fs_tests.py index 4c24b39f..66cad40e 100644 --- a/test/functional/ios/remote_fs_tests.py +++ b/test/functional/ios/remote_fs_tests.py @@ -20,7 +20,7 @@ class RemoteFsTests(BaseTestCase): - def test_push_file(self): + def test_push_file(self) -> None: file_name = 'test_image.jpg' source_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'file', file_name) destination_path = file_name diff --git a/test/functional/ios/safari_tests.py b/test/functional/ios/safari_tests.py index a0b5255f..08c73dd4 100644 --- a/test/functional/ios/safari_tests.py +++ b/test/functional/ios/safari_tests.py @@ -20,7 +20,7 @@ class SafariTests(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: desired_caps = get_desired_capabilities() desired_caps.update({ 'browserName': 'safari', @@ -30,15 +30,15 @@ def setUp(self): self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) - def tearDown(self): + def tearDown(self) -> None: self.driver.quit() - def test_context(self): + def test_context(self) -> None: self.assertEqual('NATIVE_APP', self.driver.contexts[0]) self.assertTrue(self.driver.contexts[1].startswith('WEBVIEW_')) self.assertTrue('WEBVIEW_' in self.driver.current_context) - def test_get(self): + def test_get(self) -> None: self.driver.get("http://google.com") self.assertEqual('Google', self.driver.title) diff --git a/test/functional/ios/screen_record_tests.py b/test/functional/ios/screen_record_tests.py index 7ad79af6..33a5e98a 100644 --- a/test/functional/ios/screen_record_tests.py +++ b/test/functional/ios/screen_record_tests.py @@ -19,7 +19,7 @@ class ScreenRecordTests(BaseTestCase): - def test_screen_record(self): + def test_screen_record(self) -> None: self.driver.start_recording_screen() sleep(10) result = self.driver.stop_recording_screen() diff --git a/test/functional/ios/search_context/find_by_element_webelement_tests.py b/test/functional/ios/search_context/find_by_element_webelement_tests.py index 3da2fc42..2e81fec5 100644 --- a/test/functional/ios/search_context/find_by_element_webelement_tests.py +++ b/test/functional/ios/search_context/find_by_element_webelement_tests.py @@ -19,7 +19,7 @@ class FindByElementWebelementTests(BaseTestCase): - def test_find_element_by_path(self): + def test_find_element_by_path(self) -> None: el = self.driver.find_element_by_ios_predicate('wdName == "UICatalog"') self.assertEqual('UICatalog', el.get_attribute('name')) diff --git a/test/functional/ios/search_context/find_by_ios_class_chain_tests.py b/test/functional/ios/search_context/find_by_ios_class_chain_tests.py index 12537ad3..3c02fb2b 100644 --- a/test/functional/ios/search_context/find_by_ios_class_chain_tests.py +++ b/test/functional/ios/search_context/find_by_ios_class_chain_tests.py @@ -18,12 +18,12 @@ class FindByIOClassChainTests(BaseTestCase): - def test_find_element_by_path(self): + def test_find_element_by_path(self) -> None: els = self.driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow/**/XCUIElementTypeStaticText') self.assertEqual(35, len(els)) self.assertEqual('UICatalog', els[0].get_attribute('name')) - def test_find_multiple_elements_by_path(self): + def test_find_multiple_elements_by_path(self) -> None: el = self.driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow/*/*/*') self.assertEqual(2, len(el)) self.assertEqual('UICatalog', el[0].get_attribute('name')) diff --git a/test/functional/ios/search_context/find_by_ios_predicate_tests.py b/test/functional/ios/search_context/find_by_ios_predicate_tests.py index 6890b6b5..6f5bc6d9 100644 --- a/test/functional/ios/search_context/find_by_ios_predicate_tests.py +++ b/test/functional/ios/search_context/find_by_ios_predicate_tests.py @@ -18,23 +18,23 @@ class FindByIOSPredicateTests(BaseTestCase): - def test_find_element_by_name(self): + def test_find_element_by_name(self) -> None: # Will throw exception if element is not found self.driver.find_element_by_ios_predicate('wdName == "Buttons"') - def test_find_multiple_element_by_type(self): + def test_find_multiple_element_by_type(self) -> None: e = self.driver.find_elements_by_ios_predicate('wdType == "XCUIElementTypeStaticText"') self.assertNotEqual(len(e), 0) - def test_find_element_by_label(self): + def test_find_element_by_label(self) -> None: # Will throw exception if element is not found self.driver.find_element_by_ios_predicate('label == "Buttons"') - def test_find_element_by_value(self): + def test_find_element_by_value(self) -> None: # Will throw exception if element is not found self.driver.find_element_by_ios_predicate('wdValue == "Buttons"') - def test_find_element_by_isvisible(self): + def test_find_element_by_isvisible(self) -> None: # Will throw exception if element is not found self.driver.find_element_by_ios_predicate('wdValue == "Buttons" AND visible == 1') @@ -42,7 +42,7 @@ def test_find_element_by_isvisible(self): e = self.driver.find_elements_by_ios_predicate('wdValue == "Buttons" AND visible == 0') self.assertEqual(len(e), 0) - def test_find_element_by_isenabled(self): + def test_find_element_by_isenabled(self) -> None: # Will throw exception if element is not found self.driver.find_element_by_ios_predicate('wdValue == "Buttons" AND enabled == 1') diff --git a/test/functional/ios/webdriver_tests.py b/test/functional/ios/webdriver_tests.py index 3d0f113f..7a7c5149 100644 --- a/test/functional/ios/webdriver_tests.py +++ b/test/functional/ios/webdriver_tests.py @@ -13,6 +13,7 @@ # limitations under the License. import unittest +from typing import TYPE_CHECKING from selenium.webdriver.support.ui import WebDriverWait @@ -24,10 +25,13 @@ from ..test_helper import is_ci from .helper import desired_capabilities +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + class WebDriverTests(BaseTestCase): - def test_all_sessions(self): + def test_all_sessions(self) -> None: if is_ci(): # TODO Due to not created 2nd session somehow self.skipTest('Need to fix flaky test during running on CI.') @@ -39,7 +43,7 @@ def test_all_sessions(self): class session_counts_is_two: TIMEOUT = 10 - def __call__(self, driver): + def __call__(self, driver: 'WebDriver') -> bool: return len(driver.all_sessions) == 2 driver2 = None @@ -52,7 +56,7 @@ def __call__(self, driver): if driver2 is not None: driver2.quit() - def test_app_management(self): + def test_app_management(self) -> None: # this only works in Xcode9+ if float(desired_capabilities.get_desired_capabilities( desired_capabilities.BUNDLE_ID)['platformVersion']) < 11: @@ -66,7 +70,7 @@ def test_app_management(self): self.assertEqual(self.driver.query_app_state(desired_capabilities.BUNDLE_ID), ApplicationState.RUNNING_IN_FOREGROUND) - def test_clear(self): + def test_clear(self) -> None: self._move_to_textbox() el = self.driver.find_elements_by_class_name('XCUIElementTypeTextField')[0] @@ -90,7 +94,7 @@ def test_clear(self): text = el.get_attribute('value') self.assertEqual(text, def_text) - def test_press_button(self): + def test_press_button(self) -> None: self.driver.press_button("Home") if float(desired_capabilities.get_desired_capabilities( desired_capabilities.BUNDLE_ID)['platformVersion']) < 11: @@ -98,7 +102,7 @@ def test_press_button(self): self.assertEqual(self.driver.query_app_state(desired_capabilities.BUNDLE_ID), ApplicationState.RUNNING_IN_FOREGROUND) - def _move_to_textbox(self): + def _move_to_textbox(self) -> None: el1 = self.driver.find_element_by_accessibility_id('Sliders') el2 = self.driver.find_element_by_accessibility_id('Buttons') self.driver.scroll(el1, el2) diff --git a/test/functional/test_helper.py b/test/functional/test_helper.py index ee6b6daf..ae55b386 100644 --- a/test/functional/test_helper.py +++ b/test/functional/test_helper.py @@ -6,14 +6,21 @@ class NoAvailablePortError(Exception): pass -def get_available_from_port_range(from_port, to_port): +def get_available_from_port_range(from_port: int, to_port: int) -> int: """Returns available local port number. + + Args: + from_port (int): The start port to search + to_port (int): The end port to search + + Returns: + int: available local port number which are found first + """ - r = range(from_port, to_port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - for port in r: + for port in range(from_port, to_port): try: if sock.connect_ex(('localhost', port)) != 0: return port @@ -23,7 +30,7 @@ def get_available_from_port_range(from_port, to_port): raise NoAvailablePortError(f'No available port between {from_port} and {to_port}') -def is_ci(): +def is_ci() -> bool: """Returns if current execution is running on CI Returns: diff --git a/test/unit/helper/test_helper.py b/test/unit/helper/test_helper.py index 4c1b2d07..b33d3a92 100644 --- a/test/unit/helper/test_helper.py +++ b/test/unit/helper/test_helper.py @@ -13,6 +13,7 @@ # limitations under the License. import json +from typing import TYPE_CHECKING, Any, Dict import httpretty @@ -21,8 +22,12 @@ # :return: A string of test URL SERVER_URL_BASE = 'http://localhost:4723/wd/hub' +if TYPE_CHECKING: + from appium.webdriver.webdriver import WebDriver + from httpretty.core import HTTPrettyRequestEmpty -def appium_command(command): + +def appium_command(command: str) -> str: """Return a command of Appium Returns: @@ -31,7 +36,7 @@ def appium_command(command): return f'{SERVER_URL_BASE}{command}' -def android_w3c_driver(): +def android_w3c_driver() -> 'WebDriver': """Return a W3C driver which is generated by a mock response for Android Returns: @@ -86,7 +91,7 @@ def android_w3c_driver(): return driver -def ios_w3c_driver(): +def ios_w3c_driver() -> 'WebDriver': """Return a W3C driver which is generated by a mock response for iOS Returns: @@ -127,6 +132,6 @@ def ios_w3c_driver(): return driver -def get_httpretty_request_body(request): +def get_httpretty_request_body(request: 'HTTPrettyRequestEmpty') -> Dict[str, Any]: """Returns utf-8 decoded request body""" return json.loads(request.body.decode('utf-8'))