rubium-ios 1.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/rubium.rb +21 -0
- data/lib/rubium/capabilities.rb +92 -0
- data/lib/rubium/driver.rb +233 -0
- data/lib/rubium/session.rb +26 -0
- data/lib/rubium/version.rb +16 -0
- data/lib/ui_automation.rb +325 -0
- data/lib/ui_automation/action_sheet.rb +9 -0
- data/lib/ui_automation/activity_view.rb +9 -0
- data/lib/ui_automation/alert.rb +16 -0
- data/lib/ui_automation/application.rb +57 -0
- data/lib/ui_automation/element.rb +255 -0
- data/lib/ui_automation/element_array.rb +226 -0
- data/lib/ui_automation/element_definitions.rb +51 -0
- data/lib/ui_automation/element_proxy_methods.rb +43 -0
- data/lib/ui_automation/keyboard.rb +40 -0
- data/lib/ui_automation/logger.rb +43 -0
- data/lib/ui_automation/navigation_bar.rb +17 -0
- data/lib/ui_automation/picker.rb +14 -0
- data/lib/ui_automation/popover.rb +23 -0
- data/lib/ui_automation/tab_bar.rb +31 -0
- data/lib/ui_automation/table_view.rb +35 -0
- data/lib/ui_automation/target.rb +42 -0
- data/lib/ui_automation/text_field.rb +9 -0
- data/lib/ui_automation/text_view.rb +9 -0
- data/lib/ui_automation/traits/cancellable.rb +12 -0
- data/lib/ui_automation/traits/text_input.rb +58 -0
- data/lib/ui_automation/window.rb +30 -0
- metadata +128 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# A RemoteProxy to UIAActionSheet objects in the Javascript API.
|
3
|
+
#
|
4
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAActionSheetClassReference/
|
5
|
+
#
|
6
|
+
class ActionSheet < Element
|
7
|
+
include Traits::Cancellable
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# A RemoteProxy to UIAActivityView objects in the Javascript API.
|
3
|
+
#
|
4
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIActivityViewClassReference/
|
5
|
+
#
|
6
|
+
class ActivityView < Element
|
7
|
+
include Traits::Cancellable
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# A RemoteProxy to UIAAlert objects in the Javascript API.
|
3
|
+
#
|
4
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAAlertSheetClassReference/
|
5
|
+
#
|
6
|
+
class Alert < Element
|
7
|
+
include Traits::Cancellable
|
8
|
+
|
9
|
+
### @!group Elements
|
10
|
+
|
11
|
+
# The alert's default button
|
12
|
+
has_element :defaultButton
|
13
|
+
|
14
|
+
### @!endgroup
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# A RemoteProxy to UIAApplication objects in the Javascript API.
|
3
|
+
#
|
4
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAApplicationClassReference/
|
5
|
+
#
|
6
|
+
class Application < RemoteProxy
|
7
|
+
extend ElementDefinitions
|
8
|
+
|
9
|
+
### @!group Elements
|
10
|
+
|
11
|
+
# The application's main window.
|
12
|
+
has_element :mainWindow, type: UIAutomation::Window
|
13
|
+
|
14
|
+
# The currently active action sheet.
|
15
|
+
has_element :actionSheet, type: UIAutomation::ActionSheet
|
16
|
+
|
17
|
+
# The system keyboard.
|
18
|
+
has_element :keyboard, type: UIAutomation::Keyboard
|
19
|
+
|
20
|
+
# The currently displayed alert view
|
21
|
+
has_element :alert, type: UIAutomation::Alert
|
22
|
+
|
23
|
+
# The currently displayed editing menu
|
24
|
+
has_element :editingMenu
|
25
|
+
|
26
|
+
# The application's tab bar.
|
27
|
+
#
|
28
|
+
# On an iPhone there will normally only be one tab bar but an iPad may have multiple.
|
29
|
+
has_element :tabBar, type: UIAutomation::TabBar
|
30
|
+
|
31
|
+
# The application's navigation bar.
|
32
|
+
#
|
33
|
+
# On an iPhone there will normally only be one navigation bar but an iPad may have multiple.
|
34
|
+
has_element :navigationBar, type: UIAutomation::NavigationBar
|
35
|
+
|
36
|
+
# The application's toolbar.
|
37
|
+
#
|
38
|
+
# On an iPhone there will normally only be one toolbar but an iPad may have multiple.
|
39
|
+
has_element :toolbar
|
40
|
+
|
41
|
+
# The application status bar
|
42
|
+
has_element :statusBar
|
43
|
+
|
44
|
+
### @!endgroup
|
45
|
+
|
46
|
+
### @!group Element Collections
|
47
|
+
|
48
|
+
# The application's windows.
|
49
|
+
has_element_array :windows, type: UIAutomation::Window
|
50
|
+
|
51
|
+
### @!endgroup
|
52
|
+
|
53
|
+
def bundle_id
|
54
|
+
perform :bundleID
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# Represents objects of type UIAElement in the Javascript API.
|
3
|
+
#
|
4
|
+
# UIAutomation::Element acts as the base class for all element types.
|
5
|
+
#
|
6
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAElementClassReference/
|
7
|
+
class Element < RemoteProxy
|
8
|
+
extend UIAutomation::ElementDefinitions
|
9
|
+
|
10
|
+
# The proxy for the parent element
|
11
|
+
# @note This returns the existing proxy that created this one; it does not use the UIAElement.parent() method
|
12
|
+
# @return [UIAutomation::Element]
|
13
|
+
attr_reader :parent
|
14
|
+
|
15
|
+
# The window that contains this element
|
16
|
+
# @return [UIAutomation::Window]
|
17
|
+
attr_reader :window
|
18
|
+
|
19
|
+
### @!group Elements
|
20
|
+
|
21
|
+
# The popover object associated with the current element
|
22
|
+
has_element :popover, type: UIAutomation::Popover
|
23
|
+
|
24
|
+
# The activity view associated with this element
|
25
|
+
has_element :activityView, type: UIAutomation::ActivityView
|
26
|
+
|
27
|
+
# The main tab bar.
|
28
|
+
#
|
29
|
+
# On an iPhone there will normally only be one tab bar but an iPad may have multiple.
|
30
|
+
has_element :tabBar, type: UIAutomation::TabBar
|
31
|
+
|
32
|
+
# The main navigation bar.
|
33
|
+
#
|
34
|
+
# On an iPhone there will normally only be one navigation bar but an iPad may have multiple.
|
35
|
+
has_element :navigationBar, type: UIAutomation::NavigationBar
|
36
|
+
|
37
|
+
# The main toolbar.
|
38
|
+
#
|
39
|
+
# On an iPhone there will normally only be one toolbar but an iPad may have multiple.
|
40
|
+
has_element :toolbar
|
41
|
+
|
42
|
+
# @!endgroup
|
43
|
+
|
44
|
+
### @!group Element Collections
|
45
|
+
|
46
|
+
# The element's parents
|
47
|
+
has_element_array :ancestry
|
48
|
+
|
49
|
+
# The element's children
|
50
|
+
has_element_array :elements
|
51
|
+
|
52
|
+
# All scroll views contained by this element
|
53
|
+
has_element_array :scrollViews
|
54
|
+
|
55
|
+
# All web views contained by this element
|
56
|
+
has_element_array :webViews
|
57
|
+
|
58
|
+
# All table views contained by this element
|
59
|
+
has_element_array :tableViews, type: UIAutomation::TableView
|
60
|
+
|
61
|
+
# All buttons contained by this element
|
62
|
+
has_element_array :buttons
|
63
|
+
|
64
|
+
# All static text elements contained by this element
|
65
|
+
has_element_array :staticTexts
|
66
|
+
|
67
|
+
# All text fields contained by this element
|
68
|
+
has_element_array :textFields, type: UIAutomation::TextField
|
69
|
+
|
70
|
+
# All secure text fields contained by this element
|
71
|
+
has_element_array :secureTextFields, type: UIAutomation::TextField
|
72
|
+
|
73
|
+
# All search bars contained by this element
|
74
|
+
has_element_array :searchBars, type: UIAutomation::TextField
|
75
|
+
|
76
|
+
# All segmented controls contained by this element
|
77
|
+
has_element_array :segmentedControls
|
78
|
+
|
79
|
+
# All switches contained by this element
|
80
|
+
has_element_array :switches
|
81
|
+
|
82
|
+
# All images contained by this element
|
83
|
+
has_element_array :images
|
84
|
+
|
85
|
+
# All links contained by this element
|
86
|
+
has_element_array :links
|
87
|
+
|
88
|
+
# All page indicators contained by this element
|
89
|
+
has_element_array :pageIndicators
|
90
|
+
|
91
|
+
# All pickers contained by this element
|
92
|
+
has_element_array :pickers, type: UIAutomation::Picker
|
93
|
+
|
94
|
+
# All progress indicators contained by this element
|
95
|
+
has_element_array :progressIndicators
|
96
|
+
|
97
|
+
# All sliders contained by this element
|
98
|
+
has_element_array :sliders
|
99
|
+
|
100
|
+
# All text views contained by this element
|
101
|
+
has_element_array :textViews, type: UIAutomation::TextView
|
102
|
+
|
103
|
+
# All collection views contained by this element
|
104
|
+
has_element_array :collectionViews
|
105
|
+
|
106
|
+
# All actvity indicators associated with this element
|
107
|
+
has_element_array :activityIndicators
|
108
|
+
|
109
|
+
# The window's tab bars
|
110
|
+
has_element_array :tabBars, type: UIAutomation::TabBar
|
111
|
+
|
112
|
+
# The window's navigation bars
|
113
|
+
has_element_array :navigationBars, type: UIAutomation::NavigationBar
|
114
|
+
|
115
|
+
# The window's toolbars
|
116
|
+
has_element_array :toolbars
|
117
|
+
|
118
|
+
### @!endgroup
|
119
|
+
|
120
|
+
# Initializes a new element.
|
121
|
+
# As well as the parameters of its super-class, it also takes a parent element and window proxy.
|
122
|
+
# @api private
|
123
|
+
#
|
124
|
+
def initialize(driver, remote_object, parent_element, window = nil)
|
125
|
+
super driver, remote_object
|
126
|
+
@parent = parent_element
|
127
|
+
@window = window
|
128
|
+
end
|
129
|
+
|
130
|
+
### @!group Checking Element State
|
131
|
+
|
132
|
+
# Returns true if the element is valid.
|
133
|
+
# This uses the UIAElement method checkIsValid() to ensure that the most up-to-date status is returned.
|
134
|
+
# @return [Boolean]
|
135
|
+
#
|
136
|
+
def valid?
|
137
|
+
perform :checkIsValid
|
138
|
+
end
|
139
|
+
|
140
|
+
# Indicates if the element is currently visible.
|
141
|
+
# @return [Boolean]
|
142
|
+
# @see UIAElement.isVisible()
|
143
|
+
def visible?
|
144
|
+
perform(:isVisible) == 1
|
145
|
+
end
|
146
|
+
|
147
|
+
# Indicates if the element is currently enabled.
|
148
|
+
# @return [Boolean]
|
149
|
+
# @see UIAElement.isEnabled()
|
150
|
+
#
|
151
|
+
def enabled?
|
152
|
+
perform(:isEnabled) == 1
|
153
|
+
end
|
154
|
+
|
155
|
+
# Indicates if the element is currently selected.
|
156
|
+
# @return [Boolean]
|
157
|
+
# @see UIAElement.isSelected()
|
158
|
+
#
|
159
|
+
def selected?
|
160
|
+
perform(:isSelected)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Indicates if the element has keyboard focus.
|
164
|
+
# @return [Boolean]
|
165
|
+
# @see UIAElement.hasKeyboardFocus()
|
166
|
+
#
|
167
|
+
def has_keyboard_focus?
|
168
|
+
perform(:hasKeyboardFocus) == 1
|
169
|
+
end
|
170
|
+
|
171
|
+
# Calls the given block when the element becomes valid. If the element is already valid
|
172
|
+
# the block is called immediately.
|
173
|
+
# @yieldparam [self] element
|
174
|
+
#
|
175
|
+
def when_valid(&block)
|
176
|
+
when_element_is(:valid?, &block)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Calls the given block when the element passes one ore more predicates.
|
180
|
+
#
|
181
|
+
# Each predicate method specified will be called and if they all return true, the given block will be called,
|
182
|
+
# otherwise it will wait for all predicates to return true.
|
183
|
+
#
|
184
|
+
# @param [List<Symbol>] predicates One or more symbols representing boolean methods defined on the current class.
|
185
|
+
# @yieldparam [self] element
|
186
|
+
# @raise [Rubium::Driver::TimeoutError] if all predicates do not return true within the default timeout.
|
187
|
+
#
|
188
|
+
# @example Tap the element once it is selected and has keyboard focus
|
189
|
+
# element.when_element(:selected?, :has_keyboard_focus?) { |el| el.tap }
|
190
|
+
#
|
191
|
+
def when_element(*predicates, &block)
|
192
|
+
driver.wait_until do
|
193
|
+
predicates.all? { |p| __send__(p) }
|
194
|
+
end
|
195
|
+
|
196
|
+
yield self if block_given?
|
197
|
+
|
198
|
+
rescue Wrong::Assert::AssertionFailedError => e
|
199
|
+
raise Wrong::Assert::AssertionFailedError.new("Expect #{self} #{predicates.join(", ")}")
|
200
|
+
end
|
201
|
+
alias :when_element_is :when_element
|
202
|
+
|
203
|
+
# Repeatedly calls the given block until the element passes one ore more predicates.
|
204
|
+
#
|
205
|
+
# Each predicate method specified will be called and if they all return true, the given block will never be called,
|
206
|
+
# otherwise, the block will be called continuously with a small delay between each call until they do.
|
207
|
+
#
|
208
|
+
# The predicates will be checked before each block call.
|
209
|
+
#
|
210
|
+
# @param [List<Symbol>] predicates One or more symbols representing boolean methods defined on the current class.
|
211
|
+
# @yieldparam [self] element
|
212
|
+
# @raise [Rubium::Driver::TimeoutError] if all predicates do not return true within the default timeout.
|
213
|
+
#
|
214
|
+
# @example Scroll the table view until a specific cell is visible
|
215
|
+
# expected_cell = table_view.cells['Some Name']
|
216
|
+
# expected_cell.until_element(:visible?) { table_view.scroll_down }
|
217
|
+
#
|
218
|
+
def until_element(*predicates, &block)
|
219
|
+
driver.wait_until do
|
220
|
+
if predicates.all? { |p| __send__(p) }
|
221
|
+
true
|
222
|
+
else
|
223
|
+
yield self if block_given?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
### @!endgroup
|
229
|
+
|
230
|
+
### @!group Gestures and Actions
|
231
|
+
|
232
|
+
# Perform a single tap on the element.
|
233
|
+
# This method waits for the element to become valid and visible before performing the tap.
|
234
|
+
# To perform a tap immediately without waiting, use #tap!
|
235
|
+
# @see #tap!
|
236
|
+
#
|
237
|
+
def tap # define this explicitly due to conflict with Object#tap
|
238
|
+
when_element_is(:valid?, :visible?) { tap! }
|
239
|
+
end
|
240
|
+
|
241
|
+
# Performs a single tap on the element without waiting.
|
242
|
+
# Use this method when you are certain that an element is both valid and visible - calling this
|
243
|
+
# may result in an error if the element is not tappable.
|
244
|
+
#
|
245
|
+
def tap!
|
246
|
+
perform(:tap)
|
247
|
+
end
|
248
|
+
|
249
|
+
### @!endgroup
|
250
|
+
|
251
|
+
def application
|
252
|
+
window.parent
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module UIAutomation
|
2
|
+
# Represents objects of type UIAElementArray in the Javascript API.
|
3
|
+
#
|
4
|
+
# An ElementArray represents a collection of elements of a specific type within the view hierarchy.
|
5
|
+
#
|
6
|
+
# This class implements #each and includes the Enumerable mixin, enabling you to use it like any other
|
7
|
+
# native Ruby collection class.
|
8
|
+
#
|
9
|
+
# All methods in thie class that return a UIAutomation::Element may return a specific sub-class of
|
10
|
+
# UIAutomation::Element, as determined by the #element_klass attribute.
|
11
|
+
#
|
12
|
+
# @see https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIAElementArrayClassReference/
|
13
|
+
class ElementArray < RemoteProxy
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
# The proxy for the parent element
|
17
|
+
# @note This returns the existing proxy that created this one; it does not use the UIAElement.parent() method
|
18
|
+
# @return [UIAutomation::Element]
|
19
|
+
attr_reader :parent
|
20
|
+
|
21
|
+
# The window that contains this element
|
22
|
+
# @return [UIAutomation::Window]
|
23
|
+
attr_reader :window
|
24
|
+
|
25
|
+
# The element proxy class used for each element in the array.
|
26
|
+
# @api private
|
27
|
+
attr_reader :element_klass
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def initialize(driver, remote_object, element_klass = UIAutomation::Element, parent_element = nil, window = nil)
|
31
|
+
super driver, remote_object
|
32
|
+
@element_klass = element_klass
|
33
|
+
@parent = parent_element
|
34
|
+
@window = window
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
"<RemoteProxy(#{self.class.name}) type:#{element_proxy_for}: #{to_javascript}>"
|
39
|
+
end
|
40
|
+
|
41
|
+
### @!group Accessing Elements
|
42
|
+
|
43
|
+
# Returns a proxy to the element at the given index.
|
44
|
+
#
|
45
|
+
# @param [Integer] index
|
46
|
+
# @return [UIAutomation::Element] the element proxy
|
47
|
+
#
|
48
|
+
def at_index(index)
|
49
|
+
build_proxy element_klass, remote_object.object_for_subscript(index), [parent, window]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns a new ElementArray containing all elements with the given name.
|
53
|
+
#
|
54
|
+
# @param [String] name
|
55
|
+
# @return [UIAutomation::ElementArray] a sub-set of the current element array
|
56
|
+
# @see UIAElementArray.withName()
|
57
|
+
#
|
58
|
+
def with_name(name)
|
59
|
+
element_array_proxy_for :withName, name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns a proxy to the first element with the given name.
|
63
|
+
#
|
64
|
+
# @param [String] name
|
65
|
+
# @return [UIAutomation::Element] the element proxy
|
66
|
+
# @see UIAElementArray.firstWithName()
|
67
|
+
#
|
68
|
+
def first_with_name(name)
|
69
|
+
element_proxy_for :firstWithName, name
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns a new ElementArray containing all elements matching the given predicate.
|
73
|
+
#
|
74
|
+
# Predicates use the Apple NSPredicate syntax.
|
75
|
+
#
|
76
|
+
# To avoid dealing with escaping and quoting of string values, you can use template substitution
|
77
|
+
# in your predicate string and pass in the values as a hash.
|
78
|
+
#
|
79
|
+
# @example Using predicate template substitution
|
80
|
+
# array.with_predicate("name beginswith :value", :value => 'test')
|
81
|
+
#
|
82
|
+
# @param [String] template a predicate template using NSPredicate syntax
|
83
|
+
# @param [Hash] substitutions an optional hash of template substitutions
|
84
|
+
# @return [UIAutomation::ElementArray] a sub-set of the current element array
|
85
|
+
# @see UIAElementArray.withPredicate()
|
86
|
+
# @see https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html
|
87
|
+
#
|
88
|
+
def with_predicate(template, substitutions = {})
|
89
|
+
element_array_proxy_for :withPredicate, UIAutomation::PredicateString.new(template, substitutions).to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns a proxy to the first element matching the specified predicate.
|
93
|
+
#
|
94
|
+
# Predicates use the Apple NSPredicate syntax (see #with_predicate for more information).
|
95
|
+
#
|
96
|
+
# @param [String] template a predicate template using NSPredicate syntax
|
97
|
+
# @param [Hash] substitutions an optional hash of template substitutions
|
98
|
+
# @return [UIAutomation::Element] the element proxy
|
99
|
+
# @see #with_predicate
|
100
|
+
# @see UIAElementArray.firstWithPredicate()
|
101
|
+
#
|
102
|
+
def first_with_predicate(template, substitutions = {})
|
103
|
+
element_proxy_for :firstWithPredicate, UIAutomation::PredicateString.new(template, substitutions).to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns a new ElementArray containing all elements with the given key/value pair.
|
107
|
+
#
|
108
|
+
# @param [String] key
|
109
|
+
# @param [Object] value
|
110
|
+
# @return [UIAutomation::ElementArray] a sub-set of the current element array
|
111
|
+
# @see UIAElementArray.withValueForKey()
|
112
|
+
#
|
113
|
+
def with_value_for_key(key, value)
|
114
|
+
element_array_proxy_for :withValueForKey, value, key
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns a new ElementArray containing all elements with the given value.
|
118
|
+
#
|
119
|
+
# @param [Object] value
|
120
|
+
# @return [UIAutomation::ElementArray] a sub-set of the current element array
|
121
|
+
#
|
122
|
+
def with_value(value)
|
123
|
+
with_value_for_key(:value, value)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns a proxy to the first element with the given value.
|
127
|
+
#
|
128
|
+
# @param [Object] value the element value
|
129
|
+
# @return [UIAutomation::Element] the element proxy or nil if no elements found
|
130
|
+
# @see UIAElementArray.firstWithName()
|
131
|
+
#
|
132
|
+
def first_with_value(value)
|
133
|
+
collection = with_value(value)
|
134
|
+
collection.any? ? collection.first : nil
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns a remote proxy to a specific element within the collection by index or name.
|
138
|
+
#
|
139
|
+
# You can use square-bracked syntax with either an Integer or String key to perform lookup
|
140
|
+
# by index or name respectively.
|
141
|
+
#
|
142
|
+
# Calling with an Integer is equivalent to calling #at_index. Calling with a String is
|
143
|
+
# equivalent to calling #first_with_name.
|
144
|
+
#
|
145
|
+
# @param [String or Integer] index_or_name the index or name of the attribute
|
146
|
+
# @return [UIAutomation::Element] the matching element
|
147
|
+
# @see UIAElementArray.withName()
|
148
|
+
#
|
149
|
+
def [](index_or_name)
|
150
|
+
if index_or_name.is_a?(Integer)
|
151
|
+
at_index(index_or_name)
|
152
|
+
else
|
153
|
+
first_with_name(index_or_name)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
### @!endgroup
|
158
|
+
|
159
|
+
# Returns the number of items in the array
|
160
|
+
# @return [Integer]
|
161
|
+
#
|
162
|
+
def length
|
163
|
+
fetch(:length)
|
164
|
+
end
|
165
|
+
alias :count :length
|
166
|
+
|
167
|
+
# Yields a proxy to each element in the ElementArray if a block is given.
|
168
|
+
#
|
169
|
+
# If no block is given, this method will return an Enumerator.
|
170
|
+
#
|
171
|
+
# @yieldparam [UIAutomation::Element] element if block given
|
172
|
+
# @return [Enumerator] if no block is given
|
173
|
+
#
|
174
|
+
def each(&block)
|
175
|
+
if block_given?
|
176
|
+
(0...length).each do |index|
|
177
|
+
yield self[index]
|
178
|
+
end
|
179
|
+
else
|
180
|
+
to_enum(:each)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def element_proxy_for(function_name, *function_args)
|
187
|
+
proxy_for(function_name,
|
188
|
+
function_args: function_args,
|
189
|
+
proxy_klass: @element_klass,
|
190
|
+
proxy_args: [parent, window]
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
def element_array_proxy_for(function_name, *function_args)
|
195
|
+
proxy_for(function_name,
|
196
|
+
function_args: function_args,
|
197
|
+
proxy_klass: UIAutomation::ElementArray,
|
198
|
+
proxy_args: [element_klass, parent, window]
|
199
|
+
)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# @private
|
204
|
+
class PredicateString
|
205
|
+
def initialize(template, substitutions = {})
|
206
|
+
@template = template
|
207
|
+
@substitutions = substitutions
|
208
|
+
end
|
209
|
+
|
210
|
+
def to_s
|
211
|
+
@substitutions.reduce(@template) do |string, (key, value)|
|
212
|
+
string.gsub(/:#{key}/, escaped(value))
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def escaped(value)
|
219
|
+
if value.is_a?(String)
|
220
|
+
"\"#{value}\""
|
221
|
+
else
|
222
|
+
value.to_s
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|