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.
@@ -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