Module: Appium::Ios
- Defined in:
- lib/appium_lib/ios/patch.rb,
lib/appium_lib/ios/errors.rb,
lib/appium_lib/ios/helper.rb,
lib/appium_lib/ios/element/text.rb,
lib/appium_lib/ios/element/alert.rb,
lib/appium_lib/ios/element/button.rb,
lib/appium_lib/ios/mobile_methods.rb,
lib/appium_lib/ios/element/generic.rb,
lib/appium_lib/ios/element/textfield.rb
Defined Under Namespace
Classes: CommandError, UITestElementsPrinter
Constant Summary collapse
- UIAStaticText =
'UIAStaticText'.freeze
- XCUIElementTypeStaticText =
'XCUIElementTypeStaticText'.freeze
- UIAButton =
'UIAButton'.freeze
- XCUIElementTypeButton =
'XCUIElementTypeButton'.freeze
- UIATextField =
'UIATextField'.freeze
- UIASecureTextField =
'UIASecureTextField'.freeze
- XCUIElementTypeTextField =
'XCUIElementTypeTextField'.freeze
- XCUIElementTypeSecureTextField =
'XCUIElementTypeSecureTextField'.freeze
Class Method Summary collapse
- .extended(_mod) ⇒ Object
-
.ios_class_chain_find ⇒ Object
Only for XCUITest(WebDriverAgent) find_element/s can be used with a [class chain]( github.com/facebook/WebDriverAgent/wiki/Queries).
-
.ios_predicate_string_find ⇒ Object
find_element/s can be used with a [Predicates](developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html).
-
.uiautomation_find ⇒ Object
find_element/s can be used with a [UIAutomation command](developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWindowClassReference/UIAWindow/UIAWindow.html#//apple_ref/doc/uid/TP40009930).
Instance Method Summary collapse
-
#_all_pred(opts) ⇒ Object
predicate - the predicate to evaluate on the main app.
-
#_by_json(opts) ⇒ Object
For Appium(automation name), not XCUITest typeArray - array of string types to search for.
- #_validate_object(*objects) ⇒ Object
-
#alert_accept ⇒ void
Accept the alert.
-
#alert_dismiss ⇒ void
Dismiss the alert.
-
#button(value) ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton that contains value or by index.
-
#button_class ⇒ String
Class name for button.
-
#button_exact(value) ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton that exactly matches value.
-
#buttons(value = false) ⇒ Array<UIAButton|XCUIElementTypeButton>
Find all UIAButtons|XCUIElementTypeButtons containing value.
-
#buttons_exact(value) ⇒ Array<UIAButton|XCUIElementTypeButton>
Find all UIAButtons|XCUIElementTypeButtons that exactly match value.
-
#ele_by_json(opts) ⇒ Object
see eles_by_json.
-
#ele_by_json_visible_contains(element, value) ⇒ Element
Find the first element that contains value.
-
#ele_by_json_visible_exact(element, value) ⇒ Element
Find the first element exactly matching value For Appium(automation name), not XCUITest.
-
#ele_index(class_name, index) ⇒ Element
Get the element of type class_name at matching index.
-
#ele_with_pred(opts) ⇒ Element
returns element matching predicate contained in the main app.
-
#eles_by_json(opts) ⇒ Object
For Appium(automation name), not XCUITest example usage:.
-
#eles_by_json_visible_contains(element, value) ⇒ Array<Element>
Find all elements containing value For Appium(automation name), not XCUITest.
-
#eles_by_json_visible_exact(element, value) ⇒ Element
Find all elements exactly matching value For Appium(automation name), not XCUITest.
-
#eles_with_pred(opts) ⇒ Array<Element>
returns elements matching predicate contained in the main app.
- #empty(ele) ⇒ Object
-
#find(value) ⇒ Element
Find the first element containing value.
-
#find_ele_by_attr(class_name, attr, value) ⇒ Element
Find the first element exactly matching class and attribute value.
-
#find_ele_by_attr_include(class_name, attr, value) ⇒ Element
Get the first tag by attribute that exactly matches value.
-
#find_ele_by_predicate(class_name: '*', value:) ⇒ Element
Find the first element exactly matching attribute case insensitive value.
-
#find_ele_by_predicate_include(class_name: '*', value:) ⇒ Element
Get the first elements that include insensitive value.
-
#find_eles_by_attr(class_name, attr, value) ⇒ Array<Element>
Find all elements exactly matching class and attribute value.
-
#find_eles_by_attr_include(class_name, attr, value) ⇒ Array<Element>
Get tags by attribute that include value.
-
#find_eles_by_predicate(class_name: '*', value:) ⇒ Array<Element>
Find all elements exactly matching attribute case insensitive value.
-
#find_eles_by_predicate_include(class_name: '*', value:) ⇒ Array<Element>
Get elements that include case insensitive value.
-
#find_exact(value) ⇒ Element
Find the first element exactly matching value.
-
#finds(value) ⇒ Array<Element>
Find all elements containing value.
-
#finds_exact(value) ⇒ Array<Element>
Find all elements exactly matching value.
-
#first_button ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton.
-
#first_ele(class_name) ⇒ Element
Get the first tag that matches class_name.
-
#first_text ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText.
-
#first_textfield ⇒ TextField
Find the first TextField.
- #fix_space(s) ⇒ Object
-
#get_page(element = source_window(0), class_name = nil) ⇒ String
Returns a string of interesting elements.
-
#get_source ⇒ String
Returns XML string for the current page Same as driver.page_source.
-
#hide_ios_keyboard(close_key = 'Done') ⇒ void
For Appium(automation name), not XCUITest If there’s no keyboard, then do nothing.
-
#id(id) ⇒ Element
Find by id.
-
#ios_password(length = 1) ⇒ String
iOS only.
-
#ios_version ⇒ Array<Integer>
Return the iOS version as an array of integers.
-
#last_button ⇒ UIAButton|XCUIElementTypeButton
TODO: add documentation regarding previous element.
-
#last_ele(class_name) ⇒ Element
Get the last tag that matches class_name.
-
#last_text ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the last UIAStaticText|XCUIElementTypeStaticText.
-
#last_textfield ⇒ TextField
Find the last TextField.
-
#page(opts = {}) ⇒ void
Prints a string of interesting elements to the console.
-
#page_window(window_number = 0) ⇒ void
Prints parsed page source to console.
-
#patch_webdriver_element ⇒ Object
class_eval inside a method because class Selenium::WebDriver::Element will trigger as soon as the file is required.
-
#secure_text_field_class ⇒ String
Class name for secure text field.
-
#source ⇒ void
Prints xml of the current page.
-
#source_window(_window_number = 0) ⇒ JSON
Gets the JSON source of window number.
-
#static_text_class ⇒ String
Class name for text.
- #string_attr_exact(class_name, attr, value) ⇒ Object
- #string_attr_include(class_name, attr, value) ⇒ Object
-
#string_visible_contains(element, value) ⇒ String
Returns an object that matches the first element that contains value.
-
#string_visible_exact(element, value) ⇒ String
Create an object to exactly match the first element with target value.
-
#tag(class_name) ⇒ Element
Returns the first visible element matching class_name.
-
#tags(class_name) ⇒ Element
Returns all visible elements matching class_name.
-
#tags_exact(class_names:, value: nil) ⇒ Array[Element]
Returns all visible elements matching class_names and value.
-
#tags_include(class_names:, value: nil) ⇒ Array[Element]
Returns all visible elements matching class_names and value This method calls find_element/s and element.value/text many times.
-
#text(value) ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index.
-
#text_exact(value) ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value.
-
#text_field_class ⇒ String
Class name for text field.
-
#textfield(value) ⇒ TextField
Find the first TextField that contains value or by index.
-
#textfield_exact(value) ⇒ TextField
Find the first TextField that exactly matches value.
-
#textfields(value = false) ⇒ Array<TextField>
Find all TextFields containing value.
-
#textfields_exact(value) ⇒ Array<TextField>
Find all TextFields that exactly match value.
-
#texts(value = false) ⇒ Array<UIAStaticText|XCUIElementTypeStaticText>
Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value.
-
#texts_exact(value) ⇒ Array<UIAStaticText|XCUIElementTypeStaticText>
Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value.
Class Method Details
.extended(_mod) ⇒ Object
32 33 34 35 36 |
# File 'lib/appium_lib/ios/mobile_methods.rb', line 32 def extended(_mod) ::Appium::Driver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation' ::Appium::Driver::SearchContext::FINDERS[:predicate] = '-ios predicate string' ::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain' end |
.ios_class_chain_find ⇒ Object
Only for XCUITest(WebDriverAgent) find_element/s can be used with a [class chain]( github.com/facebook/WebDriverAgent/wiki/Queries)
“‘ruby
# select the third child button of the first child window element
find_elements :class_chain, 'XCUIElementTypeWindow/XCUIElementTypeButton[3]'
# select all the children windows
find_elements :class_chain, 'XCUIElementTypeWindow'
# select the second last child of the second child window
find_elements :class_chain, 'XCUIElementTypeWindow[2]/XCUIElementTypeAny[-2]'
“‘
32 33 34 35 36 |
# File 'lib/appium_lib/ios/mobile_methods.rb', line 32 def extended(_mod) ::Appium::Driver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation' ::Appium::Driver::SearchContext::FINDERS[:predicate] = '-ios predicate string' ::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain' end |
.ios_predicate_string_find ⇒ Object
find_element/s can be used with a [Predicates](developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html)
“‘ruby
find_elements :predicate, "isWDVisible == 1"
find_elements :predicate, 'wdName == "Buttons"'
find_elements :predicate, 'wdValue == "SearchBar" AND isWDDivisible == 1'
“‘
32 33 34 35 36 |
# File 'lib/appium_lib/ios/mobile_methods.rb', line 32 def extended(_mod) ::Appium::Driver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation' ::Appium::Driver::SearchContext::FINDERS[:predicate] = '-ios predicate string' ::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain' end |
.uiautomation_find ⇒ Object
find_element/s can be used with a [UIAutomation command](developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAWindowClassReference/UIAWindow/UIAWindow.html#//apple_ref/doc/uid/TP40009930).
“‘ruby
find_elements :uiautomation, 'elements()
“‘
32 33 34 35 36 |
# File 'lib/appium_lib/ios/mobile_methods.rb', line 32 def extended(_mod) ::Appium::Driver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation' ::Appium::Driver::SearchContext::FINDERS[:predicate] = '-ios predicate string' ::Appium::Driver::SearchContext::FINDERS[:class_chain] = '-ios class chain' end |
Instance Method Details
#_all_pred(opts) ⇒ Object
predicate - the predicate to evaluate on the main app
visible - if true, only visible elements are returned. default true
591 592 593 594 595 596 |
# File 'lib/appium_lib/ios/helper.rb', line 591 def _all_pred(opts) predicate = opts[:predicate] raise 'predicate must be provided' unless predicate visible = opts.fetch :visible, true %($.mainApp().getAllWithPredicate("#{predicate}", #{visible});) end |
#_by_json(opts) ⇒ Object
For Appium(automation name), not XCUITest typeArray - array of string types to search for. Example: [“UIAStaticText”] onlyFirst - boolean. returns only the first result if true. Example: true onlyVisible - boolean. returns only visible elements if true. Example: true target - string. the target value to search for. Example: “Buttons, Various uses of UIButton” substring - boolean. matches on substrings if true otherwise an exact mathc is required. Example: true insensitive - boolean. ignores case sensitivity if true otherwise it’s case sensitive. Example: true
opts = {
typeArray: ["UIAStaticText"],
onlyFirst: true,
onlyVisible: true,
name: {
target: "Buttons, Various uses of UIButton",
substring: false,
insensitive: false,
},
label: {
target: "Buttons, Various uses of UIButton",
substring: false,
insensitive: false,
},
value: {
target: "Buttons, Various uses of UIButton",
substring: false,
insensitive: false,
}
}
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 |
# File 'lib/appium_lib/ios/helper.rb', line 674 def _by_json(opts) valid_keys = [:typeArray, :onlyFirst, :onlyVisible, :name, :label, :value] unknown_keys = opts.keys - valid_keys raise "Unknown keys: #{unknown_keys}" unless unknown_keys.empty? type_array = opts[:typeArray] raise 'typeArray must be an array' unless type_array.is_a? Array only_first = opts[:onlyFirst] raise 'onlyFirst must be a boolean' unless [true, false].include? only_first only_visible = opts[:onlyVisible] raise 'onlyVisible must be a boolean' unless [true, false].include? only_visible # name/label/value are optional. when searching for class only, then none # will be present. _validate_object opts[:name], opts[:label], opts[:value] # note that mainWindow is sometimes nil so it's passed as a param # $._elementOrElementsByType will validate that the window isn't nil element_or_elements_by_type = <<-JS (function() { var opts = #{opts.to_json}; var result = false; try { result = $._elementOrElementsByType($.mainWindow(), opts); } catch (e) { } return result; })(); JS res = execute_script element_or_elements_by_type res ? res : raise(Appium::Ios::CommandError, 'mainWindow is nil') end |
#_validate_object(*objects) ⇒ Object
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'lib/appium_lib/ios/helper.rb', line 625 def _validate_object(*objects) raise 'objects must be an array' unless objects.is_a? Array objects.each do |obj| next unless obj # obj may be nil. if so, ignore. valid_keys = [:target, :substring, :insensitive] unknown_keys = obj.keys - valid_keys raise "Unknown keys: #{unknown_keys}" unless unknown_keys.empty? target = obj[:target] raise 'target must be a string' unless target.is_a? String substring = obj[:substring] raise 'substring must be a boolean' unless [true, false].include? substring insensitive = obj[:insensitive] raise 'insensitive must be a boolean' unless [true, false].include? insensitive end end |
#alert_accept ⇒ void
This method returns an undefined value.
Accept the alert.
5 6 7 8 9 |
# File 'lib/appium_lib/ios/element/alert.rb', line 5 def alert_accept # @driver.switch_to.alert.accept # ".switch_to.alert" calls alert_text so use bridge directly driver.send(:bridge).accept_alert end |
#alert_dismiss ⇒ void
This method returns an undefined value.
Dismiss the alert.
13 14 15 16 17 |
# File 'lib/appium_lib/ios/element/alert.rb', line 13 def alert_dismiss # @driver.switch_to.alert.dismiss # ".switch_to.alert" calls alert_text so use bridge directly driver.send(:bridge).dismiss_alert end |
#button(value) ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton that contains value or by index. If int then the UIAButton|XCUIElementTypeButton at that index is returned.
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/appium_lib/ios/element/button.rb', line 16 def (value) # return button at index. return ele_index , value if value.is_a? Numeric if automation_name_is_xcuitest? raise_error_if_no_element (value).first else ele_by_json_visible_contains , value end end |
#button_class ⇒ String
Returns Class name for button.
8 9 10 |
# File 'lib/appium_lib/ios/element/button.rb', line 8 def automation_name_is_xcuitest? ? XCUIElementTypeButton : UIAButton end |
#button_exact(value) ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton that exactly matches value.
59 60 61 62 63 64 65 |
# File 'lib/appium_lib/ios/element/button.rb', line 59 def (value) if automation_name_is_xcuitest? raise_error_if_no_element (value).first else ele_by_json_visible_exact , value end end |
#buttons(value = false) ⇒ Array<UIAButton|XCUIElementTypeButton>
Find all UIAButtons|XCUIElementTypeButtons containing value. If value is omitted, all UIAButtons|XCUIElementTypeButtons are returned.
31 32 33 34 35 36 37 38 39 40 |
# File 'lib/appium_lib/ios/element/button.rb', line 31 def (value = false) return unless value if automation_name_is_xcuitest? elements = find_eles_by_predicate_include(class_name: , value: value) select_visible_elements elements else eles_by_json_visible_contains , value end end |
#buttons_exact(value) ⇒ Array<UIAButton|XCUIElementTypeButton>
Find all UIAButtons|XCUIElementTypeButtons that exactly match value.
70 71 72 73 74 75 76 77 |
# File 'lib/appium_lib/ios/element/button.rb', line 70 def (value) if automation_name_is_xcuitest? elements = find_eles_by_predicate(class_name: , value: value) select_visible_elements elements else eles_by_json_visible_exact , value end end |
#ele_by_json(opts) ⇒ Object
see eles_by_json
730 731 732 733 734 735 |
# File 'lib/appium_lib/ios/helper.rb', line 730 def ele_by_json(opts) opts[:onlyFirst] = true result = _by_json(opts).first raise _no_such_element if result.nil? result end |
#ele_by_json_visible_contains(element, value) ⇒ Element
Find the first element that contains value. For Appium(automation name), not XCUITest
478 479 480 |
# File 'lib/appium_lib/ios/helper.rb', line 478 def ele_by_json_visible_contains(element, value) ele_by_json string_visible_contains element, value end |
#ele_by_json_visible_exact(element, value) ⇒ Element
Find the first element exactly matching value For Appium(automation name), not XCUITest
517 518 519 |
# File 'lib/appium_lib/ios/helper.rb', line 517 def ele_by_json_visible_exact(element, value) ele_by_json string_visible_exact element, value end |
#ele_index(class_name, index) ⇒ Element
Get the element of type class_name at matching index.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/appium_lib/ios/helper.rb', line 212 def ele_index(class_name, index) raise 'Index must be >= 1' unless index == 'last()' || (index.is_a?(Integer) && index >= 1) elements = (class_name) if index == 'last()' result = elements.last else # elements array is 0 indexed index -= 1 result = elements[index] end raise _no_such_element if result.nil? result end |
#ele_with_pred(opts) ⇒ Element
returns element matching predicate contained in the main app
predicate - the predicate to evaluate on the main app
visible - if true, only visible elements are returned. default true
604 605 606 607 |
# File 'lib/appium_lib/ios/helper.rb', line 604 def ele_with_pred(opts) # true = return only visible find_element(:uiautomation, _all_pred(opts)) end |
#eles_by_json(opts) ⇒ Object
For Appium(automation name), not XCUITest example usage:
eles_by_json({
typeArray: ["UIAStaticText"],
onlyVisible: true,
name: {
target: "Buttons, Various uses of UIButton",
substring: false,
insensitive: false,
},
})
724 725 726 727 |
# File 'lib/appium_lib/ios/helper.rb', line 724 def eles_by_json(opts) opts[:onlyFirst] = false _by_json opts end |
#eles_by_json_visible_contains(element, value) ⇒ Array<Element>
Find all elements containing value For Appium(automation name), not XCUITest
487 488 489 |
# File 'lib/appium_lib/ios/helper.rb', line 487 def eles_by_json_visible_contains(element, value) eles_by_json string_visible_contains element, value end |
#eles_by_json_visible_exact(element, value) ⇒ Element
Find all elements exactly matching value For Appium(automation name), not XCUITest
526 527 528 |
# File 'lib/appium_lib/ios/helper.rb', line 526 def eles_by_json_visible_exact(element, value) eles_by_json string_visible_exact element, value end |
#eles_with_pred(opts) ⇒ Array<Element>
returns elements matching predicate contained in the main app
predicate - the predicate to evaluate on the main app
visible - if true, only visible elements are returned. default true
615 616 617 |
# File 'lib/appium_lib/ios/helper.rb', line 615 def eles_with_pred(opts) find_elements(:uiautomation, _all_pred(opts)) end |
#empty(ele) ⇒ Object
58 59 60 |
# File 'lib/appium_lib/ios/helper.rb', line 58 def empty(ele) (ele['name'] || ele['label'] || ele['value']).nil? end |
#find(value) ⇒ Element
Find the first element containing value
6 7 8 9 10 11 12 |
# File 'lib/appium_lib/ios/element/generic.rb', line 6 def find(value) if automation_name_is_xcuitest? raise_error_if_no_element finds(value).first else ele_by_json_visible_contains '*', value end end |
#find_ele_by_attr(class_name, attr, value) ⇒ Element
Find the first element exactly matching class and attribute value. Note: Uses XPath Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.
248 249 250 |
# File 'lib/appium_lib/ios/helper.rb', line 248 def find_ele_by_attr(class_name, attr, value) @driver.find_element :xpath, string_attr_exact(class_name, attr, value) end |
#find_ele_by_attr_include(class_name, attr, value) ⇒ Element
Get the first tag by attribute that exactly matches value. Note: Uses XPath
307 308 309 |
# File 'lib/appium_lib/ios/helper.rb', line 307 def find_ele_by_attr_include(class_name, attr, value) @driver.find_element :xpath, string_attr_include(class_name, attr, value) end |
#find_ele_by_predicate(class_name: '*', value:) ⇒ Element
Find the first element exactly matching attribute case insensitive value. Note: Uses Predicate
280 281 282 283 284 |
# File 'lib/appium_lib/ios/helper.rb', line 280 def find_ele_by_predicate(class_name: '*', value:) elements = find_eles_by_predicate(class_name: class_name, value: value) raise _no_such_element if elements.empty? elements.first end |
#find_ele_by_predicate_include(class_name: '*', value:) ⇒ Element
Get the first elements that include insensitive value. Note: Uses Predicate
325 326 327 328 329 |
# File 'lib/appium_lib/ios/helper.rb', line 325 def find_ele_by_predicate_include(class_name: '*', value:) elements = find_eles_by_predicate_include(class_name: class_name, value: value) raise _no_such_element if elements.empty? elements.first end |
#find_eles_by_attr(class_name, attr, value) ⇒ Array<Element>
Find all elements exactly matching class and attribute value. Note: Uses XPath Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.
259 260 261 |
# File 'lib/appium_lib/ios/helper.rb', line 259 def find_eles_by_attr(class_name, attr, value) @driver.find_elements :xpath, string_attr_exact(class_name, attr, value) end |
#find_eles_by_attr_include(class_name, attr, value) ⇒ Array<Element>
Get tags by attribute that include value. Note: Uses XPath
317 318 319 |
# File 'lib/appium_lib/ios/helper.rb', line 317 def find_eles_by_attr_include(class_name, attr, value) @driver.find_elements :xpath, string_attr_include(class_name, attr, value) end |
#find_eles_by_predicate(class_name: '*', value:) ⇒ Array<Element>
Find all elements exactly matching attribute case insensitive value. Note: Uses Predicate
291 292 293 294 295 296 297 298 299 |
# File 'lib/appium_lib/ios/helper.rb', line 291 def find_eles_by_predicate(class_name: '*', value:) predicate = if class_name == '*' %(name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}") else %(type == "#{class_name}" && ) + %((name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}")) end @driver.find_elements :predicate, predicate end |
#find_eles_by_predicate_include(class_name: '*', value:) ⇒ Array<Element>
Get elements that include case insensitive value. Note: Uses Predicate
336 337 338 339 340 341 342 343 344 |
# File 'lib/appium_lib/ios/helper.rb', line 336 def find_eles_by_predicate_include(class_name: '*', value:) predicate = if class_name == '*' %(name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}") else %(type == "#{class_name}" && ) + %((name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) end @driver.find_elements :predicate, predicate end |
#find_exact(value) ⇒ Element
Find the first element exactly matching value
29 30 31 32 33 34 35 |
# File 'lib/appium_lib/ios/element/generic.rb', line 29 def find_exact(value) if automation_name_is_xcuitest? raise_error_if_no_element finds_exact(value).first else ele_by_json_visible_exact '*', value end end |
#finds(value) ⇒ Array<Element>
Find all elements containing value
17 18 19 20 21 22 23 24 |
# File 'lib/appium_lib/ios/element/generic.rb', line 17 def finds(value) if automation_name_is_xcuitest? elements = find_eles_by_predicate_include value: value select_visible_elements elements else eles_by_json_visible_contains '*', value end end |
#finds_exact(value) ⇒ Array<Element>
Find all elements exactly matching value
40 41 42 43 44 45 46 47 |
# File 'lib/appium_lib/ios/element/generic.rb', line 40 def finds_exact(value) if automation_name_is_xcuitest? elements = find_eles_by_predicate value: value select_visible_elements elements else eles_by_json_visible_exact '*', value end end |
#first_button ⇒ UIAButton|XCUIElementTypeButton
Find the first UIAButton|XCUIElementTypeButton.
44 45 46 |
# File 'lib/appium_lib/ios/element/button.rb', line 44 def first_ele end |
#first_ele(class_name) ⇒ Element
Get the first tag that matches class_name
349 350 351 |
# File 'lib/appium_lib/ios/helper.rb', line 349 def first_ele(class_name) ele_index class_name, 1 end |
#first_text ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText.
43 44 45 |
# File 'lib/appium_lib/ios/element/text.rb', line 43 def first_text first_ele static_text_class end |
#first_textfield ⇒ TextField
Find the first TextField.
100 101 102 103 104 105 106 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 100 def first_textfield if automation_name_is_xcuitest? _textfield_with_predicate else ele_by_json _textfield_visible end end |
#fix_space(s) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/appium_lib/ios/helper.rb', line 63 def fix_space(s) # if s is an int, we can't call .empty return nil if s.nil? || (s.respond_to?(:empty) && s.empty?) # ints don't respond to force encoding # ensure we're converting to a string unless s.respond_to? :force_encoding s_s = s.to_s return s_s.empty? ? nil : s_s end # char code 160 (name, label) vs 32 (value) will break comparison. # convert string to binary and remove 160. # \xC2\xA0 s = s.force_encoding('binary').gsub("\xC2\xA0".force_encoding('binary'), ' ') if s s.empty? ? nil : s.force_encoding('UTF-8') end |
#get_page(element = source_window(0), class_name = nil) ⇒ String
Returns a string of interesting elements. iOS only.
Defaults to inspecting the 1st windows source only. use get_page(get_source) for all window sources
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/appium_lib/ios/helper.rb', line 53 def get_page(element = source_window(0), class_name = nil) lazy_load_strings # populate @strings_xml class_name = class_name.to_s.downcase # @private def empty(ele) (ele['name'] || ele['label'] || ele['value']).nil? end # @private def fix_space(s) # if s is an int, we can't call .empty return nil if s.nil? || (s.respond_to?(:empty) && s.empty?) # ints don't respond to force encoding # ensure we're converting to a string unless s.respond_to? :force_encoding s_s = s.to_s return s_s.empty? ? nil : s_s end # char code 160 (name, label) vs 32 (value) will break comparison. # convert string to binary and remove 160. # \xC2\xA0 s = s.force_encoding('binary').gsub("\xC2\xA0".force_encoding('binary'), ' ') if s s.empty? ? nil : s.force_encoding('UTF-8') end unless empty(element) || element['visible'] == false name = fix_space element['name'] label = fix_space element['label'] value = fix_space element['value'] hint = fix_space element['hint'] visible = fix_space element['visible'] type = fix_space element['type'] # if class_name is set, mark non-matches as invisible visible = (type.downcase.include? class_namet).to_s if class_name if visible && visible == 'true' _print_attr(type, name, label, value, hint) # there may be many ids with the same value. # output all exact matches. attributes = [name, label, value, hint].select { |attr| !attr.nil? } partial = {} id_matches = @strings_xml.select do |key, val| next if val.nil? || val.empty? partial[key] = val if attributes.detect { |attr| attr.include?(val) } attributes.detect { |attr| val == attr } end # If there are no exact matches, display partial matches. id_matches = partial if id_matches.empty? unless id_matches.empty? match_str = '' max_len = id_matches.keys.max_by(&:length).length # [0] = key, [1] = val id_matches.each do |key, val| arrow_space = ' ' * (max_len - key.length).to_i match_str += ' ' * 7 + "#{key} #{arrow_space}=> #{val}\n" end puts " id: #{match_str.strip}\n" end end end children = element['children'] children.each { |c| get_page c, class_name } if children nil end |
#get_source ⇒ String
Returns XML string for the current page Same as driver.page_source
740 741 742 |
# File 'lib/appium_lib/ios/helper.rb', line 740 def get_source @driver.page_source end |
#hide_ios_keyboard(close_key = 'Done') ⇒ void
This method returns an undefined value.
For Appium(automation name), not XCUITest If there’s no keyboard, then do nothing. If there’s no close key, fallback to window tap. If close key is present then tap it.
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/appium_lib/ios/helper.rb', line 537 def hide_ios_keyboard(close_key = 'Done') # # TODO: there are many various ways to hide the keyboard that work in different # app specific circumstances. webview keyboard will require a window.tap for example. # # Find the top left corner of the keyboard and move up 10 pixels (origin.y - 10) # now swipe down until the end of the window - 10 pixels. # -10 to ensure we're not going outside the window bounds. # # Swiping inside the keyboard will not dismiss it. # # If the 'Done' key exists then that should be pressed to dismiss the keyboard # because swiping to dismiss works only if such key doesn't exist. # # Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28 # dismiss_keyboard = <<-JS.strip if (!au.mainApp().keyboard().isNil()) { var key = au.mainApp().keyboard().buttons()['#{close_key}'] if (key.isNil()) { var startY = au.mainApp().keyboard().rect().origin.y - 10; var endY = au.mainWindow().rect().size.height - 10; au.flickApp(0, startY, 0, endY); } else { key.tap(); } au.delay(1000); } JS ignore do # wait 5 seconds for a wild keyboard to appear. if the textfield is disabled # then setValue will work, however the keyboard will never display # because users are normally not allowed to type into it. wait_true(5) do execute_script '!au.mainApp().keyboard().isNil()' end # dismiss keyboard execute_script dismiss_keyboard end # wait 5 seconds for keyboard to go away. # if the keyboard isn't dismissed then wait_true will error. wait_true(5) do execute_script 'au.mainApp().keyboard().isNil()' end end |
#id(id) ⇒ Element
Find by id
193 194 195 |
# File 'lib/appium_lib/ios/helper.rb', line 193 def id(id) find_element(:id, id) end |
#ios_password(length = 1) ⇒ String
iOS only. On Android uiautomator always returns an empty string for EditText password.
Password character returned from value of UIASecureTextField
41 42 43 |
# File 'lib/appium_lib/ios/helper.rb', line 41 def ios_password(length = 1) 8226.chr('UTF-8') * length end |
#ios_version ⇒ Array<Integer>
Return the iOS version as an array of integers
199 200 201 202 203 204 205 206 |
# File 'lib/appium_lib/ios/helper.rb', line 199 def ios_version if automation_name_is_xcuitest? @driver.capabilities['platformVersion'] else ios_version = execute_script 'UIATarget.localTarget().systemVersion()' ios_version.split('.').map(&:to_i) end end |
#last_button ⇒ UIAButton|XCUIElementTypeButton
TODO: add documentation regarding previous element.
Previous UIAElement is differ from UIAButton|XCUIElementTypeButton. So, the results are different.
Find the last UIAButton|XCUIElementTypeButton.
52 53 54 |
# File 'lib/appium_lib/ios/element/button.rb', line 52 def last_ele end |
#last_ele(class_name) ⇒ Element
Get the last tag that matches class_name
356 357 358 359 360 361 362 363 364 |
# File 'lib/appium_lib/ios/helper.rb', line 356 def last_ele(class_name) if automation_name_is_xcuitest? visible_elements = class_name raise _no_such_element if visible_elements.empty? visible_elements.last else ele_index class_name, 'last()' end end |
#last_text ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the last UIAStaticText|XCUIElementTypeStaticText.
49 50 51 |
# File 'lib/appium_lib/ios/element/text.rb', line 49 def last_text last_ele static_text_class end |
#last_textfield ⇒ TextField
Find the last TextField.
110 111 112 113 114 115 116 117 118 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 110 def last_textfield result = if automation_name_is_xcuitest? _textfields_with_predicate.last else eles_by_json(_textfield_visible).last end raise _no_such_element if result.nil? result end |
#page(opts = {}) ⇒ void
This method returns an undefined value.
Prints a string of interesting elements to the console.
Example
“‘ruby page class: :UIAButton # filter on buttons page window: 1 # show source for window 1 page class: :UIAButton, window: 1 “`
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/appium_lib/ios/helper.rb', line 139 def page(opts = {}) if opts.is_a?(Hash) window_number = opts.fetch :window, -1 class_name = opts.fetch :class, nil else window_number = -1 class_name = opts end # current_context may be nil which breaks start_with if current_context && current_context.start_with?('WEBVIEW') s = get_source parser = @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Common::HTMLElements.new) parser.document.reset parser.document.filter = class_name parser.parse s parser.document.result else s = source_window(window_number || 0) parser = Nokogiri::XML::SAX::Parser.new(UITestElementsPrinter.new) if class_name parser.document.filter = class_name.is_a?(Symbol) ? class_name.to_s : class_name end parser.parse s nil end end |
#page_window(window_number = 0) ⇒ void
This method returns an undefined value.
Prints parsed page source to console.
example: page_window 0
185 186 187 188 |
# File 'lib/appium_lib/ios/helper.rb', line 185 def page_window(window_number = 0) get_page source_window window_number nil end |
#patch_webdriver_element ⇒ Object
class_eval inside a method because class Selenium::WebDriver::Element will trigger as soon as the file is required. in contrast a method will trigger only when invoked.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/appium_lib/ios/patch.rb', line 7 def patch_webdriver_element Selenium::WebDriver::Element.class_eval do # Enable access to iOS accessibility label # accessibility identifier is supported as 'name' def label attribute('label') end # Cross platform way of entering text into a textfield def type(text) if $driver.automation_name_is_xcuitest? send_keys text else $driver.execute_script %(au.getElement('#{ref}').setValue('#{text}');) end end # def type end # Selenium::WebDriver::Element.class_eval end |
#secure_text_field_class ⇒ String
Returns Class name for secure text field.
15 16 17 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 15 def secure_text_field_class automation_name_is_xcuitest? ? XCUIElementTypeSecureTextField : UIASecureTextField end |
#source ⇒ void
This method returns an undefined value.
Prints xml of the current page
621 622 623 |
# File 'lib/appium_lib/ios/helper.rb', line 621 def source _print_source get_source end |
#source_window(_window_number = 0) ⇒ JSON
Gets the JSON source of window number
170 171 172 173 174 175 176 177 |
# File 'lib/appium_lib/ios/helper.rb', line 170 def source_window(_window_number = 0) # TODO: update comments # appium 1.0 still returns JSON when getTree() is invoked so this # doesn't need to change to XML. If getTree() is removed then # source_window will need to parse the elements of getTreeForXML()\ # https://github.com/appium/appium-uiauto/blob/247eb71383fa1a087ff8f8fc96fac25025731f3f/uiauto/appium/element.js#L145 get_source end |
#static_text_class ⇒ String
Returns Class name for text.
8 9 10 |
# File 'lib/appium_lib/ios/element/text.rb', line 8 def static_text_class automation_name_is_xcuitest? ? XCUIElementTypeStaticText : UIAStaticText end |
#string_attr_exact(class_name, attr, value) ⇒ Object
229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/appium_lib/ios/helper.rb', line 229 def string_attr_exact(class_name, attr, value) if automation_name_is_xcuitest? if attr == '*' %((//#{class_name})[@*[.="#{value}"]]) else %((//#{class_name})[@#{attr}="#{value}"]) end else %(//#{class_name}[@visible="true" and @#{attr}="#{value}"]) end end |
#string_attr_include(class_name, attr, value) ⇒ Object
264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/appium_lib/ios/helper.rb', line 264 def string_attr_include(class_name, attr, value) if automation_name_is_xcuitest? if attr == '*' %((//#{class_name})[@*[contains(translate(., "#{value.upcase}", "#{value}"), "#{value}")]]) else %((//#{class_name})[contains(translate(@#{attr}, "#{value.upcase}", "#{value}"), "#{value}")]) end else %(//#{class_name}[@visible="true" and contains(translate(@#{attr},"#{value.upcase}", "#{value}"), "#{value}")]) end end |
#string_visible_contains(element, value) ⇒ String
Returns an object that matches the first element that contains value
example: ele_by_json_visible_contains ‘UIATextField’, ‘sign in’
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/appium_lib/ios/helper.rb', line 457 def string_visible_contains(element, value) contains = { target: value, substring: true, insensitive: true } { typeArray: [element], onlyVisible: true, name: contains, label: contains, value: contains } end |
#string_visible_exact(element, value) ⇒ String
Create an object to exactly match the first element with target value
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'lib/appium_lib/ios/helper.rb', line 496 def string_visible_exact(element, value) exact = { target: value, substring: false, insensitive: false } { typeArray: [element], onlyVisible: true, name: exact, label: exact, value: exact } end |
#tag(class_name) ⇒ Element
Returns the first visible element matching class_name
370 371 372 373 374 375 376 |
# File 'lib/appium_lib/ios/helper.rb', line 370 def tag(class_name) if automation_name_is_xcuitest? raise_error_if_no_element (class_name).first else ele_by_json(typeArray: [class_name], onlyVisible: true) end end |
#tags(class_name) ⇒ Element
Returns all visible elements matching class_name
382 383 384 385 386 387 388 389 |
# File 'lib/appium_lib/ios/helper.rb', line 382 def (class_name) if automation_name_is_xcuitest? elements = @driver.find_elements :class, class_name select_visible_elements elements else eles_by_json(typeArray: [class_name], onlyVisible: true) end end |
#tags_exact(class_names:, value: nil) ⇒ Array[Element]
Returns all visible elements matching class_names and value. This method calls find_element/s and element.value/text many times. So, if you set many class_names, this method’s performance become worse.
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/appium_lib/ios/helper.rb', line 427 def (class_names:, value: nil) return unless class_names.is_a? Array if automation_name_is_xcuitest? c_names = class_names.map { |class_name| %(type == "#{class_name}") }.join(' || ') predicate = if value %((#{c_names}) && ) + %((name ==[c] "#{value}" || label ==[c] "#{value}" || value ==[c] "#{value}")) else c_names end elements = @driver.find_elements :predicate, predicate select_visible_elements elements else class_names.flat_map do |class_name| value ? eles_by_json_visible_exact(class_name, value) : (class_name) end end end |
#tags_include(class_names:, value: nil) ⇒ Array[Element]
Returns all visible elements matching class_names and value This method calls find_element/s and element.value/text many times. So, if you set many class_names, this method’s performance become worse.
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/appium_lib/ios/helper.rb', line 398 def (class_names:, value: nil) return unless class_names.is_a? Array if automation_name_is_xcuitest? c_names = class_names.map { |class_name| %(type == "#{class_name}") }.join(' || ') predicate = if value %((#{c_names}) && ) + %((name contains[c] "#{value}" || label contains[c] "#{value}" || value contains[c] "#{value}")) else c_names end elements = @driver.find_elements :predicate, predicate select_visible_elements elements else class_names.flat_map do |class_name| value ? eles_by_json_visible_contains(class_name, value) : (class_name) end end end |
#text(value) ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText that contains value or by index. If int then the UIAStaticText|XCUIElementTypeStaticText at that index is returned.
16 17 18 19 20 21 22 23 24 |
# File 'lib/appium_lib/ios/element/text.rb', line 16 def text(value) return ele_index static_text_class, value if value.is_a? Numeric if automation_name_is_xcuitest? raise_error_if_no_element texts(value).first else ele_by_json_visible_contains static_text_class, value end end |
#text_exact(value) ⇒ UIAStaticText|XCUIElementTypeStaticText
Find the first UIAStaticText|XCUIElementTypeStaticText that exactly matches value.
56 57 58 59 60 61 62 |
# File 'lib/appium_lib/ios/element/text.rb', line 56 def text_exact(value) if automation_name_is_xcuitest? raise_error_if_no_element texts_exact(value).first else ele_by_json_visible_exact static_text_class, value end end |
#text_field_class ⇒ String
Returns Class name for text field.
10 11 12 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 10 def text_field_class automation_name_is_xcuitest? ? XCUIElementTypeTextField : UIATextField end |
#textfield(value) ⇒ TextField
Find the first TextField that contains value or by index. Note: Uses XPath If int then the TextField at that index is returned.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 60 def textfield(value) if value.is_a? Numeric index = value raise "#{index} is not a valid index. Must be >= 1" if index <= 0 index -= 1 # eles_by_json and _textfields_with_predicate is 0 indexed. result = if automation_name_is_xcuitest? _textfields_with_predicate[index] else eles_by_json(_textfield_visible)[index] end raise _no_such_element if result.nil? return result end if automation_name_is_xcuitest? raise_error_if_no_element textfields(value).first else ele_by_json _textfield_contains_string value end end |
#textfield_exact(value) ⇒ TextField
Find the first TextField that exactly matches value.
123 124 125 126 127 128 129 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 123 def textfield_exact(value) if automation_name_is_xcuitest? raise_error_if_no_element textfields_exact(value).first else ele_by_json _textfield_exact_string value end end |
#textfields(value = false) ⇒ Array<TextField>
Find all TextFields containing value. If value is omitted, all TextFields are returned.
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 86 def textfields(value = false) if automation_name_is_xcuitest? return (class_names: [text_field_class, secure_text_field_class]) unless value elements = class_names: [text_field_class, secure_text_field_class], value: value select_visible_elements elements else return eles_by_json _textfield_visible unless value eles_by_json _textfield_contains_string value end end |
#textfields_exact(value) ⇒ Array<TextField>
Find all TextFields that exactly match value.
134 135 136 137 138 139 140 141 |
# File 'lib/appium_lib/ios/element/textfield.rb', line 134 def textfields_exact(value) if automation_name_is_xcuitest? elements = class_names: [text_field_class, secure_text_field_class], value: value select_visible_elements elements else eles_by_json _textfield_exact_string value end end |
#texts(value = false) ⇒ Array<UIAStaticText|XCUIElementTypeStaticText>
Find all UIAStaticTexts|XCUIElementTypeStaticTexts containing value. If value is omitted, all UIAStaticTexts|XCUIElementTypeStaticTexts are returned
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/appium_lib/ios/element/text.rb', line 30 def texts(value = false) return static_text_class unless value if automation_name_is_xcuitest? elements = find_eles_by_predicate_include(class_name: static_text_class, value: value) select_visible_elements elements else eles_by_json_visible_contains static_text_class, value end end |
#texts_exact(value) ⇒ Array<UIAStaticText|XCUIElementTypeStaticText>
Find all UIAStaticTexts|XCUIElementTypeStaticTexts that exactly match value.
67 68 69 70 71 72 73 74 |
# File 'lib/appium_lib/ios/element/text.rb', line 67 def texts_exact(value) if automation_name_is_xcuitest? elements = find_eles_by_predicate(class_name: static_text_class, value: value) select_visible_elements elements else eles_by_json_visible_exact static_text_class, value end end |