calabash 1.9.9.pre3 → 2.0.0.pre1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -0
  3. data/bin/calabash +45 -36
  4. data/lib/calabash/android/build/builder.rb +1 -1
  5. data/lib/calabash/android/build/resigner.rb +19 -1
  6. data/lib/calabash/android/device.rb +13 -2
  7. data/lib/calabash/android/interactions.rb +104 -3
  8. data/lib/calabash/android/lib/TestServer.apk +0 -0
  9. data/lib/calabash/android/life_cycle.rb +5 -4
  10. data/lib/calabash/android/physical_buttons.rb +4 -1
  11. data/lib/calabash/android/scroll.rb +5 -0
  12. data/lib/calabash/android/text.rb +10 -25
  13. data/lib/calabash/android.rb +3 -0
  14. data/lib/calabash/cli/generate.rb +2 -0
  15. data/lib/calabash/console_helpers.rb +4 -2
  16. data/lib/calabash/device.rb +1 -9
  17. data/lib/calabash/environment.rb +4 -0
  18. data/lib/calabash/gestures.rb +159 -66
  19. data/lib/calabash/http/retriable_client.rb +1 -1
  20. data/lib/calabash/interactions.rb +67 -5
  21. data/lib/calabash/ios/conditions.rb +0 -1
  22. data/lib/calabash/ios/device/device_implementation.rb +17 -5
  23. data/lib/calabash/ios/device/gestures_mixin.rb +202 -48
  24. data/lib/calabash/ios/device/rotation_mixin.rb +10 -8
  25. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +5 -1
  26. data/lib/calabash/ios/device/runtime_attributes.rb +4 -5
  27. data/lib/calabash/ios/gestures.rb +82 -8
  28. data/lib/calabash/ios/orientation.rb +21 -21
  29. data/lib/calabash/ios/runtime.rb +146 -2
  30. data/lib/calabash/ios/slider.rb +70 -0
  31. data/lib/calabash/ios/text.rb +6 -2
  32. data/lib/calabash/ios/uia.rb +24 -2
  33. data/lib/calabash/ios.rb +2 -0
  34. data/lib/calabash/lib/skeleton/features/support/dry_run.rb +8 -0
  35. data/lib/calabash/life_cycle.rb +59 -30
  36. data/lib/calabash/location.rb +0 -1
  37. data/lib/calabash/orientation.rb +0 -1
  38. data/lib/calabash/page.rb +38 -5
  39. data/lib/calabash/patch/array.rb +7 -7
  40. data/lib/calabash/query.rb +17 -2
  41. data/lib/calabash/query_result.rb +10 -0
  42. data/lib/calabash/screenshot.rb +28 -8
  43. data/lib/calabash/text.rb +52 -8
  44. data/lib/calabash/utility.rb +3 -3
  45. data/lib/calabash/version.rb +1 -1
  46. data/lib/calabash/wait.rb +33 -11
  47. data/lib/calabash.rb +124 -13
  48. metadata +114 -111
@@ -4,6 +4,7 @@ module Calabash
4
4
  # It will, unlike `Array`, raise an IndexError instead of returning nil if
5
5
  # an entry outside bounds is accessed.
6
6
  class QueryResult < Array
7
+ # @!visibility private
7
8
  def self.create(result, query)
8
9
  query_result = QueryResult.send(:new, query)
9
10
  query_result.send(:initialize_copy, result)
@@ -13,36 +14,43 @@ module Calabash
13
14
 
14
15
  private_class_method :new
15
16
 
17
+ # @!visibility private
16
18
  attr_reader :query
17
19
 
20
+ # @!visibility private
18
21
  def initialize(query)
19
22
  @query = Query.new(query)
20
23
  end
21
24
 
25
+ # @!visibility private
22
26
  def first(*several_variants)
23
27
  ensure_in_bounds(0)
24
28
 
25
29
  super(*several_variants)
26
30
  end
27
31
 
32
+ # @!visibility private
28
33
  def last(*several_variants)
29
34
  ensure_in_bounds(-1)
30
35
 
31
36
  super(*several_variants)
32
37
  end
33
38
 
39
+ # @!visibility private
34
40
  def [](index)
35
41
  ensure_in_bounds(index)
36
42
 
37
43
  super(index)
38
44
  end
39
45
 
46
+ # @!visibility private
40
47
  def at(index)
41
48
  ensure_in_bounds(index)
42
49
 
43
50
  super(index)
44
51
  end
45
52
 
53
+ # @!visibility private
46
54
  def fetch(*several_variants)
47
55
  unless block_given? || several_variants.length > 1
48
56
  ensure_in_bounds(several_variants.first)
@@ -51,6 +59,7 @@ module Calabash
51
59
  super(*several_variants)
52
60
  end
53
61
 
62
+ # @!visibility private
54
63
  def ensure_in_bounds(index)
55
64
  if empty?
56
65
  raise IndexError, "Query result is empty"
@@ -65,6 +74,7 @@ module Calabash
65
74
  end
66
75
  end
67
76
 
77
+ # @!visibility private
68
78
  def self.recursive_freeze(object)
69
79
  if object.is_a?(Array)
70
80
  object.each do |entry|
@@ -4,7 +4,6 @@ require 'pathname'
4
4
  module Calabash
5
5
 
6
6
  # A public API for taking screenshots.
7
- # @!visibility private
8
7
  module Screenshot
9
8
  # @!visibility private
10
9
  def self.screenshot_directory_prefix
@@ -12,6 +11,7 @@ module Calabash
12
11
  end
13
12
 
14
13
  # Set the screenshot directory prefix.
14
+ # @!visibility private
15
15
  def self.screenshot_directory_prefix=(value)
16
16
  if class_variable_defined?(:@@screenshots_taken) &&
17
17
  @@screenshots_taken != 0
@@ -24,22 +24,36 @@ module Calabash
24
24
  # @!visibility private
25
25
  self.screenshot_directory_prefix = 'test_run_'
26
26
 
27
- # Takes a screenshot and saves it. The file is stored in the directory
28
- # given by the ENV variable $CAL_SCREENSHOT_DIR, or by default in
29
- # the relative directory 'screenshots'. The files are saved in a
27
+ # Takes a screenshot and saves it.
28
+ #
29
+ # If `name` is a relative path or a file name, then the file is stored in
30
+ # the directory specified by the ENV variable CAL_SCREENSHOT_DIR, or by
31
+ # default in the relative directory 'screenshots'. The files are saved in a
30
32
  # sub directory named test_run_n, where n is unique and incrementing for
31
33
  # each new test run. The filename of the screenshot will be `name`.
32
34
  # If `name` is not given (nil), the screenshot will be saved as
33
35
  # screenshot_N, where N is the total amount of screenshots taken for the
34
36
  # test run.
35
37
  #
38
+ # If the name given is an absolute path, then Calabash will save the
39
+ # screenshot to the absolute directory given.
40
+ #
41
+ # If the name given starts with ./ (e.g. `screenshot('./foo.png')`) then
42
+ # the filename will be saved relative to the current working directory.
43
+ #
44
+ # If the file specified by `name` has no extension then the filename will
45
+ # default to name + '.png'.
46
+ #
47
+ # If the directories specified do not exist, Calabash will create them.
48
+ #
36
49
  # @param [String] name Name of the screenshot.
37
50
  # @return [String] Path to the screenshot
38
51
  def screenshot(name=nil)
39
52
  Device.default.screenshot(name)
40
53
  end
41
54
 
42
- # Takes a screenshot and embeds it in the test report.
55
+ # Takes a screenshot and embeds it in the test report. This method is only
56
+ # available/useful when running in the context of cucumber.
43
57
  # @see Screenshot#screenshot
44
58
  def screenshot_embed(name=nil)
45
59
  path = screenshot(name)
@@ -58,11 +72,17 @@ module Calabash
58
72
 
59
73
  @@screenshots_taken += 1
60
74
 
61
- unless Dir.exist?(File.expand_path(screenshot_directory))
62
- FileUtils.mkdir_p(File.expand_path(screenshot_directory))
75
+ if name.start_with?('./')
76
+ name = File.join(Dir.pwd, "#{name[2..-1]}")
77
+ end
78
+
79
+ file_name = File.expand_path(name, screenshot_directory)
80
+
81
+ unless Dir.exist?(File.dirname(file_name))
82
+ FileUtils.mkdir_p(File.dirname(file_name))
63
83
  end
64
84
 
65
- File.join(screenshot_directory, name)
85
+ file_name
66
86
  end
67
87
 
68
88
  # @!visibility private
data/lib/calabash/text.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module Calabash
2
2
 
3
3
  # A public API for entering text.
4
- # @!visibility private
5
4
  module Text
6
5
  # Enter `text` into the currently focused view.
7
6
  #
@@ -15,7 +14,8 @@ module Calabash
15
14
  # @see Calabash::Text#enter_text
16
15
  #
17
16
  # @param [String] text The text to type.
18
- # @param query A query describing the view to enter text into.
17
+ # @param [String, Hash, Calabash::Query] query A query describing the view
18
+ # to enter text into.
19
19
  def enter_text_in(query, text)
20
20
  _enter_text_in(query, text)
21
21
  end
@@ -28,21 +28,65 @@ module Calabash
28
28
  # Clears the text `view`
29
29
  # @see Calabash::Text#clear_text
30
30
  #
31
- # @param query A query describing the view to clear text in.
31
+ # @param [String, Hash, Calabash::Query] query A query describing the view
32
+ # to clear text in.
32
33
  def clear_text_in(query)
33
34
  _clear_text_in(query)
34
35
  end
35
36
 
36
- # @todo add docs
37
- def tap_current_keyboard_action_key
38
- _tap_current_keyboard_action_key
37
+ # Taps the keyboard action key. On iOS there is only one action key, which
38
+ # is the blue coloured key on the standard keyboard. On Android, there can
39
+ # be multiple actions keys available depending on the keyboard, but one key
40
+ # is often replacing the enter key, becoming the default action key. The
41
+ # view in focus on Android asks to keyboard to show one action key, but the
42
+ # keyboard might not adhere to this.
43
+ #
44
+ # On iOS some examples include:
45
+ # * Return
46
+ # * Next
47
+ # * Go
48
+ # * Join
49
+ # * Search
50
+ #
51
+ # On Android some examples include:
52
+ # * Search
53
+ # * Next
54
+ # * Previous
55
+ #
56
+ # See http://developer.android.com/reference/android/view/inputmethod/EditorInfo.html
57
+ #
58
+ # @example
59
+ # tap_keyboard_action_key(:search)
60
+ # tap_keyboard_action_key(:send)
61
+ # tap_keyboard_action_key(:next)
62
+ # tap_keyboard_action_key(:previous)
63
+ #
64
+ # Notice that, for Android, Calabash does not ensure that this particular action key is
65
+ # actually available on the current keyboard.
66
+ #
67
+ # Not all keyboards have an action key. For example, on iOS, numeric keyboards
68
+ # do not have an action key. On Android, if no action key is set for the
69
+ # view, the enter key is pressed instead.
70
+ #
71
+ # @param [Symbol] action_key The action key to press. This is only
72
+ # used for Android.
73
+ # @raise [ArgumentError] If action_key if set for iOS.
74
+ def tap_keyboard_action_key(action_key = nil)
75
+ _tap_keyboard_action_key(action_key)
76
+ true
39
77
  end
40
78
 
41
79
  # Escapes single quotes in `string`.
42
80
  #
43
81
  # @example
44
- # > escape_quotes("Let's get this done.")
82
+ # escape_single_quotes("Let's get this done.")
45
83
  # => "Let\\'s get this done."
84
+ #
85
+ # @example
86
+ # query("* text:'#{escape_single_quotes("Let's go")}'")
87
+ # # Equivalent to
88
+ # query("* text:'Let\\'s go'")
89
+ #
46
90
  # @param [String] string The string to escape.
47
91
  # @return [String] A string with its single quotes properly escaped.
48
92
  def escape_single_quotes(string)
@@ -70,7 +114,7 @@ module Calabash
70
114
  end
71
115
 
72
116
  # @!visibility private
73
- def _tap_current_keyboard_action_key
117
+ def _tap_keyboard_action_key(action_key)
74
118
  abstract_method!
75
119
  end
76
120
 
@@ -5,7 +5,6 @@ module Calabash
5
5
 
6
6
  end
7
7
 
8
- # @!visibility private
9
8
  module Utility
10
9
 
11
10
  # @!visibility private
@@ -27,8 +26,8 @@ module Calabash
27
26
  #
28
27
  # @example
29
28
  # # These are equivalent.
30
- # pan(percent(20, 50), percent(20, 100))
31
- # pan({x: 20, y: 50}, {x: 20, y: 100})
29
+ # pan("*", percent(20, 50), percent(20, 100))
30
+ # pan("*", {x: 20, y: 50}, {x: 20, y: 100})
32
31
  #
33
32
  # @param [Number] x The value of the x percent.
34
33
  # @param [Number] y The value of the y percent.
@@ -50,6 +49,7 @@ module Calabash
50
49
  # @param [Number] x The value of the x.
51
50
  # @param [Number] y The value of the y.
52
51
  # @return [Hash] Representing the given values.
52
+ # @!visibility private
53
53
  def coordinate(x, y)
54
54
  {x: x, y: y}
55
55
  end
@@ -1,5 +1,5 @@
1
1
  module Calabash
2
2
 
3
3
  # @!visibility private
4
- VERSION = '1.9.9.pre3'
4
+ VERSION = '2.0.0.pre1'
5
5
  end
data/lib/calabash/wait.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module Calabash
2
2
 
3
3
  # A public API for waiting for things to happen.
4
- # @!visibility private
5
4
  module Wait
6
5
  # @!visibility private
7
6
  class TimeoutError < RuntimeError
@@ -141,9 +140,15 @@ module Calabash
141
140
 
142
141
  # Waits for `query` to match one or more views.
143
142
  #
144
- # @param [String] query Query to match view
143
+ # @example
144
+ # wait_for_view({marked: 'mark'})
145
+ #
146
+ # @example
147
+ # text = wait_for_view("myview")['text']
148
+ #
149
+ # @param [String, Hash, Calabash::Query] query Query to match view
145
150
  # @see Calabash::Wait#with_timeout for options
146
- # @return [Object] The first view matching `query`.
151
+ # @return [Hash] The first view matching `query`.
147
152
  def wait_for_view(query, options={})
148
153
  if query.nil?
149
154
  raise ArgumentError, 'Query cannot be nil'
@@ -169,7 +174,9 @@ module Calabash
169
174
 
170
175
  # Waits for all `queries` to simultaneously match at least one view.
171
176
  #
172
- # @param [Array<String>, String] queries List of queries or a query.
177
+ # @param [String, Hash, Calabash::Query] queries List of queries or a
178
+ # query.
179
+ #
173
180
  # @see Calabash::Wait#with_timeout for options
174
181
  # @return [void] The return value for this method is undefined.
175
182
  def wait_for_views(*queries, **options)
@@ -200,7 +207,7 @@ module Calabash
200
207
 
201
208
  # Waits for `query` not to match any views
202
209
  #
203
- # @param [String] query Query to match view
210
+ # @param [String, Hash, Calabash::Query] query Query to match view
204
211
  # @see Calabash::Wait#with_timeout for options
205
212
  def wait_for_no_view(query, options={})
206
213
  if query.nil?
@@ -226,7 +233,9 @@ module Calabash
226
233
 
227
234
  # Waits for all `queries` to simultaneously match no views
228
235
  #
229
- # @param [Array<String>, String] queries List of queries or a query.
236
+ # @param [String, Hash, Calabash::Query] queries List of queries or a
237
+ # query.
238
+ #
230
239
  # @see Calabash::Wait#with_timeout for options
231
240
  def wait_for_no_views(*queries, **options)
232
241
  if queries.nil? || queries.any?(&:nil?)
@@ -252,7 +261,7 @@ module Calabash
252
261
 
253
262
  # Does the given `query` match at least one view?
254
263
  #
255
- # @param [String] query Query to match view
264
+ # @param [String, Hash, Calabash::Query] query Query to match view
256
265
  # @return [Object] Returns truthy if the `query` matches at least one view
257
266
  # @raise [ArgumentError] If given an invalid `query`
258
267
  def view_exists?(query)
@@ -271,7 +280,9 @@ module Calabash
271
280
 
272
281
  # Does the given `queries` all match at least one view?
273
282
  #
274
- # @param [Array<String>, String] queries List of queries or a query
283
+ # @param [String, Hash, Calabash::Query] queries List of queries or a
284
+ # query
285
+ #
275
286
  # @return Returns truthy if the `queries` all match at least one view
276
287
  # @raise [ArgumentError] If given an invalid list of queries
277
288
  def views_exist?(*queries)
@@ -291,7 +302,7 @@ module Calabash
291
302
  # Expect `query` to match at least one view. Raise an exception if it does
292
303
  # not.
293
304
  #
294
- # @param [String] query Query to match view
305
+ # @param [String, Hash, Calabash::Query] query Query to match a view
295
306
  # @raise [ArgumentError] If given an invalid `query`
296
307
  # @raise [ViewNotFoundError] If `query` does not match at least one view
297
308
  def expect_view(query)
@@ -303,6 +314,8 @@ module Calabash
303
314
  raise ViewNotFoundError,
304
315
  "No view matched #{parse_query_list(query)}"
305
316
  end
317
+
318
+ true
306
319
  end
307
320
 
308
321
  alias_method :view_should_exist, :expect_view
@@ -310,7 +323,8 @@ module Calabash
310
323
  # Expect `queries` to each match at least one view. Raise an exception if
311
324
  # they do not.
312
325
  #
313
- # @param [String] queries List of queries or a query
326
+ # @param [String, Hash, Calabash::Query] queries List of queries or a
327
+ # query.
314
328
  # @raise [ArgumentError] If given an invalid list of queries
315
329
  # @raise [ViewNotFoundError] If `queries` do not all match at least one
316
330
  # view.
@@ -323,12 +337,15 @@ module Calabash
323
337
  raise ViewNotFoundError,
324
338
  "Not all queries #{parse_query_list(queries)} matched a view"
325
339
  end
340
+
341
+ true
326
342
  end
327
343
 
328
344
  alias_method :views_should_exist, :expect_views
329
345
 
330
346
  # Expect `query` to match no views. Raise an exception if it does.
331
347
  #
348
+ # @param [String, Hash, Calabash::Query] query Query to match a view
332
349
  # @raise [ArgumentError] If given an invalid `query`
333
350
  # @raise [ViewFoundError] If `query` matches any views.
334
351
  def do_not_expect_view(query)
@@ -339,13 +356,16 @@ module Calabash
339
356
  if view_exists?(query)
340
357
  raise ViewFoundError, "A view matched #{parse_query_list(query)}"
341
358
  end
359
+
360
+ true
342
361
  end
343
362
 
344
363
  alias_method :view_should_not_exist, :do_not_expect_view
345
364
 
346
365
  # Expect `queries` to each match no views. Raise an exception if they do.
347
366
  #
348
- # @param [Array<String>, String] queries List of queries or a query
367
+ # @param [String, Hash, Calabash::Query] queries List of queries or a
368
+ # query.
349
369
  # @raise [ArgumentError] If given an invalid list of queries
350
370
  # @raise [ViewFoundError] If one of `queries` matched any views
351
371
  def do_not_expect_views(*queries)
@@ -357,6 +377,8 @@ module Calabash
357
377
  raise ViewFoundError,
358
378
  "Some views matched #{parse_query_list(queries)}"
359
379
  end
380
+
381
+ true
360
382
  end
361
383
 
362
384
  alias_method :views_should_not_exist, :do_not_expect_views
data/lib/calabash.rb CHANGED
@@ -45,22 +45,58 @@ module Calabash
45
45
 
46
46
  require 'calabash/page'
47
47
 
48
- # Instantiate a page object.
48
+ # Instantiate a page object for the current platform.
49
+ #
50
+ # @note Your pages **must** be in the scope of either Android or IOS. See the
51
+ # examples for details.
49
52
  #
50
53
  # @example
51
- # # android/pages/login_page.rb
52
- # class Android::LoginPage < Calabash::Page
54
+ # # android/pages/my_page.rb
55
+ # class Android::MyPage < Calabash::Page
53
56
  # include Calabash::Android
54
57
  #
55
- # [...]
58
+ # # [...]
56
59
  # end
57
60
  #
58
61
  # # step definition
59
- # Given([...]) do
62
+ # Given(/[...]/) do
60
63
  # # Calabash will determine your platform and pick the Android page.
61
- # page(LoginPage).method
64
+ # page(MyPage).method
65
+ # end
66
+ #
67
+ # @example
68
+ # # This example shows page code sharing across iOS and Android
69
+ # # Please see the sample 'shared-page-logic' for details.
70
+ # # pages/abstract_login_page.rb
71
+ # class AbstractLoginPage < Calabash::Page
72
+ # def login(username, password)
73
+ # enter_text_in(username_field, username)
74
+ # # [...]
75
+ # end
76
+ #
77
+ # private
78
+ #
79
+ # def username_field
80
+ # abstract_method!
81
+ # end
62
82
  # end
63
83
  #
84
+ # # pages/android_login_page.rb
85
+ # class Android::LoginPage < SharedLoginPage
86
+ # include Calabash::Android
87
+ #
88
+ # private
89
+ #
90
+ # def username_field
91
+ # "* marked:'a_username'"
92
+ # end
93
+ #
94
+ # # [...]
95
+ # end
96
+ #
97
+ #
98
+ # @see #android?
99
+ # @see #ios?
64
100
  # @param [Class] page_class The page to instantiate
65
101
  # @return [Calabash::Page] An instance of the page class
66
102
  def page(page_class)
@@ -76,9 +112,11 @@ module Calabash
76
112
  raise ArgumentError, "Expected a 'Class', got '#{page_class.class}'"
77
113
  end
78
114
 
79
- page_name = page_class.name.split('::').last
80
115
 
81
- if platform_module.const_defined?(page_name, false)
116
+ page_name = page_class.name
117
+ full_page_name = "#{platform_module}::#{page_name}"
118
+
119
+ if Calabash.is_defined?(full_page_name)
82
120
  page_class = platform_module.const_get(page_name, false)
83
121
 
84
122
  if page_class.is_a?(Class)
@@ -93,18 +131,26 @@ module Calabash
93
131
  raise "Page '#{page_class}' is not a class"
94
132
  end
95
133
  else
96
- raise "No such page defined '#{platform_module}::#{page_name}'"
134
+ raise "No such page defined '#{full_page_name}'"
97
135
  end
98
136
  end
99
137
 
100
- # Is the app under test running on Android?
138
+ # Is the device under test running Android?
139
+ #
140
+ # @return [Boolean] Returns true if
141
+ # {Calabash::Defaults#default_device Calabash.default_device} is an instance
142
+ # of {Calabash::Android::Device}.
101
143
  def android?
102
- Android.const_defined?(:Device) && Device.default.is_a?(Android::Device)
144
+ Android.const_defined?(:Device, false) && Device.default.is_a?(Android::Device)
103
145
  end
104
146
 
105
- # Is the app under test running on iOS?
147
+ # Is the device under test running iOS?
148
+ #
149
+ # @return [Boolean] Returns true if
150
+ # {Calabash::Defaults#default_device Calabash.default_device} is an instance
151
+ # of {Calabash::IOS::Device}.
106
152
  def ios?
107
- IOS.const_defined?(:Device) && Device.default.is_a?(IOS::Device)
153
+ IOS.const_defined?(:Device, false) && Device.default.is_a?(IOS::Device)
108
154
  end
109
155
 
110
156
  # @!visibility private
@@ -159,6 +205,29 @@ module Calabash
159
205
  end
160
206
  end
161
207
 
208
+ # @!visibility private
209
+ def self.is_defined?(string, scope = Object)
210
+ constant, rest = string.split('::', 2)
211
+
212
+ begin
213
+ scope.const_defined?(constant.to_sym, false) &&
214
+ (!rest || is_defined?(rest, scope.const_get(constant, false)))
215
+ rescue NameError => _
216
+ false
217
+ end
218
+ end
219
+
220
+ # @!visibility private
221
+ def self.recursive_const_get(string, scope = Object)
222
+ constant, rest = string.split('::', 2)
223
+
224
+ if rest
225
+ recursive_const_get(rest, scope.const_get(constant.to_sym, false))
226
+ else
227
+ scope.const_get(constant.to_sym, false)
228
+ end
229
+ end
230
+
162
231
  # @!visibility private
163
232
  def self.on_cucumber_context(base)
164
233
  on_new_context(base)
@@ -193,3 +262,45 @@ end
193
262
  unless Object.const_defined?(:IOS)
194
263
  Object.const_set(:IOS, Module.new)
195
264
  end
265
+
266
+ if Calabash::Environment::DEBUG_CALLED_METHODS
267
+ $stdout.puts "#{Calabash::Color.red("Will print every Calabash method called!")}"
268
+ $stdout.puts "#{Calabash::Color.red("Warning: This might slow down your test drastically")}"
269
+ $stdout.puts "#{Calabash::Color.red("and is an experimental feature.")}"
270
+
271
+ calabash_file = Calabash.method(:extended).source_location.first
272
+ $__calabash_dir_name = File.dirname(calabash_file)
273
+
274
+ trace_func = lambda do |event, file, line, id, binding, classname|
275
+ if event == 'call'
276
+ if classname.to_s.split('::').first == 'Calabash'
277
+ binding_caller_locations = binding.eval("caller_locations")
278
+ files = binding_caller_locations[3..-1].map(&:path)
279
+
280
+ calabash_not_in_stacktrace = files.none? do |file|
281
+ file.start_with?($__calabash_dir_name) &&
282
+ File.basename(file) != 'page.rb'
283
+ end
284
+
285
+ if calabash_not_in_stacktrace
286
+ unless id == :included || id == :extended || id == :inherited
287
+ arguments = {}
288
+
289
+ binding.eval('local_variables').each do |variable|
290
+ arguments[variable] = binding.eval(variable.to_s)
291
+ end
292
+
293
+ # The arguments will be in order
294
+ if arguments.empty?
295
+ $stdout.puts "Calabash method called: #{id}"
296
+ else
297
+ $stdout.puts "Calabash method called: #{id}(#{arguments.values.map(&:inspect).join(', ')})"
298
+ end
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ set_trace_func(trace_func)
306
+ end