rubium-ios 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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