calabash-cucumber 0.9.74 → 0.9.80.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ module Calabash
10
10
  DERIVED_DATA = File.expand_path("~/Library/Developer/Xcode/DerivedData")
11
11
  DEFAULT_DERIVED_DATA_INFO = File.expand_path("#{DERIVED_DATA}/*/info.plist")
12
12
 
13
- DEFAULT_SIM_WAIT = "15"
13
+ DEFAULT_SIM_WAIT = 15
14
14
 
15
15
  MAX_PING_ATTEMPTS = 5
16
16
 
@@ -149,36 +149,29 @@ module Calabash
149
149
  end
150
150
 
151
151
  def self.find_preferred_dir(sim_dirs)
152
-
153
- pref = sim_dirs.find do |d|
152
+ sim_dirs.find do |d|
154
153
  out = `otool "#{File.expand_path(d)}"/* -o 2> /dev/null | grep CalabashServer`
155
154
  /CalabashServer/.match(out)
156
155
  end
157
-
158
- if pref.nil?
159
- pref = sim_dirs.find {|d| /Calabash-iphonesimulator/.match(d)}
160
- end
161
- pref
162
156
  end
163
157
 
164
158
  def self.ensure_connectivity(app_bundle_path, sdk, version)
165
159
  begin
166
160
  timeout = (ENV['CONNECT_TIMEOUT'] || DEFAULT_SIM_WAIT).to_i
161
+ max_ping = (ENV['MAX_PING_ATTEMPTS'] || MAX_PING_ATTEMPTS).to_i
167
162
  Timeout::timeout(timeout) do
168
163
  connected = false
169
164
  until connected
170
165
  simulator = launch(app_bundle_path, sdk, version)
171
166
  num_pings = 0
172
- until connected or (num_pings == MAX_PING_ATTEMPTS)
167
+ until connected or (num_pings == max_ping)
173
168
  begin
174
169
  connected = (ping_app == '405')
175
170
  rescue Exception => e
176
- if (num_pings > 2) then p e end
171
+ p e if num_pings > 2
177
172
  ensure
178
173
  num_pings += 1
179
- unless connected
180
- sleep 1
181
- end
174
+ sleep 1 unless connected
182
175
  end
183
176
  end
184
177
  end
@@ -209,13 +202,12 @@ module Calabash
209
202
  status = res.code
210
203
  begin
211
204
  http.finish if http and http.started?
212
- rescue Exception => e
213
- puts "Finish #{e}"
205
+ rescue
206
+
214
207
  end
215
208
  status
216
209
  end
217
210
  end
218
211
 
219
-
220
212
  end
221
213
  end
@@ -1,5 +1,13 @@
1
- require 'net/http/persistent'
1
+ require 'calabash-cucumber/core'
2
+ require 'calabash-cucumber/tests_helpers'
3
+ require 'calabash-cucumber/keyboard_helpers'
4
+ require 'calabash-cucumber/wait_helpers'
5
+ require 'net/http'
6
+ require 'test/unit/assertions'
2
7
  require 'json'
8
+ require 'set'
9
+ require 'calabash-cucumber/version'
10
+
3
11
 
4
12
  if not Object.const_defined?(:CALABASH_COUNT)
5
13
  #compatability with IRB
@@ -9,22 +17,13 @@ end
9
17
 
10
18
  module Calabash
11
19
  module Cucumber
12
-
13
20
  module Operations
21
+ include Test::Unit::Assertions
22
+ include Calabash::Cucumber::Core
23
+ include Calabash::Cucumber::TestsHelpers
24
+ include Calabash::Cucumber::WaitHelpers
25
+ include Calabash::Cucumber::KeyboardHelpers
14
26
 
15
- DATA_PATH = File.expand_path(File.dirname(__FILE__))
16
-
17
- KEYBOARD_SMALL_LETTERS = "Keyboard_Small-Letters"
18
- KEYBOARD_CAPITAL_LETTERS = "Keyboard_Capital-Letters"
19
- KEYBOARD_NUMBERS_AND_PUNCTUATION = "Keyboard_Numbers-And-Punctuation"
20
-
21
- def macro(txt)
22
- if self.respond_to? :step
23
- step(txt)
24
- else
25
- Then txt
26
- end
27
- end
28
27
 
29
28
  def home_direction
30
29
  @current_rotation = @current_rotation || :down
@@ -40,57 +39,12 @@ module Calabash
40
39
  str.gsub("'", "\\\\'")
41
40
  end
42
41
 
43
- def wait_for(timeout, &block)
44
- begin
45
- Timeout::timeout(timeout) do
46
- until block.call
47
- sleep 0.3
48
- end
49
- end
50
- rescue Exception => e
51
- screenshot_and_raise e
52
- end
53
- end
54
-
55
- def wait_ready(timeout, times=2, sleep=0.3, &block)
56
- raise "Times parameter must be greater than or equal 2" if times < 2
57
- raise "Sleep parameter must be greater than 0" if sleep <= 0
58
- begin
59
- Timeout::timeout(timeout) do
60
- while times > 0 do
61
- if block.call
62
- times -= 1
63
- end
64
- sleep 0.3
65
- end
66
- end
67
- rescue Exception => e
68
- screenshot_and_raise e
69
- end
70
- end
71
-
72
- def query(uiquery, *args)
73
- map(uiquery, :query, *args)
74
- end
75
42
 
76
43
  def label(uiquery)
77
44
  query(uiquery, :accessibilityLabel)
78
45
  end
79
46
 
80
- def screenshot_and_raise(msg)
81
- screenshot
82
- sleep 5
83
- raise(msg)
84
- end
85
47
 
86
- def touch(uiquery, options={})
87
- options[:query] = uiquery
88
- views_touched = playback("touch", options)
89
- unless uiquery.nil?
90
- screenshot_and_raise "could not find view to touch: '#{uiquery}', args: #{options}" if views_touched.empty?
91
- end
92
- views_touched
93
- end
94
48
 
95
49
  def simple_touch(label, *args)
96
50
  touch("view marked:'#{label}'", *args)
@@ -104,10 +58,6 @@ module Calabash
104
58
  query(q).map { |e| e['html'] }
105
59
  end
106
60
 
107
- def ok
108
- touch("view marked:'ok'")
109
- end
110
-
111
61
  def set_text(uiquery, txt)
112
62
  text_fields_modified = map(uiquery, :setText, txt)
113
63
  screenshot_and_raise "could not find text field #{uiquery}" if text_fields_modified.empty?
@@ -115,294 +65,6 @@ module Calabash
115
65
  end
116
66
 
117
67
 
118
- def swipe(dir, options={})
119
- dir = dir.to_sym
120
- @current_rotation = @current_rotation || :down
121
- if @current_rotation == :left
122
- case dir
123
- when :left then
124
- dir = :down
125
- when :right then
126
- dir = :up
127
- when :up then
128
- dir = :left
129
- when :down then
130
- dir = :right
131
- else
132
- end
133
- end
134
- if @current_rotation == :right
135
- case dir
136
- when :left then
137
- dir = :up
138
- when :right then
139
- dir = :down
140
- when :up then
141
- dir = :right
142
- when :down then
143
- dir = :left
144
- else
145
- end
146
- end
147
- if @current_rotation == :up
148
- case dir
149
- when :left then
150
- dir = :right
151
- when :right then
152
- dir = :left
153
- when :up then
154
- dir = :down
155
- when :down then
156
- dir = :up
157
- else
158
- end
159
- end
160
- playback("swipe_#{dir}", options)
161
- end
162
-
163
- def cell_swipe(options={})
164
- playback("cell_swipe", options)
165
- end
166
-
167
- def done
168
- map(nil, :keyboard, load_playback_data("touch_done"))
169
- end
170
-
171
- #Possible values
172
- # 'Dictation'
173
- # 'Shift'
174
- # 'Delete'
175
- # 'International'
176
- # 'More'
177
- def keyboard_enter_char(chr)
178
- map(nil, :keyboard, load_playback_data("touch_done"), chr)
179
- end
180
-
181
- def keyboard_change_keyplane(plane)
182
- desc = query("view:'UIKBKeyplaneView'", "keyplane", "description")
183
- return nil if desc.empty?
184
- desc = desc.first
185
- plane_exp = Regexp.new(plane)
186
- if not plane_exp.match(desc)
187
- keyboard_enter_char "Shift"
188
- sleep(0.3)
189
- desc = query("view:'UIKBKeyplaneView'", "keyplane", "description").first
190
- if not plane_exp.match(desc)
191
- keyboard_enter_char "Shift"
192
- sleep(0.3)
193
- return nil
194
- end
195
- end
196
- desc
197
- end
198
-
199
- #TODO only letters now
200
- def keyboard_enter_text(text)
201
- text.each_char do |ch|
202
- if /[a-z]/.match(ch)
203
- keyboard_change_keyplane(KEYBOARD_SMALL_LETTERS)
204
- elsif /\d/.match(ch)
205
- #Todo - handle digits and special chars
206
- raise "Digits and special chars not handled by keyboard_enter_text yet."
207
- else
208
- keyboard_change_keyplane(KEYBOARD_CAPITAL_LETTERS)
209
- end
210
- keyboard_enter_char(ch)
211
- sleep(0.3)
212
- end
213
- end
214
-
215
-
216
- def scroll(uiquery, direction)
217
- views_touched=map(uiquery, :scroll, direction)
218
- screenshot_and_raise "could not find view to scroll: '#{uiquery}', args: #{direction}" if views_touched.empty?
219
- views_touched
220
- end
221
-
222
- def scroll_to_row(uiquery, number)
223
- views_touched=map(uiquery, :scrollToRow, number)
224
- if views_touched.empty? or views_touched.member? "<VOID>"
225
- screenshot_and_raise "Unable to scroll: '#{uiquery}' to: #{number}"
226
- end
227
- views_touched
228
- end
229
-
230
- def pinch(in_out, options={})
231
- file = "pinch_in"
232
- if in_out.to_sym==:out
233
- file = "pinch_out"
234
- end
235
- playback(file, options)
236
- end
237
-
238
- def rotate(dir)
239
- @current_rotation = @current_rotation || :down
240
- rotate_cmd = nil
241
- case dir
242
- when :left then
243
- if @current_rotation == :down
244
- rotate_cmd = "left_home_down"
245
- @current_rotation = :right
246
- elsif @current_rotation == :right
247
- rotate_cmd = "left_home_right"
248
- @current_rotation = :up
249
- elsif @current_rotation == :left
250
- rotate_cmd = "left_home_left"
251
- @current_rotation = :down
252
- elsif @current_rotation == :up
253
- rotate_cmd = "left_home_up"
254
- @current_rotation = :left
255
- end
256
- when :right then
257
- if @current_rotation == :down
258
- rotate_cmd = "right_home_down"
259
- @current_rotation = :left
260
- elsif @current_rotation == :left
261
- rotate_cmd = "right_home_left"
262
- @current_rotation = :up
263
- elsif @current_rotation == :right
264
- rotate_cmd = "right_home_right"
265
- @current_rotation = :down
266
- elsif @current_rotation == :up
267
- rotate_cmd = "right_home_up"
268
- @current_rotation = :right
269
- end
270
- end
271
-
272
- if rotate_cmd.nil?
273
- screenshot_and_raise "Does not support rotating #{dir} when home button is pointing #{@current_rotation}"
274
- end
275
- playback("rotate_#{rotate_cmd}")
276
- end
277
-
278
- def background(secs)
279
- res = http({:method=>:post, :path=>'background'}, {:duration => secs})
280
- end
281
-
282
- def element_exists(uiquery)
283
- !query(uiquery).empty?
284
- end
285
-
286
- def view_with_mark_exists(expected_mark)
287
- element_exists("view marked:'#{expected_mark}'")
288
- end
289
-
290
- def check_element_exists(query)
291
- if not element_exists(query)
292
- screenshot_and_raise "No element found for query: #{query}"
293
- end
294
- end
295
-
296
- def check_element_does_not_exist(query)
297
- if element_exists(query)
298
- screenshot_and_raise "Expected no elements to match query: #{query}"
299
- end
300
- end
301
-
302
- def check_view_with_mark_exists(expected_mark)
303
- check_element_exists("view marked:'#{expected_mark}'")
304
- end
305
-
306
- # a better name would be element_exists_and_is_not_hidden
307
- def element_is_not_hidden(uiquery)
308
- matches = query(uiquery, 'isHidden')
309
- matches.delete(true)
310
- !matches.empty?
311
- end
312
-
313
-
314
- def load_playback_data(recording, options={})
315
- os = options["OS"] || ENV["OS"] || "ios5"
316
- device = options["DEVICE"] || ENV["DEVICE"] || "iphone"
317
-
318
- rec_dir = ENV['PLAYBACK_DIR'] || "#{Dir.pwd}/playback"
319
- if !recording.end_with? ".base64"
320
- recording = "#{recording}_#{os}_#{device}.base64"
321
- end
322
- data = nil
323
- if (File.exists?(recording))
324
- data = File.read(recording)
325
- elsif (File.exists?("features/#{recording}"))
326
- data = File.read("features/#{recording}")
327
- elsif (File.exists?("#{rec_dir}/#{recording}"))
328
- data = File.read("#{rec_dir}/#{recording}")
329
- elsif (File.exists?("#{DATA_PATH}/resources/#{recording}"))
330
- data = File.read("#{DATA_PATH}/resources/#{recording}")
331
- else
332
- screenshot_and_raise "Playback not found: #{recording} (searched for #{recording} in #{Dir.pwd}, #{rec_dir}, #{DATA_PATH}/resources"
333
- end
334
- data
335
- end
336
-
337
- def playback(recording, options={})
338
- data = load_playback_data(recording)
339
-
340
- post_data = %Q|{"events":"#{data}"|
341
- post_data<< %Q|,"query":"#{escape_quotes(options[:query])}"| if options[:query]
342
- post_data<< %Q|,"offset":#{options[:offset].to_json}| if options[:offset]
343
- post_data<< %Q|,"reverse":#{options[:reverse]}| if options[:reverse]
344
- post_data<< %Q|,"prototype":"#{options[:prototype]}"| if options[:prototype]
345
- post_data << "}"
346
-
347
- res = http({:method=>:post, :raw=>true, :path=>'play'}, post_data)
348
-
349
- res = JSON.parse(res)
350
- if res['outcome'] != 'SUCCESS'
351
- screenshot_and_raise "playback failed because: #{res['reason']}\n#{res['details']}"
352
- end
353
- res['results']
354
- end
355
-
356
- def interpolate(recording, options={})
357
- data = load_playback_data(recording)
358
-
359
- post_data = %Q|{"events":"#{data}"|
360
- post_data<< %Q|,"start":"#{escape_quotes(options[:start])}"| if options[:start]
361
- post_data<< %Q|,"end":"#{escape_quotes(options[:end])}"| if options[:end]
362
- post_data<< %Q|,"offset_start":#{options[:offset_start].to_json}| if options[:offset_start]
363
- post_data<< %Q|,"offset_end":#{options[:offset_end].to_json}| if options[:offset_end]
364
- post_data << "}"
365
-
366
- res = http({:method=>:post, :raw=>true, :path=>'interpolate'}, post_data)
367
-
368
- res = JSON.parse(res)
369
- if res['outcome'] != 'SUCCESS'
370
- screenshot_and_raise "interpolate failed because: #{res['reason']}\n#{res['details']}"
371
- end
372
- res['results']
373
- end
374
-
375
- def record_begin
376
- http({:method=>:post, :path=>'record'}, {:action => :start})
377
- end
378
-
379
- def record_end(file_name)
380
- res = http({:method=>:post, :path=>'record'}, {:action => :stop})
381
- File.open("_recording.plist", 'wb') do |f|
382
- f.write res
383
- end
384
- device = ENV['DEVICE'] || 'iphone'
385
- os = ENV['OS'] || 'ios5'
386
-
387
- file_name = "#{file_name}_#{os}_#{device}.base64"
388
- system("/usr/bin/plutil -convert binary1 -o _recording_binary.plist _recording.plist")
389
- system("openssl base64 -in _recording_binary.plist -out #{file_name}")
390
- system("rm _recording.plist _recording_binary.plist")
391
- file_name
392
- end
393
-
394
- def backdoor(sel, arg)
395
- json = {
396
- :selector => sel,
397
- :arg => arg
398
- }
399
- res = http({:method=>:post, :path=>'backdoor'}, json)
400
- res = JSON.parse(res)
401
- if res['outcome'] != 'SUCCESS'
402
- screenshot_and_raise "backdoor #{json} failed because: #{res['reason']}\n#{res['details']}"
403
- end
404
- res['result']
405
- end
406
68
 
407
69
  #not officially supported yet
408
70
  #def change_slider_value_to(q, value)
@@ -460,72 +122,7 @@ module Calabash
460
122
  # file_name
461
123
  #end
462
124
 
463
- def screenshot(prefix=nil, name=nil)
464
- res = http({:method =>:get, :path => 'screenshot'})
465
- prefix = prefix || ENV['SCREENSHOT_PATH'] || ""
466
- name = "screenshot_#{CALABASH_COUNT[:step_line]}.png" if name.nil?
467
- path = "#{prefix}#{name}"
468
- File.open(path, 'wb') do |f|
469
- f.write res
470
- end
471
- puts "Saved screenshot: #{path}"
472
- path
473
- end
474
-
475
- def map(query, method_name, *method_args)
476
- operation_map = {
477
- :method_name => method_name,
478
- :arguments => method_args
479
- }
480
- res = http({:method=>:post, :path=>'map'},
481
- {:query => query, :operation => operation_map})
482
- res = JSON.parse(res)
483
- if res['outcome'] != 'SUCCESS'
484
- screenshot_and_raise "map #{query}, #{method_name} failed because: #{res['reason']}\n#{res['details']}"
485
- end
486
-
487
- res['results']
488
- end
489
-
490
- def http(options, data=nil)
491
- url = url_for(options[:path])
492
- if options[:method] == :post
493
- req = Net::HTTP::Post.new url.path
494
- if options[:raw]
495
- req.body=data
496
- else
497
- req.body = data.to_json
498
- end
499
-
500
- else
501
- req = Net::HTTP::Get.new url.path
502
- end
503
- make_http_request(url, req)
504
- end
505
-
506
-
507
- def url_for(verb)
508
- url = URI.parse(ENV['DEVICE_ENDPOINT']|| "http://localhost:37265/")
509
- url.path = '/'+verb
510
- url
511
- end
512
-
513
- def make_http_request(url, req)
514
- @http = Net::HTTP.new(url.host, url.port)
515
- res = @http.start do |sess|
516
- sess.request req
517
- end
518
- body = res.body
519
- begin
520
- @http.finish if @http and @http.started?
521
- rescue Exception => e
522
- puts "Finish #{e}"
523
- end
524
- body
525
- end
526
125
 
527
126
  end
528
-
529
-
530
127
  end
531
128
  end