appium_lib 0.0.30 → 0.3.0

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 (38) hide show
  1. checksums.yaml +8 -8
  2. data/Rakefile +15 -7
  3. data/appium_lib.gemspec +3 -3
  4. data/docs.md +7 -5
  5. data/lib/appium_lib.rb +34 -6
  6. data/lib/appium_lib/android/element/alert.rb +43 -0
  7. data/lib/appium_lib/android/element/generic.rb +94 -0
  8. data/lib/appium_lib/android/element/textfield.rb +43 -0
  9. data/lib/appium_lib/android/helper.rb +120 -0
  10. data/lib/appium_lib/android/patch.rb +10 -0
  11. data/lib/appium_lib/common/element/button.rb +83 -0
  12. data/lib/appium_lib/common/element/text.rb +44 -0
  13. data/lib/appium_lib/common/element/window.rb +9 -0
  14. data/lib/appium_lib/common/helper.rb +140 -0
  15. data/lib/appium_lib/common/patch.rb +83 -0
  16. data/lib/appium_lib/common/version.rb +6 -0
  17. data/lib/appium_lib/driver.rb +265 -0
  18. data/lib/appium_lib/ios/element/alert.rb +56 -0
  19. data/lib/appium_lib/ios/element/generic.rb +170 -0
  20. data/lib/appium_lib/ios/element/textfield.rb +90 -0
  21. data/lib/appium_lib/ios/helper.rb +103 -0
  22. data/lib/appium_lib/ios/patch.rb +15 -0
  23. data/readme.md +10 -3
  24. data/release_notes.md +8 -0
  25. metadata +19 -15
  26. data/lib/appium_lib/console.rb +0 -254
  27. data/lib/appium_lib/element/android/alert.rb +0 -45
  28. data/lib/appium_lib/element/android/generic.rb +0 -88
  29. data/lib/appium_lib/element/android/textfield.rb +0 -44
  30. data/lib/appium_lib/element/button.rb +0 -83
  31. data/lib/appium_lib/element/ios/alert.rb +0 -49
  32. data/lib/appium_lib/element/ios/generic.rb +0 -140
  33. data/lib/appium_lib/element/ios/textfield.rb +0 -93
  34. data/lib/appium_lib/element/text.rb +0 -43
  35. data/lib/appium_lib/element/window.rb +0 -12
  36. data/lib/appium_lib/helper.rb +0 -278
  37. data/lib/appium_lib/patch.rb +0 -90
  38. data/lib/appium_lib/version.rb +0 -4
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ module Appium::Android
3
+ # Implement useful features for element.
4
+ class Selenium::WebDriver::Element
5
+ # Cross platform way of entering text into a textfield
6
+ def type text
7
+ self.send_keys text
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ # UIAButton methods
3
+ module Appium::Common
4
+ # Find a button by text and optionally number.
5
+ # @param text [String, Integer] the text to exactly match. If int then the button at that index is returned.
6
+ # @param number [Integer] the occurrence of the button matching text. Defaults to the first button.
7
+ # @return [Button] the button found with text and matching number
8
+ def button text, number=0
9
+ # return button at index.
10
+ return ele_index :button, text if text.is_a? Numeric
11
+
12
+ number >= 1 ? button_num( text, number ) :
13
+ find_ele_by_text_include( :button, text )
14
+ end
15
+
16
+ # Get an array of button texts or button elements if text is provided.
17
+ # @param text [String] the text to exactly match
18
+ # @return [Array<String>, Array<Buttons>] either an array of button texts or an array of button elements if text is provided.
19
+ def buttons text=nil
20
+ text == nil ? find_eles_attr( :button, :text ) :
21
+ find_eles_by_text_include( :button, text )
22
+ end
23
+
24
+ # Get the first button element.
25
+ # @return [Button]
26
+ def first_button
27
+ first_ele :button
28
+ end
29
+
30
+ # Get the last button element.
31
+ # @return [Button]
32
+ def last_button
33
+ last_ele :button
34
+ end
35
+
36
+ # Get the first button element that exactly matches text.
37
+ # @param text [String] the text to match exactly
38
+ # @return [Button]
39
+ def button_exact text
40
+ find_ele_by_text :button, text
41
+ end
42
+
43
+ # Get all button elements that exactly match text.
44
+ # @param text [String] the text to match exactly
45
+ # @return [Array<Button>]
46
+ def buttons_exact text
47
+ find_eles_by_text :button, text
48
+ end
49
+
50
+ # Get an array of button elements.
51
+ # @return [Array<Button>]
52
+ def e_buttons
53
+ find_eles :button
54
+ end
55
+
56
+ # Expected to be called via button method.
57
+ #
58
+ # Get the button element exactly matching text and
59
+ # occurrence. number=2 means the 2nd occurrence.
60
+ #
61
+ # find the second Sign In button
62
+ #
63
+ # b = e_button 'Sign In', 2
64
+ #
65
+ # Button order will change in iOS vs Android
66
+ # so if there's no button found at number then
67
+ # return the first button.
68
+ #
69
+ # @param text [String] the text to match
70
+ # @param number [Integer] the button occurance to return. 1 = first button
71
+ # @return [Button] the button that matches text and number
72
+ def button_num text, number=1
73
+ raise 'Number must be >= 1' if number <= 0
74
+ number = number - 1 # zero indexed
75
+ result = nil
76
+
77
+ elements = buttons text
78
+ elements.size > number ? result = elements[number]
79
+ : result = elements.first
80
+
81
+ result
82
+ end
83
+ end # module Appium::Common
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ # UIAStaticText methods
3
+ module Appium::Common
4
+ # s_ prefix for static_text to avoid conflict with generic text methods.
5
+
6
+ # Get an array of text texts.
7
+ # @return [Array<String>]
8
+ def s_texts
9
+ find_eles_attr :text, :text
10
+ end
11
+
12
+ # Get an array of text elements.
13
+ # @return [Array<Text>]
14
+ def e_s_texts
15
+ find_eles :text
16
+ end
17
+
18
+ # Get the first text element.
19
+ # @return [Text]
20
+ def s_first_text
21
+ first_ele :text
22
+ end
23
+
24
+ # Get the last text element
25
+ # @return [Text]
26
+ def s_last_text
27
+ last_ele :text
28
+ end
29
+
30
+ # Get the first element that includes text.
31
+ # @param text [String, Integer] the text to find. If int then the text at that index is returned.
32
+ # @return [Text]
33
+ def s_text text
34
+ return ele_index :text, text if text.is_a? Numeric
35
+ find_ele_by_text_include :text, text
36
+ end
37
+
38
+ # Get the first textfield that matches text.
39
+ # @param text [String] the text that the tag must match
40
+ # @return [Text]
41
+ def s_text_exact text
42
+ find_ele_by_text :text, text
43
+ end
44
+ end # module Appium::Common
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ # UIAWindow methods
3
+ module Appium::Common
4
+ # Get the window's size
5
+ def window_size
6
+ return nil if @driver.nil?
7
+ @driver.manage.window.size
8
+ end
9
+ end # module Appium::Common
@@ -0,0 +1,140 @@
1
+ # encoding: utf-8
2
+ # Generic helper methods not specific
3
+ # to a particular tag name
4
+ module Appium::Common
5
+ # json and ap are required for the source method.
6
+ require 'json'
7
+ require 'ap' # awesome print
8
+ require 'timeout' # for wait
9
+
10
+ # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
11
+ # Android .name returns the accessibility attribute and nothing if it's not set.
12
+ #
13
+ # .text should be cross platform so prefer that over name, unless both
14
+ # Android and iOS have proper accessibility attributes.
15
+ # .text and .value should be the same so use .text over .value.
16
+ #
17
+ # secure tag_name is iOS only because it can't be implemented using uiautomator for Android.
18
+ #
19
+ # find_element :text doesn't work so use XPath to find by text.
20
+
21
+ # Check every 0.5 seconds to see if block.call is true.
22
+ # Give up after 30 seconds.
23
+ # @param block [Block] the block to call
24
+ # @return [Object] the result of block.call
25
+ def wait &block
26
+ # Rescue Timeout::Error: execution expired
27
+ result = nil
28
+ timeout(30) { until (result = begin; block.call; rescue; end) do; sleep 0.5 end }
29
+ result
30
+ end
31
+
32
+ # Presses the back button on Android.
33
+ # @return [void]
34
+ def back
35
+ @driver.navigate.back
36
+ end
37
+
38
+ def xpath xpath_str
39
+ find_element :xpath, xpath_str
40
+ end
41
+
42
+ def xpaths xpath_str
43
+ find_elements :xpath, xpath_str
44
+ end
45
+
46
+ # Get the element of type tag_name at matching index.
47
+ # @param tag_name [String] the tag name to find
48
+ # @param index [Integer] the index
49
+ # @return [Element] the found element of type tag_name
50
+ def ele_index tag_name, index
51
+ # XPath index starts at 1. ruby_lib index starts at 0
52
+ find_element :xpath, "//#{tag_name}[#{index + 1}]"
53
+ end
54
+
55
+ # Get all elements exactly matching tag name
56
+ # @param tag_name [String] the tag name to find
57
+ # @return [Array<Element>] the found elements of type tag_name
58
+ def find_eles tag_name
59
+ @driver.find_elements :tag_name, tag_name
60
+ end
61
+
62
+ # Get the first tag that exactly matches tag and text.
63
+ # @param tag [String] the tag name to match
64
+ # @param text [String] the text to exactly match
65
+ # @return [Element] the element of type tag exactly matching text
66
+ def find_ele_by_text tag, text
67
+ @driver.find_element :xpath, %Q(#{tag}[@text='#{text}'])
68
+ end
69
+
70
+ # Get all tags that exactly match tag and text.
71
+ # @param tag [String] the tag name to match
72
+ # @param text [String] the text to exactly match
73
+ # @return [Array<Element>] the elements of type tag exactly matching text
74
+ def find_eles_by_text tag, text
75
+ @driver.find_elements :xpath, %Q(#{tag}[@text='#{text}'])
76
+ end
77
+
78
+ # Get the first tag by attribute that exactly matches value.
79
+ # @param tag [String] the tag name to match
80
+ # @param attr [String] the attribute to compare
81
+ # @param value [String] the value of the attribute that the element must include
82
+ # @return [Element] the element of type tag who's attribute includes value
83
+ def find_ele_by_attr_include tag, attr, value
84
+ @driver.find_element :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
85
+ end
86
+
87
+ # Get tags by attribute that include value.
88
+ # @param tag [String] the tag name to match
89
+ # @param attr [String] the attribute to compare
90
+ # @param value [String] the value of the attribute that the element must include
91
+ # @return [Array<Element>] the elements of type tag who's attribute includes value
92
+ def find_eles_by_attr_include tag, attr, value
93
+ @driver.find_elements :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
94
+ end
95
+
96
+ # Get the first tag that includes text.
97
+ # @param tag [String] the tag name to match
98
+ # @param text [String] the text the element must include
99
+ # @return [Element] the element of type tag that includes text
100
+ # element.attribute(:text).include? text
101
+ def find_ele_by_text_include tag, text
102
+ find_ele_by_attr_include tag, :text, text
103
+ end
104
+
105
+ # Get the tags that include text.
106
+ # @param tag [String] the tag name to match
107
+ # @param text [String] the text the element must include
108
+ # @return [Array<Element>] the elements of type tag that includes text
109
+ # element.attribute(:text).include? text
110
+ def find_eles_by_text_include tag, text
111
+ find_eles_by_attr_include tag, :text, text
112
+ end
113
+
114
+ # Get the first tag that matches tag_name
115
+ # @param tag_name [String] the tag to match
116
+ # @return [Element]
117
+ def first_ele tag_name
118
+ # XPath index starts at 1
119
+ find_element :xpath, "//#{tag_name}[1]"
120
+ end
121
+
122
+ # Get the last tag that matches tag_name
123
+ # @param tag_name [String] the tag to match
124
+ # @return [Element]
125
+ def last_ele tag_name
126
+ xpath "//#{tag_name}[last()]"
127
+ end
128
+
129
+ # Prints a JSON view of the current page
130
+ # @return [void]
131
+ def source
132
+ ap get_source
133
+ end
134
+
135
+ # Gets a JSON view of the current page
136
+ # @return [JSON]
137
+ def get_source
138
+ JSON.parse(@driver.page_source)
139
+ end
140
+ end # module Appium::Common
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ module Appium::Common
3
+ # Implement useful features for element.
4
+ class Selenium::WebDriver::Element
5
+ # Note: For testing .text should be used over value, and name.
6
+
7
+ # Fixes NoMethodError: undefined method `value' for #<Selenium::WebDriver::Element:0x..fa4a9148235390a44 id="1">
8
+ def value
9
+ self.attribute :value
10
+ end
11
+
12
+ # Fixes NoMethodError: undefined method `name' for #<Selenium::WebDriver::Element
13
+ def name
14
+ self.attribute :name
15
+ end
16
+
17
+ # Use tag_name to get element's type.
18
+ #
19
+ # Tag name appears to be the same as type.
20
+ #
21
+ # Fixes Selenium::WebDriver::Error::UnknownError: Not yet implemented
22
+ def tag_name
23
+ self.attribute :type
24
+ end
25
+
26
+ # For use with mobile tap.
27
+ #
28
+ # execute_script 'mobile: tap', :x => 0.0, :y => 0.98
29
+ #
30
+ # https://github.com/appium/appium/wiki/Automating-mobile-gestures
31
+ # @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
32
+ def location_rel
33
+ xy = self.location
34
+ w = window_size
35
+ OpenStruct.new( x: xy.x.to_f / w.width.to_f,
36
+ y: xy.y.to_f / w.height.to_f )
37
+ end
38
+ end
39
+ end # module Appium::Common
40
+
41
+ # Print JSON posted to Appium. Not scoped to an Appium module.
42
+ #
43
+ # Requires from lib/selenium/webdriver/remote.rb
44
+ require 'selenium/webdriver/remote/capabilities'
45
+ require 'selenium/webdriver/remote/bridge'
46
+ require 'selenium/webdriver/remote/server_error'
47
+ require 'selenium/webdriver/remote/response'
48
+ require 'selenium/webdriver/remote/commands'
49
+ require 'selenium/webdriver/remote/http/common'
50
+ require 'selenium/webdriver/remote/http/default'
51
+
52
+ # Show http calls to the Selenium server.
53
+ #
54
+ # Invaluable for debugging.
55
+ module Selenium::WebDriver::Remote
56
+ class Bridge
57
+ # Code from lib/selenium/webdriver/remote/bridge.rb
58
+ def raw_execute(command, opts = {}, command_hash = nil)
59
+ verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
60
+ path = path.dup
61
+
62
+ path[':session_id'] = @session_id if path.include?(':session_id')
63
+
64
+ begin
65
+ opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
66
+ rescue IndexError
67
+ raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
68
+ end
69
+
70
+ # change path from session/efac972c-941a-499c-803c-d7d008749/execute
71
+ # to /execute
72
+ # path may be nil, session, or not have anything after the session_id.
73
+ path_str = ''
74
+ path_match = path.match /.*\h{8}-\h{4}-\h{4}-\h{4}-\h{12}/
75
+ path_str = path.sub(path_match[0], '') unless path_match.nil?
76
+
77
+ puts "#{verb} #{path_str}"
78
+ puts command_hash.to_json unless command_hash.to_json == 'null'
79
+ # puts "verb: #{verb}, path #{path}, command_hash #{command_hash.to_json}"
80
+ http.call verb, path, command_hash
81
+ end # def
82
+ end # class
83
+ end if defined? Pry # module Selenium::WebDriver::Remote
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+ module Appium
3
+ # Version and Date are defined on the 'Appium' module, not 'Appium::Common'
4
+ VERSION = '0.3.0' unless defined? ::Appium::VERSION
5
+ DATE = '2013-04-25' unless defined? ::Appium::DATE
6
+ end
@@ -0,0 +1,265 @@
1
+ # encoding: utf-8
2
+ =begin
3
+ Based on simple_test.rb
4
+ https://github.com/appium/appium/blob/82995f47408530c80c3376f4e07a1f649d96ba22/sample-code/examples/ruby/simple_test.rb
5
+ https://github.com/appium/appium/blob/c58eeb66f2d6fa3b9a89d188a2e657cca7cb300f/LICENSE
6
+ =end
7
+ module Appium
8
+ add_to_path __FILE__
9
+
10
+ require 'selenium-webdriver'
11
+
12
+ # common
13
+ require 'common/helper'
14
+ require 'common/patch'
15
+ require 'common/version'
16
+ require 'common/element/button'
17
+ require 'common/element/text'
18
+ require 'common/element/window'
19
+
20
+ # ios
21
+ require 'ios/helper'
22
+ require 'ios/patch'
23
+ require 'ios/element/alert'
24
+ require 'ios/element/generic'
25
+ require 'ios/element/textfield'
26
+
27
+ # android
28
+ require 'android/helper'
29
+ require 'android/patch'
30
+ require 'android/element/alert'
31
+ require 'android/element/generic'
32
+ require 'android/element/textfield'
33
+
34
+ class Driver
35
+ def initialize opts={}
36
+ opts = {} if opts.nil?
37
+ # Path to the .apk, .app or .app.zip.
38
+ # The path can be local or remote for Sauce.
39
+ @app_path = opts.fetch 'APP_PATH', ENV['APP_PATH']
40
+ raise 'APP_PATH must be set.' if @app_path.nil?
41
+
42
+ # The name to use for the test run on Sauce.
43
+ @app_name = opts.fetch 'APP_NAME', ENV['APP_NAME']
44
+
45
+ # Android app package
46
+ @app_package = opts.fetch 'APP_PACKAGE', ENV['APP_PACKAGE']
47
+
48
+ # Android app starting activity.
49
+ @app_activity = opts.fetch 'APP_ACTIVITY', ENV['APP_ACTIVITY']
50
+
51
+ # Android app waiting activity
52
+ @app_wait_activity = opts.fetch 'APP_WAIT_ACTIVITY', ENV['APP_WAIT_ACTIVITY']
53
+
54
+ # Sauce Username
55
+ @sauce_username = opts.fetch'SAUCE_USERNAME', ENV['SAUCE_USERNAME']
56
+
57
+ # Sauce Key
58
+ @sauce_access_key = opts.fetch 'SAUCE_ACCESS_KEY', ENV['SAUCE_ACCESS_KEY']
59
+
60
+ @port = opts.fetch 'PORT', ENV['PORT'] || 4723
61
+
62
+ @os = :ios
63
+ @os = :android if @app_path.end_with?('.apk') || @app_path.end_with?('.apk.zip')
64
+ puts "OS is: #{@os}" if defined?(Pry)
65
+
66
+ # load common methods
67
+ extend Appium::Common
68
+ if @os == :android
69
+ raise 'APP_ACTIVITY must be set.' if @app_activity.nil?
70
+
71
+ # load Android specific methods
72
+ extend Appium::Android
73
+ else
74
+ # load iOS specific methods
75
+ extend Appium::Ios
76
+ end
77
+
78
+ # Save global reference to last created Appium driver for top level methods.
79
+ $last_driver = self
80
+ end # def initialize
81
+
82
+ # WebDriver capabilities. Must be valid for Sauce to work.
83
+ # https://github.com/jlipps/appium/blob/master/app/android.js
84
+ def android_capabilities
85
+ {
86
+ browserName: 'Android',
87
+ platform: 'LINUX',
88
+ version: '4.1',
89
+ device: 'Android',
90
+ name: @app_name || 'Ruby Console Android Appium',
91
+ app: absolute_app_path,
92
+ :'app-package' => @app_package,
93
+ :'app-activity' => @app_activity,
94
+ :'app-wait-activity' => @app_wait_activity
95
+ }
96
+ end
97
+
98
+ # WebDriver capabilities. Must be valid for Sauce to work.
99
+ def ios_capabilities
100
+ {
101
+ browserName: 'iOS 6.0',
102
+ platform: 'Mac 10.8',
103
+ version: '6.0',
104
+ device: 'iPhone Simulator',
105
+ name: @app_name || 'Ruby Console iOS Appium',
106
+ app: absolute_app_path
107
+ }
108
+ end
109
+
110
+ def capabilities
111
+ @os == :ios ? ios_capabilities : android_capabilities
112
+ end
113
+
114
+ # Converts environment variable APP_PATH to an absolute path.
115
+ # @return [String] APP_PATH as an absolute path
116
+ def absolute_app_path
117
+ raise 'APP_PATH environment variable not set!' if @app_path.nil? || @app_path.empty?
118
+ return @app_path if @app_path.match(/^http/) # public URL for Sauce
119
+ if @app_path.match(/^\//) # absolute file path
120
+ raise "App doesn't exist. #{@app_path}" unless File.exist? @app_path
121
+ return @app_path
122
+ end
123
+ file = File.join(File.dirname(__FILE__), @app_path)
124
+ raise "App doesn't exist #{file}" unless File.exist? file
125
+ file
126
+ end
127
+
128
+ # Get the server url for sauce or local based on env vars.
129
+ # @return [String] the server url
130
+ def server_url
131
+ if !@sauce_username.nil? && !@sauce_access_key.nil?
132
+ "http://#{@sauce_username}:#{@sauce_access_key}@ondemand.saucelabs.com:80/wd/hub"
133
+ else
134
+ "http://127.0.0.1:#{@port}/wd/hub"
135
+ end
136
+ end
137
+
138
+ # Restarts the driver
139
+ def restart
140
+ driver_quit
141
+ start_driver
142
+ end
143
+
144
+ # Quits the driver
145
+ # @return [void]
146
+ def driver_quit
147
+ # rescue NoSuchDriverError
148
+ begin; @driver.quit unless @driver.nil?; rescue; end
149
+ end
150
+
151
+ # Creates a new global driver and quits the old one if it exists.
152
+ # @return [Selenium::WebDriver] the new global driver
153
+ def start_driver wait=30
154
+ @client = @client || Selenium::WebDriver::Remote::Http::Default.new
155
+ @client.timeout = 999999
156
+
157
+ @default_wait = wait
158
+
159
+ begin
160
+ @driver = Selenium::WebDriver.for :remote, http_client: @client, desired_capabilities: capabilities, url: server_url
161
+ rescue Errno::ECONNREFUSED
162
+ raise 'ERROR: Unable to connect to Appium. Is the server running?'
163
+ end
164
+
165
+ # Set timeout to a large number so that Appium doesn't quit
166
+ # when no commands are entered after 60 seconds.
167
+ mobile :setCommandTimeout, timeout: 9999
168
+
169
+ # Set implicit wait by default unless we're using Pry.
170
+ @driver.manage.timeouts.implicit_wait = @default_wait unless defined? Pry
171
+
172
+ @driver
173
+ end
174
+
175
+ # Set implicit wait to zero.
176
+ def no_wait
177
+ @driver.manage.timeouts.implicit_wait = 0
178
+ end
179
+
180
+ # Set implicit wait to timeout, defaults to 30.
181
+ # @param timeout [Integer] the timeout in seconds
182
+ # @return [void]
183
+ def set_wait timeout=@default_wait
184
+ @driver.manage.timeouts.implicit_wait = timeout
185
+ end
186
+
187
+ # Returns the default client side wait.
188
+ # This value is independent of what the server is using
189
+ # @return [Integer]
190
+ def get_wait
191
+ @default_wait
192
+ end
193
+
194
+ # Returns existence of element.
195
+ #
196
+ # Example:
197
+ #
198
+ # exists { button('sign in') } ? puts('true') : puts('false')
199
+ #
200
+ # @return [Boolean]
201
+ def exists &search_block
202
+ pre_check = 0
203
+ post_check = @default_wait
204
+
205
+ set_wait pre_check # set wait to zero
206
+
207
+ # the element exists unless an error is raised.
208
+ exists = true
209
+
210
+ begin
211
+ search_block.call # search for element
212
+ rescue
213
+ exists = false # error means it's not there
214
+ end
215
+
216
+ # restore wait
217
+ set_wait post_check
218
+
219
+ exists
220
+ end
221
+
222
+ # The same as @driver.execute_script
223
+ # @return [Object] the object returned by execute_script
224
+ def execute_script script, *args
225
+ @driver.execute_script script, *args
226
+ end
227
+
228
+ # Helper method for mobile gestures
229
+ #
230
+ # https://github.com/appium/appium/wiki/Automating-mobile-gestures
231
+ #
232
+ # @driver.execute_script 'mobile: swipe', endX: 100, endY: 100, duration: 0.01
233
+ #
234
+ # becomes
235
+ #
236
+ # mobile :swipe, endX: 100, endY: 100, duration: 0.01
237
+ def mobile method, *args
238
+ raise 'Method must not be nil' if method.nil?
239
+ raise 'Method must have .to_s' unless method.respond_to? :to_s
240
+ @driver.execute_script "mobile: #{method.to_s}", *args
241
+ end
242
+
243
+ # Calls @driver.find_elements
244
+ def find_elements *args
245
+ @driver.find_elements *args
246
+ end
247
+
248
+ # Calls @driver.find_elements
249
+ def find_element *args
250
+ @driver.find_element *args
251
+ end
252
+
253
+ # Quit the driver and Pry.
254
+ # quit and exit are reserved by Pry.
255
+ def x
256
+ driver_quit
257
+ exit # exit pry
258
+ end
259
+ end # end class Driver
260
+ end # end module Appium
261
+
262
+ # Paging in Pry is annoying :q required to exit.
263
+ # With pager disabled, the output is similar to IRB
264
+ # Only set if Pry is defined.
265
+ Pry.config.pager = false if defined?(Pry)