calabash-cucumber 0.9.0

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.
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