calabash 2.0.0.pre10 → 2.0.0.pre11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -17
  3. data/bin/calabash +3 -4
  4. data/lib/calabash.rb +53 -10
  5. data/lib/calabash/android.rb +89 -28
  6. data/lib/calabash/android/adb.rb +32 -20
  7. data/lib/calabash/android/application.rb +1 -1
  8. data/lib/calabash/android/build/builder.rb +1 -1
  9. data/lib/calabash/android/build/java_keystore.rb +1 -1
  10. data/lib/calabash/android/build/resigner.rb +1 -1
  11. data/lib/calabash/android/device.rb +22 -66
  12. data/lib/calabash/android/device/helper_application.rb +95 -0
  13. data/lib/calabash/android/environment.rb +14 -1
  14. data/lib/calabash/android/gestures.rb +6 -22
  15. data/lib/calabash/android/interactions.rb +14 -17
  16. data/lib/calabash/android/lib/.irbrc +9 -1
  17. data/lib/calabash/android/lib/AndroidManifest.xml +23 -2
  18. data/lib/calabash/android/lib/HelperApplication.apk +0 -0
  19. data/lib/calabash/android/lib/HelperApplicationTestServer.apk +0 -0
  20. data/lib/calabash/android/lib/TestServer.apk +0 -0
  21. data/lib/calabash/android/life_cycle.rb +3 -3
  22. data/lib/calabash/android/orientation.rb +8 -8
  23. data/lib/calabash/android/physical_buttons.rb +19 -16
  24. data/lib/calabash/android/server.rb +1 -1
  25. data/lib/calabash/android/text.rb +12 -12
  26. data/lib/calabash/android/web.rb +12 -0
  27. data/lib/calabash/application.rb +3 -0
  28. data/lib/calabash/cli/generate.rb +8 -18
  29. data/lib/calabash/cli/helpers.rb +4 -9
  30. data/lib/calabash/cli/run.rb +1 -1
  31. data/lib/calabash/console_helpers.rb +179 -11
  32. data/lib/calabash/device.rb +4 -19
  33. data/lib/calabash/gestures.rb +292 -198
  34. data/lib/calabash/interactions.rb +3 -40
  35. data/lib/calabash/internal.rb +48 -0
  36. data/lib/calabash/ios.rb +76 -16
  37. data/lib/calabash/ios/automator.rb +9 -0
  38. data/lib/calabash/ios/automator/automator.rb +217 -0
  39. data/lib/calabash/ios/automator/coordinates.rb +37 -0
  40. data/lib/calabash/ios/automator/device_agent.rb +379 -0
  41. data/lib/calabash/ios/conditions.rb +1 -1
  42. data/lib/calabash/ios/console_helpers.rb +2 -2
  43. data/lib/calabash/ios/date_picker.rb +10 -8
  44. data/lib/calabash/ios/device.rb +0 -1
  45. data/lib/calabash/ios/device/device_implementation.rb +9 -21
  46. data/lib/calabash/ios/device/gestures_mixin.rb +53 -55
  47. data/lib/calabash/ios/device/keyboard_mixin.rb +21 -0
  48. data/lib/calabash/ios/device/rotation_mixin.rb +3 -65
  49. data/lib/calabash/ios/gestures.rb +24 -90
  50. data/lib/calabash/ios/interactions.rb +1 -6
  51. data/lib/calabash/ios/lib/.irbrc +9 -2
  52. data/lib/calabash/ios/orientation.rb +8 -8
  53. data/lib/calabash/ios/runtime.rb +14 -14
  54. data/lib/calabash/ios/scroll.rb +25 -17
  55. data/lib/calabash/ios/slider.rb +11 -18
  56. data/lib/calabash/ios/text.rb +20 -74
  57. data/lib/calabash/ios/uia.rb +1 -1
  58. data/lib/calabash/ios/web.rb +10 -0
  59. data/lib/calabash/lib/skeleton/{Gemfile → Gemfile.skeleton} +0 -0
  60. data/lib/calabash/lib/skeleton/config/{cucumber.yml → cucumber.yml.skeleton} +0 -0
  61. data/lib/calabash/lib/skeleton/features/{sample.feature → sample.feature.skeleton} +0 -0
  62. data/lib/calabash/lib/skeleton/features/step_definitions/{calabash_steps.rb → sample_steps.rb.skeleton} +8 -8
  63. data/lib/calabash/lib/skeleton/features/support/{dry_run.rb → dry_run.rb.skeleton} +2 -5
  64. data/lib/calabash/lib/skeleton/features/support/{env.rb → env.rb.skeleton} +2 -8
  65. data/lib/calabash/lib/skeleton/features/support/hooks.rb.skeleton +34 -0
  66. data/lib/calabash/life_cycle.rb +16 -8
  67. data/lib/calabash/location.rb +14 -15
  68. data/lib/calabash/orientation.rb +8 -8
  69. data/lib/calabash/page.rb +1 -4
  70. data/lib/calabash/retry.rb +33 -0
  71. data/lib/calabash/screenshot.rb +3 -3
  72. data/lib/calabash/stubs.rb +21 -0
  73. data/lib/calabash/text.rb +31 -19
  74. data/lib/calabash/utility.rb +41 -8
  75. data/lib/calabash/version.rb +1 -1
  76. data/lib/calabash/wait.rb +177 -192
  77. data/lib/calabash/web.rb +44 -0
  78. metadata +39 -32
  79. data/lib/calabash/ios/device/text_mixin.rb +0 -21
  80. data/lib/calabash/lib/skeleton/features/support/hooks.rb +0 -83
@@ -62,7 +62,7 @@ module Calabash
62
62
  #
63
63
  # @return [Calabash::QueryResult] A result of the query
64
64
  def query(query, *args)
65
- Calabash::Device.default.map_route(Query.new(query), :query, *args)
65
+ Calabash::Internal.with_default_device {|device| device.map_route(Query.new(query), :query, *args)}
66
66
  end
67
67
 
68
68
  # Flashes any views matching `query`. Only one view is flashed at a time,
@@ -71,39 +71,7 @@ module Calabash
71
71
  # @param [String, Hash, Calabash::Query] query The query to match the
72
72
  # view(s)
73
73
  def flash(query)
74
- Calabash::Device.default.map_route(Query.new(query), :flash)
75
- end
76
-
77
- # Evaluate javascript in a Web View. On iOS, an implicit return is
78
- # inserted, on Android an explicit return is needed.
79
- #
80
- # @example
81
- # # iOS
82
- # evaluate_javascript_in("UIWebView", "2+2")
83
- # # Android
84
- # evaluate_javascript_in("WebView", "return 2+2")
85
- #
86
- # @example
87
- # # iOS
88
- # evaluate_javascript_in("WKWebView",
89
- # "document.body.style.backgroundColor = 'red';")
90
- #
91
- # # Android
92
- # evaluate_javascript_in("XWalkContent",
93
- # "document.body.style.backgroundColor = 'red';")
94
- #
95
- # @note No error will be raised if the javascript given is invalid, or
96
- # throws an exception.
97
- #
98
- # @param [String, Hash, Calabash::Query] query Query that matches the view
99
- # @param [String] javascript The javascript to evaluate
100
- #
101
- # @raise ViewNotFoundError If no views are found matching `query`
102
- def evaluate_javascript_in(query, javascript)
103
- wait_for_view(query,
104
- timeout: Calabash::Gestures::DEFAULT_GESTURE_WAIT_TIMEOUT)
105
-
106
- _evaluate_javascript_in(query, javascript)
74
+ Calabash::Internal.with_default_device {|device| device.map_route(Query.new(query), :flash)}
107
75
  end
108
76
 
109
77
  # Invoke a method in your application.
@@ -158,12 +126,7 @@ module Calabash
158
126
  # @return [Object] the result of performing the selector/method with the
159
127
  # arguments (serialized)
160
128
  def backdoor(name, *arguments)
161
- Device.default.backdoor(name, *arguments)
162
- end
163
-
164
- # @!visibility private
165
- def _evaluate_javascript_in(query, javascript)
166
- abstract_method!
129
+ Calabash::Internal.with_default_device {|device| device.backdoor(name, *arguments)}
167
130
  end
168
131
  end
169
132
  end
@@ -0,0 +1,48 @@
1
+ module Calabash
2
+ # @!visibility private
3
+ # Internal usage, NOT a public API
4
+ module Internal
5
+ def self.with_default_device(required_os: nil, &block)
6
+ unless block
7
+ raise ArgumentError, "No block given"
8
+ end
9
+
10
+ device = Calabash.default_device
11
+
12
+ if device.nil?
13
+ raise "The default device is not set. Set it using Calabash.default_device = ..."
14
+ end
15
+
16
+ if required_os
17
+ required_class = nil
18
+ required_type = nil
19
+ current_type = nil
20
+
21
+ case required_os
22
+ when :ios
23
+ required_class = Calabash::IOS::Device
24
+ required_type = 'iOS'
25
+ when :android
26
+ required_class = Calabash::Android::Device
27
+ required_type = 'Android'
28
+ else
29
+ raise ArgumentError, "Unknown OS '#{required_os}'"
30
+ end
31
+
32
+ if Calabash::Android.const_defined?(:Device, false) && device.is_a?(Calabash::Android::Device)
33
+ current_type = 'Android'
34
+ elsif Calabash::IOS.const_defined?(:Device, false) && device.is_a?(Calabash::IOS::Device)
35
+ current_type = 'iOS'
36
+ else
37
+ current_type = 'unknown'
38
+ end
39
+
40
+ unless device.is_a?(required_class)
41
+ raise "The default device is not set to an #{required_type} device, it is an #{current_type} device."
42
+ end
43
+ end
44
+
45
+ block.call(device)
46
+ end
47
+ end
48
+ end
@@ -1,21 +1,7 @@
1
1
  module Calabash
2
- # Contains the iOS implementations of the Calabash APIs.
3
- module IOS
2
+ # @!visibility private
3
+ module IOSInternal
4
4
  require 'calabash'
5
- include Calabash
6
-
7
- # @!visibility private
8
- def self.extended(base)
9
- Calabash.send(:extended, base)
10
- end
11
-
12
- # @!visibility private
13
- def self.included(base)
14
- Calabash.send(:included, base)
15
- end
16
-
17
- require 'calabash/ios/defaults'
18
- extend Calabash::IOS::Defaults
19
5
 
20
6
  require 'calabash/ios/environment'
21
7
  require 'calabash/ios/application'
@@ -32,6 +18,8 @@ module Calabash
32
18
  require 'calabash/ios/gestures'
33
19
  require 'calabash/ios/slider'
34
20
  require 'calabash/ios/date_picker'
21
+ require 'calabash/ios/automator'
22
+ require 'calabash/ios/web'
35
23
 
36
24
  include Calabash::IOS::Conditions
37
25
  include Calabash::IOS::Orientation
@@ -43,7 +31,79 @@ module Calabash
43
31
  include Calabash::IOS::Gestures
44
32
  include Calabash::IOS::Slider
45
33
  include Calabash::IOS::DatePicker
34
+ include Calabash::IOS::Web
35
+ end
36
+
37
+ # Contains the iOS implementations of the Calabash APIs.
38
+ module IOS
39
+ require 'calabash'
40
+ # Hide from documentation
41
+ send(:include, Calabash)
42
+
43
+ # @!visibility private
44
+ def self.extended(base)
45
+ Calabash.send(:extended, base)
46
+ end
47
+
48
+ # @!visibility private
49
+ def self.included(base)
50
+ Calabash.send(:included, base)
51
+ end
52
+
53
+ include ::Calabash::IOSInternal
54
+
55
+ require 'calabash/ios/defaults'
56
+ extend Calabash::IOS::Defaults
46
57
 
47
58
  require 'calabash/ios/legacy'
48
59
  end
49
60
  end
61
+
62
+ # @!visibility private
63
+ class CalabashIOSMethodsInternal
64
+ include ::Calabash::IOS
65
+ end
66
+
67
+ # @!visibility private
68
+ class CalabashIOSMethods < BasicObject
69
+ include ::Calabash::IOSInternal
70
+
71
+ instance_methods.each do |method_name|
72
+ define_method(method_name) do |*args, &block|
73
+ ::CalabashIOSMethodsInternal.new.send(method_name, *args, &block)
74
+ end
75
+ end
76
+ end
77
+
78
+ # Returns a object that exposes all of the public Calabash iOS API.
79
+ # This method should *always* be used to access the Calabash API. By default,
80
+ # all methods are executed using the default device and the default
81
+ # application.
82
+ #
83
+ # For iOS specific methods use {cal_android}. For cross-platform methods use
84
+ # {cal}.
85
+ #
86
+ # All iOS API methods are available with documentation in {Calabash::IOS}
87
+ #
88
+ # @see Calabash::IOS
89
+ #
90
+ # @return [Object] Instance responding to all Calabash iOS methods
91
+ # in the API.
92
+ def cal_ios
93
+ CalabashIOSMethods.new
94
+ end
95
+
96
+ # We also want to patch `cal` to invoke the iOS implementations
97
+ class CalabashMethodsInternal
98
+ include ::Calabash::IOS
99
+
100
+ instance_methods.each do |method_name|
101
+ define_method(method_name) do |*args, &block|
102
+ ::CalabashIOSMethodsInternal.new.send(method_name, *args, &block)
103
+ end
104
+ end
105
+ end
106
+
107
+ if defined?(::Calabash::AndroidInternal)
108
+ raise Calabash::RequiredBothPlatformsError, "Cannot require both calabash/android and calabash/ios"
109
+ end
@@ -0,0 +1,9 @@
1
+ module Calabash
2
+ module IOS
3
+ module Automator
4
+ require 'calabash/ios/automator/automator'
5
+ require 'calabash/ios/automator/coordinates'
6
+ require 'calabash/ios/automator/device_agent'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,217 @@
1
+ module Calabash
2
+ module IOS
3
+ # @!visibility private
4
+ module Automator
5
+ # @!visibility private
6
+ class Automator
7
+ include Utility
8
+
9
+ # @!visibility private
10
+ def initialize(*args)
11
+ abstract_method!
12
+ end
13
+
14
+ # @!visibility private
15
+ def name
16
+ abstract_method!
17
+ end
18
+
19
+ # @!visibility private
20
+ def stop
21
+ abstract_method!
22
+ end
23
+
24
+ # @!visibility private
25
+ def running?
26
+ abstract_method!
27
+ end
28
+
29
+ # @!visibility private
30
+ def client
31
+ abstract_method!
32
+ end
33
+
34
+ # @!visibility private
35
+ def touch(options)
36
+ abstract_method!
37
+ end
38
+
39
+ # @!visibility private
40
+ def double_tap(options)
41
+ abstract_method!
42
+ end
43
+
44
+ # @!visibility private
45
+ def two_finger_tap(options)
46
+ abstract_method!
47
+ end
48
+
49
+ # @!visibility private
50
+ def touch_hold(options)
51
+ abstract_method!
52
+ end
53
+
54
+ # @!visibility private
55
+ def flick(options)
56
+ abstract_method!
57
+ end
58
+
59
+ # @!visibility private
60
+ def pan(options={})
61
+ abstract_method!
62
+ end
63
+
64
+ # @!visibility private
65
+ #
66
+ # Callers must validate the options.
67
+ def pan_coordinates(from_point, to_point, options={})
68
+ abstract_method!
69
+ end
70
+
71
+ # @!visibility private
72
+ #
73
+ # Callers must validate the options.
74
+ def pinch(in_or_out, options)
75
+ abstract_method!
76
+ end
77
+
78
+ # @!visibility private
79
+ def send_app_to_background(seconds)
80
+ abstract_method!
81
+ end
82
+
83
+ # @!visibility private
84
+ #
85
+ # It is the caller's responsibility to:
86
+ # 1. expect the keyboard is visible
87
+ # 2. escape the existing text
88
+ def enter_text_with_keyboard(string, options={})
89
+ abstract_method!
90
+ end
91
+
92
+ # @!visibility private
93
+ #
94
+ # Respond to keys like 'Delete' or 'Return'.
95
+ def char_for_keyboard_action(action_key)
96
+ abstract_method!
97
+ end
98
+
99
+ # @!visibility private
100
+ # It is the caller's responsibility to ensure the keyboard is visible.
101
+ def enter_char_with_keyboard(char)
102
+ abstract_method!
103
+ end
104
+
105
+ # @!visibility private
106
+ # It is the caller's responsibility to ensure the keyboard is visible.
107
+ def tap_keyboard_action_key(return_key_type_of_first_responder)
108
+ abstract_method!
109
+ end
110
+
111
+ # @!visibility private
112
+ # It is the caller's responsibility to ensure the keyboard is visible.
113
+ def tap_keyboard_delete_key
114
+ abstract_method!
115
+ end
116
+
117
+ # @!visibility private
118
+ #
119
+ # Legacy API - can we remove this method?
120
+ #
121
+ # It is the caller's responsibility to ensure the keyboard is visible.
122
+ def fast_enter_text(text)
123
+ abstract_method!
124
+ end
125
+
126
+ # @!visibility private
127
+ #
128
+ # Caller is responsible for limiting calls to iPads and waiting for the
129
+ # keyboard to disappear.
130
+ def dismiss_ipad_keyboard
131
+ abstract_method!
132
+ end
133
+
134
+ # @!visibility private
135
+ #
136
+ # Caller is responsible for providing a valid direction.
137
+ def rotate(direction, status_bar_orientation)
138
+ abstract_method!
139
+ end
140
+
141
+ # @!visibility private
142
+ #
143
+ # Caller is responsible for normalizing and validating the position.
144
+ def rotate_home_button_to(position, status_bar_orientation)
145
+ abstract_method!
146
+ end
147
+
148
+ # @! visibility private
149
+ #
150
+ # It is important to remember that the current orientation is the
151
+ # position of the home button:
152
+ #
153
+ # :up => home button on the top => upside_down
154
+ # :bottom => home button on the bottom => portrait
155
+ # :left => home button on the left => landscape_right
156
+ # :right => home button on the right => landscape_left
157
+ #
158
+ # Notice how :left and :right are mapped.
159
+ def self.orientation_key(direction, current_orientation)
160
+ key = nil
161
+ case direction
162
+ when :left then
163
+ if current_orientation == :down
164
+ key = :landscape_left
165
+ elsif current_orientation == :right
166
+ key = :upside_down
167
+ elsif current_orientation == :left
168
+ key = :portrait
169
+ elsif current_orientation == :up
170
+ key = :landscape_right
171
+ end
172
+ when :right then
173
+ if current_orientation == :down
174
+ key = :landscape_right
175
+ elsif current_orientation == :right
176
+ key = :portrait
177
+ elsif current_orientation == :left
178
+ key = :upside_down
179
+ elsif current_orientation == :up
180
+ key = :landscape_left
181
+ end
182
+ else
183
+ raise ArgumentError,
184
+ "Expected '#{direction}' to be :left or :right"
185
+ end
186
+
187
+ key
188
+ end
189
+
190
+ # @!visibility private
191
+ def self.orientation_for_key(key)
192
+ DEVICE_ORIENTATION[key]
193
+ end
194
+
195
+ # @! visibility private
196
+ #
197
+ # It is important to remember that the current orientation is the
198
+ # position of the home button:
199
+ #
200
+ # :up => home button on the top => upside_down
201
+ # :bottom => home button on the bottom => portrait
202
+ # :left => home button on the left => landscape_right
203
+ # :right => home button on the right => landscape_left
204
+ #
205
+ # Notice how :left and :right are mapped to their logical opposite.
206
+ # @!visibility private
207
+ # @! visibility private
208
+ DEVICE_ORIENTATION = {
209
+ :portrait => 1,
210
+ :upside_down => 2,
211
+ :landscape_left => 3, # Home button on the right
212
+ :landscape_right => 4 # Home button on the left
213
+ }.freeze
214
+ end
215
+ end
216
+ end
217
+ end