calabash-cucumber 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CHANGES.txt +1 -0
- data/Gemfile +4 -0
- data/LICENSE +8 -0
- data/README.md +182 -0
- data/Rakefile +2 -0
- data/bin/calabash +21 -0
- data/calabash-cucumber.gemspec +23 -0
- data/copy_resources.sh +2 -0
- data/epl-v10.html +261 -0
- data/features-skeleton/my_first.feature +8 -0
- data/features-skeleton/step_definitions/calabash_steps.rb +1 -0
- data/features-skeleton/support/env.rb +1 -0
- data/features-skeleton/support/hooks.rb +17 -0
- data/lib/calabash-cucumber.rb +0 -0
- data/lib/calabash-cucumber/calabash_steps.rb +307 -0
- data/lib/calabash-cucumber/color_helper.rb +13 -0
- data/lib/calabash-cucumber/cucumber.rb +9 -0
- data/lib/calabash-cucumber/operations.rb +271 -0
- data/lib/calabash-cucumber/resources/cell_swipe_ios4_ipad.base64 +51 -0
- data/lib/calabash-cucumber/resources/cell_swipe_ios4_iphone.base64 +51 -0
- data/lib/calabash-cucumber/resources/cell_swipe_ios5_ipad.base64 +74 -0
- data/lib/calabash-cucumber/resources/cell_swipe_ios5_iphone.base64 +74 -0
- data/lib/calabash-cucumber/resources/pinch_in_ios4_ipad.base64 +104 -0
- data/lib/calabash-cucumber/resources/pinch_in_ios4_iphone.base64 +104 -0
- data/lib/calabash-cucumber/resources/pinch_in_ios5_ipad.base64 +144 -0
- data/lib/calabash-cucumber/resources/pinch_in_ios5_iphone.base64 +144 -0
- data/lib/calabash-cucumber/resources/pinch_out_ios5_ipad.base64 +207 -0
- data/lib/calabash-cucumber/resources/pinch_out_ios5_iphone.base64 +207 -0
- data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_ipad.base64 +15 -0
- data/lib/calabash-cucumber/resources/swipe_left_hard_ios4_iphone.base64 +15 -0
- data/lib/calabash-cucumber/resources/swipe_left_ios4_ipad.base64 +18 -0
- data/lib/calabash-cucumber/resources/swipe_left_ios4_iphone.base64 +18 -0
- data/lib/calabash-cucumber/resources/swipe_left_ios5_ipad.base64 +17 -0
- data/lib/calabash-cucumber/resources/swipe_left_ios5_iphone.base64 +17 -0
- data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_ipad.base64 +17 -0
- data/lib/calabash-cucumber/resources/swipe_right_hard_ios4_iphone.base64 +17 -0
- data/lib/calabash-cucumber/resources/swipe_right_ios4_ipad.base64 +13 -0
- data/lib/calabash-cucumber/resources/swipe_right_ios4_iphone.base64 +13 -0
- data/lib/calabash-cucumber/resources/swipe_right_ios5_ipad.base64 +17 -0
- data/lib/calabash-cucumber/resources/swipe_right_ios5_iphone.base64 +17 -0
- data/lib/calabash-cucumber/resources/touch_done_ios4_ipad.base64 +8 -0
- data/lib/calabash-cucumber/resources/touch_done_ios4_iphone.base64 +8 -0
- data/lib/calabash-cucumber/resources/touch_done_ios5_ipad.base64 +8 -0
- data/lib/calabash-cucumber/resources/touch_done_ios5_iphone.base64 +8 -0
- data/lib/calabash-cucumber/resources/touch_ios4_ipad.base64 +7 -0
- data/lib/calabash-cucumber/resources/touch_ios4_iphone.base64 +7 -0
- data/lib/calabash-cucumber/resources/touch_ios5_ipad.base64 +8 -0
- data/lib/calabash-cucumber/resources/touch_ios5_iphone.base64 +8 -0
- data/lib/calabash-cucumber/version.rb +5 -0
- metadata +141 -0
@@ -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,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
|