/
calabash_steps.rb
435 lines (364 loc) · 13.2 KB
/
calabash_steps.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
WAIT_TIMEOUT = (ENV['WAIT_TIMEOUT'] || 30).to_f
STEP_PAUSE = (ENV['STEP_PAUSE'] || 0.5).to_f
Given /^(my|the) app is running$/ do |_|
# no-op exists for backwards compatibility
end
### Touch ###
Then /^I (?:press|touch) on screen (\d+) from the left and (\d+) from the top$/ do |x, y|
touch(nil, { offset: { x: x.to_i, y: y.to_i } })
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) "([^\"]*)"$/ do |name|
touch("view marked: '#{name}'")
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) (\d+)% right and (\d+)% down from "([^\"]*)"$/ do |x, y, name|
raise 'This step is not yet implemented on iOS'
end
Then /^I (?:press|touch) button number (\d+)$/ do |index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
touch("button index: #{index - 1}")
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) the "([^\"]*)" button$/ do |name|
touch("button marked: '#{name}'")
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) (?:input|text) field number (\d+)$/ do |index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
touch("textField index: #{index - 1}")
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) the "([^\"]*)" (?:input|text) field$/ do |name|
placeholder_query = "textField placeholder: '#{name}'"
marked_query = "textField marked: '#{name}'"
if !query(placeholder_query).empty?
touch(placeholder_query)
elsif !query(marked_query).empty?
touch(marked_query)
else
screenshot_and_raise "Could not find text field with placeholder '#{name}' or marked as '#{name}'"
end
sleep(STEP_PAUSE)
end
# Note in tables views: this means visible cell index!
Then /^I (?:press|touch) list item number (\d+)$/ do |index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
touch("tableViewCell index: #{index - 1}")
sleep(STEP_PAUSE)
end
Then /^I (?:press|touch) list item "([^\"]*)"$/ do |cell_name|
if query("tableViewCell marked: '#{cell_name}'").empty?
touch("tableViewCell text: '#{cell_name}'")
else
touch("tableViewCell marked: '#{cell_name}'")
end
sleep(STEP_PAUSE)
end
Then /^I toggle the switch$/ do
touch('switch')
sleep(STEP_PAUSE)
end
Then /^I toggle the "([^\"]*)" switch$/ do |name|
touch("switch marked: '#{name}'")
sleep(STEP_PAUSE)
end
Then /^I touch (?:the)? user location$/ do
touch("view: 'MKUserLocationView'")
sleep(STEP_PAUSE)
end
Then /^I (?:touch|press) (?:done|search)$/ do
tap_keyboard_action_key
sleep(STEP_PAUSE)
end
### Entering text ###
Then /^I enter "([^\"]*)" into the "([^\"]*)" field$/ do |text_to_type, field_name|
touch("textField marked: '#{field_name}'")
wait_for_keyboard
keyboard_enter_text text_to_type
sleep(STEP_PAUSE)
end
Then /^I enter "([^\"]*)" into the "([^\"]*)" (?:text|input) field$/ do |text_to_type, field_name|
touch("textField marked: '#{field_name}'")
wait_for_keyboard
keyboard_enter_text text_to_type
sleep(STEP_PAUSE)
end
# Alias
Then /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |text_field, text_to_type|
macro %(I enter "#{text_to_type}" into the "#{text_field}" text field)
end
Then /^I use the native keyboard to enter "([^\"]*)" into the "([^\"]*)" (?:text|input) field$/ do |text_to_type, field_name|
macro %(I touch the "#{field_name}" text field)
wait_for_keyboard
keyboard_enter_text(text_to_type)
sleep(STEP_PAUSE)
end
Then /^I fill in text fields as follows:$/ do |table|
table.hashes.each do |row|
macro %(I enter "#{row['text']}" into the "#{row['field']}" text field)
end
end
Then /^I enter "([^\"]*)" into (?:input|text) field number (\d+)$/ do |text, index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
touch("textField index: #{index - 1}")
wait_for_keyboard
keyboard_enter_text text
sleep(STEP_PAUSE)
end
Then /^I use the native keyboard to enter "([^\"]*)" into (?:input|text) field number (\d+)$/ do |text_to_type, index|
macro %(I touch text field number #{index})
wait_for_keyboard
keyboard_enter_text(text_to_type)
sleep(STEP_PAUSE)
end
Then /^I clear (?:input|text) field number (\d+)$/ do |index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
clear_text("textField index: #{index - 1}")
end
### See ###
Then /^I wait to see "([^\"]*)"$/ do |expected_mark|
wait_for(WAIT_TIMEOUT) { view_with_mark_exists(expected_mark) }
end
Then /^I wait until I don't see "([^\"]*)"$/ do |expected_mark|
sleep 1 # wait for previous screen to disappear
wait_for(WAIT_TIMEOUT) { !element_exists("view marked: '#{expected_mark}'") }
end
Then /^I wait to not see "([^\"]*)"$/ do |expected_mark|
macro %(I wait until I don't see "#{expected_mark}")
end
Then /^I wait for "([^\"]*)" to appear$/ do |name|
macro %(I wait to see "#{name}")
end
Then /^I wait for the "([^\"]*)" button to appear$/ do |name|
wait_for(WAIT_TIMEOUT) { element_exists("button marked: '#{name}'") }
end
Then /^I wait to see a navigation bar titled "([^\"]*)"$/ do |expected_mark|
msg = "Waited for '#{WAIT_TIMEOUT}' seconds but did not see the navbar with title '#{expected_mark}'"
wait_for(timeout: WAIT_TIMEOUT, timeout_message: msg ) do
all_items = query("navigationItemView marked: '#{expected_mark}'")
button_items = query('navigationItemButtonView')
non_button_items = all_items.delete_if { |item| button_items.include?(item) }
!non_button_items.empty?
end
end
Then /^I wait for the "([^\"]*)" (?:input|text) field$/ do |placeholder_or_view_mark|
wait_for(WAIT_TIMEOUT) do
element_exists("textField placeholder: '#{placeholder_or_view_mark}'") ||
element_exists("textField marked: '#{placeholder_or_view_mark}'")
end
end
Then /^I wait for (\d+) (?:input|text) field(?:s)?$/ do |count|
wait_for(WAIT_TIMEOUT) { query(:textField).count >= count.to_i }
end
Then /^I wait$/ do
sleep 2
end
Then /^I wait and wait$/ do
sleep 4
end
Then /^I wait and wait and wait...$/ do
sleep 10
end
When /^I wait for ([\d\.]+) second(?:s)?$/ do |num_seconds|
sleep num_seconds.to_f
end
Then /^I go back$/ do
touch('navigationItemButtonView first')
sleep(STEP_PAUSE)
end
Then /^(?:I\s)?take (?:picture|screenshot)$/ do
sleep(STEP_PAUSE)
screenshot_embed
end
Then /^I swipe (left|right|up|down)$/ do |dir|
swipe(dir)
sleep(STEP_PAUSE)
end
Then /^I swipe (left|right|up|down) on number (\d+)$/ do |dir, index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
swipe(dir, { query: "scrollView index: #{index - 1}" })
sleep(STEP_PAUSE)
end
Then /^I swipe (left|right|up|down) on number (\d+) at x (\d+) and y (\d+)$/ do |dir, index, x, y|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
swipe(dir, { offset: { x: x.to_i, y: y.to_i }, query: "scrollView index: #{index - 1}" })
sleep(STEP_PAUSE)
end
Then /^I swipe (left|right|up|down) on "([^\"]*)"$/ do |dir, mark|
swipe(dir, { query: "view marked: '#{mark}'" })
sleep(STEP_PAUSE)
end
Then /^I swipe on cell number (\d+)$/ do |index|
index = index.to_i
screenshot_and_raise("Index should be positive (was: #{index})") if index <= 0
cell_swipe({ query: "tableViewCell index: #{index - 1}" })
sleep(STEP_PAUSE)
end
### Pinch ###
Then /^I pinch to zoom (in|out)$/ do |in_out|
pinch(in_out)
sleep(STEP_PAUSE)
end
Then /^I pinch to zoom (in|out) on "([^\"]*)"$/ do |in_out, name|
pinch(in_out, { query: "view marked: '#{name}'" })
sleep(STEP_PAUSE)
end
# Note "up/left/right" seems to be missing on the web base
Then /^I scroll (left|right|up|down)$/ do |dir|
scroll('scrollView index: 0', dir)
sleep(STEP_PAUSE)
end
Then /^I scroll (left|right|up|down) on "([^\"]*)"$/ do |dir, name|
scroll("view marked: '#{name}'", dir)
sleep(STEP_PAUSE)
end
### Playback ###
Then /^I playback recording "([^\"]*)"$/ do |filename|
playback(filename)
sleep(STEP_PAUSE)
end
Then /^I playback recording "([^\"]*)" on "([^\"]*)"$/ do |filename, name|
playback(filename, { query: "view marked: '#{name}'" })
sleep(STEP_PAUSE)
end
Then /^I playback recording "([^\"]*)" on "([^\"]*)" with offset (\d+),(\d+)$/ do |filename, name, x, y|
playback(filename, { query: "view marked:'#{name}'", offset: { x: x.to_i, y: y.to_i } })
sleep(STEP_PAUSE)
end
Then /^I reverse playback recording "([^\"]*)"$/ do |filename|
playback(filename, { reverse: true })
sleep(STEP_PAUSE)
end
Then /^I reverse playback recording "([^\"]*)" on "([^\"]*)"$/ do |filename, name|
playback(filename, { query: "view marked: '#{name}'", reverse: true })
sleep(STEP_PAUSE)
end
Then /^I reverse playback recording "([^\"]*)" on "([^\"]*)" with offset (\d+),(\d+)$/ do |filename, name, x, y|
playback(filename, { query: "view marked: '#{name}'", offset: { x: x.to_i, y: y.to_i }, reverse: true })
sleep(STEP_PAUSE)
end
### Device orientation ###
Then /^I rotate device (left|right)$/ do |dir|
rotate(dir.to_sym)
sleep 5 # Servo wait
end
Then /^I send app to background for (\d+) seconds$/ do |secs|
secs = secs.to_f
send_app_to_background(secs)
sleep(secs + 10)
end
### Assertions ###
Then /^I should see "([^\"]*)"$/ do |expected_mark|
until element_exists("view marked:'#{expected_mark}'") ||
element_exists("view text:'#{expected_mark}'")
screenshot_and_raise "No element found with mark or text: #{expected_mark}"
end
end
Then /^I should not see "([^\"]*)"$/ do |expected_mark|
res = query("view marked: '#{expected_mark}'")
res.concat query("view text: '#{expected_mark}'")
unless res.empty?
screenshot_and_raise "Expected no element with text nor accessibilityLabel: #{expected_mark}, found #{res.join(', ')}"
end
end
Then /^I should see a "([^\"]*)" button$/ do |expected_mark|
check_element_exists("button marked: '#{expected_mark}'")
end
Then /^I should not see a "([^\"]*)" button$/ do |expected_mark|
check_element_does_not_exist("button marked: '#{expected_mark}'")
end
Then /^I don't see the text "([^\"]*)"$/ do |text|
macro %(I should not see "#{text}")
end
Then /^I don't see the "([^\"]*)"$/ do |text|
macro %(I should not see "#{text}")
end
Then /^I see the text "([^\"]*)"$/ do |text|
macro %(I should see "#{text}")
end
Then /^I see the "([^\"]*)"$/ do |text|
macro %(I should see "#{text}")
end
Then /^I (?:should)? see text starting with "([^\"]*)"$/ do |text|
if query("view {text BEGINSWITH '#{text}'}").empty?
screenshot_and_raise "No text found starting with: #{text}"
end
end
Then /^I (?:should)? see text containing "([^\"]*)"$/ do |text|
if query("view {text LIKE '*#{text}*'}").empty?
screenshot_and_raise "No text found containing: #{text}"
end
end
Then /^I (?:should)? see text ending with "([^\"]*)"$/ do |text|
if query("view {text ENDSWITH '#{text}'}").empty?
screenshot_and_raise "No text found ending with: #{text}"
end
end
Then /^I see (\d+) (?:input|text) field(?:s)?$/ do |count|
cnt = query(:textField).count
if cnt < count.to_i
screenshot_and_raise "Expected at least #{count} text/input fields, found #{cnt}"
end
end
Then /^I should see a "([^\"]*)" (?:input|text) field$/ do |expected_mark|
unless element_exists("textField placeholder: '#{expected_mark}'") ||
element_exists("textField marked: '#{expected_mark}'")
screenshot_and_raise "Expected textfield with placeholder or accessibilityLabel: #{expected_mark}"
end
end
Then /^I should not see a "([^\"]*)" (?:input|text) field$/ do |expected_mark|
res = query("textField placeholder: '#{expected_mark}'")
res.concat query("textField marked: '#{expected_mark}'")
unless res.empty?
screenshot_and_raise "Expected no textfield with placeholder nor accessibilityLabel: #{expected_mark}, found #{res}"
end
end
Then /^I should see a map$/ do
check_element_exists("view: 'MKMapView'")
end
Then /^I should see (?:the)? user location$/ do
check_element_exists("view: 'MKUserLocationView'")
end
### Date Picker ###
# time_str can be in any format that Time can parse
Then(/^I change the date picker time to "([^"]*)"$/) do |time_str|
target_time = Time.parse(time_str)
current_date = date_time_from_picker
current_date = DateTime.new(current_date.year,
current_date.mon,
current_date.day,
target_time.hour,
target_time.min,
0,
target_time.gmt_offset)
picker_set_date_time current_date
sleep(STEP_PAUSE)
end
# date_str can be in any format that Date can parse
Then(/^I change the date picker date to "([^"]*)"$/) do |date_str|
target_date = Date.parse(date_str)
current_time = date_time_from_picker
date_time = DateTime.new(target_date.year,
target_date.mon,
target_date.day,
current_time.hour,
current_time.min,
0,
Time.now.sec,
current_time.offset)
picker_set_date_time date_time
sleep(STEP_PAUSE)
end
# date_str can be in any format that Date can parse
Then(/^I change the date picker date to "([^"]*)" at "([^"]*)"$/) do |date_str, time_str|
macro %(I change the date picker time to "#{time_str}")
macro %(I change the date picker date to "#{date_str}")
end