Module: Appium::Ios

Defined in:
lib/appium_lib/ios/patch.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

Constant Summary collapse

UIAStaticText =
'UIAStaticText'
UIAButton =
'UIAButton'
UIATextField =
'UIATextField'
UIASecureTextField =
'UIASecureTextField'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(_mod) ⇒ Object



10
11
12
13
14
# File 'lib/appium_lib/ios/mobile_methods.rb', line 10

def extended(_mod)
  Selenium::WebDriver::SearchContext.class_eval do
    Selenium::WebDriver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation'
  end
end

.uiautomation_findObject

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()

“‘



10
11
12
13
14
# File 'lib/appium_lib/ios/mobile_methods.rb', line 10

def extended(_mod)
  Selenium::WebDriver::SearchContext.class_eval do
    Selenium::WebDriver::SearchContext::FINDERS[:uiautomation] = '-ios uiautomation'
  end
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



438
439
440
441
442
443
# File 'lib/appium_lib/ios/helper.rb', line 438

def _all_pred(opts)
  predicate = opts[:predicate]
  fail 'predicate must be provided' unless predicate
  visible = opts.fetch :visible, true
  %($.mainApp().getAllWithPredicate("#{predicate}", #{visible});)
end

#_by_json(opts) ⇒ Object

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,
}

}



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/appium_lib/ios/helper.rb', line 520

def _by_json(opts)
  valid_keys   = [:typeArray, :onlyFirst, :onlyVisible, :name, :label, :value]
  unknown_keys = opts.keys - valid_keys
  fail "Unknown keys: #{unknown_keys}" unless unknown_keys.empty?

  type_array = opts[:typeArray]
  fail 'typeArray must be an array' unless type_array.is_a? Array

  only_first = opts[:onlyFirst]
  fail 'onlyFirst must be a boolean' unless [true, false].include? only_first

  only_visible = opts[:onlyVisible]
  fail '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 : fail(Selenium::Client::CommandError, 'mainWindow is nil')
end

#_validate_object(*objects) ⇒ Object



472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'lib/appium_lib/ios/helper.rb', line 472

def _validate_object(*objects)
  fail '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
    fail "Unknown keys: #{unknown_keys}" unless unknown_keys.empty?

    target = obj[:target]
    fail 'target must be a string' unless target.is_a? String

    substring = obj[:substring]
    fail 'substring must be a boolean' unless [true, false].include? substring

    insensitive = obj[:insensitive]
    fail 'insensitive must be a boolean' unless [true, false].include? insensitive
  end
end

#alert_acceptvoid

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 getAlertText so use bridge directly
  driver.send(:bridge).acceptAlert
end

#alert_dismissvoid

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 getAlertText so use bridge directly
  driver.send(:bridge).dismissAlert
end

#button(value) ⇒ UIAButton

Find the first UIAButton that contains value or by index. If int then the UIAButton at that index is returned.

Parameters:

  • value (String, Integer)

    the value to exactly match.

Returns:



10
11
12
13
14
# File 'lib/appium_lib/ios/element/button.rb', line 10

def button(value)
  # return button at index.
  return ele_index UIAButton, value if value.is_a? Numeric
  ele_by_json_visible_contains UIAButton, value
end

#button_exact(value) ⇒ UIAButton

Find the first UIAButton that exactly matches value.

Parameters:

  • value (String)

    the value to match exactly

Returns:



40
41
42
# File 'lib/appium_lib/ios/element/button.rb', line 40

def button_exact(value)
  ele_by_json_visible_exact UIAButton, value
end

#buttons(value = false) ⇒ Array<UIAButton>

Find all UIAButtons containing value. If value is omitted, all UIAButtons are returned.

Parameters:

  • value (String) (defaults to: false)

    the value to search for

Returns:



20
21
22
23
# File 'lib/appium_lib/ios/element/button.rb', line 20

def buttons(value = false)
  return tags UIAButton unless value
  eles_by_json_visible_contains UIAButton, value
end

#buttons_exact(value) ⇒ Array<UIAButton>

Find all UIAButtons that exactly match value.

Parameters:

  • value (String)

    the value to match exactly

Returns:



47
48
49
# File 'lib/appium_lib/ios/element/button.rb', line 47

def buttons_exact(value)
  eles_by_json_visible_exact UIAButton, value
end

#ele_by_json(opts) ⇒ Object

see eles_by_json



575
576
577
578
579
580
# File 'lib/appium_lib/ios/helper.rb', line 575

def ele_by_json(opts)
  opts[:onlyFirst] = true
  result           = _by_json(opts).first
  fail _no_such_element if result.nil?
  result
end

#ele_by_json_visible_contains(element, value) ⇒ Element

Find the first element that contains value

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (Element)


329
330
331
# File 'lib/appium_lib/ios/helper.rb', line 329

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

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (Element)


366
367
368
# File 'lib/appium_lib/ios/helper.rb', line 366

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.

Parameters:

  • class_name (String)

    the class name to find

  • index (Integer)

    the index

Returns:

  • (Element)


198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/appium_lib/ios/helper.rb', line 198

def ele_index(class_name, index)
  fail 'Index must be >= 1' unless index == 'last()' || (index.is_a?(Integer) && index >= 1)
  elements = tags(class_name)

  if index == 'last()'
    result = elements.last
  else
    # elements array is 0 indexed
    index -= 1
    result = elements[index]
  end

  fail _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

Returns:

  • (Element)


451
452
453
454
# File 'lib/appium_lib/ios/helper.rb', line 451

def ele_with_pred(opts)
  # true = return only visible
  find_element(:uiautomation, _all_pred(opts))
end

#eles_by_json(opts) ⇒ Object

example usage:

eles_by_json({

typeArray: ["UIAStaticText"],
onlyVisible: true,
name: {
  target: "Buttons, Various uses of UIButton",
  substring: false,
  insensitive: false,
},

})



569
570
571
572
# File 'lib/appium_lib/ios/helper.rb', line 569

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

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (Array<Element>)


337
338
339
# File 'lib/appium_lib/ios/helper.rb', line 337

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

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (Element)


374
375
376
# File 'lib/appium_lib/ios/helper.rb', line 374

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

Returns:

  • (Array<Element>)


462
463
464
# File 'lib/appium_lib/ios/helper.rb', line 462

def eles_with_pred(opts)
  find_elements(:uiautomation, _all_pred(opts))
end

#empty(ele) ⇒ Object



25
26
27
# File 'lib/appium_lib/ios/helper.rb', line 25

def empty(ele)
  (ele['name'] || ele['label'] || ele['value']).nil?
end

#find(value) ⇒ Element

Find the first element containing value

Parameters:

  • value (String)

    the value to search for

Returns:

  • (Element)


6
7
8
# File 'lib/appium_lib/ios/element/generic.rb', line 6

def find(value)
  ele_by_json_visible_contains '*', value
end

#find_ele_by_attr(class_name, attr, value) ⇒ Element

Find the first element exactly matching class and attribute value. Note: Uses XPath

Parameters:

  • class_name (String)

    the class name to search for

  • attr (String)

    the attribute to inspect

  • value (String)

    the expected value of the attribute

Returns:

  • (Element)


225
226
227
# File 'lib/appium_lib/ios/helper.rb', line 225

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

Parameters:

  • class_name (String)

    the tag name to match

  • attr (String)

    the attribute to compare

  • value (String)

    the value of the attribute that the element must include

Returns:

  • (Element)

    the element of type tag who’s attribute includes value



250
251
252
# File 'lib/appium_lib/ios/helper.rb', line 250

def find_ele_by_attr_include(class_name, attr, value)
  @driver.find_element :xpath, string_attr_include(class_name, attr, value)
end

#find_eles_by_attr(class_name, attr, value) ⇒ Array<Element>

Find all elements exactly matching class and attribute value. Note: Uses XPath

Parameters:

  • class_name (String)

    the class name to match

  • attr (String)

    the attribute to compare

  • value (String)

    the value of the attribute that the element must have

Returns:

  • (Array<Element>)


235
236
237
# File 'lib/appium_lib/ios/helper.rb', line 235

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

Parameters:

  • class_name (String)

    the tag name to match

  • attr (String)

    the attribute to compare

  • value (String)

    the value of the attribute that the element must include

Returns:

  • (Array<Element>)

    the elements of type tag who’s attribute includes value



260
261
262
# File 'lib/appium_lib/ios/helper.rb', line 260

def find_eles_by_attr_include(class_name, attr, value)
  @driver.find_elements :xpath, string_attr_include(class_name, attr, value)
end

#find_exact(value) ⇒ Element

Find the first element exactly matching value

Parameters:

  • value (String)

    the value to search for

Returns:

  • (Element)


20
21
22
# File 'lib/appium_lib/ios/element/generic.rb', line 20

def find_exact(value)
  ele_by_json_visible_exact '*', value
end

#finds(value) ⇒ Array<Element>

Find all elements containing value

Parameters:

  • value (String)

    the value to search for

Returns:

  • (Array<Element>)


13
14
15
# File 'lib/appium_lib/ios/element/generic.rb', line 13

def finds(value)
  eles_by_json_visible_contains '*', value
end

#finds_exact(value) ⇒ Array<Element>

Find all elements exactly matching value

Parameters:

  • value (String)

    the value to search for

Returns:

  • (Array<Element>)


27
28
29
# File 'lib/appium_lib/ios/element/generic.rb', line 27

def finds_exact(value)
  eles_by_json_visible_exact '*', value
end

#first_buttonUIAButton

Find the first UIAButton.

Returns:



27
28
29
# File 'lib/appium_lib/ios/element/button.rb', line 27

def first_button
  first_ele UIAButton
end

#first_ele(class_name) ⇒ Element

Get the first tag that matches class_name

Parameters:

  • class_name (String)

    the tag to match

Returns:

  • (Element)


267
268
269
270
# File 'lib/appium_lib/ios/helper.rb', line 267

def first_ele(class_name)
  # XPath index starts at 1
  ele_index class_name, 1
end

#first_textUIAStaticText

Find the first UIAStaticText.

Returns:



26
27
28
# File 'lib/appium_lib/ios/element/text.rb', line 26

def first_text
  first_ele UIAStaticText
end

#first_textfieldTextField

Find the first TextField.

Returns:

  • (TextField)


79
80
81
# File 'lib/appium_lib/ios/element/textfield.rb', line 79

def first_textfield
  ele_by_json _textfield_visible
end

#fix_space(s) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/appium_lib/ios/helper.rb', line 30

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

Parameters:

  • element (Hash) (defaults to: source_window(0))

    a customizable set of options

  • class_name (Hash) (defaults to: nil)

    a customizable set of options

Options Hash (element):

  • the (Object)

    element to search. omit to search everything

Options Hash (class_name):

  • the (String, Symbol)

    class name to filter on. case insensitive include match.

Returns:

  • (String)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
# File 'lib/appium_lib/ios/helper.rb', line 20

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']

    # TODO: Rubocop warning cleanup
    # rubocop:disable Metrics/BlockNesting

    # if class_name is set, mark non-matches as invisible
    visible = (type.downcase.include?(class_name)).to_s if class_name
    if visible && visible == 'true'
      if name == label && name == value
        puts "#{type}" if name || label || value || hint
        puts "   name, label, value: #{name}" if name
        puts "   hint: #{hint}" if hint
      elsif name == label
        puts "#{type}" if name || label || value || hint
        puts "   name, label: #{name}" if name
        puts "   value: #{value}" if value
        puts "   hint: #{hint}" if hint
      elsif name == value
        puts "#{type}" if name || label || value || hint
        puts "   name, value: #{name}" if name
        puts "  label: #{label}" if label
        puts "   hint: #{hint}" if hint
      else
        puts "#{type}" if name || label || value || hint
        puts "   name: #{name}" if name
        puts "  label: #{label}" if label
        puts "  value: #{value}" if value
        puts "   hint: #{hint}" if hint
      end
      # rubocop:enable Metrics/BlockNesting

      # 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_sourceString

Returns XML string for the current page Same as driver.page_source

Returns:

  • (String)


585
586
587
# File 'lib/appium_lib/ios/helper.rb', line 585

def get_source
  @driver.page_source
end

#hide_ios_keyboard(close_key = 'Done') ⇒ void

This method returns an undefined value.

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.

Parameters:

  • close_key (String) (defaults to: 'Done')

    close key to tap. Default value is ‘Done’



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/appium_lib/ios/helper.rb', line 384

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

Parameters:

  • id (String)

    the id to search for

Returns:

  • (Element)


183
184
185
# File 'lib/appium_lib/ios/helper.rb', line 183

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

Parameters:

  • length (Integer) (defaults to: 1)

    the length of the password to generate

Returns:

  • (String)

    the returned string is of size length



8
9
10
# File 'lib/appium_lib/ios/helper.rb', line 8

def ios_password(length = 1)
  8226.chr('UTF-8') * length
end

#ios_versionArray<Integer>

Return the iOS version as an array of integers

Returns:

  • (Array<Integer>)


189
190
191
192
# File 'lib/appium_lib/ios/helper.rb', line 189

def ios_version
  ios_version = execute_script 'UIATarget.localTarget().systemVersion()'
  ios_version.split('.').map(&:to_i)
end

#last_buttonUIAButton

Find the last UIAButton.

Returns:



33
34
35
# File 'lib/appium_lib/ios/element/button.rb', line 33

def last_button
  last_ele UIAButton
end

#last_ele(class_name) ⇒ Element

Get the last tag that matches class_name

Parameters:

  • class_name (String)

    the tag to match

Returns:

  • (Element)


275
276
277
# File 'lib/appium_lib/ios/helper.rb', line 275

def last_ele(class_name)
  ele_index class_name, 'last()'
end

#last_textUIAStaticText

Find the last UIAStaticText.

Returns:



32
33
34
# File 'lib/appium_lib/ios/element/text.rb', line 32

def last_text
  last_ele UIAStaticText
end

#last_textfieldTextField

Find the last TextField.

Returns:

  • (TextField)


85
86
87
88
89
# File 'lib/appium_lib/ios/element/textfield.rb', line 85

def last_textfield
  result = eles_by_json(_textfield_visible).last
  fail _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 “`

Parameters:

  • window (Hash)

    a customizable set of options

  • class (Hash)

    a customizable set of options



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/appium_lib/ios/helper.rb', line 129

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
    if window_number == -1
      # if the 0th window has no children, find the next window that does.
      target_window = source_window 0
      target_window = source_window 1 if target_window['children'].empty?
      get_page target_window, class_name
    else
      get_page source_window(window_number || 0), class_name
    end
    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

Parameters:

  • window_number (Integer) (defaults to: 0)

    the int index of the target window



175
176
177
178
# File 'lib/appium_lib/ios/helper.rb', line 175

def page_window(window_number = 0)
  get_page source_window window_number
  nil
end

#patch_webdriver_elementObject

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
# 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)
      # type
      $driver.execute_script %(au.getElement('#{ref}').setValue('#{text}');)
    end # def type
  end # Selenium::WebDriver::Element.class_eval
end

#sourcevoid

This method returns an undefined value.

Prints xml of the current page



468
469
470
# File 'lib/appium_lib/ios/helper.rb', line 468

def source
  _print_source get_source
end

#source_window(window_number = 0) ⇒ JSON

Gets the JSON source of window number

Parameters:

  • window_number (Integer) (defaults to: 0)

    the int index of the target window

Returns:

  • (JSON)


161
162
163
164
165
166
167
# File 'lib/appium_lib/ios/helper.rb', line 161

def source_window(window_number = 0)
  # 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
  execute_script "UIATarget.localTarget().frontMostApp().windows()[#{window_number}].getTree()"
end

#string_attr_exact(class_name, attr, value) ⇒ Object



215
216
217
# File 'lib/appium_lib/ios/helper.rb', line 215

def string_attr_exact(class_name, attr, value)
  %(//#{class_name}[@visible="true" and @#{attr}='#{value}'])
end

#string_attr_include(class_name, attr, value) ⇒ Object



240
241
242
# File 'lib/appium_lib/ios/helper.rb', line 240

def string_attr_include(class_name, attr, value)
  %(//#{class_name}[@visible="true" and contains(translate(@#{attr},'#{value.upcase}', '#{value}'), '#{value}')])
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’

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (String)


309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/appium_lib/ios/helper.rb', line 309

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

Parameters:

  • element (String)

    the class name for the element

  • value (String)

    the value to search for

Returns:

  • (String)


346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/appium_lib/ios/helper.rb', line 346

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

Parameters:

  • class_name (String)

    the class_name to search for

Returns:

  • (Element)


283
284
285
286
287
288
# File 'lib/appium_lib/ios/helper.rb', line 283

def tag(class_name)
  ele_by_json(
    typeArray:   [class_name],
    onlyVisible: true
  )
end

#tags(class_name) ⇒ Element

Returns all visible elements matching class_name

Parameters:

  • class_name (String)

    the class_name to search for

Returns:

  • (Element)


294
295
296
297
298
299
# File 'lib/appium_lib/ios/helper.rb', line 294

def tags(class_name)
  eles_by_json(
    typeArray:   [class_name],
    onlyVisible: true
  )
end

#text(value) ⇒ UIAStaticText

Find the first UIAStaticText that contains value or by index. If int then the UIAStaticText at that index is returned.

Parameters:

  • value (String, Integer)

    the value to find.

Returns:



10
11
12
13
# File 'lib/appium_lib/ios/element/text.rb', line 10

def text(value)
  return ele_index UIAStaticText, value if value.is_a? Numeric
  ele_by_json_visible_contains UIAStaticText, value
end

#text_exact(value) ⇒ UIAStaticText

Find the first UIAStaticText that exactly matches value.

Parameters:

  • value (String)

    the value to match exactly

Returns:



39
40
41
# File 'lib/appium_lib/ios/element/text.rb', line 39

def text_exact(value)
  ele_by_json_visible_exact UIAStaticText, value
end

#textfield(value) ⇒ TextField

Find the first TextField that contains value or by index. If int then the TextField at that index is returned.

Parameters:

  • value (String, Integer)

    the text to match exactly.

Returns:

  • (TextField)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/appium_lib/ios/element/textfield.rb', line 52

def textfield(value)
  # Don't use ele_index because that only works on one element type.
  # iOS needs to combine textfield and secure to match Android.
  if value.is_a? Numeric
    index = value
    fail "#{index} is not a valid index. Must be >= 1" if index <= 0
    index -= 1 # eles_by_json is 0 indexed.

    result = eles_by_json(_textfield_visible)[index]
    fail _no_such_element if result.nil?
    return result
  end

  ele_by_json _textfield_contains_string value
end

#textfield_exact(value) ⇒ TextField

Find the first TextField that exactly matches value.

Parameters:

  • value (String)

    the value to match exactly

Returns:

  • (TextField)


94
95
96
# File 'lib/appium_lib/ios/element/textfield.rb', line 94

def textfield_exact(value)
  ele_by_json _textfield_exact_string value
end

#textfields(value = false) ⇒ Array<TextField>

Find all TextFields containing value. If value is omitted, all TextFields are returned.

Parameters:

  • value (String) (defaults to: false)

    the value to search for

Returns:

  • (Array<TextField>)


72
73
74
75
# File 'lib/appium_lib/ios/element/textfield.rb', line 72

def textfields(value = false)
  return eles_by_json _textfield_visible unless value
  eles_by_json _textfield_contains_string value
end

#textfields_exact(value) ⇒ Array<TextField>

Find all TextFields that exactly match value.

Parameters:

  • value (String)

    the value to match exactly

Returns:

  • (Array<TextField>)


101
102
103
# File 'lib/appium_lib/ios/element/textfield.rb', line 101

def textfields_exact(value)
  eles_by_json _textfield_exact_string value
end

#texts(value = false) ⇒ Array<UIAStaticText>

Find all UIAStaticText containing value. If value is omitted, all UIAStaticTexts are returned

Parameters:

  • value (String) (defaults to: false)

    the value to search for

Returns:



19
20
21
22
# File 'lib/appium_lib/ios/element/text.rb', line 19

def texts(value = false)
  return tags UIAStaticText unless value
  eles_by_json_visible_contains UIAStaticText, value
end

#texts_exact(value) ⇒ Array<UIAStaticText>

Find all UIAStaticTexts that exactly match value.

Parameters:

  • value (String)

    the value to match exactly

Returns:



46
47
48
# File 'lib/appium_lib/ios/element/text.rb', line 46

def texts_exact(value)
  eles_by_json_visible_exact UIAStaticText, value
end