class Appium::Driver
Attributes
Boolean debug mode for the Appium
Ruby bindings
Appium's server version
Instance of Appium::Core::Driver
Returns the driver @return [Driver] the driver
The amount to sleep in seconds before every webdriver http call.
SauceLab's settings
Access Key for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_ACCESS_KEY is in ENV. same as @sauce.access_key
Override the Sauce Appium
endpoint to allow e.g. TestObject tests same as @sauce.endpoint
Username for use on Sauce Labs. Set `false` to disable Sauce, even when SAUCE_USERNAME is in ENV. same as @sauce.username
Public Class Methods
Converts app_path to an absolute path.
opts is the full options hash (caps and appium_lib). If server_url
is set then the app path is used as is.
if app isn't set then an error is raised.
@return [String] APP_PATH as an absolute path
# File lib/appium_lib/driver.rb, line 382 def self.absolute_app_path(opts) raise 'opts must be a hash' unless opts.is_a? Hash caps = opts[:caps] || {} app_path = caps[:app] raise 'absolute_app_path invoked and app is not set!' if app_path.nil? || app_path.empty? # Sauce storage API. http://saucelabs.com/docs/rest#storage return app_path if app_path.start_with? 'sauce-storage:' return app_path if app_path =~ URI::DEFAULT_PARSER.make_regexp # public URL for Sauce absolute_app_path = File.expand_path app_path if File.exist? absolute_app_path absolute_app_path else ::Appium::Logger.info("Use #{app_path}") app_path end end
Creates a new driver. The driver is defined as global scope by default. We can avoid defining global driver.
@example
require 'rubygems' require 'appium_lib' # platformName takes a string or a symbol. # Start iOS driver with global scope opts = { caps: { platformName: :ios, app: '/path/to/MyiOS.app' }, appium_lib: { wait_timeout: 30 } } appium_driver = Appium::Driver.new(opts, true) appium_driver.start_driver # Start Android driver with global scope opts = { caps: { platformName: :android, app: '/path/to/my.apk' }, appium_lib: { wait_timeout: 30, wait_interval: 1 } } appium_driver = Appium::Driver.new(opts, true) appium_driver.start_driver # Start iOS driver without global scope opts = { caps: { platformName: :ios, app: '/path/to/MyiOS.app' }, appium_lib: { wait_timeout: 30 } } appium_driver = Appium::Driver.new(opts, false) appium_driver.start_driver # Start iOS driver without global scope opts = { caps: { platformName: :ios, app: '/path/to/MyiOS.app' }, appium_lib: { wait_timeout: 30 }, global_driver: false } appium_driver = Appium::Driver.new(opts) appium_driver.start_driver
@param opts [Object] A hash containing various options. @param global_driver [Bool] A bool require global driver before initialize. @return [Driver]
# File lib/appium_lib/driver.rb, line 154 def initialize(opts = {}, global_driver = false) # Capybara can't put `global_driver` as the 2nd argument. global_driver = opts.delete :global_driver if global_driver.nil? $driver&.driver_quit if global_driver raise 'opts must be a hash' unless opts.is_a? Hash @core = ::Appium::Core.for(opts) extend ::Appium::Core::Device opts = Appium.symbolize_keys opts appium_lib_opts = opts[:appium_lib] || {} @caps = @core.caps @custom_url = @core.custom_url @export_session = @core.export_session @export_session_path = @core.export_session_path @default_wait = @core.default_wait @appium_port = @core.port @appium_wait_timeout = @core.wait_timeout @appium_wait_interval = @core.wait_interval @listener = @core.listener @appium_device = @core.device @automation_name = @core.automation_name # Arrange the app capability. This must be after @core = ::Appium::Core.for(opts) set_app_path(opts) # enable debug patch @appium_debug = appium_lib_opts.fetch :debug, !!defined?(Pry) # rubocop:disable Style/DoubleNegation set_sauce_related_values(appium_lib_opts) # Extend Common methods extend Appium::Common extend Appium::Device # Extend each driver's methods extend_for(device: @core.device, automation_name: @core.automation_name) # for command if @appium_debug Appium::Logger.debug opts unless opts.empty? Appium::Logger.debug "Debug is: #{@appium_debug}" Appium::Logger.debug "Device is: #{@core.device}" end # Save global reference to last created Appium driver for top level methods. $driver = self if global_driver self # rubocop:disable Lint/Void # return newly created driver end
Public Instance Methods
An entry point to chain W3C actions Read www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Base/Bridge/W3C#action-instance_method
@return [TouchAction|Selenium::WebDriver::PointerActions]
@example
element = find_element(:id, "some id") action.click(element).perform # The `click` is a part of `PointerActions`
# File lib/appium_lib/driver.rb, line 330 def action @driver.action end
Returns the client's version info
@example
{ "version" => "9.1.1" }
@return [Hash]
# File lib/appium_lib/driver.rb, line 370 def appium_client_version { version: ::Appium::VERSION } end
Returns the server's version info
@example
{ "build" => { "version" => "0.18.1", "revision" => "d242ebcfd92046a974347ccc3a28f0e898595198" } }
@return [Hash]
# File lib/appium_lib/driver.rb, line 345 def appium_server_version @core.appium_server_version rescue Selenium::WebDriver::Error::WebDriverError => ex raise ::Appium::Core::Error::ServerError unless ex.message.include?('content-type=""') # server (TestObject for instance) does not respond to status call {} end
Return true if automationName is 'Espresso' @return [Boolean]
# File lib/appium_lib/driver.rb, line 310 def automation_name_is_espresso? !@core.automation_name.nil? && @core.automation_name == :espresso end
Return true if automationName is 'uiautomator2' @return [Boolean]
# File lib/appium_lib/driver.rb, line 304 def automation_name_is_uiautomator2? !@core.automation_name.nil? && @core.automation_name == :uiautomator2 end
Return true if automationName is 'XCUITest' @return [Boolean]
# File lib/appium_lib/driver.rb, line 316 def automation_name_is_xcuitest? !@core.automation_name.nil? && @core.automation_name == :xcuitest end
# File lib/appium_lib/driver.rb, line 660 def current_url @driver.current_url end
# File lib/appium_lib/driver.rb, line 290 def device_is_android? @core.device == :android end
# File lib/appium_lib/driver.rb, line 294 def device_is_ios? @core.device == :ios end
# File lib/appium_lib/driver.rb, line 298 def device_is_windows? @core.device == :windows end
Returns a hash of the driver attributes
# File lib/appium_lib/driver.rb, line 270 def driver_attributes { caps: @core.caps, automation_name: @core.automation_name, custom_url: @core.custom_url, export_session: @core.export_session, export_session_path: @core.export_session_path, default_wait: @core.default_wait, sauce_username: @sauce.username, sauce_access_key: @sauce.access_key, sauce_endpoint: @sauce.endpoint, port: @core.port, device: @core.device, debug: @appium_debug, listener: @listener, wait_timeout: @core.wait_timeout, wait_interval: @core.wait_interval } end
Quits the driver @return [void]
# File lib/appium_lib/driver.rb, line 446 def driver_quit @core.quit_driver end
Takes a png screenshot of particular element's area
@example
el = find_element :accessibility_id, zzz element_screenshot el, '/tmp/hi.png'
@param [String] element Element take a screenshot @param [String] png_save_path the full path to save the png @return [File]
# File lib/appium_lib/driver.rb, line 439 def element_screenshot(element, png_save_path) @driver.take_element_screenshot element, png_save_path nil end
Wrap calling selenium webdrier APIs via ruby_core
Get the window handles of open browser windows
# File lib/appium_lib/driver.rb, line 603 def execute_async_script(script, *args) @driver.execute_async_script script, *args end
Run a set of script against the current session, allowing execution of many commands in one Appium
request. Supports {webdriver.io/docs/api.html WebdriverIO} API so far. Please read {appium.io/docs/en/commands/session/execute-driver command API} for more details about acceptable scripts and the output.
@param [String] script The string consisting of the script itself @param [String] type The name of the script type.
Defaults to 'webdriverio'. Depends on server implementation which type is supported.
@param [Integer] timeout_ms The number of `ms` Appium
should wait for the script to finish
before killing it due to timeout.
@return [Appium::Core::Base::Device::ExecuteDriver::Result] The script result parsed by
Appium::Core::Base::Device::ExecuteDriver::Result.
@raise [::Selenium::WebDriver::Error::UnknownError] If something error happens in the script.
It has the original message.
@example
script = <<~SCRIPT const status = await driver.status(); console.warn('warning message'); return [status]; SCRIPT r = @@driver.execute_driver(script: script, type: 'webdriverio', timeout: 10_000) r #=> An instance of Appium::Core::Base::Device::ExecuteDriver::Result r.result #=> The `result` key part as the result of the script r.logs #=> The `logs` key part as `{'log' => [], 'warn' => [], 'error' => []}`
# File lib/appium_lib/driver.rb, line 635 def execute_driver(script: '', type: 'webdriverio', timeout_ms: nil) @driver.execute_driver(script: script, type: type, timeout_ms: timeout_ms) end
The same as @driver.execute_script @param [String] script The script to execute @param [*args] args The args to pass to the script @return [Object]
# File lib/appium_lib/driver.rb, line 595 def execute_script(script, *args) @driver.execute_script script, *args end
Returns existence of element.
Example:
exists { button('sign in') } ? puts('true') : puts('false')
@param [Integer] pre_check The amount in seconds to set the
wait to before checking existence
@param [Integer] post_check The amount in seconds to set the
wait to after checking existence
@yield The block to call @return [Boolean]
# File lib/appium_lib/driver.rb, line 571 def exists(pre_check = 0, post_check = @core.default_wait) # do not uset set_wait here. # it will cause problems with other methods reading the default_wait of 0 # which then gets converted to a 1 second wait. @driver.manage.timeouts.implicit_wait = pre_check # the element exists unless an error is raised. exists = true begin yield # search for element rescue StandardError exists = false # error means it's not there end # restore wait @driver.manage.timeouts.implicit_wait = post_check if post_check != pre_check exists end
Calls @driver.find_element
@example
@driver = Appium::Driver.new(opts, false) @driver.start_driver @driver.find_element :accessibility_id, zzz
If you call `Appium.promote_appium_methods`, you can call `find_element` directly.
@param [*args] args The args to use @return [Element]
# File lib/appium_lib/driver.rb, line 713 def find_element(*args) @driver.find_element(*args) end
Return ImageElement if current view has a partial image
@param [String] png_img_path A path to a partial image you'd like to find
@return [::Appium::Core::ImageElement] @raise [::Appium::Core::Error::NoSuchElementError|::Appium::Core::Error::CoreError] No such element
@example
@driver.find_element_by_image './test/functional/data/test_element_image.png'
# File lib/appium_lib/driver.rb, line 728 def find_element_by_image(png_img_path) @driver.find_element_by_image(png_img_path) end
Calls @driver.find_elements_with_appium
@example
@driver = Appium::Driver.new(opts, false) @driver.start_driver @driver.find_elements :predicate, yyy
If you call `Appium.promote_appium_methods`, you can call `find_elements` directly.
@example
@driver = Appium::Driver.new(opts, false) @driver.start_driver @driver.find_elements :predicate, yyy
If you call `Appium.promote_appium_methods`, you can call `find_elements` directly.
@param [*args] args The args to use @return [Array<Element>] Array is empty when no elements are found.
# File lib/appium_lib/driver.rb, line 697 def find_elements(*args) @driver.find_elements(*args) end
Return ImageElement if current view has partial images
@param [[String]] png_img_paths Paths to a partial image you'd like to find
@return [[::Appium::Core::ImageElement]] @return [::Appium::Core::Error::CoreError]
@example
@driver.find_elements_by_image ['./test/functional/data/test_element_image.png']
# File lib/appium_lib/driver.rb, line 743 def find_elements_by_image(png_img_paths) @driver.find_elements_by_image(png_img_paths) end
# File lib/appium_lib/driver.rb, line 656 def get(url) @driver.get(url) end
@since Appium
1.16.0
Logs a custom event. The event is available via {::Appium::Core::Events#get} or driver.session_capabilities['events']
with eventTimings
capabilities.
@param [String] vendor The vendor prefix for the event @param [String] event The name of event @return [nil]
@example
log_event vendor: 'appium', event: 'funEvent' log_event = { vendor: 'appium', event: 'anotherEvent' } log_events #=> {...., 'appium:funEvent' => [1572957315, 1572960305], # 'appium:anotherEvent' => 1572959315}
# File lib/appium_lib/driver.rb, line 780 def log_event(vendor:, event:) @driver.logs.event vendor: vendor, event: event end
# File lib/appium_lib/driver.rb, line 784 def log_event=(log_event) unless log_event.is_a?(Hash) raise ::Appium::Core::Error::ArgumentError('log_event should be Hash like { vendor: "appium", event: "funEvent"}') end @driver.logs.event vendor: log_event[:vendor], event: log_event[:event] end
@since Appium
1.16.0 Returns events with filtering with 'type'. Defaults to all available events.
@param [String] type The type of events to get @return [Hash]
@example
log_events #=> {} log_events #=> {'commands' => [{'cmd' => 123455, ....}], 'startTime' => 1572954894127, }
# File lib/appium_lib/driver.rb, line 803 def log_events(type = nil) @driver.logs.events(type) end
# File lib/appium_lib/driver.rb, line 652 def manage @driver.manage end
Set implicit wait to zero.
# File lib/appium_lib/driver.rb, line 540 def no_wait @driver.manage.timeouts.implicit_wait = 0 end
Return the platform version as an array of integers @return [Array<Integer>]
# File lib/appium_lib/driver.rb, line 357 def platform_version @core.platform_version end
Restarts the driver @return [Driver] the driver
# File lib/appium_lib/driver.rb, line 412 def restart driver_quit start_driver end
Takes a png screenshot and saves to the target path.
@example
screenshot '/tmp/hi.png'
@param png_save_path [String] the full path to save the png @return [File]
# File lib/appium_lib/driver.rb, line 425 def screenshot(png_save_path) @driver.save_screenshot png_save_path end
Get the server url @return [String] the server url
# File lib/appium_lib/driver.rb, line 403 def server_url return @core.custom_url if @core.custom_url return @sauce.server_url if @sauce.sauce_server_url? "http://127.0.0.1:#{@core.port}/wd/hub" end
To ignore error for Espresso Driver
# File lib/appium_lib/driver.rb, line 529 def set_implicit_wait(wait) @driver.manage.timeouts.implicit_wait = wait rescue Selenium::WebDriver::Error::UnknownError => e unless e.message.include?('The operation requested is not yet implemented by Espresso driver') raise ::Appium::Core::Error::ServerError end {} end
Calls @driver.set_location
@note This method does not work on real devices.
@param [Hash] opts consisting of: @option opts [Float] :latitude the latitude in degrees (required) @option opts [Float] :longitude the longitude in degees (required) @option opts [Float] :altitude the altitude, defaulting to 75 @return [Selenium::WebDriver::Location] the location constructed by the selenium webdriver
# File lib/appium_lib/driver.rb, line 756 def set_location(opts = {}) latitude = opts.fetch(:latitude) longitude = opts.fetch(:longitude) altitude = opts.fetch(:altitude, 75) @driver.set_location(latitude, longitude, altitude) end
Set implicit wait. Default to @core.default_wait.
@example
set_wait 2 set_wait # @core.default_wait
@param timeout [Integer] the timeout in seconds @return [void]
# File lib/appium_lib/driver.rb, line 554 def set_wait(timeout = nil) timeout = @core.default_wait if timeout.nil? @driver.manage.timeouts.implicit_wait = timeout end
Creates a new global driver and quits the old one if it exists. You can customise http_client
as the following
Read www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Device to understand more what the driver can call instance methods.
@example
require 'rubygems' require 'appium_lib' # platformName takes a string or a symbol. # Start iOS driver opts = { caps: { platformName: :ios, app: '/path/to/MyiOS.app' }, appium_lib: { wait_timeout: 30 } } appium_driver = Appium::Driver.new(opts) #=> return an Appium::Driver instance appium_driver.start_driver #=> return an Appium::Core::Base::Driver
@option http_client_ops [Hash] :http_client Custom HTTP Client @option http_client_ops [Hash] :open_timeout Custom open timeout for http client. @option http_client_ops [Hash] :read_timeout Custom read timeout for http client. @return [Selenium::WebDriver] the new global driver
# File lib/appium_lib/driver.rb, line 508 def start_driver(http_client_ops = { http_client: ::Appium::Http::Default.new, open_timeout: 999_999, read_timeout: 999_999 }) @core.quit_driver # If automationName is set only in server side, then the following automation_name should be nil before # starting driver. automation_name = @core.automation_name @driver = @core.start_driver(server_url: server_url, http_client_ops: http_client_ops) @http_client = @core.http_client # if automation_name was nil before start_driver, then re-extend driver specific methods # to be able to extend correctly. extend_for(device: @core.device, automation_name: @core.automation_name) if automation_name.nil? @appium_server_status = appium_server_version @driver end
@return [TargetLocator] @see TargetLocator
# File lib/appium_lib/driver.rb, line 670 def switch_to @driver.switch_to end
# File lib/appium_lib/driver.rb, line 664 def title @driver.title end
Get the current window handle
# File lib/appium_lib/driver.rb, line 644 def window_handle @driver.window_handle end
# File lib/appium_lib/driver.rb, line 639 def window_handles @driver.window_handles end
Get the device window's rect. @return [Selenium::WebDriver::Rectangle]
@example
size = @driver.window_size size.width #=> Integer size.height #=> Integer size.x #=> Integer size.y #=> Integer
# File lib/appium_lib/driver.rb, line 475 def window_rect @driver.window_rect end
Get the device window's size. @return [Selenium::WebDriver::Dimension]
@example
size = @driver.window_size size.width #=> Integer size.height #=> Integer
# File lib/appium_lib/driver.rb, line 460 def window_size @driver.window_size end
Quit the driver and Pry. quit and exit are reserved by Pry. @return [void]
# File lib/appium_lib/driver.rb, line 810 def x driver_quit exit # exit pry end
Private Instance Methods
@private
# File lib/appium_lib/driver.rb, line 211 def extend_for(device:, automation_name:) case device when :android case automation_name when :uiautomator2 ::Appium::Android::Uiautomator2::Bridge.for(self) when :espresso ::Appium::Android::Espresso::Bridge.for(self) else # default and UiAutomator ::Appium::Android::Bridge.for(self) end when :ios, :tvos case automation_name when :xcuitest ::Appium::Ios::Xcuitest::Bridge.for(self) else # default and UIAutomation ::Appium::Ios::Bridge.for(self) end when :mac # no Mac specific extentions Appium::Logger.debug('mac') when :windows # no windows specific extentions Appium::Logger.debug('windows') when :tizen # https://github.com/Samsung/appium-tizen-driver Appium::Logger.debug('tizen') when :youiengine # https://github.com/YOU-i-Labs/appium-youiengine-driver Appium::Logger.debug('YouiEngine') else case automation_name when :youiengine # https://github.com/YOU-i-Labs/appium-youiengine-driver Appium::Logger.debug('YouiEngine') else Appium::Logger.debug('no device matched') # core also shows warning message end end end
@private
# File lib/appium_lib/driver.rb, line 253 def set_app_path(opts) return unless @core.caps && @core.caps[:app] && !@core.caps[:app].empty? @core.caps[:app] = self.class.absolute_app_path opts end