calabash-cucumber 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGES.txt +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +8 -0
  5. data/README.md +182 -0
  6. data/Rakefile +2 -0
  7. data/bin/calabash +21 -0
  8. data/calabash-cucumber.gemspec +23 -0
  9. data/copy_resources.sh +2 -0
  10. data/epl-v10.html +261 -0
  11. data/features-skeleton/my_first.feature +8 -0
  12. data/features-skeleton/step_definitions/calabash_steps.rb +1 -0
  13. data/features-skeleton/support/env.rb +1 -0
  14. data/features-skeleton/support/hooks.rb +17 -0
  15. data/lib/calabash-cucumber.rb +0 -0
  16. data/lib/calabash-cucumber/calabash_steps.rb +307 -0
  17. data/lib/calabash-cucumber/color_helper.rb +13 -0
  18. data/lib/calabash-cucumber/cucumber.rb +9 -0
  19. data/lib/calabash-cucumber/operations.rb +271 -0
  20. data/lib/calabash-cucumber/resources/cell_swipe_ios4_ipad.base64 +51 -0
  21. data/lib/calabash-cucumber/resources/cell_swipe_ios4_iphone.base64 +51 -0
  22. data/lib/calabash-cucumber/resources/cell_swipe_ios5_ipad.base64 +74 -0
  23. data/lib/calabash-cucumber/resources/cell_swipe_ios5_iphone.base64 +74 -0
  24. data/lib/calabash-cucumber/resources/pinch_in_ios4_ipad.base64 +104 -0
  25. data/lib/calabash-cucumber/resources/pinch_in_ios4_iphone.base64 +104 -0
  26. data/lib/calabash-cucumber/resources/pinch_in_ios5_ipad.base64 +144 -0
  27. data/lib/calabash-cucumber/resources/pinch_in_ios5_iphone.base64 +144 -0
  28. data/lib/calabash-cucumber/resources/pinch_out_ios5_ipad.base64 +207 -0
  29. data/lib/calabash-cucumber/resources/pinch_out_ios5_iphone.base64 +207 -0
  30. data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_ipad.base64 +15 -0
  31. data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_iphone.base64 +15 -0
  32. data/lib/calabash-cucumber/resources/swipe_left_ios4_ipad.base64 +18 -0
  33. data/lib/calabash-cucumber/resources/swipe_left_ios4_iphone.base64 +18 -0
  34. data/lib/calabash-cucumber/resources/swipe_left_ios5_ipad.base64 +17 -0
  35. data/lib/calabash-cucumber/resources/swipe_left_ios5_iphone.base64 +17 -0
  36. data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_ipad.base64 +17 -0
  37. data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_iphone.base64 +17 -0
  38. data/lib/calabash-cucumber/resources/swipe_right_ios4_ipad.base64 +13 -0
  39. data/lib/calabash-cucumber/resources/swipe_right_ios4_iphone.base64 +13 -0
  40. data/lib/calabash-cucumber/resources/swipe_right_ios5_ipad.base64 +17 -0
  41. data/lib/calabash-cucumber/resources/swipe_right_ios5_iphone.base64 +17 -0
  42. data/lib/calabash-cucumber/resources/touch_done_ios4_ipad.base64 +8 -0
  43. data/lib/calabash-cucumber/resources/touch_done_ios4_iphone.base64 +8 -0
  44. data/lib/calabash-cucumber/resources/touch_done_ios5_ipad.base64 +8 -0
  45. data/lib/calabash-cucumber/resources/touch_done_ios5_iphone.base64 +8 -0
  46. data/lib/calabash-cucumber/resources/touch_ios4_ipad.base64 +7 -0
  47. data/lib/calabash-cucumber/resources/touch_ios4_iphone.base64 +7 -0
  48. data/lib/calabash-cucumber/resources/touch_ios5_ipad.base64 +8 -0
  49. data/lib/calabash-cucumber/resources/touch_ios5_iphone.base64 +8 -0
  50. data/lib/calabash-cucumber/version.rb +5 -0
  51. metadata +141 -0
@@ -0,0 +1,8 @@
1
+ Feature: Running a test
2
+ As an iOS developer
3
+ I want to have a sample feature file
4
+ So I can begin testing quickly
5
+
6
+ Scenario: Example steps
7
+ Given the app is running
8
+ Then take picture
@@ -0,0 +1 @@
1
+ require 'calabash-cucumber/calabash_steps'
@@ -0,0 +1 @@
1
+ require 'calabash-cucumber/cucumber'
@@ -0,0 +1,17 @@
1
+ CALABASH_COUNT = {:step_index => 0, :step_line => nil}
2
+
3
+ Before do |scenario|
4
+ begin
5
+ CALABASH_COUNT[:step_index] = 0
6
+ CALABASH_COUNT[:step_line] = scenario.raw_steps[CALABASH_COUNT[:step_index]].line
7
+ rescue Exception => e
8
+ puts "#{Time.now} - Exception:#{e}"
9
+ end
10
+ end
11
+
12
+ AfterStep do |scenario|
13
+ #Håndtering af den situation hvor Feature/Scenario/steps er mulitline
14
+ CALABASH_COUNT[:step_index] = CALABASH_COUNT[:step_index] + 1
15
+ raw = scenario.raw_steps[CALABASH_COUNT[:step_index]]
16
+ CALABASH_COUNT[:step_line] = raw.line unless raw.nil?
17
+ end
File without changes
@@ -0,0 +1,307 @@
1
+ WAIT_TIMEOUT = ENV['WAIT_TIMEOUT'] || 30
2
+ STEP_PAUSE = ENV['STEP_PAUSE'].to_f || 0.3
3
+
4
+ require 'rspec/expectations'
5
+
6
+ Given /^(my|the) app is running$/ do |_|
7
+ #no-op on iOS
8
+ end
9
+
10
+
11
+ # -- Touch --#
12
+ Then /^I (press|touch) on screen (\d+) from the left and (\d+) from the top$/ do |_, x, y|
13
+ touch(nil, {:x => x, :y => y})
14
+ sleep(STEP_PAUSE)
15
+ end
16
+
17
+ Then /^I (press|touch) "([^\"]*)"$/ do |_,name|
18
+ touch("view marked:'#{name}'")
19
+
20
+ sleep(STEP_PAUSE)
21
+ end
22
+
23
+ #Then /^I (press|touch) (\d+)% right and (\d+)% down from "([^\"]*)" $/ do |_,x,y,name|
24
+ # touch({:query => "view marked:'#{name}'", :offset => {:x => x, :y => y}})
25
+ #end
26
+
27
+ Then /^I (press|touch) button number (\d+)$/ do |_,index|
28
+ index = index.to_i
29
+ raise "Index should be positive (was: #{index})" if (index<=0)
30
+ touch("button index:#{index-1}")
31
+ sleep(STEP_PAUSE)
32
+ end
33
+
34
+ Then /^I (press|touch) the "([^\"]*)" button$/ do |_,name|
35
+ touch("button marked:'#{name}'")
36
+ sleep(STEP_PAUSE)
37
+ end
38
+
39
+ # /^I press view with name "([^\"]*)"$/
40
+ # like touch "..."
41
+ # /^I press image button number (\d+)$/
42
+ # iOS doesn't have image buttons'
43
+
44
+ ##TODO note in tables views: this means visible cell index!
45
+ Then /^I (press|touch) list item number (\d+)$/ do |_,index|
46
+ index = index.to_i
47
+ raise "Index should be positive (was: #{index})" if (index<=0)
48
+ touch("tableViewCell index:#{index-1}")
49
+ sleep(STEP_PAUSE)
50
+ end
51
+
52
+ Then /^I toggle the switch$/ do
53
+ touch("view:'UISwitch'")
54
+ sleep(STEP_PAUSE)
55
+ end
56
+
57
+ Then /^I toggle the "([^\"]*)" switch$/ do |name|
58
+ touch("view:'UISwitch' marked:'#{name}'")
59
+ sleep(STEP_PAUSE)
60
+ end
61
+
62
+ #/^I enter "([^\"]*)" as "([^\"]*)"$/
63
+ ## -- Entering text directly --##
64
+ When /^I enter "([^\"]*)" into the "([^\"]*)" text field$/ do |text_to_type, field_name|
65
+ set_text("textField placeholder:'#{field_name}'", text_to_type)
66
+ sleep(STEP_PAUSE)
67
+ end
68
+
69
+ # alias
70
+ When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |text_field, text_to_type|
71
+ When %Q|I enter "#{text_to_type}" into the "#{text_field}" text field|
72
+ end
73
+
74
+ When /^I fill in text fields as follows:$/ do |table|
75
+ table.hashes.each do |row|
76
+ When %Q|I enter "#{row['text']}" into the "#{row['field']}" text field|
77
+ end
78
+ end
79
+
80
+ Then /^I enter "([^\"]*)" into input field number (\d+)$/ do |text, index|
81
+ index = index.to_i
82
+ raise "Index should be positive (was: #{index})" if (index<=0)
83
+ set_text("textField index:#{index-1}",text)
84
+ sleep(STEP_PAUSE)
85
+ end
86
+
87
+ When /^I clear "([^\"]*)"$/ do |name|
88
+ When %Q|I enter "" into the "#{name}" text field|
89
+ end
90
+
91
+ Then /^I clear input field number (\d+)$/ do |index|
92
+ index = index.to_i
93
+ raise "Index should be positive (was: #{index})" if (index<=0)
94
+ set_text("textField index:#{index-1}","")
95
+ sleep(STEP_PAUSE)
96
+ end
97
+
98
+
99
+
100
+
101
+ # -- See -- #
102
+ Then /^I wait to see "([^\"]*)"$/ do |expected_mark|
103
+ Timeout::timeout(WAIT_TIMEOUT) do
104
+ until view_with_mark_exists( expected_mark )
105
+ sleep 0.3
106
+ end
107
+ end
108
+ end
109
+
110
+ Then /^I wait to not see "([^\"]*)"$/ do |expected_mark|
111
+ sleep 2
112
+ Timeout::timeout(WAIT_TIMEOUT) do
113
+ while element_exists( "view marked:'#{expected_mark}'" )
114
+ sleep 0.3
115
+ end
116
+ end
117
+ end
118
+
119
+ Then /^I wait for "([^\"]*)" to appear$/ do |name|
120
+ Then %Q|I wait to see "#{name}"|
121
+ end
122
+
123
+ When /^I wait for ([\d\.]+) second(?:s)?$/ do |num_seconds|
124
+ num_seconds = num_seconds.to_f
125
+ sleep num_seconds
126
+ end
127
+ #/^I wait for dialog to close$/
128
+ #/^I wait for progress$/
129
+
130
+ Then /^I wait for the "([^\"]*)" button to appear$/ do |name|
131
+ Timeout::timeout(WAIT_TIMEOUT) do
132
+ until element_exists( "button marked:'#{name}'" )
133
+ sleep 0.3
134
+ end
135
+ end
136
+ end
137
+
138
+ Then /^I wait to see a navigation bar titled "([^\"]*)"$/ do |expected_mark|
139
+ Timeout::timeout(30) do
140
+ values = query('navigationItemView', :accessibilityLabel)
141
+ until values.include?(expected_mark)
142
+ values = query('navigationItemView', :accessibilityLabel)
143
+ sleep 0.3
144
+ end
145
+ end
146
+ end
147
+
148
+ Then /^I wait$/ do
149
+ sleep 2
150
+ end
151
+
152
+ Then /^I wait and wait$/ do
153
+ sleep 4
154
+ end
155
+
156
+ Then /^I wait and wait and wait\.\.\.$/ do
157
+ sleep 10
158
+ end
159
+
160
+ Then /^I go back$/ do
161
+ touch("navigationItemButtonView first")
162
+ sleep(STEP_PAUSE)
163
+ end
164
+
165
+ Then /^take picture$/ do
166
+ sleep(STEP_PAUSE)
167
+ screenshot
168
+ end
169
+
170
+ # Note "up/down" seems to be missing on the web page?
171
+ # Should be /^I swipe (left|right|up|down)$/
172
+ Then /^I swipe (left|right)$/ do |dir|
173
+ swipe(dir)
174
+ sleep(STEP_PAUSE)
175
+ end
176
+
177
+ Then /^I swipe (left|right) on "([^\"]*)"$/ do |dir, mark|
178
+ swipe(dir, {:query => "view marked:'#{mark}'"})
179
+ sleep(STEP_PAUSE)
180
+ end
181
+
182
+ Then /^I swipe on cell number (\d+)$/ do |index|
183
+ index = index.to_i
184
+ raise "Index should be positive (was: #{index})" if (index<=0)
185
+ cell_swipe({:query => "tableViewCell index:#{index-1}"})
186
+ sleep(STEP_PAUSE)
187
+ end
188
+
189
+
190
+ ##pinch##
191
+ Then /^I pinch to zoom (in|out)$/ do |in_out|
192
+ pinch(in_out)
193
+ sleep([STEP_PAUSE+4,6].max)
194
+ end
195
+
196
+ Then /^I pinch to zoom (in|out) on "([^\"]*)"$/ do |in_out, name|
197
+ pinch(in_out,{:query => "view marked:'#{name}'"})
198
+ sleep([STEP_PAUSE+4,6].max)
199
+ end
200
+
201
+ # Note "up/left/right" seems to be missing on the web page
202
+ Then /^I scroll (left|right|up|down)$/ do |dir|
203
+ scroll("scrollView index:0", dir)
204
+ sleep(STEP_PAUSE)
205
+ end
206
+
207
+ Then /^I scroll (left|right|up|down) on "([^\"]*)"$/ do |dir,name|
208
+ scroll("view marked:'#{name}'", dir)
209
+ sleep(STEP_PAUSE)
210
+ end
211
+
212
+
213
+
214
+ ### Playback ###
215
+ Then /^I playback recording "([^"]*)"$/ do |filename|
216
+ playback(filename)
217
+ sleep(STEP_PAUSE)
218
+ end
219
+
220
+ Then /^I playback recording "([^"]*) on "([^"]*)"$/ do |filename, name|
221
+ playback(filename, {:query => "view marked:'#{name}'"})
222
+ sleep(STEP_PAUSE)
223
+ end
224
+
225
+ Then /^I playback recording "([^"]*) on "([^"]*)" with offset (\d+),(\d+)$/ do |filename, name, x, y|
226
+ x = x.to_i
227
+ y = y.to_i
228
+ playback(filename, {:query => "view marked:'#{name}'", :offset => {:x => x, :y => y}})
229
+ sleep(STEP_PAUSE)
230
+ end
231
+
232
+ Then /^I reverse playback recording "([^"]*)"$/ do |filename|
233
+ playback(filename, {:reverse => true})
234
+ sleep(STEP_PAUSE)
235
+ end
236
+
237
+ Then /^I reverse playback recording "([^"]*) on "([^"]*)"$/ do |filename, name|
238
+ playback(filename, {:query => "view marked:'#{name}'",:reverse => true})
239
+ sleep(STEP_PAUSE)
240
+ end
241
+
242
+ Then /^I reverse playback recording "([^"]*) on "([^"]*)" with offset (\d+),(\d+)$/ do |filename, name, x, y|
243
+ x = x.to_i
244
+ y = y.to_i
245
+ playback(filename, {:query => "view marked:'#{name}'", :offset => {:x => x, :y => y},:reverse => true})
246
+ sleep(STEP_PAUSE)
247
+ end
248
+
249
+
250
+ ### Device orientation ###
251
+ Then /^I rotate device (left|right)$/ do |dir|
252
+ dir = dir.to_sym
253
+ rotate(dir)
254
+ sleep(STEP_PAUSE)
255
+ end
256
+
257
+ Then /^I send app to background for (\d+) seconds$/ do |secs|
258
+ secs = secs.to_f
259
+ background(secs)
260
+ end
261
+
262
+ ### Assertions ###
263
+ Then /^I should see "([^\"]*)"$/ do |expected_mark|
264
+ res = (element_exists( "view marked:'#{expected_mark}'" ) ||
265
+ element_exists( "view text:'#{expected_mark}'"))
266
+ res.should be_true
267
+ end
268
+
269
+ Then /^I should not see "([^\"]*)"$/ do |expected_mark|
270
+ check_element_does_not_exist("view marked:'#{expected_mark}'")
271
+ end
272
+
273
+ Then /^I should see a "([^\"]*)" button$/ do |expected_mark|
274
+ check_element_exists("button marked:'#{expected_mark}'")
275
+ end
276
+ Then /^I should not see a "([^\"]*)" button$/ do |expected_mark|
277
+ check_element_does_not_exist("button marked:'#{expected_mark}'")
278
+ end
279
+
280
+ Then /^I don't see the text "([^\"]*)"$/ do |text|
281
+ Then %Q|I should not see "#{text}"|
282
+ end
283
+ Then /^I don't see the "([^\"]*)"$/ do |text|
284
+ Then %Q|I should not see "#{text}"|
285
+ end
286
+
287
+ Then /^I see the text "([^\"]*)"$/ do |text|
288
+ Then %Q|I should see "#{text}"|
289
+ end
290
+ Then /^I see the "([^\"]*)"$/ do |text|
291
+ Then %Q|I should see "#{text}"|
292
+ end
293
+
294
+
295
+ Then /^I should see a map$/ do
296
+ check_element_exists("view:'MKMapView'")
297
+ end
298
+
299
+ Then /^I touch user location$/ do
300
+ touch("view:'MKUserLocationView'")
301
+ end
302
+
303
+ Then /^I (touch|press) (done|search)$/ do |_,__|
304
+ done
305
+ sleep(STEP_PAUSE)
306
+ end
307
+
@@ -0,0 +1,13 @@
1
+ module Calabash module Cucumber
2
+
3
+ module ColorHelper
4
+ def colorize(text, color_code)
5
+ "\e[#{color_code}m#{text}\e[0m"
6
+ end
7
+
8
+ def red(text); colorize(text, 31); end
9
+ def green(text); colorize(text, 32); end
10
+ def blue(text); colorize(text, 34); end
11
+ end
12
+
13
+ end end
@@ -0,0 +1,9 @@
1
+ require 'calabash-cucumber/color_helper'
2
+ require 'calabash-cucumber/operations'
3
+
4
+ World(Calabash::Cucumber::ColorHelper)
5
+ World(Calabash::Cucumber::Operations)
6
+
7
+ AfterConfiguration do
8
+ require 'calabash-cucumber/calabash_steps'
9
+ end
@@ -0,0 +1,271 @@
1
+ require 'net/http/persistent'
2
+ require 'json'
3
+
4
+ module Calabash module Cucumber
5
+
6
+ module Operations
7
+
8
+ DATA_PATH = File.expand_path(File.dirname(__FILE__))
9
+
10
+ def query(uiquery, *args)
11
+ map(uiquery, :query, *args)
12
+ end
13
+
14
+ def touch(uiquery,options={})
15
+ options[:query] = uiquery
16
+ views_touched = playback("touch",options)
17
+ raise "could not find view to touch: '#{uiquery}', args: #{args}" if views_touched.empty?
18
+ views_touched
19
+ end
20
+
21
+ def simple_touch(label,*args)
22
+ touch("view marked:'#{label}'", *args)
23
+ end
24
+
25
+ def tap(label,*args)
26
+ simple_touch(label,*args)
27
+ end
28
+
29
+ def ok
30
+ touch("view marked:'ok'")
31
+ end
32
+
33
+ def set_text(uiquery, txt)
34
+ text_fields_modified = map(uiquery, :setText, txt)
35
+ raise "could not find text field #{uiquery}" if text_fields_modified.empty?
36
+ text_fields_modified
37
+ end
38
+
39
+
40
+ def swipe(dir,options={})
41
+ playback("swipe_#{dir}",options)
42
+ end
43
+
44
+ def cell_swipe(options={})
45
+ playback("cell_swipe",options)
46
+ end
47
+
48
+ def done
49
+ map(nil,:touchDone,load_playback_data("touch_done"))
50
+ end
51
+
52
+ def scroll(uiquery,direction)
53
+ views_touched=map(uiquery, :scroll, direction)
54
+ raise "could not find view to scroll: '#{uiquery}', args: #{direction}" if views_touched.empty?
55
+ views_touched
56
+ end
57
+
58
+ def scroll_to_row(uiquery,number)
59
+ views_touched=map(uiquery, :scrollToRow, number)
60
+ raise "could not find view to scroll: '#{uiquery}', args: #{number}" if views_touched.empty?
61
+ views_touched
62
+ end
63
+
64
+ def pinch(in_out,options={})
65
+ file = "pinch_in"
66
+ if in_out.to_sym==:out
67
+ file = "pinch_out"
68
+ end
69
+ playback(file, options)
70
+ end
71
+
72
+ def rotate(dir)
73
+ @current_rotation = @current_rotation || :down
74
+ rotate_cmd = nil
75
+ case dir
76
+ when :left then
77
+ if @current_rotation == :down
78
+ @current_rotation = :right
79
+ rotate_cmd = "down_to_right"
80
+ elsif @current_rotation == :left
81
+ @current_rotation = :down
82
+ rotate_cmd = "left_to_down"
83
+ end
84
+ when :right then
85
+ if @current_rotation == :down
86
+ @current_rotation = :left
87
+ rotate_cmd = "down_to_left"
88
+ elsif @current_rotation == :right
89
+ @current_rotation = :down
90
+ rotate_cmd = "right_to_down"
91
+ end
92
+ end
93
+
94
+ if rotate_cmd.nil?
95
+ throw "Does not support rotating #{dir} when home button is pointing #{@current_rotation}"
96
+ end
97
+ playback("rotate_home_#{rotate_cmd}")
98
+ end
99
+
100
+ def background(secs)
101
+ raise "Not implemented yet"
102
+ end
103
+
104
+ def element_exists(uiquery)
105
+ !query(uiquery).empty?
106
+ end
107
+
108
+ def view_with_mark_exists(expected_mark)
109
+ element_exists( "view marked:'#{expected_mark}'" )
110
+ end
111
+
112
+ def check_element_exists( query )
113
+ element_exists( query ).should be_true
114
+ end
115
+
116
+ def check_element_does_not_exist( query )
117
+ element_exists( query ).should be_false
118
+ end
119
+
120
+ def check_view_with_mark_exists(expected_mark)
121
+ check_element_exists( "view marked:'#{expected_mark}'" )
122
+ end
123
+
124
+ # a better name would be element_exists_and_is_not_hidden
125
+ def element_is_not_hidden(uiquery)
126
+ matches = query(uiquery, 'isHidden')
127
+ matches.delete(true)
128
+ !matches.empty?
129
+ end
130
+
131
+
132
+ def load_playback_data(recording,options={})
133
+ os = options["OS"] || ENV["OS"]
134
+ device = options["DEVICE"] || ENV["DEVICE"]
135
+
136
+ rec_dir = ENV['PLAYBACK_DIR'] || "#{Dir.pwd}/playback"
137
+ if !recording.end_with?".base64"
138
+ recording = "#{recording}_#{os}_#{device}.base64"
139
+ end
140
+ data = nil
141
+ if (File.exists?(recording))
142
+ data = File.read(recording)
143
+ elsif (File.exists?("#{rec_dir}/#{recording}"))
144
+ data = File.read("#{rec_dir}/#{recording}")
145
+ elsif (File.exists?("#{DATA_PATH}/resources/#{recording}"))
146
+ data = File.read("#{DATA_PATH}/resources/#{recording}")
147
+ else
148
+ raise "Playback not found: #{recording} (searched for #{recording} in #{Dir.pwd}, #{rec_dir}, #{DATA_PATH}/resources"
149
+ end
150
+ data
151
+ end
152
+ def playback(recording, options={})
153
+ data = load_playback_data(recording)
154
+
155
+ post_data = %Q|{"events":"#{data}"|
156
+ post_data<< %Q|,"query":"#{options[:query]}"| if options[:query]
157
+ post_data<< %Q|,"offset":#{options[:offset].to_json}| if options[:offset]
158
+ post_data<< %Q|,"reverse":#{options[:reverse]}| if options[:reverse]
159
+ post_data<< %Q|,"prototype":"#{options[:prototype]}"| if options[:prototype]
160
+ post_data << "}"
161
+
162
+ res = http({:method=>:post, :raw=>true, :path=>'play'}, post_data)
163
+
164
+ res = JSON.parse( res )
165
+ if res['outcome'] != 'SUCCESS'
166
+ raise "playback failed because: #{res['reason']}\n#{res['details']}"
167
+ end
168
+ res['results']
169
+ end
170
+
171
+ def record_begin
172
+ http({:method=>:post, :path=>'record'}, {:action => :start})
173
+ end
174
+
175
+ def record_end(file_name)
176
+ res = http({:method=>:post, :path=>'record'}, {:action => :stop})
177
+ File.open("_recording.plist",'wb') do |f|
178
+ f.write res
179
+ end
180
+ file_name = "#{file_name}_#{ENV['OS']}_#{ENV['DEVICE']}.base64"
181
+ system("plutil -i _recording.plist -o _recording_binary.plist -convert binary1")
182
+ system("openssl base64 -in _recording_binary.plist -out #{file_name}")
183
+ system("rm _recording.plist _recording_binary.plist")
184
+ file_name
185
+ end
186
+
187
+ #def screencast_begin
188
+ # http({:method=>:post, :path=>'screencast'}, {:action => :start})
189
+ #end
190
+ #
191
+ #def screencast_end(file_name)
192
+ # res = http({:method=>:post, :path=>'screencast'}, {:action => :stop})
193
+ # File.open(file_name,'wb') do |f|
194
+ # f.write res
195
+ # end
196
+ # file_name
197
+ #end
198
+
199
+ def screenshot
200
+ if ENV['UUID'] && !/localhost/.match(ENV['DEVICE_ENDPOINT'])
201
+ f = %x[idevicescreenshot -u #{ENV['UUID']}]
202
+ line=f.strip().split("\n").last
203
+ filename=line.split(" ").last
204
+ outfile = "#{ENV['SCREENSHOT_PATH_PREFIX']}_#{CALABASH_COUNT[:step_line]}.png"
205
+ if File.exist?filename
206
+ puts "converting screenshot: #{filename} to #{outfile}"
207
+ system("convert #{filename} #{outfile}")
208
+ else
209
+ raise "Error. Unable to screenshot for device #{ENV['UUID']}."
210
+ end
211
+ else
212
+ res = http({:method =>:get, :path => 'screenshot'})
213
+ path = "screenshot_#{CALABASH_COUNT[:step_line]}.png"
214
+ File.open(path,'wb') do |f|
215
+ f.write res
216
+ end
217
+ puts "Saved screenshot: #{path}"
218
+ end
219
+ end
220
+
221
+ def map( query, method_name, *method_args )
222
+ operation_map = {
223
+ :method_name => method_name,
224
+ :arguments => method_args
225
+ }
226
+ res = http({:method=>:post, :path=>'map'},
227
+ {:query => query, :operation => operation_map})
228
+ res = JSON.parse(res)
229
+ if res['outcome'] != 'SUCCESS'
230
+ raise "map #{query}, #{method_name} failed because: #{res['reason']}\n#{res['details']}"
231
+ end
232
+
233
+ res['results']
234
+ end
235
+
236
+ def http(options, data=nil)
237
+ url = url_for(options[:path])
238
+ if options[:method] == :post
239
+ req = Net::HTTP::Post.new url.path
240
+ if options[:raw]
241
+ req.body=data
242
+ else
243
+ req.body = data.to_json
244
+ end
245
+
246
+ else
247
+ req = Net::HTTP::Get.new url.path
248
+ end
249
+ make_http_request( url, req )
250
+ end
251
+
252
+
253
+ def url_for( verb )
254
+ url = URI.parse (ENV['DEVICE_ENDPOINT']|| "http://localhost:37265/")
255
+ url.path = '/'+verb
256
+ url
257
+ end
258
+
259
+ def make_http_request( url, req )
260
+ @http = @http || Net::HTTP.new(url.host, url.port)
261
+ res = @http.start do |sess|
262
+ sess.request req
263
+ end
264
+ res.body
265
+ end
266
+
267
+
268
+ end
269
+
270
+
271
+ end end