calabash 2.0.0.pre10 → 2.0.0.pre11

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