appium_lib 0.24.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +17 -8
  3. data/android_tests/Gemfile +1 -0
  4. data/android_tests/LICENSE-2.0.txt +202 -0
  5. data/android_tests/Rakefile +61 -0
  6. data/android_tests/api.apk +0 -0
  7. data/android_tests/appium.txt +3 -0
  8. data/android_tests/flaky.txt +1 -0
  9. data/android_tests/lib/android/specs/android/dynamic.rb +5 -0
  10. data/android_tests/lib/android/specs/android/element/alert.rb +41 -0
  11. data/android_tests/lib/android/specs/android/element/button.rb +55 -0
  12. data/android_tests/lib/android/specs/android/element/generic.rb +48 -0
  13. data/android_tests/lib/android/specs/android/element/text.rb +39 -0
  14. data/android_tests/lib/android/specs/android/element/textfield.rb +60 -0
  15. data/android_tests/lib/android/specs/android/helper.rb +80 -0
  16. data/android_tests/lib/android/specs/android/patch.rb +14 -0
  17. data/android_tests/lib/android/specs/common/device.rb +117 -0
  18. data/android_tests/lib/android/specs/common/element/window.rb +9 -0
  19. data/android_tests/lib/android/specs/common/helper.rb +112 -0
  20. data/android_tests/lib/android/specs/common/patch.rb +69 -0
  21. data/android_tests/lib/android/specs/common/version.rb +9 -0
  22. data/android_tests/lib/android/specs/driver.rb +174 -0
  23. data/android_tests/lib/format.rb +49 -0
  24. data/android_tests/lib/run.rb +72 -0
  25. data/android_tests/readme.md +27 -0
  26. data/appium_lib.gemspec +8 -5
  27. data/docs/android_docs.md +1052 -716
  28. data/docs/ios_docs.md +657 -834
  29. data/docs_gen/make_docs.rb +1 -3
  30. data/ios_tests/Gemfile +1 -0
  31. data/ios_tests/LICENSE-2.0.txt +202 -0
  32. data/ios_tests/Rakefile +47 -0
  33. data/ios_tests/UICatalog.app.zip +0 -0
  34. data/ios_tests/UICatalog.app/12-6AM.png +0 -0
  35. data/ios_tests/UICatalog.app/12-6PM.png +0 -0
  36. data/ios_tests/UICatalog.app/6-12AM.png +0 -0
  37. data/ios_tests/UICatalog.app/6-12PM.png +0 -0
  38. data/ios_tests/UICatalog.app/Default-568h@2x.png +0 -0
  39. data/ios_tests/UICatalog.app/Default@2x.png +0 -0
  40. data/ios_tests/UICatalog.app/Info.plist +0 -0
  41. data/ios_tests/UICatalog.app/PkgInfo +1 -0
  42. data/ios_tests/UICatalog.app/UIButton_custom.png +0 -0
  43. data/ios_tests/UICatalog.app/UICatalog +0 -0
  44. data/ios_tests/UICatalog.app/blueButton.png +0 -0
  45. data/ios_tests/UICatalog.app/bookmarkImage.png +0 -0
  46. data/ios_tests/UICatalog.app/bookmarkImageHighlighted.png +0 -0
  47. data/ios_tests/UICatalog.app/divider.png +0 -0
  48. data/ios_tests/UICatalog.app/en.lproj/AlertsViewController.nib +0 -0
  49. data/ios_tests/UICatalog.app/en.lproj/ButtonsViewController.nib +0 -0
  50. data/ios_tests/UICatalog.app/en.lproj/ControlsViewController.nib +0 -0
  51. data/ios_tests/UICatalog.app/en.lproj/ImagesViewController.nib +0 -0
  52. data/ios_tests/UICatalog.app/en.lproj/Localizable.strings +0 -0
  53. data/ios_tests/UICatalog.app/en.lproj/MainWindow.nib +0 -0
  54. data/ios_tests/UICatalog.app/en.lproj/PickerViewController.nib +0 -0
  55. data/ios_tests/UICatalog.app/en.lproj/SearchBarController.nib +0 -0
  56. data/ios_tests/UICatalog.app/en.lproj/SegmentViewController.nib +0 -0
  57. data/ios_tests/UICatalog.app/en.lproj/TextFieldController.nib +0 -0
  58. data/ios_tests/UICatalog.app/en.lproj/TextViewController.nib +0 -0
  59. data/ios_tests/UICatalog.app/en.lproj/ToolbarViewController.nib +0 -0
  60. data/ios_tests/UICatalog.app/en.lproj/TransitionViewController.nib +0 -0
  61. data/ios_tests/UICatalog.app/en.lproj/WebViewController.nib +0 -0
  62. data/ios_tests/UICatalog.app/orangeslide.png +0 -0
  63. data/ios_tests/UICatalog.app/scene1.jpg +0 -0
  64. data/ios_tests/UICatalog.app/scene2.jpg +0 -0
  65. data/ios_tests/UICatalog.app/scene3.jpg +0 -0
  66. data/ios_tests/UICatalog.app/scene4.jpg +0 -0
  67. data/ios_tests/UICatalog.app/scene5.jpg +0 -0
  68. data/ios_tests/UICatalog.app/searchBarBackground.png +0 -0
  69. data/ios_tests/UICatalog.app/segment_check.png +0 -0
  70. data/ios_tests/UICatalog.app/segment_search.png +0 -0
  71. data/ios_tests/UICatalog.app/segment_tools.png +0 -0
  72. data/ios_tests/UICatalog.app/segmentedBackground.png +0 -0
  73. data/ios_tests/UICatalog.app/slider_ball.png +0 -0
  74. data/ios_tests/UICatalog.app/toolbarBackground.png +0 -0
  75. data/ios_tests/UICatalog.app/whiteButton.png +0 -0
  76. data/ios_tests/UICatalog.app/yellowslide.png +0 -0
  77. data/ios_tests/appium.txt +3 -0
  78. data/ios_tests/flaky.txt +1 -0
  79. data/ios_tests/lib/format.rb +25 -0
  80. data/ios_tests/lib/ios/specs/common/element/window.rb +15 -0
  81. data/ios_tests/lib/ios/specs/common/helper.rb +204 -0
  82. data/ios_tests/lib/ios/specs/common/patch.rb +50 -0
  83. data/ios_tests/lib/ios/specs/common/version.rb +17 -0
  84. data/ios_tests/lib/ios/specs/device/device.rb +82 -0
  85. data/ios_tests/lib/ios/specs/device/multi_touch.rb +12 -0
  86. data/ios_tests/lib/ios/specs/device/touch_actions.rb +15 -0
  87. data/ios_tests/lib/ios/specs/driver.rb +203 -0
  88. data/ios_tests/lib/ios/specs/ios/element/alert.rb +48 -0
  89. data/ios_tests/lib/ios/specs/ios/element/button.rb +58 -0
  90. data/ios_tests/lib/ios/specs/ios/element/generic.rb +35 -0
  91. data/ios_tests/lib/ios/specs/ios/element/text.rb +54 -0
  92. data/ios_tests/lib/ios/specs/ios/element/textfield.rb +123 -0
  93. data/ios_tests/lib/ios/specs/ios/helper.rb +27 -0
  94. data/ios_tests/lib/ios/specs/ios/patch.rb +30 -0
  95. data/ios_tests/lib/run.rb +106 -0
  96. data/ios_tests/readme.md +30 -0
  97. data/ios_tests/upload/sauce_storage.rb +64 -0
  98. data/ios_tests/upload/upload.rb +6 -0
  99. data/lib/appium_lib.rb +4 -14
  100. data/lib/appium_lib/android/dynamic.rb +30 -32
  101. data/lib/appium_lib/android/element/alert.rb +34 -33
  102. data/lib/appium_lib/android/element/button.rb +91 -0
  103. data/lib/appium_lib/android/element/generic.rb +51 -146
  104. data/lib/appium_lib/android/element/text.rb +54 -0
  105. data/lib/appium_lib/android/element/textfield.rb +46 -41
  106. data/lib/appium_lib/android/helper.rb +248 -417
  107. data/lib/appium_lib/android/mobile_methods.rb +17 -0
  108. data/lib/appium_lib/android/patch.rb +9 -8
  109. data/lib/appium_lib/awesome_print/ostruct.rb +33 -0
  110. data/lib/appium_lib/common/element/window.rb +9 -8
  111. data/lib/appium_lib/common/helper.rb +182 -243
  112. data/lib/appium_lib/common/patch.rb +65 -79
  113. data/lib/appium_lib/common/version.rb +2 -3
  114. data/lib/appium_lib/device/device.rb +339 -0
  115. data/lib/appium_lib/device/multi_touch.rb +94 -0
  116. data/lib/appium_lib/device/touch_actions.rb +142 -0
  117. data/lib/appium_lib/driver.rb +217 -306
  118. data/lib/appium_lib/ios/element/alert.rb +16 -92
  119. data/lib/appium_lib/ios/element/button.rb +55 -0
  120. data/lib/appium_lib/ios/element/generic.rb +27 -160
  121. data/lib/appium_lib/ios/element/text.rb +54 -0
  122. data/lib/appium_lib/ios/element/textfield.rb +78 -65
  123. data/lib/appium_lib/ios/helper.rb +300 -190
  124. data/lib/appium_lib/ios/mobile_methods.rb +17 -0
  125. data/lib/appium_lib/ios/patch.rb +55 -41
  126. data/lib/appium_lib/logger.rb +13 -0
  127. data/lib/appium_lib/rails/duplicable.rb +116 -0
  128. data/readme.md +6 -1
  129. data/release_notes.md +118 -0
  130. metadata +170 -12
  131. data/lib/appium_lib/common/element/button.rb +0 -83
  132. data/lib/appium_lib/common/element/text.rb +0 -61
@@ -0,0 +1,17 @@
1
+ module Appium
2
+ module Android
3
+ class << self
4
+ # @!method uiautomator_find
5
+ # find_element/s can be used with a [UISelector](http://developer.android.com/tools/help/uiautomator/UiSelector.html).
6
+ #
7
+ # ```ruby
8
+ # find_elements :uiautomator, 'new UiSelector().clickable(true)'
9
+ # ```
10
+ def extended(mod)
11
+ Selenium::WebDriver::SearchContext.class_eval do
12
+ Selenium::WebDriver::SearchContext::FINDERS[:uiautomator] = '-android uiautomator'
13
+ end
14
+ end
15
+ end # class << self
16
+ end # module Android
17
+ end # module Appium
@@ -1,10 +1,10 @@
1
- # encoding: utf-8
2
- module Appium::Android
3
- # @private
4
- # class_eval inside a method because class Selenium::WebDriver::Element
5
- # will trigger as soon as the file is required. in contrast a method
6
- # will trigger only when invoked.
7
- def patch_webdriver_element
1
+ module Appium
2
+ module Android
3
+ # @private
4
+ # class_eval inside a method because class Selenium::WebDriver::Element
5
+ # will trigger as soon as the file is required. in contrast a method
6
+ # will trigger only when invoked.
7
+ def patch_webdriver_element
8
8
  Selenium::WebDriver::Element.class_eval do
9
9
  # Cross platform way of entering text into a textfield
10
10
  def type text
@@ -12,4 +12,5 @@ module Appium::Android
12
12
  end
13
13
  end
14
14
  end
15
- end
15
+ end # Android
16
+ end # Appium
@@ -0,0 +1,33 @@
1
+ # Enable OpenStruct support in awesome print
2
+ # Code from @marshallshen https://github.com/michaeldv/awesome_print/pull/145
3
+ #
4
+ # Copyright (c) 2010-2013 Michael Dvorkin
5
+ #
6
+ # Awesome Print is freely distributable under the terms of MIT license.
7
+ # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
8
+ #------------------------------------------------------------------------------
9
+
10
+ if defined?(OpenStruct)
11
+ module AwesomePrint
12
+ module OpenStruct
13
+ def self.included(base)
14
+ base.send :alias_method, :cast_without_ostruct, :cast
15
+ base.send :alias_method, :cast, :cast_with_ostruct
16
+ end
17
+
18
+ def cast_with_ostruct(object, type)
19
+ cast = cast_without_ostruct(object, type)
20
+ if (defined?(::OpenStruct)) && (object.is_a?(::OpenStruct))
21
+ cast = :open_struct_instance
22
+ end
23
+ cast
24
+ end
25
+
26
+ def awesome_open_struct_instance(object)
27
+ "#{object.class} #{awesome_hash(object.marshal_dump)}"
28
+ end
29
+ end # module OpenStruct
30
+ end # module AwesomePrint
31
+
32
+ AwesomePrint::Formatter.send(:include, AwesomePrint::OpenStruct)
33
+ end
@@ -1,9 +1,10 @@
1
- # encoding: utf-8
2
1
  # UIAWindow methods
3
- module Appium::Common
4
- # Get the window's size
5
- def window_size
6
- return nil if @driver.nil?
7
- @driver.manage.window.size
8
- end
9
- end # module Appium::Common
2
+ module Appium
3
+ module Common
4
+ # Get the window's size
5
+ def window_size
6
+ return nil if @driver.nil?
7
+ @driver.manage.window.size
8
+ end
9
+ end # module Common
10
+ end # module Appium
@@ -1,271 +1,210 @@
1
- # encoding: utf-8
2
1
  # Generic helper methods not specific
3
2
  # to a particular tag name
4
- module Appium::Common
5
- # json and ap are required for the source method.
6
- require 'json'
7
- require 'ap' # awesome print
8
- require 'timeout' # for wait
9
-
10
- # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
11
- # Android .name returns the accessibility attribute and nothing if it's not set.
12
- #
13
- # .text should be cross platform so prefer that over name, unless both
14
- # Android and iOS have proper accessibility attributes.
15
- # .text and .value should be the same so use .text over .value.
16
- #
17
- # secure tag_name is iOS only because it can't be implemented using uiautomator for Android.
18
- #
19
- # find_element :text doesn't work so use XPath to find by text.
20
-
21
- # Check every 0.5 seconds to see if block.call doesn't raise an exception.
22
- # if .call raises an exception then it will be tried again.
23
- # if .call doesn't raise an exception then it will stop waiting.
24
- #
25
- # Example: wait { name('back').click }
26
- #
27
- # Give up after 30 seconds.
28
- # @param max_wait [Integer] the maximum time in seconds to wait for.
29
- # Note that max wait 0 means infinity.
30
- # @param interval [Float] the time in seconds to wait after calling the block
31
- # @param block [Block] the block to call
32
- # @return [Object] the result of block.call
33
- def wait max_wait=30, interval=0.5, &block
34
- max_wait = 1 if max_wait <= 0
35
- result = nil
36
- timeout max_wait do
37
- until (result = begin; block.call || true; rescue; end)
38
- sleep interval
3
+ module Appium
4
+ module Common
5
+ # json and ap are required for the source method.
6
+ require 'json'
7
+ require 'ap' # awesome print
8
+ require 'timeout' # for wait
9
+
10
+ # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
11
+ # Android .name returns the accessibility attribute and nothing if it's not set.
12
+ #
13
+ # .text should be cross platform so prefer that over name, unless both
14
+ # Android and iOS have proper accessibility attributes.
15
+ # .text and .value should be the same so use .text over .value.
16
+ #
17
+ # secure class_name is iOS only because it can't be implemented using uiautomator for Android.
18
+ #
19
+ # find_element :text doesn't work so use XPath to find by text.
20
+
21
+ # Check every 0.5 seconds to see if block.call doesn't raise an exception.
22
+ # if .call raises an exception then it will be tried again.
23
+ # if .call doesn't raise an exception then it will stop waiting.
24
+ #
25
+ # Example: wait { name('back').click }
26
+ #
27
+ # Give up after 30 seconds.
28
+ # @param max_wait [Integer] the maximum time in seconds to wait for.
29
+ # Note that max wait 0 means infinity.
30
+ # @param interval [Float] the time in seconds to wait after calling the block
31
+ # @param block [Block] the block to call
32
+ # @return [Object] the result of block.call
33
+ def wait max_wait=30, interval=0.5, &block
34
+ max_wait = 1 if max_wait <= 0
35
+ result = nil
36
+ timeout max_wait do
37
+ until (
38
+ begin
39
+ result = block.call || true
40
+ rescue Exception
41
+ end)
42
+ sleep interval
43
+ end
39
44
  end
45
+ result
40
46
  end
41
- result
42
- end
43
47
 
44
- # Return block.call and ignore any exceptions.
45
- def ignore &block
46
- begin; block.call; rescue; end
47
- end
48
-
49
- # Check every 0.5 seconds to see if block.call returns true. nil is considered a failure.
50
- # Give up after 30 seconds.
51
- # @param max_wait [Integer] the maximum time in seconds to wait for
52
- # @param interval [Float] the time in seconds to wait after calling the block
53
- # @param block [Block] the block to call
54
- # @return [Object] the result of block.call
55
- def wait_true max_wait=30, interval=0.5, &block
56
- max_wait = 1 if max_wait <= 0
57
- result = nil
58
- timeout max_wait do
59
- until (result = begin; block.call; rescue; end)
60
- sleep interval
48
+ # Return block.call and ignore any exceptions.
49
+ def ignore &block
50
+ begin
51
+ block.call
52
+ rescue Exception
61
53
  end
62
54
  end
63
- result
64
- end
65
-
66
- # Navigate back.
67
- # @return [void]
68
- def back
69
- @driver.navigate.back
70
- end
71
-
72
- # For Sauce Labs reporting. Returns the current session id.
73
- def session_id
74
- @driver.session_id
75
- end
76
-
77
- # Returns the first element that matches the provided xpath.
78
- #
79
- # @param xpath_str [String] the XPath string
80
- # @return [Element]
81
- def xpath xpath_str
82
- find_element :xpath, xpath_str
83
- end
84
-
85
- # Returns all elements that match the provided xpath.
86
- #
87
- # @param xpath_str [String] the XPath string
88
- # @return [Array<Element>]
89
- def xpaths xpath_str
90
- find_elements :xpath, xpath_str
91
- end
92
-
93
- # Get the element of type tag_name at matching index.
94
- # @param tag_name [String] the tag name to find
95
- # @param index [Integer] the index
96
- # @return [Element] the found element of type tag_name
97
- def ele_index tag_name, index
98
- # XPath index starts at 1.
99
- raise "#{index} is not a valid xpath index. Must be >= 1" if index <= 0
100
- find_element :xpath, "//#{tag_name}[#{index}]"
101
- end
102
55
 
103
- # Get all elements exactly matching tag name
104
- # @param tag_name [String] the tag name to find
105
- # @return [Array<Element>] the found elements of type tag_name
106
- def find_eles tag_name
107
- @driver.find_elements :tag_name, tag_name
108
- end
109
-
110
- # Get the first tag that exactly matches tag and text.
111
- # @param tag [String] the tag name to match
112
- # @param text [String] the text to exactly match
113
- # @return [Element] the element of type tag exactly matching text
114
- def find_ele_by_text tag, text
115
- @driver.find_element :xpath, %Q(#{tag}[@text='#{text}'])
116
- end
117
-
118
- # Get all tags that exactly match tag and text.
119
- # @param tag [String] the tag name to match
120
- # @param text [String] the text to exactly match
121
- # @return [Array<Element>] the elements of type tag exactly matching text
122
- def find_eles_by_text tag, text
123
- @driver.find_elements :xpath, %Q(#{tag}[@text='#{text}'])
124
- end
125
-
126
- # Get the first tag by attribute that exactly matches value.
127
- # @param tag [String] the tag name to match
128
- # @param attr [String] the attribute to compare
129
- # @param value [String] the value of the attribute that the element must include
130
- # @return [Element] the element of type tag who's attribute includes value
131
- def find_ele_by_attr_include tag, attr, value
132
- @driver.find_element :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
133
- end
134
-
135
- # Get tags by attribute that include value.
136
- # @param tag [String] the tag name to match
137
- # @param attr [String] the attribute to compare
138
- # @param value [String] the value of the attribute that the element must include
139
- # @return [Array<Element>] the elements of type tag who's attribute includes value
140
- def find_eles_by_attr_include tag, attr, value
141
- @driver.find_elements :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
142
- end
56
+ # Check every 0.5 seconds to see if block.call returns a truthy value.
57
+ # Note this isn't a strict boolean true, any truthy value is accepted.
58
+ # false and nil are considered failures.
59
+ # Give up after 30 seconds.
60
+ # @param max_wait [Integer] the maximum time in seconds to wait for
61
+ # @param interval [Float] the time in seconds to wait after calling the block
62
+ # @param block [Block] the block to call
63
+ # @return [Object] the result of block.call
64
+ def wait_true max_wait=30, interval=0.5, &block
65
+ max_wait = 1 if max_wait <= 0
66
+ result = nil
67
+ timeout max_wait do
68
+ until (
69
+ begin
70
+ result = block.call
71
+ rescue Exception
72
+ end)
73
+ sleep interval
74
+ end
75
+ end
76
+ result
77
+ end
143
78
 
144
- # Get the first tag that includes text.
145
- # @param tag [String] the tag name to match
146
- # @param text [String] the text the element must include
147
- # @return [Element] the element of type tag that includes text
148
- # element.attribute(:text).include? text
149
- def find_ele_by_text_include tag, text
150
- find_ele_by_attr_include tag, :text, text
151
- end
79
+ # Navigate back.
80
+ # @return [void]
81
+ def back
82
+ @driver.navigate.back
83
+ end
152
84
 
153
- # Get the tags that include text.
154
- # @param tag [String] the tag name to match
155
- # @param text [String] the text the element must include
156
- # @return [Array<Element>] the elements of type tag that includes text
157
- # element.attribute(:text).include? text
158
- def find_eles_by_text_include tag, text
159
- find_eles_by_attr_include tag, :text, text
160
- end
85
+ # For Sauce Labs reporting. Returns the current session id.
86
+ def session_id
87
+ @driver.session_id
88
+ end
161
89
 
162
- # Get the first tag that matches tag_name
163
- # @param tag_name [String] the tag to match
164
- # @return [Element]
165
- def first_ele tag_name
166
- # XPath index starts at 1
167
- find_element :xpath, "//#{tag_name}[1]"
168
- end
90
+ # Returns the first element that matches the provided xpath.
91
+ #
92
+ # @param xpath_str [String] the XPath string
93
+ # @return [Element]
94
+ def xpath xpath_str
95
+ find_element :xpath, xpath_str
96
+ end
169
97
 
170
- # Get the last tag that matches tag_name
171
- # @param tag_name [String] the tag to match
172
- # @return [Element]
173
- def last_ele tag_name
174
- xpath "//#{tag_name}[last()]"
175
- end
98
+ # Returns all elements that match the provided xpath.
99
+ #
100
+ # @param xpath_str [String] the XPath string
101
+ # @return [Array<Element>]
102
+ def xpaths xpath_str
103
+ find_elements :xpath, xpath_str
104
+ end
176
105
 
177
- # Prints a JSON view of the current page
178
- # @return [void]
179
- def source
180
- ap get_source
181
- end
106
+ # Prints xml of the current page
107
+ # @return [void]
108
+ def source
109
+ doc = Nokogiri::XML(@driver.page_source) do |config|
110
+ config.options = Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NONET
111
+ end
112
+ puts doc.to_xml indent: 2
113
+ end
182
114
 
183
- # Gets a JSON view of the current page
184
- # @return [JSON]
185
- def get_source
186
- # must set max nesting. default limit of 20 is too low for selendroid
187
- JSON.parse @driver.page_source, max_nesting: 9999
188
- end
115
+ # Returns XML string for the current page
116
+ # Same as driver.page_source
117
+ # @return [String]
118
+ def get_source
119
+ @driver.page_source
120
+ end
189
121
 
190
- # Returns the first element that exactly matches name
191
- #
192
- # @param name [String] the name to exactly match
193
- # @return [Element]
194
- def find_name name
195
- find_element :name, name
196
- end
122
+ # @private
123
+ # http://nokogiri.org/Nokogiri/XML/SAX.html
124
+ class CountElements < Nokogiri::XML::SAX::Document
125
+ attr_reader :result
197
126
 
198
- # Returns all elements that exactly match name
199
- #
200
- # @param name [String] the name to exactly match
201
- # @return [Array<Element>]
202
- def find_names name
203
- find_elements :name, name
204
- end
127
+ def initialize
128
+ reset
129
+ end
205
130
 
206
- # Returns the first element matching tag_name
207
- #
208
- # @param tag_name [String] the tag_name to search for
209
- # @return [Element]
210
- def tag tag_name
211
- find_element :tag_name, tag_name
212
- end
131
+ def reset
132
+ @result = Hash.new 0
133
+ end
213
134
 
214
- # Returns all elements matching tag_name
215
- #
216
- # @param tag_name [String] the tag_name to search for
217
- # @return [Element]
218
- def tags tag_name
219
- find_elements :tag_name, tag_name
220
- end
135
+ # http://nokogiri.org/Nokogiri/XML/SAX/Document.html
136
+ def start_element name, attrs = []
137
+ @result[name] += 1
138
+ end
221
139
 
222
- # Converts pixel values to window relative values
223
- #
224
- # ```ruby
225
- # px_to_window_rel x: 50, y: 150
226
- # ```
140
+ def formatted_result
141
+ message = ''
142
+ sorted = @result.sort_by { |element, count| count }.reverse
143
+ sorted.each do |element, count|
144
+ message += "#{count}x #{element}\n"
145
+ end
146
+ message.strip
147
+ end
148
+ end # class CountElements
227
149
 
228
- def px_to_window_rel opts={}
150
+ # Returns a string of class counts.
151
+ def get_page_class
152
+ parser = @count_elements_parser ||= Nokogiri::XML::SAX::Parser.new(CountElements.new)
229
153
 
230
- w = $driver.window_size
231
- x = opts.fetch :x, 0
232
- y = opts.fetch :y, 0
154
+ parser.document.reset
155
+ parser.parse get_source
233
156
 
234
- OpenStruct.new( x: "#{x.to_f} / #{w.width.to_f}",
235
- y: "#{y.to_f} / #{w.height.to_f}" )
236
- end
157
+ parser.document.formatted_result
158
+ end
237
159
 
238
- def lazy_load_strings
239
- @strings_xml ||= mobile(:getStrings)
240
- end
160
+ # Count all classes on screen and print to stdout.
161
+ # Useful for appium_console.
162
+ def page_class
163
+ puts get_page_class
164
+ nil
165
+ end
241
166
 
242
- # Search strings.xml's values for target.
243
- # @param target [String] the target to search for in strings.xml values
244
- # @return [Array]
245
- def xml_keys target
246
- lazy_load_strings
247
- @strings_xml.select { |key, value| key.downcase.include? target.downcase }
248
- end
167
+ # Converts pixel values to window relative values
168
+ #
169
+ # ```ruby
170
+ # px_to_window_rel x: 50, y: 150
171
+ # ```
172
+ def px_to_window_rel opts={}
173
+ w = $driver.window_size
174
+ x = opts.fetch :x, 0
175
+ y = opts.fetch :y, 0
176
+
177
+ OpenStruct.new(x: "#{x.to_f} / #{w.width.to_f}",
178
+ y: "#{y.to_f} / #{w.height.to_f}")
179
+ end
249
180
 
250
- # Search strings.xml's keys for target.
251
- # @param target [String] the target to search for in strings.xml keys
252
- # @return [Array]
253
- def xml_values target
254
- lazy_load_strings
255
- @strings_xml.select { |key, value| value.downcase.include? target.downcase }
256
- end
181
+ # @private
182
+ def lazy_load_strings
183
+ @strings_xml ||= app_strings
184
+ end
257
185
 
258
- # Resolve id in strings.xml and return the value.
259
- # @param id [String] the id to resolve
260
- # @return [String]
261
- def resolve_id id
262
- lazy_load_strings
263
- @strings_xml[id]
264
- end
186
+ # Search strings.xml's values for target.
187
+ # @param target [String] the target to search for in strings.xml values
188
+ # @return [Array]
189
+ def xml_keys target
190
+ lazy_load_strings
191
+ @strings_xml.select { |key, value| key.downcase.include? target.downcase }
192
+ end
265
193
 
266
- # Used to error when finding a single element fails.
267
- def raise_no_element_error
268
- raise Selenium::WebDriver::Error::NoSuchElementError, 'An element could not be located on the page using the given search parameters.'
269
- end
194
+ # Search strings.xml's keys for target.
195
+ # @param target [String] the target to search for in strings.xml keys
196
+ # @return [Array]
197
+ def xml_values target
198
+ lazy_load_strings
199
+ @strings_xml.select { |key, value| value.downcase.include? target.downcase }
200
+ end
270
201
 
271
- end # module Appium::Common
202
+ # Resolve id in strings.xml and return the value.
203
+ # @param id [String] the id to resolve
204
+ # @return [String]
205
+ def resolve_id id
206
+ lazy_load_strings
207
+ @strings_xml[id]
208
+ end
209
+ end # module Common
210
+ end # module Appium