calabash-cucumber 0.9.68 → 0.9.70
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/Gemfile.lock +3 -3
- data/bin/CalabashSetup +0 -0
- data/bin/calabash-ios-helpers.rb +6 -3
- data/calabash-cucumber.gemspec +1 -1
- data/features-skeleton/my_first.feature +6 -2
- data/features/step_definitions/my_first_steps.rb +4 -0
- data/lib/calabash-cucumber/launch/simulator_helper.rb +4 -1
- data/lib/calabash-cucumber/operations.rb +402 -358
- data/lib/calabash-cucumber/version.rb +2 -2
- metadata +5 -3
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
calabash-cucumber (0.9.
|
4
|
+
calabash-cucumber (0.9.70)
|
5
5
|
CFPropertyList
|
6
6
|
cucumber
|
7
7
|
json
|
@@ -20,9 +20,9 @@ GEM
|
|
20
20
|
gherkin (~> 2.11.0)
|
21
21
|
json (>= 1.4.6)
|
22
22
|
diff-lcs (1.1.3)
|
23
|
-
gherkin (2.11.
|
23
|
+
gherkin (2.11.1)
|
24
24
|
json (>= 1.4.6)
|
25
|
-
json (1.
|
25
|
+
json (1.7.3)
|
26
26
|
net-http-persistent (2.7)
|
27
27
|
rack (1.4.1)
|
28
28
|
rack-protection (1.2.0)
|
data/bin/CalabashSetup
CHANGED
Binary file
|
data/bin/calabash-ios-helpers.rb
CHANGED
@@ -103,11 +103,14 @@ def calabash_submit(args)
|
|
103
103
|
end
|
104
104
|
system ("zip -r -o #{archive_path} #{feature_path}")
|
105
105
|
|
106
|
+
|
107
|
+
|
108
|
+
url = ENV['SUBMIT_URL'] || "https://www.lesspainful.com/cmd_upload"
|
109
|
+
|
106
110
|
msg("Info") do
|
107
|
-
puts "Uploading ipa and features to
|
111
|
+
puts "Uploading ipa and features to #{url}"
|
108
112
|
end
|
109
|
-
|
110
|
-
result = `curl -F "secret=#{secret}" -F "app=@#{ipa_file}" -F "env=@#{archive_path}" https://www.lesspainful.com/cmd_upload`
|
113
|
+
result = `curl -F "secret=#{secret}" -F "app=@#{ipa_file}" -F "env=@#{archive_path}" #{url}`
|
111
114
|
|
112
115
|
if is_json? result
|
113
116
|
json_result = JSON.parse(result)
|
data/calabash-cucumber.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Karl Krukow"]
|
10
10
|
s.email = ["karl@lesspainful.com"]
|
11
|
-
s.homepage = "http://
|
11
|
+
s.homepage = "http://calaba.sh"
|
12
12
|
s.summary = %q{Client for calabash-ios-server for automated functional testing on iOS}
|
13
13
|
s.description = %q{calabash-cucumber drives tests for native iOS apps. You must link your app with calabash-ios-server framework to execute tests.}
|
14
14
|
s.files = `git ls-files`.split("\n")
|
@@ -4,5 +4,9 @@ Feature: Running a test
|
|
4
4
|
So I can begin testing quickly
|
5
5
|
|
6
6
|
Scenario: Example steps
|
7
|
-
Given the
|
8
|
-
|
7
|
+
Given I am on the Welcome Screen
|
8
|
+
When I swipe left
|
9
|
+
Then I wait until I don't see "Please swipe left"
|
10
|
+
And take picture
|
11
|
+
|
12
|
+
|
@@ -10,6 +10,8 @@ module Calabash
|
|
10
10
|
DERIVED_DATA = File.expand_path("~/Library/Developer/Xcode/DerivedData")
|
11
11
|
DEFAULT_DERIVED_DATA_INFO = File.expand_path("#{DERIVED_DATA}/*/info.plist")
|
12
12
|
|
13
|
+
DEFAULT_SIM_WAIT = "15"
|
14
|
+
|
13
15
|
MAX_PING_ATTEMPTS = 5
|
14
16
|
|
15
17
|
def self.relaunch(path, sdk = nil, version = 'iphone')
|
@@ -161,7 +163,8 @@ module Calabash
|
|
161
163
|
|
162
164
|
def self.ensure_connectivity(app_bundle_path, sdk, version)
|
163
165
|
begin
|
164
|
-
|
166
|
+
timeout = (ENV['CONNECT_TIMEOUT'] || DEFAULT_SIM_WAIT).to_i
|
167
|
+
Timeout::timeout(timeout) do
|
165
168
|
connected = false
|
166
169
|
until connected
|
167
170
|
simulator = launch(app_bundle_path, sdk, version)
|
@@ -7,437 +7,481 @@ if not Object.const_defined?(:CALABASH_COUNT)
|
|
7
7
|
end
|
8
8
|
|
9
9
|
|
10
|
+
module Calabash
|
11
|
+
module Cucumber
|
10
12
|
|
13
|
+
module Operations
|
11
14
|
|
12
|
-
|
15
|
+
DATA_PATH = File.expand_path(File.dirname(__FILE__))
|
13
16
|
|
14
|
-
|
17
|
+
KEYBOARD_SMALL_LETTERS = "Keyboard_Small-Letters"
|
18
|
+
KEYBOARD_CAPITAL_LETTERS = "Keyboard_Capital-Letters"
|
19
|
+
KEYBOARD_NUMBERS_AND_PUNCTUATION = "Keyboard_Numbers-And-Punctuation"
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
21
|
+
def macro(txt)
|
22
|
+
if self.respond_to? :step
|
23
|
+
step(txt)
|
24
|
+
else
|
25
|
+
Then txt
|
26
|
+
end
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
def home_direction
|
30
|
+
@current_rotation = @current_rotation || :down
|
31
|
+
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
def assert_home_direction(expected)
|
34
|
+
unless expected.to_sym == home_direction
|
35
|
+
screenshot_and_raise "Expected home button to have direction #{expected} but had #{home_direction}"
|
36
|
+
end
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
def escape_quotes(str)
|
40
|
+
str.gsub("'", "\\\\'")
|
41
|
+
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def wait_for(timeout, &block)
|
44
|
+
begin
|
45
|
+
Timeout::timeout(timeout) do
|
46
|
+
until block.call
|
47
|
+
sleep 0.3
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rescue Exception => e
|
51
|
+
screenshot_and_raise e
|
45
52
|
end
|
46
53
|
end
|
47
|
-
rescue Exception => e
|
48
|
-
screenshot_and_raise e
|
49
|
-
end
|
50
|
-
end
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
def wait_ready(timeout, times=2, sleep=0.3, &block)
|
56
|
+
raise "Times parameter must be greater than or equal 2" if times < 2
|
57
|
+
raise "Sleep parameter must be greater than 0" if sleep <= 0
|
58
|
+
begin
|
59
|
+
Timeout::timeout(timeout) do
|
60
|
+
while times > 0 do
|
61
|
+
if block.call
|
62
|
+
times -= 1
|
63
|
+
end
|
64
|
+
sleep 0.3
|
65
|
+
end
|
60
66
|
end
|
61
|
-
|
67
|
+
rescue Exception => e
|
68
|
+
screenshot_and_raise e
|
62
69
|
end
|
63
70
|
end
|
64
|
-
rescue Exception => e
|
65
|
-
screenshot_and_raise e
|
66
|
-
end
|
67
|
-
end
|
68
71
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
def query(uiquery, *args)
|
73
|
+
map(uiquery, :query, *args)
|
74
|
+
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
def label(uiquery)
|
77
|
+
query(uiquery, :accessibilityLabel)
|
78
|
+
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
def screenshot_and_raise(msg)
|
81
|
+
screenshot
|
82
|
+
sleep 5
|
83
|
+
raise(msg)
|
84
|
+
end
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
def touch(uiquery, options={})
|
87
|
+
options[:query] = uiquery
|
88
|
+
views_touched = playback("touch", options)
|
89
|
+
unless uiquery.nil?
|
90
|
+
screenshot_and_raise "could not find view to touch: '#{uiquery}', args: #{options}" if views_touched.empty?
|
91
|
+
end
|
92
|
+
views_touched
|
93
|
+
end
|
91
94
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
+
def simple_touch(label, *args)
|
96
|
+
touch("view marked:'#{label}'", *args)
|
97
|
+
end
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
+
def tap(label, *args)
|
100
|
+
simple_touch(label, *args)
|
101
|
+
end
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
+
def html(q)
|
104
|
+
query(q).map { |e| e['html'] }
|
105
|
+
end
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
+
def ok
|
108
|
+
touch("view marked:'ok'")
|
109
|
+
end
|
107
110
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
def set_text(uiquery, txt)
|
112
|
+
text_fields_modified = map(uiquery, :setText, txt)
|
113
|
+
screenshot_and_raise "could not find text field #{uiquery}" if text_fields_modified.empty?
|
114
|
+
text_fields_modified
|
115
|
+
end
|
113
116
|
|
114
117
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
def swipe(dir, options={})
|
119
|
+
dir = dir.to_sym
|
120
|
+
@current_rotation = @current_rotation || :down
|
121
|
+
if @current_rotation == :left
|
119
122
|
case dir
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
123
|
+
when :left then
|
124
|
+
dir = :down
|
125
|
+
when :right then
|
126
|
+
dir = :up
|
127
|
+
when :up then
|
128
|
+
dir = :left
|
129
|
+
when :down then
|
130
|
+
dir = :right
|
131
|
+
else
|
125
132
|
end
|
126
|
-
|
127
|
-
|
133
|
+
end
|
134
|
+
if @current_rotation == :right
|
128
135
|
case dir
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
136
|
+
when :left then
|
137
|
+
dir = :up
|
138
|
+
when :right then
|
139
|
+
dir = :down
|
140
|
+
when :up then
|
141
|
+
dir = :right
|
142
|
+
when :down then
|
143
|
+
dir = :left
|
144
|
+
else
|
134
145
|
end
|
135
|
-
|
136
|
-
|
146
|
+
end
|
147
|
+
if @current_rotation == :up
|
137
148
|
case dir
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
149
|
+
when :left then
|
150
|
+
dir = :right
|
151
|
+
when :right then
|
152
|
+
dir = :left
|
153
|
+
when :up then
|
154
|
+
dir = :down
|
155
|
+
when :down then
|
156
|
+
dir = :up
|
157
|
+
else
|
143
158
|
end
|
159
|
+
end
|
160
|
+
playback("swipe_#{dir}", options)
|
144
161
|
end
|
145
|
-
playback("swipe_#{dir}",options)
|
146
|
-
end
|
147
162
|
|
148
|
-
|
149
|
-
|
150
|
-
|
163
|
+
def cell_swipe(options={})
|
164
|
+
playback("cell_swipe", options)
|
165
|
+
end
|
151
166
|
|
152
|
-
|
153
|
-
|
154
|
-
|
167
|
+
def done
|
168
|
+
map(nil, :keyboard, load_playback_data("touch_done"))
|
169
|
+
end
|
155
170
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
171
|
+
#Possible values
|
172
|
+
# 'Dictation'
|
173
|
+
# 'Shift'
|
174
|
+
# 'Delete'
|
175
|
+
# 'International'
|
176
|
+
# 'More'
|
177
|
+
def keyboard_enter_char(chr)
|
178
|
+
map(nil, :keyboard, load_playback_data("touch_done"), chr)
|
179
|
+
end
|
162
180
|
|
163
|
-
|
164
|
-
|
165
|
-
|
181
|
+
def keyboard_change_keyplane(plane)
|
182
|
+
desc = query("view:'UIKBKeyplaneView'", "keyplane", "description")
|
183
|
+
return nil if desc.empty?
|
184
|
+
desc = desc.first
|
185
|
+
plane_exp = Regexp.new(plane)
|
186
|
+
if not plane_exp.match(desc)
|
187
|
+
keyboard_enter_char "Shift"
|
188
|
+
sleep(0.3)
|
189
|
+
desc = query("view:'UIKBKeyplaneView'", "keyplane", "description").first
|
190
|
+
if not plane_exp.match(desc)
|
191
|
+
keyboard_enter_char "Shift"
|
192
|
+
sleep(0.3)
|
193
|
+
return nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
desc
|
197
|
+
end
|
166
198
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
199
|
+
#TODO only letters now
|
200
|
+
def keyboard_enter_text(text)
|
201
|
+
text.each_char do |ch|
|
202
|
+
if /[a-z]/.match(ch)
|
203
|
+
keyboard_change_keyplane(KEYBOARD_SMALL_LETTERS)
|
204
|
+
elsif /\d/.match(ch)
|
205
|
+
#Todo - handle digits and special chars
|
206
|
+
raise "Digits and special chars not handled by keyboard_enter_text yet."
|
207
|
+
else
|
208
|
+
keyboard_change_keyplane(KEYBOARD_CAPITAL_LETTERS)
|
209
|
+
end
|
210
|
+
keyboard_enter_char(ch)
|
211
|
+
sleep(0.3)
|
212
|
+
end
|
213
|
+
end
|
172
214
|
|
173
|
-
def scroll_to_row(uiquery,number)
|
174
|
-
views_touched=map(uiquery, :scrollToRow, number)
|
175
|
-
if views_touched.empty? or views_touched.member?"<VOID>"
|
176
|
-
screenshot_and_raise "Unable to scroll: '#{uiquery}' to: #{number}"
|
177
|
-
end
|
178
|
-
views_touched
|
179
|
-
end
|
180
215
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
playback(file, options)
|
187
|
-
end
|
216
|
+
def scroll(uiquery, direction)
|
217
|
+
views_touched=map(uiquery, :scroll, direction)
|
218
|
+
screenshot_and_raise "could not find view to scroll: '#{uiquery}', args: #{direction}" if views_touched.empty?
|
219
|
+
views_touched
|
220
|
+
end
|
188
221
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
when :left then
|
194
|
-
if @current_rotation == :down
|
195
|
-
rotate_cmd = "left_home_down"
|
196
|
-
@current_rotation = :right
|
197
|
-
elsif @current_rotation == :right
|
198
|
-
rotate_cmd = "left_home_right"
|
199
|
-
@current_rotation = :up
|
200
|
-
elsif @current_rotation == :left
|
201
|
-
rotate_cmd = "left_home_left"
|
202
|
-
@current_rotation = :down
|
203
|
-
elsif @current_rotation == :up
|
204
|
-
rotate_cmd = "left_home_up"
|
205
|
-
@current_rotation = :left
|
222
|
+
def scroll_to_row(uiquery, number)
|
223
|
+
views_touched=map(uiquery, :scrollToRow, number)
|
224
|
+
if views_touched.empty? or views_touched.member? "<VOID>"
|
225
|
+
screenshot_and_raise "Unable to scroll: '#{uiquery}' to: #{number}"
|
206
226
|
end
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
elsif @current_rotation == :right
|
215
|
-
rotate_cmd = "right_home_right"
|
216
|
-
@current_rotation = :down
|
217
|
-
elsif @current_rotation == :up
|
218
|
-
rotate_cmd = "right_home_up"
|
219
|
-
@current_rotation = :right
|
227
|
+
views_touched
|
228
|
+
end
|
229
|
+
|
230
|
+
def pinch(in_out, options={})
|
231
|
+
file = "pinch_in"
|
232
|
+
if in_out.to_sym==:out
|
233
|
+
file = "pinch_out"
|
220
234
|
end
|
221
|
-
|
235
|
+
playback(file, options)
|
236
|
+
end
|
222
237
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
238
|
+
def rotate(dir)
|
239
|
+
@current_rotation = @current_rotation || :down
|
240
|
+
rotate_cmd = nil
|
241
|
+
case dir
|
242
|
+
when :left then
|
243
|
+
if @current_rotation == :down
|
244
|
+
rotate_cmd = "left_home_down"
|
245
|
+
@current_rotation = :right
|
246
|
+
elsif @current_rotation == :right
|
247
|
+
rotate_cmd = "left_home_right"
|
248
|
+
@current_rotation = :up
|
249
|
+
elsif @current_rotation == :left
|
250
|
+
rotate_cmd = "left_home_left"
|
251
|
+
@current_rotation = :down
|
252
|
+
elsif @current_rotation == :up
|
253
|
+
rotate_cmd = "left_home_up"
|
254
|
+
@current_rotation = :left
|
255
|
+
end
|
256
|
+
when :right then
|
257
|
+
if @current_rotation == :down
|
258
|
+
rotate_cmd = "right_home_down"
|
259
|
+
@current_rotation = :left
|
260
|
+
elsif @current_rotation == :left
|
261
|
+
rotate_cmd = "right_home_left"
|
262
|
+
@current_rotation = :up
|
263
|
+
elsif @current_rotation == :right
|
264
|
+
rotate_cmd = "right_home_right"
|
265
|
+
@current_rotation = :down
|
266
|
+
elsif @current_rotation == :up
|
267
|
+
rotate_cmd = "right_home_up"
|
268
|
+
@current_rotation = :right
|
269
|
+
end
|
270
|
+
end
|
228
271
|
|
229
|
-
|
230
|
-
|
231
|
-
|
272
|
+
if rotate_cmd.nil?
|
273
|
+
screenshot_and_raise "Does not support rotating #{dir} when home button is pointing #{@current_rotation}"
|
274
|
+
end
|
275
|
+
playback("rotate_#{rotate_cmd}")
|
276
|
+
end
|
232
277
|
|
233
|
-
|
234
|
-
|
235
|
-
|
278
|
+
def background(secs)
|
279
|
+
res = http({:method=>:post, :path=>'background'}, {:duration => secs})
|
280
|
+
end
|
236
281
|
|
237
|
-
|
238
|
-
|
239
|
-
|
282
|
+
def element_exists(uiquery)
|
283
|
+
!query(uiquery).empty?
|
284
|
+
end
|
240
285
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
end
|
245
|
-
end
|
286
|
+
def view_with_mark_exists(expected_mark)
|
287
|
+
element_exists("view marked:'#{expected_mark}'")
|
288
|
+
end
|
246
289
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
290
|
+
def check_element_exists(query)
|
291
|
+
if not element_exists(query)
|
292
|
+
screenshot_and_raise "No element found for query: #{query}"
|
293
|
+
end
|
294
|
+
end
|
252
295
|
|
253
|
-
|
254
|
-
|
255
|
-
|
296
|
+
def check_element_does_not_exist(query)
|
297
|
+
if element_exists(query)
|
298
|
+
screenshot_and_raise "Expected no elements to match query: #{query}"
|
299
|
+
end
|
300
|
+
end
|
256
301
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
matches.delete(true)
|
261
|
-
!matches.empty?
|
262
|
-
end
|
302
|
+
def check_view_with_mark_exists(expected_mark)
|
303
|
+
check_element_exists("view marked:'#{expected_mark}'")
|
304
|
+
end
|
263
305
|
|
306
|
+
# a better name would be element_exists_and_is_not_hidden
|
307
|
+
def element_is_not_hidden(uiquery)
|
308
|
+
matches = query(uiquery, 'isHidden')
|
309
|
+
matches.delete(true)
|
310
|
+
!matches.empty?
|
311
|
+
end
|
264
312
|
|
265
|
-
def load_playback_data(recording,options={})
|
266
|
-
os = options["OS"] || ENV["OS"] || "ios5"
|
267
|
-
device = options["DEVICE"] || ENV["DEVICE"] || "iphone"
|
268
313
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
end
|
273
|
-
data = nil
|
274
|
-
if (File.exists?(recording))
|
275
|
-
data = File.read(recording)
|
276
|
-
elsif (File.exists?("features/#{recording}"))
|
277
|
-
data = File.read("features/#{recording}")
|
278
|
-
elsif (File.exists?("#{rec_dir}/#{recording}"))
|
279
|
-
data = File.read("#{rec_dir}/#{recording}")
|
280
|
-
elsif (File.exists?("#{DATA_PATH}/resources/#{recording}"))
|
281
|
-
data = File.read("#{DATA_PATH}/resources/#{recording}")
|
282
|
-
else
|
283
|
-
screenshot_and_raise "Playback not found: #{recording} (searched for #{recording} in #{Dir.pwd}, #{rec_dir}, #{DATA_PATH}/resources"
|
284
|
-
end
|
285
|
-
data
|
286
|
-
end
|
287
|
-
def playback(recording, options={})
|
288
|
-
data = load_playback_data(recording)
|
314
|
+
def load_playback_data(recording, options={})
|
315
|
+
os = options["OS"] || ENV["OS"] || "ios5"
|
316
|
+
device = options["DEVICE"] || ENV["DEVICE"] || "iphone"
|
289
317
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
318
|
+
rec_dir = ENV['PLAYBACK_DIR'] || "#{Dir.pwd}/playback"
|
319
|
+
if !recording.end_with? ".base64"
|
320
|
+
recording = "#{recording}_#{os}_#{device}.base64"
|
321
|
+
end
|
322
|
+
data = nil
|
323
|
+
if (File.exists?(recording))
|
324
|
+
data = File.read(recording)
|
325
|
+
elsif (File.exists?("features/#{recording}"))
|
326
|
+
data = File.read("features/#{recording}")
|
327
|
+
elsif (File.exists?("#{rec_dir}/#{recording}"))
|
328
|
+
data = File.read("#{rec_dir}/#{recording}")
|
329
|
+
elsif (File.exists?("#{DATA_PATH}/resources/#{recording}"))
|
330
|
+
data = File.read("#{DATA_PATH}/resources/#{recording}")
|
331
|
+
else
|
332
|
+
screenshot_and_raise "Playback not found: #{recording} (searched for #{recording} in #{Dir.pwd}, #{rec_dir}, #{DATA_PATH}/resources"
|
333
|
+
end
|
334
|
+
data
|
335
|
+
end
|
296
336
|
|
297
|
-
|
337
|
+
def playback(recording, options={})
|
338
|
+
data = load_playback_data(recording)
|
298
339
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
340
|
+
post_data = %Q|{"events":"#{data}"|
|
341
|
+
post_data<< %Q|,"query":"#{escape_quotes(options[:query])}"| if options[:query]
|
342
|
+
post_data<< %Q|,"offset":#{options[:offset].to_json}| if options[:offset]
|
343
|
+
post_data<< %Q|,"reverse":#{options[:reverse]}| if options[:reverse]
|
344
|
+
post_data<< %Q|,"prototype":"#{options[:prototype]}"| if options[:prototype]
|
345
|
+
post_data << "}"
|
346
|
+
|
347
|
+
res = http({:method=>:post, :raw=>true, :path=>'play'}, post_data)
|
348
|
+
|
349
|
+
res = JSON.parse(res)
|
350
|
+
if res['outcome'] != 'SUCCESS'
|
351
|
+
screenshot_and_raise "playback failed because: #{res['reason']}\n#{res['details']}"
|
352
|
+
end
|
353
|
+
res['results']
|
354
|
+
end
|
305
355
|
|
306
|
-
|
307
|
-
|
356
|
+
def interpolate(recording, options={})
|
357
|
+
data = load_playback_data(recording)
|
308
358
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
359
|
+
post_data = %Q|{"events":"#{data}"|
|
360
|
+
post_data<< %Q|,"start":"#{escape_quotes(options[:start])}"| if options[:start]
|
361
|
+
post_data<< %Q|,"end":"#{escape_quotes(options[:end])}"| if options[:end]
|
362
|
+
post_data<< %Q|,"offset_start":#{options[:offset_start].to_json}| if options[:offset_start]
|
363
|
+
post_data<< %Q|,"offset_end":#{options[:offset_end].to_json}| if options[:offset_end]
|
364
|
+
post_data << "}"
|
315
365
|
|
316
|
-
|
366
|
+
res = http({:method=>:post, :raw=>true, :path=>'interpolate'}, post_data)
|
317
367
|
|
318
|
-
|
319
|
-
|
320
|
-
|
368
|
+
res = JSON.parse(res)
|
369
|
+
if res['outcome'] != 'SUCCESS'
|
370
|
+
screenshot_and_raise "interpolate failed because: #{res['reason']}\n#{res['details']}"
|
371
|
+
end
|
372
|
+
res['results']
|
321
373
|
end
|
322
|
-
res['results']
|
323
|
-
end
|
324
374
|
|
325
|
-
|
326
|
-
|
327
|
-
|
375
|
+
def record_begin
|
376
|
+
http({:method=>:post, :path=>'record'}, {:action => :start})
|
377
|
+
end
|
328
378
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
raise "Either SDK_VERSION or OS environment vars must be set."
|
344
|
-
end
|
345
|
-
file_name = "#{file_name}_#{os}_#{device}.base64"
|
346
|
-
system("/usr/bin/plutil -convert binary1 -o _recording_binary.plist _recording.plist")
|
347
|
-
system("openssl base64 -in _recording_binary.plist -out #{file_name}")
|
348
|
-
system("rm _recording.plist _recording_binary.plist")
|
349
|
-
file_name
|
350
|
-
end
|
379
|
+
def record_end(file_name)
|
380
|
+
res = http({:method=>:post, :path=>'record'}, {:action => :stop})
|
381
|
+
File.open("_recording.plist", 'wb') do |f|
|
382
|
+
f.write res
|
383
|
+
end
|
384
|
+
device = ENV['DEVICE'] || 'iphone'
|
385
|
+
os = ENV['OS'] || 'ios5'
|
386
|
+
|
387
|
+
file_name = "#{file_name}_#{os}_#{device}.base64"
|
388
|
+
system("/usr/bin/plutil -convert binary1 -o _recording_binary.plist _recording.plist")
|
389
|
+
system("openssl base64 -in _recording_binary.plist -out #{file_name}")
|
390
|
+
system("rm _recording.plist _recording_binary.plist")
|
391
|
+
file_name
|
392
|
+
end
|
351
393
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
screenshot_and_raise "
|
361
|
-
|
362
|
-
|
363
|
-
|
394
|
+
def backdoor(sel, arg)
|
395
|
+
json = {
|
396
|
+
:selector => sel,
|
397
|
+
:arg => arg
|
398
|
+
}
|
399
|
+
res = http({:method=>:post, :path=>'backdoor'}, json)
|
400
|
+
res = JSON.parse(res)
|
401
|
+
if res['outcome'] != 'SUCCESS'
|
402
|
+
screenshot_and_raise "backdoor #{json} failed because: #{res['reason']}\n#{res['details']}"
|
403
|
+
end
|
404
|
+
res['result']
|
405
|
+
end
|
364
406
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
407
|
+
#def screencast_begin
|
408
|
+
# http({:method=>:post, :path=>'screencast'}, {:action => :start})
|
409
|
+
#end
|
410
|
+
#
|
411
|
+
#def screencast_end(file_name)
|
412
|
+
# res = http({:method=>:post, :path=>'screencast'}, {:action => :stop})
|
413
|
+
# File.open(file_name,'wb') do |f|
|
414
|
+
# f.write res
|
415
|
+
# end
|
416
|
+
# file_name
|
417
|
+
#end
|
418
|
+
|
419
|
+
def screenshot(prefix=nil, name=nil)
|
420
|
+
res = http({:method =>:get, :path => 'screenshot'})
|
421
|
+
prefix = prefix || ENV['SCREENSHOT_PATH'] || ""
|
422
|
+
name = "screenshot_#{CALABASH_COUNT[:step_line]}.png" if name.nil?
|
423
|
+
path = "#{prefix}#{name}"
|
424
|
+
File.open(path, 'wb') do |f|
|
425
|
+
f.write res
|
426
|
+
end
|
427
|
+
puts "Saved screenshot: #{path}"
|
428
|
+
path
|
429
|
+
end
|
387
430
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
431
|
+
def map(query, method_name, *method_args)
|
432
|
+
operation_map = {
|
433
|
+
:method_name => method_name,
|
434
|
+
:arguments => method_args
|
435
|
+
}
|
436
|
+
res = http({:method=>:post, :path=>'map'},
|
437
|
+
{:query => query, :operation => operation_map})
|
438
|
+
res = JSON.parse(res)
|
439
|
+
if res['outcome'] != 'SUCCESS'
|
440
|
+
screenshot_and_raise "map #{query}, #{method_name} failed because: #{res['reason']}\n#{res['details']}"
|
441
|
+
end
|
399
442
|
|
400
|
-
|
401
|
-
|
443
|
+
res['results']
|
444
|
+
end
|
402
445
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
446
|
+
def http(options, data=nil)
|
447
|
+
url = url_for(options[:path])
|
448
|
+
if options[:method] == :post
|
449
|
+
req = Net::HTTP::Post.new url.path
|
450
|
+
if options[:raw]
|
451
|
+
req.body=data
|
452
|
+
else
|
453
|
+
req.body = data.to_json
|
454
|
+
end
|
455
|
+
|
456
|
+
else
|
457
|
+
req = Net::HTTP::Get.new url.path
|
458
|
+
end
|
459
|
+
make_http_request(url, req)
|
411
460
|
end
|
412
461
|
|
413
|
-
else
|
414
|
-
req = Net::HTTP::Get.new url.path
|
415
|
-
end
|
416
|
-
make_http_request( url, req )
|
417
|
-
end
|
418
462
|
|
463
|
+
def url_for(verb)
|
464
|
+
url = URI.parse(ENV['DEVICE_ENDPOINT']|| "http://localhost:37265/")
|
465
|
+
url.path = '/'+verb
|
466
|
+
url
|
467
|
+
end
|
419
468
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
469
|
+
def make_http_request(url, req)
|
470
|
+
@http = Net::HTTP.new(url.host, url.port)
|
471
|
+
res = @http.start do |sess|
|
472
|
+
sess.request req
|
473
|
+
end
|
474
|
+
body = res.body
|
475
|
+
begin
|
476
|
+
@http.finish if @http and @http.started?
|
477
|
+
rescue Exception => e
|
478
|
+
puts "Finish #{e}"
|
479
|
+
end
|
480
|
+
body
|
481
|
+
end
|
425
482
|
|
426
|
-
def make_http_request( url, req )
|
427
|
-
@http = Net::HTTP.new(url.host, url.port)
|
428
|
-
res = @http.start do |sess|
|
429
|
-
sess.request req
|
430
483
|
end
|
431
|
-
body = res.body
|
432
|
-
begin
|
433
|
-
@http.finish if @http and @http.started?
|
434
|
-
rescue Exception => e
|
435
|
-
puts "Finish #{e}"
|
436
|
-
end
|
437
|
-
body
|
438
|
-
end
|
439
|
-
|
440
|
-
end
|
441
484
|
|
442
485
|
|
443
|
-
end
|
486
|
+
end
|
487
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calabash-cucumber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.70
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cucumber
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- features-skeleton/support/hooks.rb
|
143
143
|
- features-skeleton/support/launch.rb
|
144
144
|
- features/step_definitions/calabash_steps.rb
|
145
|
+
- features/step_definitions/my_first_steps.rb
|
145
146
|
- lib/calabash-cucumber.rb
|
146
147
|
- lib/calabash-cucumber/calabash_steps.rb
|
147
148
|
- lib/calabash-cucumber/color_helper.rb
|
@@ -218,7 +219,7 @@ files:
|
|
218
219
|
- scripts/data/.GlobalPreferences.plist
|
219
220
|
- scripts/data/com.apple.Accessibility.plist
|
220
221
|
- scripts/reset_simulator.scpt
|
221
|
-
homepage: http://
|
222
|
+
homepage: http://calaba.sh
|
222
223
|
licenses: []
|
223
224
|
post_install_message:
|
224
225
|
rdoc_options: []
|
@@ -244,3 +245,4 @@ specification_version: 3
|
|
244
245
|
summary: Client for calabash-ios-server for automated functional testing on iOS
|
245
246
|
test_files:
|
246
247
|
- features/step_definitions/calabash_steps.rb
|
248
|
+
- features/step_definitions/my_first_steps.rb
|