lib/appium_lib/driver.rb in appium_lib-9.5.0 vs lib/appium_lib/driver.rb in appium_lib-9.6.0

- old
+ new

@@ -22,12 +22,22 @@ require_relative 'ios/element/button' require_relative 'ios/element/generic' require_relative 'ios/element/textfield' require_relative 'ios/element/text' require_relative 'ios/mobile_methods' -require_relative 'ios/xcuitest_gestures' +# ios - xcuitest +require_relative 'ios/xcuitest/element' +require_relative 'ios/xcuitest/gestures' +require_relative 'ios/xcuitest/mobile_methods' +require_relative 'ios/xcuitest/device' +require_relative 'ios/xcuitest/helper' +require_relative 'ios/xcuitest/element/text' +require_relative 'ios/xcuitest/element/textfield' +require_relative 'ios/xcuitest/element/generic' +require_relative 'ios/xcuitest/element/button' + # android require_relative 'android/helper' require_relative 'android/patch' require_relative 'android/client_xpath' require_relative 'android/element/alert' @@ -35,10 +45,15 @@ require_relative 'android/element/generic' require_relative 'android/element/textfield' require_relative 'android/element/text' require_relative 'android/mobile_methods' +require_relative 'android/device' + +# android - uiautomator2 +require_relative 'android/uiautomator2/helper.rb' + # device methods require_relative 'device/device' require_relative 'device/touch_actions' require_relative 'device/multi_touch' @@ -166,12 +181,12 @@ # only for the shared module use case. # # if modules is a module instead of an array, then the constants of # that module are promoted on. # otherwise, the array of modules will be used as the promotion target. - def self.promote_singleton_appium_methods(modules) - raise 'Driver is nil' if $driver.nil? + def self.promote_singleton_appium_methods(modules, driver = $driver) + raise 'Global $driver is nil' if driver.nil? target_modules = [] if modules.is_a? Module modules.constants.each do |sub_module| @@ -183,19 +198,19 @@ end target_modules.each do |const| # noinspection RubyResolve # rubocop:disable Style/MultilineIfModifier - $driver.public_methods(false).each do |m| + driver.public_methods(false).each do |m| const.send(:define_singleton_method, m) do |*args, &block| begin super(*args, &block) # promote.rb rescue NoMethodError, ArgumentError - $driver.send m, *args, &block if $driver.respond_to?(m) + driver.send m, *args, &block if driver.respond_to?(m) end # override unless there's an existing method with matching arity - end unless const.respond_to?(m) && const.method(m).arity == $driver.method(m).arity + end unless const.respond_to?(m) && const.method(m).arity == driver.method(m).arity end # rubocop:enable Style/MultilineIfModifier end end @@ -219,17 +234,17 @@ # # ```ruby # # promote on minispec # Appium.promote_appium_methods Minitest::Spec # ``` - def self.promote_appium_methods(class_array) - raise 'Driver is nil' if $driver.nil? + def self.promote_appium_methods(class_array, driver = $driver) + raise 'Driver is nil' if driver.nil? # Wrap single class into an array class_array = [class_array] unless class_array.class == Array # Promote Appium driver methods to class instance methods. class_array.each do |klass| - $driver.public_methods(false).each do |m| + driver.public_methods(false).each do |m| klass.class_eval do define_method m do |*args, &block| begin # Prefer existing method. # super will invoke method missing on driver @@ -237,11 +252,11 @@ # minitest also defines a name method, # so rescue argument error # and call the name method on $driver rescue NoMethodError, ArgumentError - $driver.send m, *args, &block if $driver.respond_to?(m) + driver.send m, *args, &block if driver.respond_to?(m) end end end end end @@ -318,21 +333,22 @@ # Wait interval time for ::Appium::Common.wait or ::Appium::Common.wait_true. # Provide Appium::Drive like { appium_lib: { wait_interval: 20 } } # @return [Integer] attr_reader :appium_wait_interval - # Creates a new driver + # Creates a new driver. The driver is defined as global scope by default. + # We can avoid defining global driver. # # @example # # ```ruby # require 'rubygems' # require 'appium_lib' # # # platformName takes a string or a symbol. # - # # Start iOS driver + # # Start iOS driver with global scope # opts = { # caps: { # platformName: :ios, # app: '/path/to/MyiOS.app' # }, @@ -340,11 +356,11 @@ # wait_timeout: 30 # } # } # Appium::Driver.new(opts).start_driver # - # # Start Android driver + # # Start Android driver with global scope # opts = { # caps: { # platformName: :android, # app: '/path/to/my.apk' # }, @@ -352,17 +368,34 @@ # wait_timeout: 30, # wait_interval: 1 # } # } # Appium::Driver.new(opts).start_driver + # + # # Start iOS driver without global scope + # opts = { + # caps: { + # platformName: :ios, + # app: '/path/to/MyiOS.app' + # }, + # appium_lib: { + # wait_timeout: 30 + # } + # } + # Appium::Driver.new(opts, false).start_driver # ``` # # @param opts [Object] A hash containing various options. + # @param global_driver [Bool] A bool require global driver before initialize. # @return [Driver] - def initialize(opts = {}) - # quit last driver - $driver.driver_quit if $driver + def initialize(opts = {}, global_driver = true) + if global_driver + warn '[DEPRECATION] Appium::Driver.new(opts) will not generate global driver by default.' \ + 'If you would like to generate the global driver dy default, ' \ + 'please initialise driver with Appium::Driver.new(opts, true)' + $driver.driver_quit if $driver + end raise 'opts must be a hash' unless opts.is_a? Hash opts = Appium.symbolize_keys opts @caps = Capabilities.init_caps_for_appium(opts[:caps] || {}) @@ -389,15 +422,23 @@ extend Appium::Common extend Appium::Device if device_is_android? extend Appium::Android + extend Appium::Android::Device + if automation_name_is_uiautomator2? + extend Appium::Android::Uiautomator2::Helper + end else extend Appium::Ios - if automation_name_is_xcuitest? # Override touch actions + if automation_name_is_xcuitest? + # Override touch actions and patch_webdriver_element extend Appium::Ios::Xcuitest + extend Appium::Ios::Xcuitest::Helper extend Appium::Ios::Xcuitest::Gesture + extend Appium::Ios::Xcuitest::Device + extend Appium::Ios::Xcuitest::Element end end # apply os specific patches patch_webdriver_element @@ -415,11 +456,11 @@ Appium::Logger.debug "Device is: #{@appium_device}" patch_webdriver_bridge end # Save global reference to last created Appium driver for top level methods. - $driver = self + $driver = self if global_driver self # return newly created driver end private @@ -483,10 +524,16 @@ # @return [Boolean] def automation_name_is_uiautomator2? !@automation_name.nil? && @automation_name == :uiautomator2 end + # Return true if automationName is 'Espresso' + # @return [Boolean] + def automation_name_is_espresso? + !@automation_name.nil? && @automation_name == :espresso + 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] def check_server_version_xcuitest if automation_name_is_xcuitest? && @@ -615,10 +662,13 @@ @driver.quit rescue nil end + # Alias for driver_quit + alias_method :quit_driver, :driver_quit + # Creates a new global driver and quits the old one if it exists. # You can customise http_client as the following # # @example # ```ruby @@ -675,12 +725,22 @@ @appium_server_status = appium_server_version check_server_version_xcuitest set_automation_name_if_nil - @driver.manage.timeouts.implicit_wait = @default_wait + set_implicit_wait(@default_wait) @driver + end + + # To ignore error for Espresso Driver + 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::Error::ServerError + end + {} end # Set implicit wait to zero. def no_wait @driver.manage.timeouts.implicit_wait = 0