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