lib/appium_lib/driver.rb in appium_lib-9.4.9 vs lib/appium_lib/driver.rb in appium_lib-9.4.10
- old
+ new
@@ -246,10 +246,15 @@
end
end
nil # return nil
end
+ def self.selenium_webdriver_version_more?(version)
+ require 'rubygems'
+ Gem.loaded_specs['selenium-webdriver'].version >= Gem::Version.new(version)
+ end
+
class Driver
module Capabilities
# except for browser_name, default capability is equal to ::Selenium::WebDriver::Remote::Capabilities.firefox
# Because Selenium::WebDriver::Remote::Bridge uses Capabilities.firefox by default
# https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/rb/lib/selenium/webdriver/remote/bridge.rb#L67
@@ -364,35 +369,16 @@
# quit last driver
$driver.driver_quit if $driver
raise 'opts must be a hash' unless opts.is_a? Hash
opts = Appium.symbolize_keys opts
-
@caps = Capabilities.init_caps_for_appium(opts[:caps] || {})
appium_lib_opts = opts[:appium_lib] || {}
- # appium_lib specific values
- @custom_url = appium_lib_opts.fetch :server_url, false
- @export_session = appium_lib_opts.fetch :export_session, false
- @default_wait = appium_lib_opts.fetch :wait, 0
- @sauce_username = appium_lib_opts.fetch :sauce_username, ENV['SAUCE_USERNAME']
- @sauce_username = nil if !@sauce_username || (@sauce_username.is_a?(String) && @sauce_username.empty?)
- @sauce_access_key = appium_lib_opts.fetch :sauce_access_key, ENV['SAUCE_ACCESS_KEY']
- @sauce_access_key = nil if !@sauce_access_key || (@sauce_access_key.is_a?(String) && @sauce_access_key.empty?)
- @sauce_endpoint = appium_lib_opts.fetch :sauce_endpoint, ENV['SAUCE_ENDPOINT']
- @sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub' if
- !@sauce_endpoint || (@sauce_endpoint.is_a?(String) && @sauce_endpoint.empty?)
- @appium_port = appium_lib_opts.fetch :port, 4723
- # timeout and interval used in ::Appium::Comm.wait/wait_true
- @appium_wait_timeout = appium_lib_opts.fetch :wait_timeout, 30
- @appium_wait_interval = appium_lib_opts.fetch :wait_interval, 0.5
+ set_appium_lib_specific_values(appium_lib_opts)
- # to pass it in Selenium.new.
- # `listener = opts.delete(:listener)` is called in Selenium::Driver.new
- @listener = appium_lib_opts.fetch :listener, nil
-
# Path to the .apk, .app or .app.zip.
# The path can be local or remote for Sauce.
if @caps && @caps[:app] && !@caps[:app].empty?
@caps[:app] = self.class.absolute_app_path opts
end
@@ -400,20 +386,26 @@
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
@appium_device = @caps[:platformName]
@appium_device = @appium_device.is_a?(Symbol) ? @appium_device : @appium_device.downcase.strip.intern if @appium_device
@automation_name = @caps[:automationName] if @caps[:automationName]
+ @automation_name = if @automation_name
+ @automation_name.is_a?(Symbol) ? @automation_name : @automation_name.downcase.strip.intern
+ end
# load common methods
extend Appium::Common
extend Appium::Device
if device_is_android?
extend Appium::Android
else
extend Appium::Ios
- extend Appium::Ios::XcuitestGesture if automation_name_is_xcuitest? # Override touch actions
+ if automation_name_is_xcuitest? # Override touch actions
+ extend Appium::Ios::Xcuitest
+ extend Appium::Ios::Xcuitest::Gesture
+ end
end
# apply os specific patches
patch_webdriver_element
@@ -435,13 +427,40 @@
$driver = self
self # return newly created driver
end
+ private
+
+ def set_appium_lib_specific_values(appium_lib_opts)
+ @custom_url = appium_lib_opts.fetch :server_url, false
+ @export_session = appium_lib_opts.fetch :export_session, false
+ @default_wait = appium_lib_opts.fetch :wait, 0
+
+ @sauce_username = appium_lib_opts.fetch :sauce_username, ENV['SAUCE_USERNAME']
+ @sauce_username = nil if !@sauce_username || (@sauce_username.is_a?(String) && @sauce_username.empty?)
+ @sauce_access_key = appium_lib_opts.fetch :sauce_access_key, ENV['SAUCE_ACCESS_KEY']
+ @sauce_access_key = nil if !@sauce_access_key || (@sauce_access_key.is_a?(String) && @sauce_access_key.empty?)
+ @sauce_endpoint = appium_lib_opts.fetch :sauce_endpoint, ENV['SAUCE_ENDPOINT']
+ @sauce_endpoint = 'ondemand.saucelabs.com:443/wd/hub' if
+ !@sauce_endpoint || (@sauce_endpoint.is_a?(String) && @sauce_endpoint.empty?)
+
+ @appium_port = appium_lib_opts.fetch :port, 4723
+ # timeout and interval used in ::Appium::Comm.wait/wait_true
+ @appium_wait_timeout = appium_lib_opts.fetch :wait_timeout, 30
+ @appium_wait_interval = appium_lib_opts.fetch :wait_interval, 0.5
+
+ # to pass it in Selenium.new.
+ # `listener = opts.delete(:listener)` is called in Selenium::Driver.new
+ @listener = appium_lib_opts.fetch :listener, nil
+ end
+
+ public
+
# Returns a hash of the driver attributes
def driver_attributes
- attributes = {
+ {
caps: @caps,
automation_name: @automation_name,
custom_url: @custom_url,
export_session: @export_session,
default_wait: @default_wait,
@@ -453,32 +472,26 @@
debug: @appium_debug,
listener: @listener,
wait_timeout: @appium_wait_timeout,
wait_interval: @appium_wait_interval
}
-
- # Return duplicates so attributes are immutable
- attributes.each do |key, value|
- attributes[key] = value.duplicable? ? value.dup : value
- end
- attributes
end
def device_is_android?
@appium_device == :android
end
# Return true if automationName is 'XCUITest'
# @return [Boolean]
def automation_name_is_xcuitest?
- !@automation_name.nil? && 'xcuitest'.casecmp(@automation_name).zero?
+ !@automation_name.nil? && @automation_name == :xcuitest
end
# Return true if automationName is 'uiautomator2'
# @return [Boolean]
def automation_name_is_uiautomator2?
- !@automation_name.nil? && 'uiautomator2'.casecmp(@automation_name).zero?
+ !@automation_name.nil? && @automation_name == :uiautomator2
end
# Return true if the target Appium server is over REQUIRED_VERSION_XCUITEST.
# If the Appium server is under REQUIRED_VERSION_XCUITEST, then error is raised.
# @return [Boolean]
@@ -510,15 +523,15 @@
#
# @return [Hash]
def appium_server_version
driver.remote_status
rescue Selenium::WebDriver::Error::WebDriverError => ex
- raise unless ex.message.include?('content-type=""')
+ raise ::Appium::Error::ServerError unless ex.message.include?('content-type=""')
# server (TestObject for instance) does not respond to status call
{}
rescue Selenium::WebDriver::Error::ServerError => e
- raise unless e.message.include?('status code 500')
+ raise ::Appium::Error::ServerError unless e.message.include?('status code 500')
# driver.remote_status returns 500 error for using selenium grid
{}
end
# Returns the client's version info
@@ -610,15 +623,37 @@
rescue
nil
end
# Creates a new global driver and quits the old one if it exists.
+ # You can customise http_client as the following
#
+ # @example
+ # ```ruby
+ # 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
+ # }
+ # }
+ # custom_http_client = Custom::Http::Client.new(opts)
+ # Appium::Driver.new(opts).start_driver(custom_http_client)
+ #
# @return [Selenium::WebDriver] the new global driver
- def start_driver
+ def start_driver(http_client =
+ Selenium::WebDriver::Remote::Http::Default.new(open_timeout: 999_999, read_timeout: 999_999))
# open_timeout and read_timeout are explicit wait.
- @http_client ||= Selenium::WebDriver::Remote::Http::Default.new(open_timeout: 999_999, read_timeout: 999_999)
+ @http_client ||= http_client
begin
driver_quit
@driver = Selenium::WebDriver.for(:remote,
http_client: @http_client,
@@ -629,16 +664,11 @@
# Load touch methods.
@driver.extend Selenium::WebDriver::DriverExtensions::HasTouchScreen
@driver.extend Selenium::WebDriver::DriverExtensions::HasLocation
# export session
- if @export_session
- # rubocop:disable Style/RescueModifier
- File.open('/tmp/appium_lib_session', 'w') do |f|
- f.puts @driver.session_id
- end rescue nil
- end
+ write_session_id(@driver.session_id) if @export_session
rescue Errno::ECONNREFUSED
raise "ERROR: Unable to connect to Appium. Is the server running on #{server_url}?"
end
@appium_server_status = appium_server_version
@@ -771,9 +801,16 @@
driver_quit
exit # exit pry
end
private
+
+ def write_session_id(session_id)
+ File.open('/tmp/appium_lib_session', 'w') { |f| f.puts session_id }
+ rescue IOError => e
+ ::Appium::Logger.warn e
+ nil
+ end
# If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
# Since @automation_name is set only client side before start_driver is called.
def set_automation_name_if_nil
return unless @automation_name.nil?