calabash 1.2.1 → 1.9.9.pre1
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 +4 -4
- data/CONTRIBUTING.md +39 -0
- data/LICENSE +204 -21
- data/README.md +36 -6
- data/VERSIONING.md +16 -0
- data/bin/calabash +95 -0
- data/lib/calabash.rb +185 -1
- data/lib/calabash/android.rb +64 -0
- data/lib/calabash/android/adb.rb +277 -0
- data/lib/calabash/android/application.rb +110 -0
- data/lib/calabash/android/build.rb +12 -0
- data/lib/calabash/android/build/application.rb +13 -0
- data/lib/calabash/android/build/build_error.rb +11 -0
- data/lib/calabash/android/build/builder.rb +119 -0
- data/lib/calabash/android/build/java_keystore.rb +177 -0
- data/lib/calabash/android/build/resigner.rb +56 -0
- data/lib/calabash/android/build/test_server.rb +27 -0
- data/lib/calabash/android/console_helpers.rb +44 -0
- data/lib/calabash/android/cucumber.rb +3 -0
- data/lib/calabash/android/device.rb +965 -0
- data/lib/calabash/android/environment.rb +470 -0
- data/lib/calabash/android/gestures.rb +369 -0
- data/lib/calabash/android/interactions.rb +45 -0
- data/lib/calabash/android/lib/.irbrc +55 -0
- data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
- data/lib/calabash/android/lib/TestServer.apk +0 -0
- data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
- data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
- data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
- data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
- data/lib/calabash/android/life_cycle.rb +37 -0
- data/lib/calabash/android/orientation.rb +30 -0
- data/lib/calabash/android/physical_buttons.rb +39 -0
- data/lib/calabash/android/screenshot.rb +9 -0
- data/lib/calabash/android/scroll.rb +5 -0
- data/lib/calabash/android/server.rb +10 -0
- data/lib/calabash/android/text.rb +54 -0
- data/lib/calabash/application.rb +74 -0
- data/lib/calabash/cli.rb +12 -0
- data/lib/calabash/cli/build.rb +33 -0
- data/lib/calabash/cli/console.rb +90 -0
- data/lib/calabash/cli/generate.rb +110 -0
- data/lib/calabash/cli/helpers.rb +130 -0
- data/lib/calabash/cli/resign.rb +33 -0
- data/lib/calabash/cli/run.rb +99 -0
- data/lib/calabash/cli/setup_keystore.rb +39 -0
- data/lib/calabash/color.rb +32 -0
- data/lib/calabash/console_helpers.rb +90 -0
- data/lib/calabash/defaults.rb +56 -0
- data/lib/calabash/device.rb +401 -0
- data/lib/calabash/environment.rb +75 -0
- data/lib/calabash/gestures.rb +384 -0
- data/lib/calabash/http.rb +8 -0
- data/lib/calabash/http/error.rb +15 -0
- data/lib/calabash/http/request.rb +42 -0
- data/lib/calabash/http/retriable_client.rb +156 -0
- data/lib/calabash/interactions.rb +105 -0
- data/lib/calabash/ios.rb +37 -0
- data/lib/calabash/ios/application.rb +119 -0
- data/lib/calabash/ios/conditions.rb +79 -0
- data/lib/calabash/ios/console_helpers.rb +72 -0
- data/lib/calabash/ios/device.rb +24 -0
- data/lib/calabash/ios/device/device_implementation.rb +779 -0
- data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
- data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
- data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
- data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
- data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
- data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
- data/lib/calabash/ios/device/routes/error.rb +8 -0
- data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
- data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
- data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
- data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
- data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
- data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
- data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
- data/lib/calabash/ios/device/text_mixin.rb +19 -0
- data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
- data/lib/calabash/ios/device/uia_mixin.rb +12 -0
- data/lib/calabash/ios/environment.rb +41 -0
- data/lib/calabash/ios/interactions.rb +10 -0
- data/lib/calabash/ios/lib/.irbrc +55 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
- data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
- data/lib/calabash/ios/orientation.rb +117 -0
- data/lib/calabash/ios/scroll.rb +504 -0
- data/lib/calabash/ios/server.rb +73 -0
- data/lib/calabash/ios/text.rb +248 -0
- data/lib/calabash/ios/uia.rb +24 -0
- data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
- data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
- data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
- data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
- data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
- data/lib/calabash/life_cycle.rb +111 -0
- data/lib/calabash/location.rb +51 -0
- data/lib/calabash/logger.rb +87 -0
- data/lib/calabash/orientation.rb +84 -0
- data/lib/calabash/page.rb +35 -0
- data/lib/calabash/patch.rb +14 -0
- data/lib/calabash/patch/array.rb +16 -0
- data/lib/calabash/patch/run_loop.rb +90 -0
- data/lib/calabash/query.rb +160 -0
- data/lib/calabash/query_result.rb +85 -0
- data/lib/calabash/screenshot.rb +89 -0
- data/lib/calabash/server.rb +16 -0
- data/lib/calabash/text.rb +76 -0
- data/lib/calabash/utility.rb +58 -0
- data/lib/calabash/version.rb +3 -1
- data/lib/calabash/wait.rb +474 -0
- metadata +462 -24
@@ -0,0 +1,504 @@
|
|
1
|
+
module Calabash
|
2
|
+
module IOS
|
3
|
+
|
4
|
+
# Scrolling gestures for UIScrollView, UITableView, MKMapView, UIWebView,
|
5
|
+
# WKWebView, and UICollectionView.
|
6
|
+
#
|
7
|
+
# Starting iOS, Apple's official UIAutomation API has been broken on the
|
8
|
+
# iOS Simulators for these methods:
|
9
|
+
#
|
10
|
+
# * dragInsideWithOptions
|
11
|
+
# * flickInsideWithOptions
|
12
|
+
#
|
13
|
+
# The result is that gestures like swipe and flick do not work on
|
14
|
+
# iOS Simulators.
|
15
|
+
#
|
16
|
+
# Calabash iOS implements several scrolling methods that allow you to work
|
17
|
+
# around these bugs.
|
18
|
+
#
|
19
|
+
# @see Calabash::Gestures#pan
|
20
|
+
# @see Calabash::Gestures#flick
|
21
|
+
module Scroll
|
22
|
+
|
23
|
+
# Scrolls the first view matching `query` in `direction`.
|
24
|
+
#
|
25
|
+
# View are scrolled half of their frame size.
|
26
|
+
#
|
27
|
+
# If `query` matches a view that is not a UIScrollView or a subclass, an
|
28
|
+
# error will be raised. UITableView, MKMapView, UIWebView, WKWebView, and
|
29
|
+
# UICollectionView are all examples of subclasses of UIScrollView.
|
30
|
+
#
|
31
|
+
# An error will be raised if more than on view is matched by `query`.
|
32
|
+
#
|
33
|
+
# To avoid matching more than one UIScrollView (or subclass):
|
34
|
+
# * Make the query more specific: "UITableView marked:'table'"
|
35
|
+
# * Use the index language feature: "UIScrollView index:0"
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# scroll("UITableView", :down)
|
39
|
+
#
|
40
|
+
# @note This is implemented by calling the Objective-C
|
41
|
+
# `setContentOffset:animated:` method and can do things users cannot.
|
42
|
+
#
|
43
|
+
# This is the only alternative for `pan` and `flick` which do not work
|
44
|
+
# on iOS Simulators starting with iOS 7.
|
45
|
+
#
|
46
|
+
# @see Calabash::Gestures#pan
|
47
|
+
# @see Calabash::Gestures#flick
|
48
|
+
#
|
49
|
+
# @param [String,Query,Hash] query A query describing the view to scroll.
|
50
|
+
# @param [Symbol] direction The direction to scroll. Valid directions are:
|
51
|
+
# 'up', 'down', 'left', and 'right'
|
52
|
+
#
|
53
|
+
# @raise [ArgumentError] If direction is invalid.
|
54
|
+
# @raise [ArgumentError] If query is invalid.
|
55
|
+
# @raise [ViewNotFoundError] If query matches no views.
|
56
|
+
# @raise [RuntimeError] If query matches more than one view.
|
57
|
+
# @raise [RuntimeError] If query matches a view that is not a UIScrollView.
|
58
|
+
def scroll(query, direction)
|
59
|
+
allowed_directions = [:up, :down, :left, :right]
|
60
|
+
dir_symbol = direction.to_sym
|
61
|
+
unless allowed_directions.include?(dir_symbol)
|
62
|
+
raise ArgumentError,
|
63
|
+
"Expected '#{direction}' to be one of #{allowed_directions.join(',')}"
|
64
|
+
end
|
65
|
+
|
66
|
+
Query.ensure_valid_query(query)
|
67
|
+
|
68
|
+
begin
|
69
|
+
view_to_scroll = _wait_for_exactly_one_scroll_view(query)
|
70
|
+
rescue RuntimeError => e
|
71
|
+
raise RuntimeError, e
|
72
|
+
end
|
73
|
+
|
74
|
+
results = Device.default.map_route(query, :scroll, direction)
|
75
|
+
|
76
|
+
if results.first.nil?
|
77
|
+
fail("Expected '#{query}' to match a UIScrollView or a subclass")
|
78
|
+
end
|
79
|
+
|
80
|
+
Calabash::QueryResult.create([view_to_scroll], query)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Scroll the UITableView matching `query` to `row` in `section`.
|
84
|
+
#
|
85
|
+
# If `query` matches a view that is not a UITableView or a subclass, an
|
86
|
+
# error will be raised.
|
87
|
+
#
|
88
|
+
# An error will be raised if more than on view is matched by `query`.
|
89
|
+
#
|
90
|
+
# To avoid matching more than one UITableView (or subclass):
|
91
|
+
# * Make the query more specific: "UITableView marked:'table'"
|
92
|
+
# * Use the index language feature: "UITableView index:1"
|
93
|
+
#
|
94
|
+
# Row and section are zero indexed. The first row is row 0.
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# # Scroll to the 5th row in the first section.
|
98
|
+
# > scroll_to_row("UITableView", 5)
|
99
|
+
#
|
100
|
+
# # Scroll to the 3rd row, in the 5th section
|
101
|
+
# > scroll_to_row("UITableView", 3, 5)
|
102
|
+
#
|
103
|
+
# @note This is implement by calling the Objective-C
|
104
|
+
# `scrollToRowAtIndexPath:atScrollPosition:animated:` method and can do
|
105
|
+
# things that users cannot.
|
106
|
+
#
|
107
|
+
# This is the only alternative for `pan` and `flick` which do not work
|
108
|
+
# on iOS Simulators starting with iOS 7.
|
109
|
+
#
|
110
|
+
# @see Calabash::Gestures#pan
|
111
|
+
# @see Calabash::Gestures#flick
|
112
|
+
#
|
113
|
+
# @param [String,Query,Hash] query A query describing the table to scroll.
|
114
|
+
# @param [Numeric] row The row number to scroll to.
|
115
|
+
# @param [Numeric] section The section number to scroll to.
|
116
|
+
# @param [Hash] options Options to control the scroll behavior.
|
117
|
+
# @option options [Symbol] :scroll_position (:middle) The final position
|
118
|
+
# of the row in the view. Can be :top, :middle, :bottom
|
119
|
+
# @option options [Boolean] :animate (true) Should the scrolling be
|
120
|
+
# animated?
|
121
|
+
#
|
122
|
+
# @raise [ArgumentError] If the :scroll_position is invalid.
|
123
|
+
# @raise [ArgumentError] If the :animate key is not a Boolean.
|
124
|
+
# @raise [ArgumentError] If query is invalid.
|
125
|
+
# @raise [ViewNotFoundError] If query matches no views.
|
126
|
+
# @raise [RuntimeError] If query matches more than one view.
|
127
|
+
# @raise [RuntimeError] If query matches a view that is not a UITableView.
|
128
|
+
# @raise [RuntimeError] If the row and section are invalid for the table.
|
129
|
+
def scroll_to_row(query, row, section=0, **options)
|
130
|
+
default_options = {
|
131
|
+
:scroll_position => :middle,
|
132
|
+
:animate => true
|
133
|
+
}
|
134
|
+
|
135
|
+
merged_options = default_options.merge(options)
|
136
|
+
|
137
|
+
begin
|
138
|
+
_expect_valid_scroll_options(VALID_TABLE_SCROLL_POSITIONS, merged_options)
|
139
|
+
rescue ArgumentError => e
|
140
|
+
raise ArgumentError, e
|
141
|
+
end
|
142
|
+
|
143
|
+
Query.ensure_valid_query(query)
|
144
|
+
|
145
|
+
begin
|
146
|
+
view_to_scroll = _wait_for_exactly_one_scroll_view(query)
|
147
|
+
rescue RuntimeError => e
|
148
|
+
raise RuntimeError, e
|
149
|
+
end
|
150
|
+
|
151
|
+
position = merged_options[:scroll_position].to_sym
|
152
|
+
animate = merged_options[:animate]
|
153
|
+
|
154
|
+
results = Device.default.map_route(query, :scrollToRow, row.to_i,
|
155
|
+
section.to_i, position, animate)
|
156
|
+
|
157
|
+
if results.first.nil?
|
158
|
+
message = [
|
159
|
+
"Could not scroll table to row '#{row}' and section '#{section}'.",
|
160
|
+
"Either query '#{query}' did not match a UITableView or",
|
161
|
+
"the row '#{row}' in section '#{section}' does not exist."
|
162
|
+
].join("\n")
|
163
|
+
fail(message)
|
164
|
+
end
|
165
|
+
|
166
|
+
Calabash::QueryResult.create([view_to_scroll], query)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Scroll the UITableView matching `query` to the row with `mark`. This
|
170
|
+
# method is particularly useful when testing tables with dynamic content.
|
171
|
+
#
|
172
|
+
# An error will be raised If `query` matches a view that is not a
|
173
|
+
# UITableView or a subclass.
|
174
|
+
#
|
175
|
+
# To avoid matching more than one UITableView (or subclass):
|
176
|
+
# * Make the query more specific: "UITableView marked:'table'"
|
177
|
+
# * Use the index language feature: "UITableView index:1"
|
178
|
+
#
|
179
|
+
# The `mark` can be on any subview in a UITableViewCell or the cell
|
180
|
+
# itself. If no cell with `mark` can be found, an error will be raised.
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# > scroll_to_row_with_mark("UITableView", "apples")
|
184
|
+
#
|
185
|
+
# @note This is implement by calling the Objective-C
|
186
|
+
# `scrollToRowAtIndexPath:atScrollPosition:animated:` method and can do
|
187
|
+
# things that users cannot. The implementation generates a new cell
|
188
|
+
# for every index path in your table. This can cause performance
|
189
|
+
# issues if your table is very large.
|
190
|
+
#
|
191
|
+
# This is the only alternative for `pan` and `flick` which do not work
|
192
|
+
# on iOS Simulators starting with iOS 7.
|
193
|
+
#
|
194
|
+
# @see Calabash::Gestures#pan
|
195
|
+
# @see Calabash::Gestures#flick
|
196
|
+
#
|
197
|
+
# @param [String,Query,Hash] query A query describing the table to scroll.
|
198
|
+
# @param [String] mark The cell identifier.
|
199
|
+
# @param [Hash] options Options to control the scroll behavior.
|
200
|
+
# @option options [Symbol] :scroll_position (:middle) The final position
|
201
|
+
# of the row in the view. Can be :top, :middle, :bottom
|
202
|
+
# @option options [Boolean] :animate (true) Should the scrolling be
|
203
|
+
# animated?
|
204
|
+
#
|
205
|
+
# @raise [ArgumentError] If mark is nil or the empty string.
|
206
|
+
# @raise [ArgumentError] If the :scroll_position is invalid.
|
207
|
+
# @raise [ArgumentError] If the :animate key is not a Boolean.
|
208
|
+
# @raise [ArgumentError] If query is invalid.
|
209
|
+
# @raise [ViewNotFoundError] If query matches no views.
|
210
|
+
# @raise [RuntimeError] If query matches more than one view.
|
211
|
+
# @raise [RuntimeError] If query matches a view that is not a UITableView.
|
212
|
+
# @raise [RuntimeError] If no cell with `mark` is found.
|
213
|
+
def scroll_to_row_with_mark(query, mark, options={})
|
214
|
+
default_options = {
|
215
|
+
:scroll_position => :middle,
|
216
|
+
:animate => true
|
217
|
+
}
|
218
|
+
|
219
|
+
merged_options = default_options.merge(options)
|
220
|
+
|
221
|
+
begin
|
222
|
+
_expect_valid_scroll_options(VALID_TABLE_SCROLL_POSITIONS, merged_options)
|
223
|
+
_expect_valid_scroll_mark(mark)
|
224
|
+
rescue ArgumentError => e
|
225
|
+
raise ArgumentError, e
|
226
|
+
end
|
227
|
+
|
228
|
+
Query.ensure_valid_query(query)
|
229
|
+
|
230
|
+
begin
|
231
|
+
view_to_scroll = _wait_for_exactly_one_scroll_view(query)
|
232
|
+
rescue RuntimeError => e
|
233
|
+
raise RuntimeError e
|
234
|
+
end
|
235
|
+
|
236
|
+
position = merged_options[:scroll_position].to_sym
|
237
|
+
animate = merged_options[:animate]
|
238
|
+
|
239
|
+
results = Device.default.map_route(query, :scrollToRowWithMark, mark,
|
240
|
+
position, animate)
|
241
|
+
|
242
|
+
if results.first.nil?
|
243
|
+
message = [
|
244
|
+
"Could not scroll table to row with mark: '#{mark}'",
|
245
|
+
"Either the '#{query}' did not match a UITableView or",
|
246
|
+
"there is no cell with mark '#{mark}'."
|
247
|
+
].join("\n")
|
248
|
+
fail(message)
|
249
|
+
end
|
250
|
+
|
251
|
+
Calabash::QueryResult.create([view_to_scroll], query)
|
252
|
+
end
|
253
|
+
|
254
|
+
# Scrolls the UICollectionView matching `query` to `item` in `section`.
|
255
|
+
#
|
256
|
+
# If `query` matches a view that is not a UICollectionView or a subclass,
|
257
|
+
# an error will be raised.
|
258
|
+
#
|
259
|
+
# An error will be raised if more than on view is matched by `query`.
|
260
|
+
#
|
261
|
+
# To avoid matching more than one UICollectionView (or subclass):
|
262
|
+
# * Make the query more specific: "UICollectionView marked:'gallery'"
|
263
|
+
# * Use the index language feature: "UICollectionView index:1"
|
264
|
+
#
|
265
|
+
#
|
266
|
+
# Item and section are zero indexed. The first item is 0.
|
267
|
+
#
|
268
|
+
# @example
|
269
|
+
# # Scroll to the 5th item in the first section.
|
270
|
+
# > scroll_to_item("UICollectionView", 5)
|
271
|
+
#
|
272
|
+
# # Scroll to the 3rd row, in the 5th section
|
273
|
+
# > scroll_to_item("UICollectionView", 3, 5)
|
274
|
+
#
|
275
|
+
# @example The following are the allowed :scroll_position values.
|
276
|
+
# :top, :center_vertical, :bottom, :left, :center_horizontal, :right
|
277
|
+
#
|
278
|
+
# @note This is implement by calling the Objective-C
|
279
|
+
# `scrollToItemAtIndexPath:atScrollPosition:animated:` method and can do
|
280
|
+
# things that users cannot.
|
281
|
+
#
|
282
|
+
# This is the only alternative for `pan` and `flick` which do not work
|
283
|
+
# on iOS Simulators starting with iOS 7.
|
284
|
+
#
|
285
|
+
# @see Calabash::Gestures#pan
|
286
|
+
# @see Calabash::Gestures#flick
|
287
|
+
#
|
288
|
+
# @param [String,Query,Hash] query A query describing the table to scroll.
|
289
|
+
# @param [Numeric] item The item number to scroll to.
|
290
|
+
# @param [Numeric] section The section number to scroll to.
|
291
|
+
# @param [Hash] options Options to control the scroll behavior.
|
292
|
+
# @option options [Symbol] :scroll_position (:top) The final position
|
293
|
+
# of the row in the view. See the examples for valid positions.
|
294
|
+
# @option options [Boolean] :animate (true) Should the scrolling be
|
295
|
+
# animated?
|
296
|
+
#
|
297
|
+
# @raise [ArgumentError] If the :scroll_position is invalid.
|
298
|
+
# @raise [ArgumentError] If the :animate key is not a Boolean.
|
299
|
+
# @raise [ArgumentError] If query is invalid.
|
300
|
+
# @raise [ViewNotFoundError] If query matches no views.
|
301
|
+
# @raise [RuntimeError] If query matches more than one view.
|
302
|
+
# @raise [RuntimeError] If query matches a view that is not a
|
303
|
+
# UICollectionView.
|
304
|
+
# @raise [RuntimeError] If the item and section are not valid for
|
305
|
+
# the collection.
|
306
|
+
def scroll_to_item(query, item, section=0, **options)
|
307
|
+
default_options = {
|
308
|
+
:scroll_position => :top,
|
309
|
+
:animate => true
|
310
|
+
}
|
311
|
+
|
312
|
+
merged_options = default_options.merge(options)
|
313
|
+
|
314
|
+
begin
|
315
|
+
_expect_valid_scroll_options(VALID_COLLECTION_SCROLL_POSITIONS, merged_options)
|
316
|
+
rescue ArgumentError => e
|
317
|
+
raise ArgumentError, e
|
318
|
+
end
|
319
|
+
|
320
|
+
Query.ensure_valid_query(query)
|
321
|
+
|
322
|
+
begin
|
323
|
+
view_to_scroll = _wait_for_exactly_one_scroll_view(query)
|
324
|
+
rescue RuntimeError => e
|
325
|
+
raise RuntimeError e
|
326
|
+
end
|
327
|
+
|
328
|
+
position = merged_options[:scroll_position].to_sym
|
329
|
+
animate = merged_options[:animate]
|
330
|
+
|
331
|
+
results = Device.default.map_route(query, :collectionViewScroll,
|
332
|
+
item.to_i, section.to_i,
|
333
|
+
position, animate)
|
334
|
+
if results.first.nil?
|
335
|
+
message = [
|
336
|
+
"Could not scroll collection to item '#{item}' and section '#{section}'.",
|
337
|
+
"Either query '#{query}' did not match a UICollectionView or",
|
338
|
+
"the item '#{item}' in section '#{section}' does not exist."
|
339
|
+
].join("\n")
|
340
|
+
fail(message)
|
341
|
+
end
|
342
|
+
|
343
|
+
Calabash::QueryResult.create([view_to_scroll], query)
|
344
|
+
end
|
345
|
+
|
346
|
+
# Scroll the UICollectionView matching `query` to the row with `mark`.
|
347
|
+
# This method is particularly useful when testing collections with dynamic
|
348
|
+
# content.
|
349
|
+
#
|
350
|
+
# An error will be raised If `query` matches a view that is not a
|
351
|
+
# UICollectionView or a subclass.
|
352
|
+
#
|
353
|
+
# To avoid matching more than one UICollectionView (or subclass):
|
354
|
+
# * Make the query more specific: "UICollectionView marked:'gallery'"
|
355
|
+
# * Use the index language feature: "UICollectionView index:1"
|
356
|
+
#
|
357
|
+
# The `mark` can be on any subview in a UICollectionViewCell or the cell
|
358
|
+
# itself. If no cell with `mark` can be found, an error will be raised.
|
359
|
+
#
|
360
|
+
# @example
|
361
|
+
# > scroll_to_item_with_mark("UICollectionView", "mom")
|
362
|
+
#
|
363
|
+
# @example The following are the allowed :scroll_position values.
|
364
|
+
# :top, :center_vertical, :bottom, :left, :center_horizontal, :right
|
365
|
+
#
|
366
|
+
# @note This is implement by calling the Objective-C
|
367
|
+
# `scrollToRowAtIndexPath:atScrollPosition:animated:` method and can do
|
368
|
+
# things that users cannot. The implementation generates a new item
|
369
|
+
# for every index path in your collection. This can cause performance
|
370
|
+
# issues if your collection is very large.
|
371
|
+
#
|
372
|
+
# This is the only alternative for `pan` and `flick` which do not work
|
373
|
+
# on iOS Simulators starting with iOS 7.
|
374
|
+
#
|
375
|
+
# @see Calabash::Gestures#pan
|
376
|
+
# @see Calabash::Gestures#flick
|
377
|
+
#
|
378
|
+
# @param [String,Query,Hash] query A query describing the collection to
|
379
|
+
# scroll.
|
380
|
+
# @param [String] mark The cell identifier.
|
381
|
+
# @param [Hash] options Options to control the scroll behavior.
|
382
|
+
# @option options [Symbol] :scroll_position (:top) The final position
|
383
|
+
# of the row in the view. See the examples for valid positions.
|
384
|
+
# @option options [Boolean] :animate (true) Should the scrolling be
|
385
|
+
# animated?
|
386
|
+
#
|
387
|
+
# @raise [ArgumentError] If mark is nil or the empty string.
|
388
|
+
# @raise [ArgumentError] If the :scroll_position is invalid.
|
389
|
+
# @raise [ArgumentError] If the :animate key is not a Boolean.
|
390
|
+
# @raise [ArgumentError] If query is invalid.
|
391
|
+
# @raise [ViewNotFoundError] If query matches no views.
|
392
|
+
# @raise [RuntimeError] If query matches more than one view.
|
393
|
+
# @raise [RuntimeError] If query matches a view that is not a
|
394
|
+
# UICollectionView.
|
395
|
+
# @raise [RuntimeError] If no item with `mark` is found.
|
396
|
+
def scroll_to_item_with_mark(query, mark, options={})
|
397
|
+
default_options = {
|
398
|
+
:scroll_position => :top,
|
399
|
+
:animate => true,
|
400
|
+
}
|
401
|
+
|
402
|
+
merged_options = default_options.merge(options)
|
403
|
+
|
404
|
+
begin
|
405
|
+
_expect_valid_scroll_options(VALID_COLLECTION_SCROLL_POSITIONS, merged_options)
|
406
|
+
_expect_valid_scroll_mark(mark)
|
407
|
+
rescue ArgumentError => e
|
408
|
+
raise ArgumentError, e
|
409
|
+
end
|
410
|
+
|
411
|
+
Query.ensure_valid_query(query)
|
412
|
+
|
413
|
+
begin
|
414
|
+
view_to_scroll = _wait_for_exactly_one_scroll_view(query)
|
415
|
+
rescue RuntimeError => e
|
416
|
+
raise RuntimeError e
|
417
|
+
end
|
418
|
+
|
419
|
+
position = merged_options[:scroll_position].to_sym
|
420
|
+
animate = merged_options[:animate]
|
421
|
+
|
422
|
+
results = Device.default.map_route(query,
|
423
|
+
:collectionViewScrollToItemWithMark,
|
424
|
+
mark, position, animate)
|
425
|
+
|
426
|
+
if results.first.nil?
|
427
|
+
message = [
|
428
|
+
"Could not scroll collection to item with mark: '#{mark}'",
|
429
|
+
"Either the '#{query}' did not match a UICollectionView or",
|
430
|
+
"there is no item with mark '#{mark}'."
|
431
|
+
].join("\n")
|
432
|
+
fail(message)
|
433
|
+
end
|
434
|
+
|
435
|
+
Calabash::QueryResult.create([view_to_scroll], query)
|
436
|
+
end
|
437
|
+
|
438
|
+
private
|
439
|
+
|
440
|
+
# !@visibility private
|
441
|
+
VALID_TABLE_SCROLL_POSITIONS = [:top, :middle, :bottom]
|
442
|
+
|
443
|
+
# !@visibility private
|
444
|
+
VALID_COLLECTION_SCROLL_POSITIONS = [:top, :center_vertical, :bottom,
|
445
|
+
:left, :center_horizontal, :right]
|
446
|
+
|
447
|
+
# !@visibility private
|
448
|
+
def _wait_for_exactly_one_scroll_view(query)
|
449
|
+
|
450
|
+
results = []
|
451
|
+
|
452
|
+
found_none = "Expected '#{query}' to match exactly one view, but found no matches."
|
453
|
+
query_object = Query.new(query)
|
454
|
+
wait_for(found_none) do
|
455
|
+
results = query(query_object)
|
456
|
+
if results.length > 1
|
457
|
+
message = [
|
458
|
+
"Expected '#{query}' to match exactly one view, but found '#{results.length}'",
|
459
|
+
results.join("\n")
|
460
|
+
].join("\n")
|
461
|
+
fail(message)
|
462
|
+
else
|
463
|
+
results.length == 1
|
464
|
+
end
|
465
|
+
end
|
466
|
+
results.first
|
467
|
+
end
|
468
|
+
|
469
|
+
# !@visibility private
|
470
|
+
def _expect_valid_scroll_positions(valid_positions, position)
|
471
|
+
unless valid_positions.include?(position.to_sym)
|
472
|
+
raise ArgumentError,
|
473
|
+
"Expected '#{position}' to be one of #{valid_positions.join(', ')}"
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
# !@visibility private
|
478
|
+
def _expect_valid_scroll_animate(animate)
|
479
|
+
unless [true, false].include?(animate)
|
480
|
+
raise ArgumentError,
|
481
|
+
"Expected '#{animate}' to be a Boolean true or false"
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# !@visibility private
|
486
|
+
def _expect_valid_scroll_options(valid_positions, options)
|
487
|
+
_expect_valid_scroll_positions(valid_positions, options[:scroll_position])
|
488
|
+
_expect_valid_scroll_animate(options[:animate])
|
489
|
+
end
|
490
|
+
|
491
|
+
# !@visibility private
|
492
|
+
def _expect_valid_scroll_mark(mark)
|
493
|
+
if mark.nil? || mark == ''
|
494
|
+
raise ArgumentError,
|
495
|
+
if mark.nil?
|
496
|
+
'Mark cannot be nil.'
|
497
|
+
else
|
498
|
+
'Mark cannot be an empty string.'
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|