calabash 1.2.1 → 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +39 -0
  3. data/LICENSE +204 -21
  4. data/README.md +36 -6
  5. data/VERSIONING.md +16 -0
  6. data/bin/calabash +95 -0
  7. data/lib/calabash.rb +185 -1
  8. data/lib/calabash/android.rb +64 -0
  9. data/lib/calabash/android/adb.rb +277 -0
  10. data/lib/calabash/android/application.rb +110 -0
  11. data/lib/calabash/android/build.rb +12 -0
  12. data/lib/calabash/android/build/application.rb +13 -0
  13. data/lib/calabash/android/build/build_error.rb +11 -0
  14. data/lib/calabash/android/build/builder.rb +119 -0
  15. data/lib/calabash/android/build/java_keystore.rb +177 -0
  16. data/lib/calabash/android/build/resigner.rb +56 -0
  17. data/lib/calabash/android/build/test_server.rb +27 -0
  18. data/lib/calabash/android/console_helpers.rb +44 -0
  19. data/lib/calabash/android/cucumber.rb +3 -0
  20. data/lib/calabash/android/device.rb +965 -0
  21. data/lib/calabash/android/environment.rb +470 -0
  22. data/lib/calabash/android/gestures.rb +369 -0
  23. data/lib/calabash/android/interactions.rb +45 -0
  24. data/lib/calabash/android/lib/.irbrc +55 -0
  25. data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
  26. data/lib/calabash/android/lib/TestServer.apk +0 -0
  27. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
  28. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
  29. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
  30. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
  31. data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
  32. data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
  33. data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
  34. data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
  35. data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
  36. data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
  37. data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
  38. data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
  39. data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
  40. data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
  41. data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
  42. data/lib/calabash/android/life_cycle.rb +37 -0
  43. data/lib/calabash/android/orientation.rb +30 -0
  44. data/lib/calabash/android/physical_buttons.rb +39 -0
  45. data/lib/calabash/android/screenshot.rb +9 -0
  46. data/lib/calabash/android/scroll.rb +5 -0
  47. data/lib/calabash/android/server.rb +10 -0
  48. data/lib/calabash/android/text.rb +54 -0
  49. data/lib/calabash/application.rb +74 -0
  50. data/lib/calabash/cli.rb +12 -0
  51. data/lib/calabash/cli/build.rb +33 -0
  52. data/lib/calabash/cli/console.rb +90 -0
  53. data/lib/calabash/cli/generate.rb +110 -0
  54. data/lib/calabash/cli/helpers.rb +130 -0
  55. data/lib/calabash/cli/resign.rb +33 -0
  56. data/lib/calabash/cli/run.rb +99 -0
  57. data/lib/calabash/cli/setup_keystore.rb +39 -0
  58. data/lib/calabash/color.rb +32 -0
  59. data/lib/calabash/console_helpers.rb +90 -0
  60. data/lib/calabash/defaults.rb +56 -0
  61. data/lib/calabash/device.rb +401 -0
  62. data/lib/calabash/environment.rb +75 -0
  63. data/lib/calabash/gestures.rb +384 -0
  64. data/lib/calabash/http.rb +8 -0
  65. data/lib/calabash/http/error.rb +15 -0
  66. data/lib/calabash/http/request.rb +42 -0
  67. data/lib/calabash/http/retriable_client.rb +156 -0
  68. data/lib/calabash/interactions.rb +105 -0
  69. data/lib/calabash/ios.rb +37 -0
  70. data/lib/calabash/ios/application.rb +119 -0
  71. data/lib/calabash/ios/conditions.rb +79 -0
  72. data/lib/calabash/ios/console_helpers.rb +72 -0
  73. data/lib/calabash/ios/device.rb +24 -0
  74. data/lib/calabash/ios/device/device_implementation.rb +779 -0
  75. data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
  76. data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
  77. data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
  78. data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
  79. data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
  80. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
  81. data/lib/calabash/ios/device/routes/error.rb +8 -0
  82. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
  83. data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
  84. data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
  85. data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
  86. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
  87. data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
  88. data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
  89. data/lib/calabash/ios/device/text_mixin.rb +19 -0
  90. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
  91. data/lib/calabash/ios/device/uia_mixin.rb +12 -0
  92. data/lib/calabash/ios/environment.rb +41 -0
  93. data/lib/calabash/ios/interactions.rb +10 -0
  94. data/lib/calabash/ios/lib/.irbrc +55 -0
  95. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
  96. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
  97. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
  98. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
  99. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
  100. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
  101. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
  102. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
  103. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
  104. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
  105. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
  106. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
  107. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
  108. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
  109. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
  110. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
  111. data/lib/calabash/ios/orientation.rb +117 -0
  112. data/lib/calabash/ios/scroll.rb +504 -0
  113. data/lib/calabash/ios/server.rb +73 -0
  114. data/lib/calabash/ios/text.rb +248 -0
  115. data/lib/calabash/ios/uia.rb +24 -0
  116. data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
  117. data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
  118. data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
  119. data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
  120. data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
  121. data/lib/calabash/life_cycle.rb +111 -0
  122. data/lib/calabash/location.rb +51 -0
  123. data/lib/calabash/logger.rb +87 -0
  124. data/lib/calabash/orientation.rb +84 -0
  125. data/lib/calabash/page.rb +35 -0
  126. data/lib/calabash/patch.rb +14 -0
  127. data/lib/calabash/patch/array.rb +16 -0
  128. data/lib/calabash/patch/run_loop.rb +90 -0
  129. data/lib/calabash/query.rb +160 -0
  130. data/lib/calabash/query_result.rb +85 -0
  131. data/lib/calabash/screenshot.rb +89 -0
  132. data/lib/calabash/server.rb +16 -0
  133. data/lib/calabash/text.rb +76 -0
  134. data/lib/calabash/utility.rb +58 -0
  135. data/lib/calabash/version.rb +3 -1
  136. data/lib/calabash/wait.rb +474 -0
  137. metadata +462 -24
@@ -0,0 +1,160 @@
1
+ module Calabash
2
+
3
+ # A representation of a Calabash query.
4
+ # @todo Query needs more documentation.
5
+ # @todo Query needs some methods moved to private or doc'd private.
6
+ class Query
7
+ # @!visibility private
8
+ def self.web_query?(query_string)
9
+ # :no, :double or :single
10
+ in_quotes = :no
11
+
12
+ # Number of slashes before the current char
13
+ slash_count = 0
14
+
15
+ # If the query starts with css: or xpath:
16
+ # We could change the regex from /(\s|\'|\")css:/ to /(^|\s|\'|\")css:/
17
+ # and change if (query[i, indicator[:length]] =~ indicator[:regex]) == 0
18
+ # to if (query[0, i+indicator[:length]] =~ indicator[:regex]) == i
19
+ # (not working)
20
+ # to avoid having to do this check.
21
+ results = WEB_QUERY_INDICATORS.map do |indicator|
22
+ query_string =~ /^\s*#{indicator[:string]}/
23
+ end
24
+
25
+ if results.any?
26
+ return true
27
+ end
28
+
29
+ length = query_string.length
30
+
31
+ length.times do |i|
32
+ char = query_string[i]
33
+
34
+ if char == "\\"
35
+ slash_count += 1
36
+ next
37
+ end
38
+
39
+ if char == "'"
40
+ if slash_count == 0
41
+ if in_quotes == :no
42
+ in_quotes = :single
43
+ elsif in_quotes == :single
44
+ in_quotes = :no
45
+ end
46
+ end
47
+ elsif char == '"'
48
+ if slash_count == 0
49
+ if in_quotes == :no
50
+ in_quotes = :double
51
+ elsif in_quotes == :double
52
+ in_quotes = :no
53
+ end
54
+ end
55
+ end
56
+
57
+ if slash_count == 0 && in_quotes == :no
58
+ WEB_QUERY_INDICATORS.each do |indicator|
59
+ if (query_string[i, indicator[:length]] =~ indicator[:regex]) == 0
60
+ return true
61
+ end
62
+ end
63
+ end
64
+
65
+ slash_count = 0
66
+ end
67
+
68
+ false
69
+ end
70
+
71
+ # @!visibility private
72
+ def self.query_hash_to_string(hash)
73
+ result = hash.fetch(:class, '*')
74
+
75
+ if hash[:marked] && (hash[:id] || hash[:text])
76
+ raise 'Cannot use both marked and id/text'
77
+ end
78
+
79
+ if hash[:marked]
80
+ result = "#{result} marked:'#{Text.escape_single_quotes(hash[:marked])}'"
81
+ end
82
+
83
+ if hash[:id]
84
+ result = "#{result} id:'#{Text.escape_single_quotes(hash[:id])}'"
85
+ end
86
+
87
+ if hash[:text]
88
+ result = "#{result} text:'#{Text.escape_single_quotes(hash[:text])}'"
89
+ end
90
+
91
+ if hash[:index]
92
+ result = "#{result} index:#{hash[:index]}"
93
+ end
94
+
95
+ if hash[:css]
96
+ result = "#{result} css:'#{Text.escape_single_quotes(hash[:css])}'"
97
+ end
98
+
99
+ if hash[:xpath]
100
+ result = "#{result} xpath:'#{Text.escape_single_quotes(hash[:xpath])}'"
101
+ end
102
+
103
+ result
104
+ end
105
+
106
+ def initialize(query)
107
+ unless query.is_a?(Query) || query.is_a?(Hash) || query.is_a?(String)
108
+ raise ArgumentError, "Invalid argument for query: '#{query}' (#{query.class})"
109
+ end
110
+
111
+ @query = query.dup
112
+
113
+ freeze
114
+ end
115
+
116
+ def to_s
117
+ if @query.is_a?(Query)
118
+ @query.to_s
119
+ elsif @query.is_a?(Hash)
120
+ Query.query_hash_to_string(@query)
121
+ else
122
+ @query.dup
123
+ end
124
+ end
125
+
126
+ def inspect
127
+ "<Calabash::Query #{@query.inspect}>"
128
+ end
129
+
130
+ def web_query?
131
+ Query.web_query?(to_s)
132
+ end
133
+
134
+ WEB_QUERY_INDICATORS =
135
+ [
136
+ {
137
+ string: 'css:',
138
+ regex: /(\s|\'|\")css:/,
139
+ length: 5
140
+ },
141
+ {
142
+ string: 'xpath:',
143
+ regex: /(\s|\'|\")xpath:/,
144
+ length: 7
145
+ }
146
+ ]
147
+
148
+ # @!visibility private
149
+ def self.valid_query?(query)
150
+ query.is_a?(String) || query.is_a?(Hash) || query.is_a?(Query)
151
+ end
152
+
153
+ # @!visibility private
154
+ def self.ensure_valid_query(query)
155
+ unless valid_query?(query)
156
+ raise ArgumentError, "invalid query '#{query}' (#{query.class})"
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,85 @@
1
+ module Calabash
2
+ # A QueryResult represents the returned value of a query.
3
+ # It is an immutable collection of matches or the result of applied methods.
4
+ # It will, unlike `Array`, raise an IndexError instead of returning nil if
5
+ # an entry outside bounds is accessed.
6
+ class QueryResult < Array
7
+ def self.create(result, query)
8
+ query_result = QueryResult.send(:new, query)
9
+ query_result.send(:initialize_copy, result)
10
+ recursive_freeze(query_result)
11
+ query_result
12
+ end
13
+
14
+ private_class_method :new
15
+
16
+ attr_reader :query
17
+
18
+ def initialize(query)
19
+ @query = Query.new(query)
20
+ end
21
+
22
+ def first(*several_variants)
23
+ ensure_in_bounds(0)
24
+
25
+ super(*several_variants)
26
+ end
27
+
28
+ def last(*several_variants)
29
+ ensure_in_bounds(-1)
30
+
31
+ super(*several_variants)
32
+ end
33
+
34
+ def [](index)
35
+ ensure_in_bounds(index)
36
+
37
+ super(index)
38
+ end
39
+
40
+ def at(index)
41
+ ensure_in_bounds(index)
42
+
43
+ super(index)
44
+ end
45
+
46
+ def fetch(*several_variants)
47
+ unless block_given? || several_variants.length > 1
48
+ ensure_in_bounds(several_variants.first)
49
+ end
50
+
51
+ super(*several_variants)
52
+ end
53
+
54
+ def ensure_in_bounds(index)
55
+ if empty?
56
+ raise IndexError, "Query result is empty"
57
+ end
58
+
59
+ if index > 0 && index >= length
60
+ raise IndexError, "Index out of bounds [index: #{index}, length: #{length}]"
61
+ end
62
+
63
+ if index < 0 && -index > length
64
+ raise IndexError, "Index out of bounds [index: #{index}, length: #{length}]"
65
+ end
66
+ end
67
+
68
+ def self.recursive_freeze(object)
69
+ if object.is_a?(Array)
70
+ object.each do |entry|
71
+ recursive_freeze(entry)
72
+ end
73
+ end
74
+
75
+ if object.is_a?(Hash)
76
+ object.each do |key, value|
77
+ recursive_freeze(key)
78
+ recursive_freeze(value)
79
+ end
80
+ end
81
+
82
+ object.freeze
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,89 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+
4
+ module Calabash
5
+
6
+ # A public API for taking screenshots.
7
+ module Screenshot
8
+ # @!visibility private
9
+ def self.screenshot_directory_prefix
10
+ @@screenshot_directory_prefix
11
+ end
12
+
13
+ # Set the screenshot directory prefix.
14
+ def self.screenshot_directory_prefix=(value)
15
+ if class_variable_defined?(:@@screenshots_taken) &&
16
+ @@screenshots_taken != 0
17
+ raise 'Cannot change the screenshot directory prefix after a screenshot has been taken'
18
+ end
19
+
20
+ @@screenshot_directory_prefix = value
21
+ end
22
+
23
+ # @!visibility private
24
+ self.screenshot_directory_prefix = 'test_run_'
25
+
26
+ # Takes a screenshot and saves it. The file is stored in the directory
27
+ # given by the ENV variable $CAL_SCREENSHOT_DIR, or by default in
28
+ # the relative directory 'screenshots'. The files are saved in a
29
+ # sub directory named test_run_n, where n is unique and incrementing for
30
+ # each new test run. The filename of the screenshot will be `name`.
31
+ # If `name` is not given (nil), the screenshot will be saved as
32
+ # screenshot_N, where N is the total amount of screenshots taken for the
33
+ # test run.
34
+ #
35
+ # @param [String] name Name of the screenshot.
36
+ # @return [String] Path to the screenshot
37
+ def screenshot(name=nil)
38
+ Device.default.screenshot(name)
39
+ end
40
+
41
+ # Takes a screenshot and embeds it in the test report.
42
+ # @see Screenshot#screenshot
43
+ def screenshot_embed(name=nil)
44
+ path = screenshot(name)
45
+ embed(path, 'image/png', name || File.basename(path))
46
+ end
47
+
48
+ # @!visibility private
49
+ def self.obtain_screenshot_path!(name=nil)
50
+ @@screenshots_taken ||= 1
51
+
52
+ if name.nil?
53
+ name = "screenshot_#{@@screenshots_taken}.png"
54
+ end
55
+
56
+ name = "#{name}.png" if File.extname(name).empty?
57
+
58
+ @@screenshots_taken += 1
59
+
60
+ unless Dir.exist?(File.expand_path(screenshot_directory))
61
+ FileUtils.mkdir_p(File.expand_path(screenshot_directory))
62
+ end
63
+
64
+ File.join(screenshot_directory, name)
65
+ end
66
+
67
+ # @!visibility private
68
+ def self.screenshot_directory
69
+ @@screenshot_directory ||= new_screenshot_sub_directory
70
+ end
71
+
72
+ # @!visibility private
73
+ def self.new_screenshot_sub_directory
74
+ count = screenshot_directory_test_run_directories.count
75
+ File.join(Environment::SCREENSHOT_DIRECTORY,
76
+ "#{screenshot_directory_prefix}#{count+1}")
77
+ end
78
+
79
+ # @!visibility private
80
+ def self.screenshot_directory_test_run_directories
81
+ dir = File.expand_path(File.join(Environment::SCREENSHOT_DIRECTORY, '*'))
82
+
83
+ Dir.glob(dir).select do |file|
84
+ File.directory?(file) &&
85
+ File.basename(file) =~ /^#{screenshot_directory_prefix}\d+$/
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,16 @@
1
+ module Calabash
2
+
3
+ # A representation of the Calabash test server.
4
+ class Server
5
+ attr_reader :endpoint
6
+ attr_reader :test_server_port
7
+
8
+ # @param [URI] endpoint The endpoint to reach the test server.
9
+ # @param [Integer] test_server_port The port bound to the test server
10
+ # running on the device. On iOS this is same as the endpoint port.
11
+ def initialize(endpoint, test_server_port = nil)
12
+ @endpoint = endpoint
13
+ @test_server_port = test_server_port || endpoint.port
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ module Calabash
2
+
3
+ # A public API for entering text.
4
+ module Text
5
+ # Enter `text` into the currently focused view.
6
+ #
7
+ # @param [String] text The text to type.
8
+ # @raise [RuntimeError] if the text cannot be typed.
9
+ def enter_text(text)
10
+ Device.default.enter_text(text)
11
+ end
12
+
13
+ # Enter `text` into `query`.
14
+ # @see Calabash::Text#enter_text
15
+ #
16
+ # @param [String] text The text to type.
17
+ # @param query A query describing the view to enter text into.
18
+ def enter_text_in(query, text)
19
+ _enter_text_in(query, text)
20
+ end
21
+
22
+ # Clears the text of the currently focused view.
23
+ def clear_text
24
+ _clear_text
25
+ end
26
+
27
+ # Clears the text `view`
28
+ # @see Calabash::Text#clear_text
29
+ #
30
+ # @param query A query describing the view to clear text in.
31
+ def clear_text_in(view)
32
+ _clear_text_in(view)
33
+ end
34
+
35
+ # @todo add docs
36
+ def tap_current_keyboard_action_key
37
+ _tap_current_keyboard_action_key
38
+ end
39
+
40
+ # Escapes single quotes in `string`.
41
+ #
42
+ # @example
43
+ # > escape_quotes("Let's get this done.")
44
+ # => "Let\\'s get this done."
45
+ # @param [String] string The string to escape.
46
+ # @return [String] A string with its single quotes properly escaped.
47
+ def escape_single_quotes(string)
48
+ Text.escape_single_quotes(string)
49
+ end
50
+
51
+ # @!visibility private
52
+ def _enter_text_in(view, text)
53
+ abstract_method!
54
+ end
55
+
56
+ # @!visibility private
57
+ def _clear_text
58
+ abstract_method!
59
+ end
60
+
61
+ # @!visibility private
62
+ def _clear_text_in(view)
63
+ abstract_method!
64
+ end
65
+
66
+ # @!visibility private
67
+ def _tap_current_keyboard_action_key
68
+ abstract_method!
69
+ end
70
+
71
+ # @!visibility private
72
+ def self.escape_single_quotes(string)
73
+ string.gsub("'", "\\\\'")
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ module Calabash
2
+
3
+ # @!visibility private
4
+ class AbstractMethodError < StandardError
5
+
6
+ end
7
+
8
+ module Utility
9
+
10
+ # @!visibility private
11
+ def abstract_method!
12
+ method_name = if Kernel.method_defined?(:caller_locations)
13
+ caller_locations.first.label
14
+ else
15
+ caller.first[/\`(.*)\'/, 1]
16
+ end
17
+
18
+ raise AbstractMethodError.new("Abstract method '#{method_name}'")
19
+ end
20
+
21
+ # @! visibility private
22
+ class RetryError < RuntimeError; end
23
+
24
+ # A convenience method for creating a percentage hash that that can be
25
+ # passed to gestures.
26
+ #
27
+ # @example
28
+ # # These are equivalent.
29
+ # pan(percent(20, 50), percent(20, 100))
30
+ # pan({x: 20, y: 50}, {x: 20, y: 100})
31
+ #
32
+ # @param [Number] x The value of the x percent.
33
+ # @param [Number] y The value of the y percent.
34
+ # @return [Hash] Representing the given values.
35
+ def percent(x, y)
36
+ {x: x, y: y}
37
+ end
38
+
39
+ alias_method :pct, :percent
40
+
41
+ # A convenience method for creating a coordinate hash that that can be
42
+ # passed to gestures.
43
+ #
44
+ # @example
45
+ # # These are equivalent.
46
+ # tap(query, offset: coordinate(20, 50))
47
+ # tap(query, offset: {x: 20, y: 50})
48
+ #
49
+ # @param [Number] x The value of the x.
50
+ # @param [Number] y The value of the y.
51
+ # @return [Hash] Representing the given values.
52
+ def coordinate(x, y)
53
+ {x: x, y: y}
54
+ end
55
+
56
+ alias_method :coord, :coordinate
57
+ end
58
+ end