diff --git a/appium/webdriver/common/mobileby.py b/appium/webdriver/common/mobileby.py index 710248fe..1b5e31dd 100644 --- a/appium/webdriver/common/mobileby.py +++ b/appium/webdriver/common/mobileby.py @@ -16,6 +16,7 @@ class MobileBy(By): + IOS_PREDICATE = '-ios predicate string' IOS_UIAUTOMATION = '-ios uiautomation' ANDROID_UIAUTOMATOR = '-android uiautomator' ACCESSIBILITY_ID = 'accessibility id' diff --git a/appium/webdriver/mobilecommand.py b/appium/webdriver/mobilecommand.py index d28ed02f..b0a2e654 100644 --- a/appium/webdriver/mobilecommand.py +++ b/appium/webdriver/mobilecommand.py @@ -58,3 +58,4 @@ class MobileCommand(object): UPDATE_SETTINGS = 'updateSettings' SET_LOCATION = 'setLocation' GET_DEVICE_TIME = 'getDeviceTime' + CLEAR = 'clear' \ No newline at end of file diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 847087d2..9cc0ce14 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -43,6 +43,7 @@ def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub', # add new method to the `find_by_*` pantheon By.IOS_UIAUTOMATION = MobileBy.IOS_UIAUTOMATION + By.IOS_PREDICATE = MobileBy.IOS_PREDICATE By.ANDROID_UIAUTOMATOR = MobileBy.ANDROID_UIAUTOMATOR By.ACCESSIBILITY_ID = MobileBy.ACCESSIBILITY_ID @@ -98,6 +99,28 @@ def find_elements_by_ios_uiautomation(self, uia_string): """ return self.find_elements(by=By.IOS_UIAUTOMATION, value=uia_string) + def find_element_by_ios_predicate(self, predicate_string): + """Find an element by ios predicate string. + + :Args: + - predicate_string - The predicate string + + :Usage: + driver.find_element_by_ios_predicate('label == "myLabel"') + """ + return self.find_element(by=By.IOS_PREDICATE, value=predicate_string) + + def find_elements_by_ios_predicate(self, predicate_string): + """Finds elements by ios predicate string. + + :Args: + - predicate_string - The predicate string + + :Usage: + driver.find_elements_by_ios_predicate('label == "myLabel"') + """ + return self.find_elements(by=By.IOS_PREDICATE, value=predicate_string) + def find_element_by_android_uiautomator(self, uia_string): """Finds element by uiautomator in Android. @@ -829,3 +852,5 @@ def _addCommands(self): ('GET', '/session/$sessionId/element/$id/location_in_view') self.command_executor._commands[Command.GET_DEVICE_TIME] = \ ('GET', '/session/$sessionId/appium/device/system_time') + self.command_executor._commands[Command.CLEAR] = \ + ('POST', '/session/$sessionId/element/$id/clear') diff --git a/appium/webdriver/webelement.py b/appium/webdriver/webelement.py index d4f50ee9..71e8e041 100644 --- a/appium/webdriver/webelement.py +++ b/appium/webdriver/webelement.py @@ -41,6 +41,28 @@ def find_elements_by_ios_uiautomation(self, uia_string): """ return self.find_elements(by=By.IOS_UIAUTOMATION, value=uia_string) + def find_element_by_ios_predicate(self, predicate_string): + """Find an element by ios predicate string. + + :Args: + - predicate_string - The predicate string + + :Usage: + driver.find_element_by_ios_predicate('label == "myLabel"') + """ + return self.find_element(by=By.IOS_PREDICATE, value=predicate_string) + + def find_elements_by_ios_predicate(self, predicate_string): + """Finds elements by ios predicate string. + + :Args: + - predicate_string - The predicate string + + :Usage: + driver.find_elements_by_ios_predicate('label == "myLabel"') + """ + return self.find_elements(by=By.IOS_PREDICATE, value=predicate_string) + def find_element_by_android_uiautomator(self, uia_string): """Finds element by uiautomator in Android. @@ -122,3 +144,10 @@ def set_value(self, value): } self._execute(Command.SET_IMMEDIATE_VALUE, data) return self + + def clear(self): + """Clears text. + """ + data = {'id': self.id} + self._execute(Command.CLEAR, data) + return self diff --git a/test/functional/ios/appium_tests.py b/test/functional/ios/appium_tests.py index 4c544dc7..10d4c3e9 100644 --- a/test/functional/ios/appium_tests.py +++ b/test/functional/ios/appium_tests.py @@ -96,6 +96,26 @@ def test_hide_keyboard_no_key_name(self): # currently fails. self.assertFalse(el.is_displayed()) + def test_clear(self): + # Click text fields + self.driver.find_element_by_accessibility_id('TextFields').click() + + # Verify default text + def_text = '' + text = self.driver.find_element_by_accessibility_id('Normal').get_attribute('value') + self.assertEqual(text, def_text) + + # Input some text, verify + input_text = 'blah' + self.driver.find_element_by_accessibility_id('Normal').send_keys(input_text) + text = self.driver.find_element_by_accessibility_id('Normal').get_attribute('value') + self.assertEqual(text, input_text) + + # Clear text, verify + self.driver.find_element_by_accessibility_id('Normal').clear() + text = self.driver.find_element_by_accessibility_id('Normal').get_attribute('value') + self.assertEqual(text, def_text) + if __name__ == "__main__": suite = unittest.TestLoader().loadTestsFromTestCase(AppiumTests) diff --git a/test/functional/ios/find_by_ios_predicate_tests.py b/test/functional/ios/find_by_ios_predicate_tests.py new file mode 100644 index 00000000..03f9cad7 --- /dev/null +++ b/test/functional/ios/find_by_ios_predicate_tests.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from appium import webdriver +import desired_capabilities + + +class FindByIOSPredicateTests(unittest.TestCase): + @classmethod + def setUpClass(self): + desired_caps = desired_capabilities.get_desired_capabilities('UICatalog.app.zip') + self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) + + @classmethod + def tearDownClass(self): + self.driver.quit() + + def test_find_element_by_name(self): + # 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): + e = self.driver.find_elements_by_ios_predicate('wdType == "XCUIElementTypeStaticText"') + self.assertNotEqual(len(e), 0) + + def test_find_element_by_label(self): + # Will throw exception if element is not found + self.driver.find_element_by_ios_predicate('label == "TextFields"') + + def test_find_element_by_value(self): + # Will throw exception if element is not found + self.driver.find_element_by_ios_predicate('wdValue == "Controls"') + + def test_find_element_by_isvisible(self): + # Will throw exception if element is not found + self.driver.find_element_by_ios_predicate('wdValue == "SearchBar" AND isWDVisible == 1') + + # Should not find any elements + e = self.driver.find_elements_by_ios_predicate('wdValue == "SearchBar" AND isWDVisible == 0') + self.assertEqual(len(e), 0) + + def test_find_element_by_isenabled(self): + # Will throw exception if element is not found + self.driver.find_element_by_ios_predicate('wdValue == "SearchBar" AND isWDEnabled == 1') + + # Should not find any elements + e = self.driver.find_elements_by_ios_predicate('wdValue == "SearchBar" AND isWDEnabled == 0') + self.assertEqual(len(e), 0) + + +if __name__ == "__main__": + suite = unittest.TestLoader().loadTestsFromTestCase(FindByIOSPredicateTests) + unittest.TextTestRunner(verbosity=2).run(suite)