testautoi 0.9.127

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGES.txt +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +8 -0
  5. data/Rakefile +2 -0
  6. data/bin/CalabashSetup +0 -0
  7. data/bin/cal.xcconfig +3 -0
  8. data/bin/calabash-ios +79 -0
  9. data/bin/calabash-ios-build.rb +110 -0
  10. data/bin/calabash-ios-generate.rb +26 -0
  11. data/bin/calabash-ios-helpers.rb +130 -0
  12. data/bin/calabash-ios-setup.rb +334 -0
  13. data/bin/calabash-ios-sim.rb +149 -0
  14. data/calabash-cucumber.gemspec +29 -0
  15. data/doc/calabash-ios-help.txt +73 -0
  16. data/epl-v10.html +261 -0
  17. data/features-skeleton/.irbrc +23 -0
  18. data/features-skeleton/irb_ios4.sh +2 -0
  19. data/features-skeleton/irb_ios5.sh +2 -0
  20. data/features-skeleton/my_first.feature +12 -0
  21. data/features-skeleton/step_definitions/calabash_steps.rb +1 -0
  22. data/features-skeleton/step_definitions/my_first_steps.rb +4 -0
  23. data/features-skeleton/support/env.rb +1 -0
  24. data/features-skeleton/support/hooks.rb +0 -0
  25. data/features-skeleton/support/launch.rb +77 -0
  26. data/features/step_definitions/calabash_steps.rb +439 -0
  27. data/lib/calabash-cucumber.rb +7 -0
  28. data/lib/calabash-cucumber/calabash_steps.rb +1 -0
  29. data/lib/calabash-cucumber/core.rb +553 -0
  30. data/lib/calabash-cucumber/cucumber.rb +8 -0
  31. data/lib/calabash-cucumber/ibase.rb +45 -0
  32. data/lib/calabash-cucumber/keyboard_helpers.rb +124 -0
  33. data/lib/calabash-cucumber/launch/simulator_helper.rb +297 -0
  34. data/lib/calabash-cucumber/location.rb +26 -0
  35. data/lib/calabash-cucumber/operations.rb +162 -0
  36. data/lib/calabash-cucumber/resources/cell_swipe_ios4_ipad.base64 +51 -0
  37. data/lib/calabash-cucumber/resources/cell_swipe_ios4_iphone.base64 +51 -0
  38. data/lib/calabash-cucumber/resources/cell_swipe_ios5_ipad.base64 +74 -0
  39. data/lib/calabash-cucumber/resources/cell_swipe_ios5_iphone.base64 +74 -0
  40. data/lib/calabash-cucumber/resources/pinch_in_ios4_ipad.base64 +104 -0
  41. data/lib/calabash-cucumber/resources/pinch_in_ios4_iphone.base64 +104 -0
  42. data/lib/calabash-cucumber/resources/pinch_in_ios5_ipad.base64 +144 -0
  43. data/lib/calabash-cucumber/resources/pinch_in_ios5_iphone.base64 +144 -0
  44. data/lib/calabash-cucumber/resources/pinch_in_ios6_ipad.base64 +70 -0
  45. data/lib/calabash-cucumber/resources/pinch_in_ios6_iphone.base64 +70 -0
  46. data/lib/calabash-cucumber/resources/pinch_out_ios5_ipad.base64 +207 -0
  47. data/lib/calabash-cucumber/resources/pinch_out_ios5_iphone.base64 +207 -0
  48. data/lib/calabash-cucumber/resources/pinch_out_ios6_ipad.base64 +96 -0
  49. data/lib/calabash-cucumber/resources/pinch_out_ios6_iphone.base64 +96 -0
  50. data/lib/calabash-cucumber/resources/rotate_left_home_down_ios4_ipad.base64 +2 -0
  51. data/lib/calabash-cucumber/resources/rotate_left_home_down_ios4_iphone.base64 +2 -0
  52. data/lib/calabash-cucumber/resources/rotate_left_home_down_ios5_ipad.base64 +2 -0
  53. data/lib/calabash-cucumber/resources/rotate_left_home_down_ios5_iphone.base64 +2 -0
  54. data/lib/calabash-cucumber/resources/rotate_left_home_left_ios4_ipad.base64 +2 -0
  55. data/lib/calabash-cucumber/resources/rotate_left_home_left_ios4_iphone.base64 +2 -0
  56. data/lib/calabash-cucumber/resources/rotate_left_home_left_ios5_ipad.base64 +2 -0
  57. data/lib/calabash-cucumber/resources/rotate_left_home_left_ios5_iphone.base64 +2 -0
  58. data/lib/calabash-cucumber/resources/rotate_left_home_right_ios4_ipad.base64 +2 -0
  59. data/lib/calabash-cucumber/resources/rotate_left_home_right_ios4_iphone.base64 +2 -0
  60. data/lib/calabash-cucumber/resources/rotate_left_home_right_ios5_ipad.base64 +2 -0
  61. data/lib/calabash-cucumber/resources/rotate_left_home_right_ios5_iphone.base64 +2 -0
  62. data/lib/calabash-cucumber/resources/rotate_left_home_up_ios4_ipad.base64 +2 -0
  63. data/lib/calabash-cucumber/resources/rotate_left_home_up_ios4_iphone.base64 +2 -0
  64. data/lib/calabash-cucumber/resources/rotate_left_home_up_ios5_ipad.base64 +2 -0
  65. data/lib/calabash-cucumber/resources/rotate_left_home_up_ios5_iphone.base64 +2 -0
  66. data/lib/calabash-cucumber/resources/rotate_right_home_down_ios4_ipad.base64 +2 -0
  67. data/lib/calabash-cucumber/resources/rotate_right_home_down_ios4_iphone.base64 +2 -0
  68. data/lib/calabash-cucumber/resources/rotate_right_home_down_ios5_ipad.base64 +2 -0
  69. data/lib/calabash-cucumber/resources/rotate_right_home_down_ios5_iphone.base64 +2 -0
  70. data/lib/calabash-cucumber/resources/rotate_right_home_left_ios4_ipad.base64 +2 -0
  71. data/lib/calabash-cucumber/resources/rotate_right_home_left_ios4_iphone.base64 +2 -0
  72. data/lib/calabash-cucumber/resources/rotate_right_home_left_ios5_ipad.base64 +2 -0
  73. data/lib/calabash-cucumber/resources/rotate_right_home_left_ios5_iphone.base64 +2 -0
  74. data/lib/calabash-cucumber/resources/rotate_right_home_right_ios4_ipad.base64 +2 -0
  75. data/lib/calabash-cucumber/resources/rotate_right_home_right_ios4_iphone.base64 +2 -0
  76. data/lib/calabash-cucumber/resources/rotate_right_home_right_ios5_ipad.base64 +2 -0
  77. data/lib/calabash-cucumber/resources/rotate_right_home_right_ios5_iphone.base64 +2 -0
  78. data/lib/calabash-cucumber/resources/rotate_right_home_up_ios4_ipad.base64 +2 -0
  79. data/lib/calabash-cucumber/resources/rotate_right_home_up_ios4_iphone.base64 +2 -0
  80. data/lib/calabash-cucumber/resources/rotate_right_home_up_ios5_ipad.base64 +2 -0
  81. data/lib/calabash-cucumber/resources/rotate_right_home_up_ios5_iphone.base64 +2 -0
  82. data/lib/calabash-cucumber/resources/swipe_down_ios5_ipad.base64 +18 -0
  83. data/lib/calabash-cucumber/resources/swipe_down_ios5_iphone.base64 +18 -0
  84. data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_ipad.base64 +15 -0
  85. data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_iphone.base64 +15 -0
  86. data/lib/calabash-cucumber/resources/swipe_left_ios4_ipad.base64 +18 -0
  87. data/lib/calabash-cucumber/resources/swipe_left_ios4_iphone.base64 +18 -0
  88. data/lib/calabash-cucumber/resources/swipe_left_ios5_ipad.base64 +17 -0
  89. data/lib/calabash-cucumber/resources/swipe_left_ios5_iphone.base64 +17 -0
  90. data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_ipad.base64 +17 -0
  91. data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_iphone.base64 +17 -0
  92. data/lib/calabash-cucumber/resources/swipe_right_ios4_ipad.base64 +13 -0
  93. data/lib/calabash-cucumber/resources/swipe_right_ios4_iphone.base64 +13 -0
  94. data/lib/calabash-cucumber/resources/swipe_right_ios5_ipad.base64 +17 -0
  95. data/lib/calabash-cucumber/resources/swipe_right_ios5_iphone.base64 +17 -0
  96. data/lib/calabash-cucumber/resources/swipe_up_ios5_ipad.base64 +34 -0
  97. data/lib/calabash-cucumber/resources/swipe_up_ios5_iphone.base64 +34 -0
  98. data/lib/calabash-cucumber/resources/touch_done_ios4_ipad.base64 +7 -0
  99. data/lib/calabash-cucumber/resources/touch_done_ios4_iphone.base64 +9 -0
  100. data/lib/calabash-cucumber/resources/touch_done_ios5_ipad.base64 +7 -0
  101. data/lib/calabash-cucumber/resources/touch_done_ios5_iphone.base64 +9 -0
  102. data/lib/calabash-cucumber/resources/touch_ios4_ipad.base64 +9 -0
  103. data/lib/calabash-cucumber/resources/touch_ios4_iphone.base64 +9 -0
  104. data/lib/calabash-cucumber/resources/touch_ios5_ipad.base64 +9 -0
  105. data/lib/calabash-cucumber/resources/touch_ios5_iphone.base64 +9 -0
  106. data/lib/calabash-cucumber/resources/wheel_down_ios4_ipad.base64 +159 -0
  107. data/lib/calabash-cucumber/resources/wheel_down_ios4_iphone.base64 +159 -0
  108. data/lib/calabash-cucumber/resources/wheel_down_ios5_ipad.base64 +156 -0
  109. data/lib/calabash-cucumber/resources/wheel_down_ios5_iphone.base64 +156 -0
  110. data/lib/calabash-cucumber/resources/wheel_up_ios4_ipad.base64 +166 -0
  111. data/lib/calabash-cucumber/resources/wheel_up_ios4_iphone.base64 +166 -0
  112. data/lib/calabash-cucumber/resources/wheel_up_ios5_ipad.base64 +156 -0
  113. data/lib/calabash-cucumber/resources/wheel_up_ios5_iphone.base64 +156 -0
  114. data/lib/calabash-cucumber/tests_helpers.rb +136 -0
  115. data/lib/calabash-cucumber/version.rb +6 -0
  116. data/lib/calabash-cucumber/wait_helpers.rb +149 -0
  117. data/scripts/data/.GlobalPreferences.plist +0 -0
  118. data/scripts/data/clients.plist +0 -0
  119. data/scripts/data/com.apple.Accessibility.plist +0 -0
  120. data/scripts/reset_simulator.scpt +0 -0
  121. metadata +319 -0
@@ -0,0 +1,7 @@
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 'calabash-cucumber/operations'
6
+ require 'calabash-cucumber/version'
7
+ require 'calabash-cucumber/location'
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__),'..','..','features','step_definitions',"calabash_steps")
@@ -0,0 +1,553 @@
1
+ require 'httpclient'
2
+ require 'calabash-cucumber/launch/simulator_helper'
3
+
4
+ module Calabash
5
+ module Cucumber
6
+ module Core
7
+
8
+ DATA_PATH = File.expand_path(File.dirname(__FILE__))
9
+ CAL_HTTP_RETRY_COUNT=3
10
+ RETRYABLE_ERRORS = [Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::ETIMEDOUT]
11
+
12
+ def macro(txt)
13
+ if self.respond_to? :step
14
+ step(txt)
15
+ else
16
+ Then txt
17
+ end
18
+ end
19
+
20
+ def query(uiquery, *args)
21
+ map(uiquery, :query, *args)
22
+ end
23
+
24
+ def server_version
25
+ JSON.parse(http(:path => 'version'))
26
+ end
27
+
28
+ def client_version
29
+ Calabash::Cucumber::VERSION
30
+ end
31
+
32
+ def perform(*args)
33
+ if args.length == 1
34
+ #simple selector
35
+ hash = args.first
36
+ q = hash[:on]
37
+ hash = hash.dup
38
+ hash.delete(:on)
39
+ args = [hash]
40
+ elsif args.length == 2
41
+ q = args[1][:on]
42
+ if args[0].is_a? Hash
43
+ args = [args[0]]
44
+ else
45
+ args = args[0]
46
+ end
47
+ end
48
+ map(q, :query_all, *args)
49
+ end
50
+
51
+ def query_all(uiquery, *args)
52
+ map(uiquery, :query_all, *args)
53
+ end
54
+
55
+ def touch(uiquery, options={})
56
+ options[:query] = uiquery
57
+ views_touched = playback("touch", options)
58
+ unless uiquery.nil?
59
+ screenshot_and_raise "could not find view to touch: '#{uiquery}', args: #{options}" if views_touched.empty?
60
+ end
61
+ views_touched
62
+ end
63
+
64
+ def swipe(dir, options={})
65
+ dir = dir.to_sym
66
+ @current_rotation = @current_rotation || :down
67
+ if @current_rotation == :left
68
+ case dir
69
+ when :left then
70
+ dir = :down
71
+ when :right then
72
+ dir = :up
73
+ when :up then
74
+ dir = :left
75
+ when :down then
76
+ dir = :right
77
+ else
78
+ end
79
+ end
80
+ if @current_rotation == :right
81
+ case dir
82
+ when :left then
83
+ dir = :up
84
+ when :right then
85
+ dir = :down
86
+ when :up then
87
+ dir = :right
88
+ when :down then
89
+ dir = :left
90
+ else
91
+ end
92
+ end
93
+ if @current_rotation == :up
94
+ case dir
95
+ when :left then
96
+ dir = :right
97
+ when :right then
98
+ dir = :left
99
+ when :up then
100
+ dir = :down
101
+ when :down then
102
+ dir = :up
103
+ else
104
+ end
105
+ end
106
+ playback("swipe_#{dir}", options)
107
+ end
108
+
109
+ def cell_swipe(options={})
110
+ playback("cell_swipe", options)
111
+ end
112
+
113
+ def scroll(uiquery, direction)
114
+ views_touched=map(uiquery, :scroll, direction)
115
+ screenshot_and_raise "could not find view to scroll: '#{uiquery}', args: #{direction}" if views_touched.empty?
116
+ views_touched
117
+ end
118
+
119
+ def scroll_to_row(uiquery, number)
120
+ views_touched=map(uiquery, :scrollToRow, number)
121
+ if views_touched.empty? or views_touched.member? "<VOID>"
122
+ screenshot_and_raise "Unable to scroll: '#{uiquery}' to: #{number}"
123
+ end
124
+ views_touched
125
+ end
126
+
127
+ def scroll_to_cell(options={:query => "tableView",
128
+ :row => 0,
129
+ :section => 0,
130
+ :scroll_position => :top,
131
+ :animate => true})
132
+ uiquery = options[:query] || "tableView"
133
+ row = options[:row]
134
+ sec = options[:section]
135
+ if row.nil? or sec.nil?
136
+ raise "You must supply both :row and :section keys to scroll_to_cell"
137
+ end
138
+
139
+ args = []
140
+ if options.has_key?(:scroll_position)
141
+ args << options[:scroll_position]
142
+ else
143
+ args << "top"
144
+ end
145
+ if options.has_key?(:animate)
146
+ args << options[:animate]
147
+ end
148
+ views_touched=map(uiquery, :scrollToRow, row.to_i, sec.to_i, *args)
149
+
150
+ if views_touched.empty? or views_touched.member? "<VOID>"
151
+ screenshot_and_raise "Unable to scroll: '#{uiquery}' to: #{options}"
152
+ end
153
+ views_touched
154
+ end
155
+
156
+ def pinch(in_out, options={})
157
+ file = "pinch_in"
158
+ if in_out.to_sym==:out
159
+ file = "pinch_out"
160
+ end
161
+ playback(file, options)
162
+ end
163
+
164
+ #Current position of home button
165
+ def current_rotation
166
+ @current_rotation
167
+ end
168
+
169
+ def rotate(dir)
170
+ @current_rotation = @current_rotation || :down
171
+ rotate_cmd = nil
172
+ case dir
173
+ when :left then
174
+ if @current_rotation == :down
175
+ rotate_cmd = "left_home_down"
176
+ @current_rotation = :right
177
+ elsif @current_rotation == :right
178
+ rotate_cmd = "left_home_right"
179
+ @current_rotation = :up
180
+ elsif @current_rotation == :left
181
+ rotate_cmd = "left_home_left"
182
+ @current_rotation = :down
183
+ elsif @current_rotation == :up
184
+ rotate_cmd = "left_home_up"
185
+ @current_rotation = :left
186
+ end
187
+ when :right then
188
+ if @current_rotation == :down
189
+ rotate_cmd = "right_home_down"
190
+ @current_rotation = :left
191
+ elsif @current_rotation == :left
192
+ rotate_cmd = "right_home_left"
193
+ @current_rotation = :up
194
+ elsif @current_rotation == :right
195
+ rotate_cmd = "right_home_right"
196
+ @current_rotation = :down
197
+ elsif @current_rotation == :up
198
+ rotate_cmd = "right_home_up"
199
+ @current_rotation = :right
200
+ end
201
+ end
202
+
203
+ if rotate_cmd.nil?
204
+ screenshot_and_raise "Does not support rotating #{dir} when home button is pointing #{@current_rotation}"
205
+ end
206
+ playback("rotate_#{rotate_cmd}")
207
+ end
208
+
209
+ def background(secs)
210
+ set_user_pref("__calabash_action", {:action => :background, :duration => secs})
211
+ end
212
+
213
+ def prepare_dialog_action(opts={:dialog => nil, :answer => "Ok"})
214
+ if opts[:dialog].nil? || opts[:dialog].length < 1
215
+ raise ":dialog must be specified as a non-empty string (used as regexp to match dialog text)"
216
+ end
217
+ txt = opts[:answer] || 'Ok'
218
+ set_user_pref("__calabash_action", {:action => :dialog,
219
+ :text => opts[:dialog],
220
+ :answer => txt})
221
+ end
222
+
223
+ def move_wheel(opts={})
224
+ q = opts[:query] || "pickerView"
225
+ wheel = opts[:wheel] || 0
226
+ dir = opts[:dir] || :down
227
+
228
+ raise "Wheel index must be non negative" if wheel < 0
229
+ raise "Only up and down supported :dir (#{dir})" unless [:up, :down].include?(dir)
230
+
231
+ if ENV['OS'] == "ios4"
232
+ playback "wheel_#{dir}", :query => "#{q} pickerTable index:#{wheel}"
233
+ else
234
+ playback "wheel_#{dir}", :query => "#{q} pickerTableView index:#{wheel}"
235
+ end
236
+
237
+ end
238
+
239
+ def picker(opts={:query => "pickerView", :action => :texts})
240
+ raise "Not implemented" unless opts[:action] == :texts
241
+
242
+ q = opts[:query]
243
+
244
+ check_element_exists(q)
245
+
246
+ comps = query(q, :numberOfComponents).first
247
+ row_counts = []
248
+ texts = []
249
+ comps.times do |i|
250
+ row_counts[i] = query(q, :numberOfRowsInComponent => i).first
251
+ texts[i] = []
252
+ end
253
+
254
+ row_counts.each_with_index do |row_count, comp|
255
+ row_count.times do |i|
256
+ #view = query(q,[{:viewForRow => 0}, {:forComponent => 0}],:accessibilityLabel).first
257
+ spec = [{:viewForRow => i}, {:forComponent => comp}]
258
+ view = query(q, spec).first
259
+ if view
260
+ txt = query(q, spec, :accessibilityLabel).first
261
+ else
262
+ txt = query(q, :delegate, [{:pickerView => :view},
263
+ {:titleForRow => i},
264
+ {:forComponent => comp}]).first
265
+ end
266
+ texts[comp] << txt
267
+ end
268
+ end
269
+ texts
270
+ end
271
+
272
+ def recording_name_for(recording_name, os, device)
273
+ if !recording_name.end_with? ".base64"
274
+ "#{recording_name}_#{os}_#{device}.base64"
275
+ else
276
+ recording_name
277
+ end
278
+ end
279
+
280
+
281
+ def load_recording(recording,rec_dir)
282
+ data = nil
283
+ if (File.exists?(recording))
284
+ data = File.read(recording)
285
+ elsif (File.exists?("features/#{recording}"))
286
+ data = File.read("features/#{recording}")
287
+ elsif (File.exists?("#{rec_dir}/#{recording}"))
288
+ data = File.read("#{rec_dir}/#{recording}")
289
+ elsif (File.exists?("#{DATA_PATH}/resources/#{recording}"))
290
+ data = File.read("#{DATA_PATH}/resources/#{recording}")
291
+ end
292
+ data
293
+ end
294
+
295
+ def load_playback_data(recording_name, options={})
296
+ os = options["OS"] || ENV["OS"]
297
+ device = options["DEVICE"] || ENV["DEVICE"] || "iphone"
298
+
299
+ unless os
300
+ major = Calabash::Cucumber::SimulatorHelper.ios_major_version
301
+ unless major
302
+ raise <<EOF
303
+ Unable to determine iOS major version
304
+ Most likely you have updated your calabash-cucumber client
305
+ but not your server. Please follow closely:
306
+
307
+ https://github.com/calabash/calabash-ios/wiki/B1-Updating-your-Calabash-iOS-version
308
+
309
+ If you are running version 0.9.120+ then please report this message as a bug.
310
+ EOF
311
+ end
312
+ os = "ios#{major}"
313
+ end
314
+
315
+ rec_dir = ENV['PLAYBACK_DIR'] || "#{Dir.pwd}/playback"
316
+
317
+ recording = recording_name_for(recording_name, os, device)
318
+ data = load_recording(recording,rec_dir)
319
+
320
+ if data.nil? and os=="ios6"
321
+ recording = recording_name_for(recording_name, "ios5", device)
322
+ end
323
+
324
+ data = load_recording(recording,rec_dir)
325
+
326
+ if data.nil?
327
+ screenshot_and_raise "Playback not found: #{recording} (searched for #{recording} in #{Dir.pwd}, #{rec_dir}, #{DATA_PATH}/resources"
328
+ end
329
+
330
+ data
331
+ end
332
+
333
+ def playback(recording, options={})
334
+ data = load_playback_data(recording)
335
+
336
+ post_data = %Q|{"events":"#{data}"|
337
+ post_data<< %Q|,"query":"#{escape_quotes(options[:query])}"| if options[:query]
338
+ post_data<< %Q|,"offset":#{options[:offset].to_json}| if options[:offset]
339
+ post_data<< %Q|,"reverse":#{options[:reverse]}| if options[:reverse]
340
+ post_data<< %Q|,"prototype":"#{options[:prototype]}"| if options[:prototype]
341
+ post_data << "}"
342
+
343
+ res = http({:method => :post, :raw => true, :path => 'play'}, post_data)
344
+
345
+ res = JSON.parse(res)
346
+ if res['outcome'] != 'SUCCESS'
347
+ screenshot_and_raise "playback failed because: #{res['reason']}\n#{res['details']}"
348
+ end
349
+ res['results']
350
+ end
351
+
352
+ def interpolate(recording, options={})
353
+ data = load_playback_data(recording)
354
+
355
+ post_data = %Q|{"events":"#{data}"|
356
+ post_data<< %Q|,"start":"#{escape_quotes(options[:start])}"| if options[:start]
357
+ post_data<< %Q|,"end":"#{escape_quotes(options[:end])}"| if options[:end]
358
+ post_data<< %Q|,"offset_start":#{options[:offset_start].to_json}| if options[:offset_start]
359
+ post_data<< %Q|,"offset_end":#{options[:offset_end].to_json}| if options[:offset_end]
360
+ post_data << "}"
361
+
362
+ res = http({:method => :post, :raw => true, :path => 'interpolate'}, post_data)
363
+
364
+ res = JSON.parse(res)
365
+ if res['outcome'] != 'SUCCESS'
366
+ screenshot_and_raise "interpolate failed because: #{res['reason']}\n#{res['details']}"
367
+ end
368
+ res['results']
369
+ end
370
+
371
+ def record_begin
372
+ http({:method => :post, :path => 'record'}, {:action => :start})
373
+ end
374
+
375
+ def record_end(file_name)
376
+ res = http({:method => :post, :path => 'record'}, {:action => :stop})
377
+ File.open("_recording.plist", 'wb') do |f|
378
+ f.write res
379
+ end
380
+
381
+ device = ENV['DEVICE'] || 'iphone'
382
+ os = ENV['OS']
383
+
384
+ unless os
385
+ major = Calabash::Cucumber::SimulatorHelper.ios_major_version
386
+ unless major
387
+ raise <<EOF
388
+ Unable to determine iOS major version
389
+ Most likely you have updated your calabash-cucumber client
390
+ but not your server. Please follow closely:
391
+
392
+ https://github.com/calabash/calabash-ios/wiki/B1-Updating-your-Calabash-iOS-version
393
+
394
+ If you are running version 0.9.120+ then please report this message as a bug.
395
+ EOF
396
+ end
397
+ os = "ios#{major}"
398
+ end
399
+
400
+ file_name = "#{file_name}_#{os}_#{device}.base64"
401
+ system("/usr/bin/plutil -convert binary1 -o _recording_binary.plist _recording.plist")
402
+ system("openssl base64 -in _recording_binary.plist -out #{file_name}")
403
+ system("rm _recording.plist _recording_binary.plist")
404
+ file_name
405
+ end
406
+
407
+ def backdoor(sel, arg)
408
+ json = {
409
+ :selector => sel,
410
+ :arg => arg
411
+ }
412
+ res = http({:method => :post, :path => 'backdoor'}, json)
413
+ res = JSON.parse(res)
414
+ if res['outcome'] != 'SUCCESS'
415
+ screenshot_and_raise "backdoor #{json} failed because: #{res['reason']}\n#{res['details']}"
416
+ end
417
+ res['result']
418
+ end
419
+
420
+ def calabash_exit
421
+ # Exiting the app shuts down the HTTP connection and generates ECONNREFUSED,
422
+ # which needs to be suppressed.
423
+ begin
424
+ http(:path => 'exit', :retryable_errors => RETRYABLE_ERRORS - [Errno::ECONNREFUSED])
425
+ rescue Errno::ECONNREFUSED
426
+ []
427
+ end
428
+ end
429
+
430
+ def map(query, method_name, *method_args)
431
+ operation_map = {
432
+ :method_name => method_name,
433
+ :arguments => method_args
434
+ }
435
+ res = http({:method => :post, :path => 'map'},
436
+ {:query => query, :operation => operation_map})
437
+ res = JSON.parse(res)
438
+ if res['outcome'] != 'SUCCESS'
439
+ screenshot_and_raise "map #{query}, #{method_name} failed because: #{res['reason']}\n#{res['details']}"
440
+ end
441
+
442
+ res['results']
443
+ end
444
+
445
+
446
+ def start_app_in_background(path=nil, sdk = nil, version = 'iphone', args = nil)
447
+
448
+ if path.nil?
449
+ path = ENV['APP_BUNDLE_PATH'] || (defined?(APP_BUNDLE_PATH) && APP_BUNDLE_PATH)
450
+ end
451
+ app_bundle_path = Calabash::Cucumber::SimulatorHelper.app_bundle_or_raise(path)
452
+
453
+ @ios_device = RunLoop.run(:app => app_bundle_path)
454
+ end
455
+
456
+ def send_uia_command(opts ={})
457
+ RunLoop.send_command(opts[:device] ||@ios_device, opts[:command])
458
+ end
459
+
460
+ def stop_background_app(stop_spec = nil)
461
+
462
+ @ios_device = RunLoop.stop(stop_spec || @ios_device)
463
+
464
+ end
465
+
466
+
467
+
468
+ def http(options, data=nil)
469
+ options[:uri] = url_for(options[:path])
470
+ options[:method] = options[:method] || :get
471
+ if data
472
+ if options[:raw]
473
+ options[:body] = data
474
+ else
475
+ options[:body] = data.to_json
476
+ end
477
+ end
478
+ res = make_http_request(options)
479
+ res.force_encoding("UTF-8") if res.respond_to?(:force_encoding)
480
+ res
481
+ end
482
+
483
+
484
+ def url_for(verb)
485
+ url = URI.parse(ENV['DEVICE_ENDPOINT']|| "http://localhost:37265")
486
+ path = url.path
487
+ if path.end_with? "/"
488
+ path = "#{path}#{verb}"
489
+ else
490
+ path = "#{path}/#{verb}"
491
+ end
492
+ url.path = path
493
+ url
494
+ end
495
+
496
+ def make_http_request(options)
497
+ body = nil
498
+ retryable_errors = options[:retryable_errors] || RETRYABLE_ERRORS
499
+ CAL_HTTP_RETRY_COUNT.times do |count|
500
+ begin
501
+ if not @http
502
+ @http = init_request(options)
503
+ end
504
+ if options[:method] == :post
505
+ body = @http.post(options[:uri], options[:body]).body
506
+ else
507
+ body = @http.get(options[:uri], options[:body]).body
508
+ end
509
+ break
510
+ rescue HTTPClient::TimeoutError => e
511
+ if count < CAL_HTTP_RETRY_COUNT-1
512
+ sleep(0.5)
513
+ @http.reset_all
514
+ @http=nil
515
+ STDOUT.write "Retrying.. #{e.class}: (#{e})\n"
516
+ STDOUT.flush
517
+
518
+ else
519
+ puts "Failing... #{e.class}"
520
+ raise e
521
+ end
522
+ rescue Exception => e
523
+ if retryable_errors.include?(e)
524
+ if count < CAL_HTTP_RETRY_COUNT-1
525
+ sleep(0.5)
526
+ @http.reset_all
527
+ @http=nil
528
+ STDOUT.write "Retrying.. #{e.class}: (#{e})\n"
529
+ STDOUT.flush
530
+
531
+ else
532
+ puts "Failing... #{e.class}"
533
+ raise e
534
+ end
535
+ else
536
+ raise e
537
+ end
538
+ end
539
+ end
540
+
541
+ body
542
+ end
543
+
544
+ def init_request(url)
545
+ http = HTTPClient.new
546
+ http.connect_timeout = 15
547
+ http.send_timeout = 15
548
+ http.receive_timeout = 15
549
+ http
550
+ end
551
+ end
552
+ end
553
+ end