calabash-cucumber 0.9.163.pre6 → 0.9.163.pre7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/calabash-cucumber.gemspec +1 -1
  3. data/lib/calabash-cucumber/actions/instruments_actions.rb +135 -0
  4. data/lib/calabash-cucumber/actions/playback_actions.rb +104 -0
  5. data/lib/calabash-cucumber/connection.rb +16 -0
  6. data/lib/calabash-cucumber/connection_helpers.rb +17 -0
  7. data/lib/calabash-cucumber/core.rb +80 -553
  8. data/lib/calabash-cucumber/failure_helpers.rb +44 -0
  9. data/lib/calabash-cucumber/http_helpers.rb +102 -0
  10. data/lib/calabash-cucumber/ios7_operations.rb +46 -31
  11. data/lib/calabash-cucumber/keyboard_helpers.rb +26 -16
  12. data/lib/calabash-cucumber/launcher.rb +42 -8
  13. data/lib/calabash-cucumber/map.rb +28 -0
  14. data/lib/calabash-cucumber/operations.rb +0 -4
  15. data/lib/calabash-cucumber/playback_helpers.rb +200 -0
  16. data/lib/calabash-cucumber/query_helpers.rb +32 -0
  17. data/lib/calabash-cucumber/resources/double_tap_ios5_ipad.base64 +15 -0
  18. data/lib/calabash-cucumber/resources/double_tap_ios5_iphone.base64 +15 -0
  19. data/lib/calabash-cucumber/resources/double_tap_ios6_ipad.base64 +22 -0
  20. data/lib/calabash-cucumber/resources/double_tap_ios6_iphone.base64 +22 -0
  21. data/lib/calabash-cucumber/resources/swipe_down_ios5_iphone.base64 +31 -18
  22. data/lib/calabash-cucumber/resources/swipe_down_ios6_ipad.base64 +25 -0
  23. data/lib/calabash-cucumber/resources/swipe_down_ios6_iphone.base64 +25 -0
  24. data/lib/calabash-cucumber/resources/swipe_left_ios5_iphone.base64 +34 -79
  25. data/lib/calabash-cucumber/resources/swipe_left_ios6_ipad.base64 +28 -0
  26. data/lib/calabash-cucumber/resources/swipe_left_ios6_iphone.base64 +28 -0
  27. data/lib/calabash-cucumber/resources/swipe_right_ios6_ipad.base64 +25 -0
  28. data/lib/calabash-cucumber/resources/swipe_right_ios6_iphone.base64 +25 -0
  29. data/lib/calabash-cucumber/resources/swipe_up_ios5_iphone.base64 +28 -34
  30. data/lib/calabash-cucumber/resources/swipe_up_ios6_ipad.base64 +25 -0
  31. data/lib/calabash-cucumber/resources/swipe_up_ios6_iphone.base64 +25 -0
  32. data/lib/calabash-cucumber/resources/touch_hold_ios5_ipad.base64 +9 -0
  33. data/lib/calabash-cucumber/resources/touch_hold_ios5_iphone.base64 +9 -0
  34. data/lib/calabash-cucumber/resources/touch_hold_ios6_ipad.base64 +9 -0
  35. data/lib/calabash-cucumber/resources/touch_hold_ios6_iphone.base64 +9 -0
  36. data/lib/calabash-cucumber/rotation_helpers.rb +112 -0
  37. data/lib/calabash-cucumber/status_bar_helpers.rb +30 -0
  38. data/lib/calabash-cucumber/tests_helpers.rb +3 -42
  39. data/lib/calabash-cucumber/uia.rb +8 -7
  40. data/lib/calabash-cucumber/version.rb +2 -2
  41. data/lib/calabash-cucumber/wait_helpers.rb +19 -2
  42. metadata +31 -4
@@ -0,0 +1,44 @@
1
+ module Calabash
2
+ module Cucumber
3
+ module FailureHelpers
4
+
5
+ def screenshot(options={:prefix => nil, :name => nil})
6
+ prefix = options[:prefix]
7
+ name = options[:name]
8
+
9
+ @@screenshot_count ||= 0
10
+ res = http({:method => :get, :path => 'screenshot'})
11
+ prefix = prefix || ENV['SCREENSHOT_PATH'] || ""
12
+ if name.nil?
13
+ name = "screenshot"
14
+ else
15
+ if File.extname(name).downcase == ".png"
16
+ name = name.split(".png")[0]
17
+ end
18
+ end
19
+
20
+ path = "#{prefix}#{name}_#{@@screenshot_count}.png"
21
+ File.open(path, 'wb') do |f|
22
+ f.write res
23
+ end
24
+ @@screenshot_count += 1
25
+ path
26
+ end
27
+
28
+ def screenshot_embed(options={:prefix => nil, :name => nil, :label => nil})
29
+ path = screenshot(options)
30
+ embed(path, "image/png", options[:label] || File.basename(path))
31
+ end
32
+
33
+ def screenshot_and_raise(msg, options={:prefix => nil, :name => nil, :label => nil})
34
+ screenshot_embed(options)
35
+ raise(msg)
36
+ end
37
+
38
+ def fail(msg="Error. Check log for details.", options={:prefix => nil, :name => nil, :label => nil})
39
+ screenshot_and_raise(msg, options)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,102 @@
1
+ require 'httpclient'
2
+
3
+ module Calabash
4
+ module Cucumber
5
+ module HTTPHelpers
6
+
7
+ CAL_HTTP_RETRY_COUNT=3
8
+ RETRYABLE_ERRORS = [HTTPClient::TimeoutError,
9
+ HTTPClient::KeepAliveDisconnected,
10
+ Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED,
11
+ Errno::ETIMEDOUT]
12
+
13
+
14
+ def http(options, data=nil)
15
+ options[:uri] = url_for(options[:path])
16
+ options[:method] = options[:method] || :get
17
+ if data
18
+ if options[:raw]
19
+ options[:body] = data
20
+ else
21
+ options[:body] = data.to_json
22
+ end
23
+ end
24
+ res = make_http_request(options)
25
+ res.force_encoding("UTF-8") if res.respond_to?(:force_encoding)
26
+ res
27
+ end
28
+
29
+
30
+ def url_for(verb)
31
+ url = URI.parse(ENV['DEVICE_ENDPOINT']|| "http://localhost:37265")
32
+ path = url.path
33
+ if path.end_with? "/"
34
+ path = "#{path}#{verb}"
35
+ else
36
+ path = "#{path}/#{verb}"
37
+ end
38
+ url.path = path
39
+ url
40
+ end
41
+
42
+ def make_http_request(options)
43
+
44
+ body = nil
45
+ retryable_errors = options[:retryable_errors] || RETRYABLE_ERRORS
46
+ CAL_HTTP_RETRY_COUNT.times do |count|
47
+ previous_debug_dev = nil
48
+ begin
49
+ if not @http
50
+ @http = init_request(options)
51
+ end
52
+ if options[:debug] || (ENV['DEBUG_HTTP'] == '1' && options[:debug] != false)
53
+ previous_debug_dev = @http.debug_dev
54
+ @http.debug_dev = $stdout
55
+ end
56
+ if options[:method] == :post
57
+ body = @http.post(options[:uri], options[:body]).body
58
+ else
59
+ body = @http.get(options[:uri], options[:body]).body
60
+ end
61
+ if options[:debug] || (ENV['DEBUG_HTTP'] == '1' && options[:debug] != false)
62
+ @http.debug_dev = previous_debug_dev
63
+ end
64
+ break
65
+ rescue Exception => e
66
+
67
+ if retryable_errors.include?(e) || retryable_errors.any? { |c| e.is_a?(c) }
68
+
69
+ if count < CAL_HTTP_RETRY_COUNT-1
70
+ if e.is_a?(HTTPClient::TimeoutError)
71
+ sleep(3)
72
+ else
73
+ sleep(0.5)
74
+ end
75
+ @http.reset_all
76
+ @http=nil
77
+ STDOUT.write "Retrying.. #{e.class}: (#{e})\n"
78
+ STDOUT.flush
79
+ else
80
+ puts "Failing... #{e.class}"
81
+ raise e
82
+ end
83
+ else
84
+ raise e
85
+ end
86
+ end
87
+ end
88
+
89
+ body
90
+ end
91
+
92
+ def init_request(url=nil)
93
+ http = HTTPClient.new
94
+ http.connect_timeout = 30
95
+ http.send_timeout = 30
96
+ http.receive_timeout = 30
97
+ http
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -1,6 +1,7 @@
1
1
  require 'calabash-cucumber/launcher'
2
2
  require 'calabash-cucumber/uia'
3
-
3
+ require 'calabash-cucumber/actions/instruments_actions'
4
+ require 'calabash-cucumber/actions/playback_actions'
4
5
 
5
6
  module Calabash
6
7
  module Cucumber
@@ -60,42 +61,56 @@ module Calabash
60
61
  [to_result]
61
62
  end
62
63
 
63
- private
64
- def find_and_normalize_or_raise(ui_query)
65
- res = find_or_raise(ui_query)
66
- normalize_rect_for_orientation!(res['rect']) if res['rect']
67
- res
64
+ def double_tap_ios7(options)
65
+ ui_query = options[:query]
66
+ offset = options[:offset]
67
+ if ui_query.nil?
68
+ uia_double_tap_offset(offset)
69
+ else
70
+ el_to_swipe = find_and_normalize_or_raise(ui_query)
71
+ offset = point_from(el_to_swipe, options)
72
+ uia_double_tap_offset(offset)
73
+ [el_to_swipe]
74
+ end
75
+ end
76
+
77
+ def two_finger_tap_ios7(options)
78
+ ui_query = options[:query]
79
+ offset = options[:offset]
80
+ if ui_query.nil?
81
+ uia_two_finger_tap_offset(offset)
82
+ else
83
+ el_to_swipe = find_and_normalize_or_raise(ui_query)
84
+ offset = point_from(el_to_swipe, options)
85
+ uia_two_finger_tap_offset(offset)
86
+ [el_to_swipe]
87
+ end
68
88
  end
69
89
 
70
- def find_or_raise(ui_query)
71
- results = query(ui_query)
72
- if results.empty?
73
- screenshot_and_raise "Unable to find element matching query #{ui_query}"
90
+ def flick_ios7(options, delta)
91
+ ui_query = options[:query]
92
+ offset = options[:offset]
93
+ if ui_query.nil?
94
+ uia_flick_offset(offset, add_offset(offset, delta))
74
95
  else
75
- results.first
96
+ el_to_swipe = find_and_normalize_or_raise(ui_query)
97
+ offset = point_from(el_to_swipe, options)
98
+ uia_flick_offset(offset, add_offset(offset, delta))
99
+ [el_to_swipe]
76
100
  end
77
101
  end
78
102
 
79
- def normalize_rect_for_orientation!(rect)
80
- orientation = status_bar_orientation().to_sym
81
- launcher = Calabash::Cucumber::Launcher.launcher
82
- screen_size = launcher.device.screen_size
83
- case orientation
84
- when :right
85
- cx = rect['center_x']
86
- rect['center_x'] = rect['center_y']
87
- rect['center_y'] = screen_size[:width] - cx
88
- when :left
89
- cx = rect['center_x']
90
- rect['center_x'] = screen_size[:height] - rect['center_y']
91
- rect['center_y'] = cx
92
- when :up
93
- cy = rect['center_y']
94
- cx = rect['center_x']
95
- rect['center_y'] = screen_size[:height] - cy
96
- rect['center_x'] = screen_size[:width] - cx
97
- else
98
- # no-op by design.
103
+ def touch_hold_ios7(options)
104
+ ui_query = options[:query]
105
+ offset = options[:offset]
106
+ duration = options[:duration] || 4
107
+ if ui_query.nil?
108
+ uia_touch_hold_offset(duration, offset)
109
+ else
110
+ el_to_swipe = find_and_normalize_or_raise(ui_query)
111
+ offset = point_from(el_to_swipe, options)
112
+ uia_touch_hold_offset(duration, offset)
113
+ [el_to_swipe]
99
114
  end
100
115
  end
101
116
 
@@ -1,21 +1,23 @@
1
+ require 'calabash-cucumber/core'
1
2
  require 'calabash-cucumber/tests_helpers'
3
+ require 'calabash-cucumber/playback_helpers'
2
4
 
3
5
  module Calabash
4
6
  module Cucumber
5
7
  module KeyboardHelpers
6
- include Calabash::Cucumber::Core
7
8
  include Calabash::Cucumber::TestsHelpers
9
+ include Calabash::Cucumber::PlaybackHelpers
8
10
 
9
11
  KEYPLANE_NAMES = {
10
- :small_letters => "small-letters",
11
- :capital_letters => "capital-letters",
12
- :numbers_and_punctuation => "numbers-and-punctuation",
13
- :first_alternate => "first-alternate",
14
- :numbers_and_punctuation_alternate => "numbers-and-punctuation-alternate"
12
+ :small_letters => 'small-letters',
13
+ :capital_letters => 'capital-letters',
14
+ :numbers_and_punctuation => 'numbers-and-punctuation',
15
+ :first_alternate => 'first-alternate',
16
+ :numbers_and_punctuation_alternate => 'numbers-and-punctuation-alternate'
15
17
  }
16
18
 
17
19
 
18
- IOS7_SUPPORTED_CHARS = {
20
+ UIA_SUPPORTED_CHARS = {
19
21
  'Dictation' => nil,
20
22
  'Shift' => nil,
21
23
  'Delete' => '\b',
@@ -32,11 +34,11 @@ module Calabash
32
34
  # 'Return'
33
35
  def keyboard_enter_char(chr, should_screenshot=true)
34
36
  #map(nil, :keyboard, load_playback_data("touch_done"), chr)
35
- if ios7?
37
+ if uia?
36
38
  if chr.length == 1
37
39
  uia_type_string chr
38
40
  else
39
- code = IOS7_SUPPORTED_CHARS[chr]
41
+ code = UIA_SUPPORTED_CHARS[chr]
40
42
  if code
41
43
  uia_type_string code
42
44
  else
@@ -46,7 +48,7 @@ module Calabash
46
48
  res = {'results' => []}
47
49
  else
48
50
  res = http({:method => :post, :path => 'keyboard'},
49
- {:key => chr, :events => load_playback_data("touch_done")})
51
+ {:key => chr, :events => load_playback_data('touch_done')})
50
52
  res = JSON.parse(res)
51
53
  if res['outcome'] != 'SUCCESS'
52
54
  msg = "Keyboard enter failed failed because: #{res['reason']}\n#{res['details']}"
@@ -68,10 +70,10 @@ module Calabash
68
70
  end
69
71
 
70
72
  def done
71
- if ios7?
73
+ if uia?
72
74
  uia_type_string '\n'
73
75
  else
74
- keyboard_enter_char "Return"
76
+ keyboard_enter_char 'Return'
75
77
  end
76
78
 
77
79
  end
@@ -122,13 +124,21 @@ module Calabash
122
124
  end
123
125
 
124
126
  def await_keyboard
125
- wait_for_elements_exist(["view:'UIKBKeyplaneView'"])
126
- sleep(0.3)
127
+ #deprecated inconsistent wait naming
128
+ # use wait_for_keyboard
129
+ wait_for_keyboard
130
+ end
131
+
132
+ #noinspection RubyLiteralArrayInspection
133
+ def wait_for_keyboard
134
+ wait_for_elements_exist(["view:'UIKBKeyplaneView'"], :timeout_message => 'No visible keyboard')
135
+ sleep(0.5)
127
136
  end
128
137
 
129
138
  def keyboard_enter_text(text)
130
- fail("No visible keyboard") if element_does_not_exist("view:'UIKBKeyplaneView'")
131
- if ios7?
139
+ wait_for_keyboard if element_does_not_exist("view:'UIKBKeyplaneView'")
140
+
141
+ if uia?
132
142
  uia_type_string(text)
133
143
  else
134
144
  text.each_char do |ch|
@@ -1,6 +1,8 @@
1
1
  require 'calabash-cucumber/launch/simulator_helper'
2
2
  require 'sim_launcher'
3
3
  require 'calabash-cucumber/device'
4
+ require 'calabash-cucumber/actions/instruments_actions'
5
+ require 'calabash-cucumber/actions/playback_actions'
4
6
  require 'run_loop'
5
7
  require 'cfpropertylist'
6
8
 
@@ -10,6 +12,7 @@ class Calabash::Cucumber::Launcher
10
12
 
11
13
  attr_accessor :run_loop
12
14
  attr_accessor :device
15
+ attr_accessor :actions
13
16
  attr_accessor :launch_args
14
17
 
15
18
  @@launcher = nil
@@ -29,6 +32,12 @@ class Calabash::Cucumber::Launcher
29
32
  class CalabashLauncherTimeoutErr < Timeout::Error
30
33
  end
31
34
 
35
+
36
+ def actions
37
+ attach if @actions.nil?
38
+ @actions
39
+ end
40
+
32
41
  def self.attach
33
42
  l = launcher
34
43
  return l if l && l.active?
@@ -36,15 +45,32 @@ class Calabash::Cucumber::Launcher
36
45
 
37
46
  end
38
47
 
39
- def attach
48
+ def attach(max_retry=1, timeout=10)
40
49
  pids_str = `ps x -o pid,command | grep -v grep | grep "instruments" | awk '{printf "%s,", $1}'`
41
50
  pids = pids_str.split(',').map { |pid| pid.to_i }
42
51
  pid = pids.first
43
52
  rl = {}
44
- rl[:pid] = pid if pid
53
+ if pid
54
+ rl[:pid] = pid
55
+ self.actions= Calabash::Cucumber::InstrumentsActions.new
56
+ else
57
+ self.actions= Calabash::Cucumber::PlaybackActions.new
58
+ end
45
59
 
46
60
  self.run_loop= rl
47
- ensure_connectivity
61
+
62
+ ensure_connectivity(max_retry, timeout)
63
+
64
+ major = self.device.ios_major_version
65
+ if major.to_i >= 7 && self.actions.is_a?(Calabash::Cucumber::PlaybackActions)
66
+ puts "\n\n WARNING \n\n"
67
+ puts 'Warning Trying to connect to simulator that was not launched by Calabash/instruments.'
68
+ puts 'To fix this you must let Calabash or instruments launch the app'
69
+ puts 'Continuing... query et al will work.'
70
+ puts "\n\n WARNING \n\n"
71
+ puts "Please read: https://github.com/calabash/calabash-ios/wiki/A0-UIAutomation---instruments-problems"
72
+ end
73
+
48
74
 
49
75
  self
50
76
  end
@@ -52,7 +78,7 @@ class Calabash::Cucumber::Launcher
52
78
  def self.instruments?
53
79
  l = launcher_if_used
54
80
  return false unless l
55
- l.active?
81
+ l.instruments?
56
82
  end
57
83
 
58
84
  def self.launcher
@@ -67,6 +93,8 @@ class Calabash::Cucumber::Launcher
67
93
  @@launcher = self
68
94
  end
69
95
 
96
+
97
+
70
98
  def ios_major_version
71
99
  return nil if device.nil? or device.ios_version.nil?
72
100
  device.ios_major_version
@@ -280,10 +308,12 @@ class Calabash::Cucumber::Launcher
280
308
 
281
309
  if run_with_instruments?(args)
282
310
  self.run_loop = new_run_loop(args)
311
+ self.actions= Calabash::Cucumber::InstrumentsActions.new
283
312
  else
284
313
  # run with sim launcher
285
314
  sdk = sdk_version || SimLauncher::SdkDetector.new().available_sdk_versions.reverse.find { |x| !x.start_with?('7') }
286
315
  path = Calabash::Cucumber::SimulatorHelper.app_bundle_or_raise(app_path)
316
+ self.actions= Calabash::Cucumber::PlaybackActions.new
287
317
  Calabash::Cucumber::SimulatorHelper.relaunch(path, sdk, args[:device].to_s, args)
288
318
  end
289
319
  self.launch_args = args
@@ -353,10 +383,10 @@ class Calabash::Cucumber::Launcher
353
383
  raise StartError.new(last_err)
354
384
  end
355
385
 
356
- def ensure_connectivity
386
+ def ensure_connectivity(max_retry=10, timeout=30)
357
387
  begin
358
- max_retry_count = (ENV['MAX_CONNECT_RETRY'] || 10).to_i
359
- timeout = (ENV['CONNECT_TIMEOUT'] || 30).to_i
388
+ max_retry_count = (ENV['MAX_CONNECT_RETRY'] || max_retry).to_i
389
+ timeout = (ENV['CONNECT_TIMEOUT'] || timeout).to_i
360
390
  retry_count = 0
361
391
  connected = false
362
392
  if ENV['CALABASH_FULL_CONSOLE_OUTPUT'] == '1'
@@ -414,7 +444,7 @@ class Calabash::Cucumber::Launcher
414
444
  end
415
445
 
416
446
  def stop
417
- RunLoop.stop(run_loop)
447
+ RunLoop.stop(run_loop) if run_loop && run_loop[:pid]
418
448
  end
419
449
 
420
450
  def calabash_notify(world)
@@ -486,6 +516,10 @@ class Calabash::Cucumber::Launcher
486
516
  not run_loop.nil?
487
517
  end
488
518
 
519
+ def instruments?
520
+ !!(active? && run_loop[:pid])
521
+ end
522
+
489
523
  def inspect
490
524
  msg = ["#{self.class}: Launch Method #{launch_args && launch_args[:launch_method]}"]
491
525
  if run_with_instruments?(self.launch_args) && self.run_loop