appium_lib_core 4.1.0 → 6.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +207 -272
- data/README.md +41 -14
- data/Rakefile +4 -0
- data/appium_lib_core.gemspec +5 -8
- data/bin/console +0 -4
- data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
- data/lib/appium_lib_core/android/device.rb +4 -4
- data/lib/appium_lib_core/common/base/bridge.rb +311 -90
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
- data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
- data/lib/appium_lib_core/common/base/driver.rb +222 -187
- data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
- data/lib/appium_lib_core/common/base/has_location.rb +80 -0
- data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
- data/lib/appium_lib_core/common/base/http_default.rb +1 -3
- data/lib/appium_lib_core/{ios/uiautomation/bridge.rb → common/base/remote_status.rb} +9 -8
- data/lib/appium_lib_core/common/base/rotable.rb +54 -0
- data/lib/appium_lib_core/common/base/screenshot.rb +6 -6
- data/lib/appium_lib_core/common/base/search_context.rb +20 -6
- data/lib/appium_lib_core/common/base.rb +1 -3
- data/lib/appium_lib_core/common/command.rb +259 -4
- data/lib/appium_lib_core/common/device/app_management.rb +8 -14
- data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
- data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
- data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
- data/lib/appium_lib_core/common/device/touch_actions.rb +2 -0
- data/lib/appium_lib_core/common/device/value.rb +6 -8
- data/lib/appium_lib_core/common/error.rb +4 -5
- data/lib/appium_lib_core/common/log.rb +4 -1
- data/lib/appium_lib_core/common/touch_action/multi_touch.rb +19 -0
- data/lib/appium_lib_core/common/touch_action/touch_actions.rb +16 -2
- data/lib/appium_lib_core/common/wait.rb +38 -6
- data/lib/appium_lib_core/device.rb +1 -5
- data/lib/appium_lib_core/driver.rb +177 -102
- data/lib/appium_lib_core/{patch.rb → element.rb} +66 -9
- data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
- data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
- data/lib/appium_lib_core/mac2/device.rb +92 -0
- data/lib/appium_lib_core/{ios.rb → mac2.rb} +2 -5
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core/windows/device/app_management.rb +38 -0
- data/lib/appium_lib_core/windows/device.rb +2 -0
- data/lib/appium_lib_core.rb +20 -10
- metadata +27 -83
- data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
- data/.github/contributing.md +0 -26
- data/.github/issue_template.md +0 -20
- data/.github/workflows/unittest.yml +0 -68
- data/.gitignore +0 -18
- data/.rubocop.yml +0 -58
- data/azure-pipelines.yml +0 -15
- data/ci-jobs/functional/android_setup.yml +0 -3
- data/ci-jobs/functional/ios_setup.yml +0 -7
- data/ci-jobs/functional/publish_test_result.yml +0 -18
- data/ci-jobs/functional/run_appium.yml +0 -25
- data/ci-jobs/functional/start-emulator.sh +0 -26
- data/ci-jobs/functional_test.yml +0 -298
- data/docs/mobile_command.md +0 -34
- data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
- data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
- data/lib/appium_lib_core/common/command/common.rb +0 -110
- data/lib/appium_lib_core/common/command/w3c.rb +0 -56
- data/lib/appium_lib_core/ios/uiautomation/device.rb +0 -44
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
- data/release_notes.md +0 -816
- data/script/commands.rb +0 -200
| @@ -38,6 +38,8 @@ module Appium | |
| 38 38 | 
             
                    #
         | 
| 39 39 | 
             
                    #     result = Appium::Core::Wait.until { @driver.find_element(:id, 'something') }
         | 
| 40 40 | 
             
                    #
         | 
| 41 | 
            +
                    #     result = Appium::Core::Wait.until(timeout: 30, message: 'timeout') { @driver.find_element(:id, 'something') }
         | 
| 42 | 
            +
                    #
         | 
| 41 43 | 
             
                    #     result = Appium::Core::Wait.until(object: 'some object') { |object|
         | 
| 42 44 | 
             
                    #        @driver.find_element(:id, object)
         | 
| 43 45 | 
             
                    #     }
         | 
| @@ -82,6 +84,8 @@ module Appium | |
| 82 84 | 
             
                    #
         | 
| 83 85 | 
             
                    #     Appium::Core::Wait.until_true { @driver.find_element(:id, 'something') }
         | 
| 84 86 | 
             
                    #
         | 
| 87 | 
            +
                    #     Appium::Core::Wait.until_true(timeout: 30) { @driver.find_element(:id, 'something') }
         | 
| 88 | 
            +
                    #
         | 
| 85 89 | 
             
                    #     Appium::Core::Wait.until_true(object: 'some object') { |object|
         | 
| 86 90 | 
             
                    #        @driver.find_element(:id, object)
         | 
| 87 91 | 
             
                    #     }
         | 
| @@ -133,17 +137,31 @@ module Appium | |
| 133 137 | 
             
                  # @param [String] message Exception message if timed out.
         | 
| 134 138 | 
             
                  # @param [Array, Exception] ignored Exceptions to ignore while polling (default: Exception)
         | 
| 135 139 | 
             
                  #
         | 
| 136 | 
            -
                  # @example
         | 
| 140 | 
            +
                  # @example With core instance
         | 
| 137 141 | 
             
                  #
         | 
| 138 142 | 
             
                  #   @core.wait_true { @driver.find_element :accessibility_id, 'something' }
         | 
| 143 | 
            +
                  #   @core.wait_true(timeout: 30, interval: 2) { @driver.find_element :accessibility_id, 'something' }
         | 
| 144 | 
            +
                  #
         | 
| 145 | 
            +
                  #   @core.wait_until_true { @driver.find_element :accessibility_id, 'something' }
         | 
| 146 | 
            +
                  #   @core.wait_until_true(timeout: 30, interval: 2) { @driver.find_element :accessibility_id, 'something' }
         | 
| 147 | 
            +
                  #
         | 
| 148 | 
            +
                  # @example With driver instance
         | 
| 149 | 
            +
                  #
         | 
| 150 | 
            +
                  #   @driver.wait_true { |d| d.find_element :accessibility_id, 'something' }
         | 
| 151 | 
            +
                  #   @driver.wait_true(timeout: 30, interval: 2) { |d| driver.find_element :accessibility_id, 'something' }
         | 
| 139 152 | 
             
                  #
         | 
| 140 | 
            -
                   | 
| 153 | 
            +
                  #   @driver.wait_until_true { |d| d.find_element :accessibility_id, 'something' }
         | 
| 154 | 
            +
                  #   @driver.wait_until_true(timeout: 30, interval: 2) { |d| driver.find_element :accessibility_id, 'something' }
         | 
| 155 | 
            +
                  #
         | 
| 156 | 
            +
                  def wait_until_true(timeout: nil, interval: nil, message: nil, ignored: nil, &block)
         | 
| 141 157 | 
             
                    Wait.until_true(timeout: timeout || @wait_timeout,
         | 
| 142 158 | 
             
                                    interval: interval || @wait_interval,
         | 
| 143 159 | 
             
                                    message: message,
         | 
| 144 160 | 
             
                                    ignored: ignored,
         | 
| 145 | 
            -
                                    object: self | 
| 161 | 
            +
                                    object: self,
         | 
| 162 | 
            +
                                    &block)
         | 
| 146 163 | 
             
                  end
         | 
| 164 | 
            +
                  alias wait_true wait_until_true
         | 
| 147 165 |  | 
| 148 166 | 
             
                  # Check every interval seconds to see if yield doesn't raise an exception.
         | 
| 149 167 | 
             
                  # Give up after timeout seconds.
         | 
| @@ -155,17 +173,31 @@ module Appium | |
| 155 173 | 
             
                  # @param [String] message Exception message if timed out.
         | 
| 156 174 | 
             
                  # @param [Array, Exception] ignored Exceptions to ignore while polling (default: Exception)
         | 
| 157 175 | 
             
                  #
         | 
| 158 | 
            -
                  # @example
         | 
| 176 | 
            +
                  # @example With core instance
         | 
| 159 177 | 
             
                  #
         | 
| 160 178 | 
             
                  #   @core.wait { @driver.find_element :accessibility_id, 'something' }
         | 
| 179 | 
            +
                  #   @core.wait(timeout: 30, interval: 2) { @driver.find_element :accessibility_id, 'something' }
         | 
| 180 | 
            +
                  #
         | 
| 181 | 
            +
                  #   @core.wait_until { @driver.find_element :accessibility_id, 'something' }
         | 
| 182 | 
            +
                  #   @core.wait_until(timeout: 30, interval: 2) { @driver.find_element :accessibility_id, 'something' }
         | 
| 183 | 
            +
                  #
         | 
| 184 | 
            +
                  # @example With driver instance
         | 
| 185 | 
            +
                  #
         | 
| 186 | 
            +
                  #   @driver.wait { @driver.find_element :accessibility_id, 'something' }
         | 
| 187 | 
            +
                  #   @driver.wait(timeout: 30, interval: 2) { @driver.find_element :accessibility_id, 'something' }
         | 
| 188 | 
            +
                  #
         | 
| 189 | 
            +
                  #   @driver.wait_until { |d| d.find_element :accessibility_id, 'something' }
         | 
| 190 | 
            +
                  #   @driver.wait_until(timeout: 30, interval: 2) { |d| d.find_element :accessibility_id, 'something' }
         | 
| 161 191 | 
             
                  #
         | 
| 162 | 
            -
                  def  | 
| 192 | 
            +
                  def wait_until(timeout: nil, interval: nil, message: nil, ignored: nil, &block)
         | 
| 163 193 | 
             
                    Wait.until(timeout: timeout || @wait_timeout,
         | 
| 164 194 | 
             
                               interval: interval || @wait_interval,
         | 
| 165 195 | 
             
                               message: message,
         | 
| 166 196 | 
             
                               ignored: ignored,
         | 
| 167 | 
            -
                               object: self | 
| 197 | 
            +
                               object: self,
         | 
| 198 | 
            +
                               &block)
         | 
| 168 199 | 
             
                  end
         | 
| 200 | 
            +
                  alias wait wait_until
         | 
| 169 201 | 
             
                end
         | 
| 170 202 | 
             
              end # module Core
         | 
| 171 203 | 
             
            end # module Appium
         | 
| @@ -79,11 +79,7 @@ module Appium | |
| 79 79 | 
             
                    end
         | 
| 80 80 |  | 
| 81 81 | 
             
                    def create_bridge_command(method, &block)
         | 
| 82 | 
            -
                      ::Appium::Core::Base::Bridge | 
| 83 | 
            -
                        undef_method method if method_defined? method
         | 
| 84 | 
            -
                        block_given? ? class_eval(&block) : define_method(method) { execute method }
         | 
| 85 | 
            -
                      end
         | 
| 86 | 
            -
                      ::Appium::Core::Base::Bridge::W3C.class_eval do
         | 
| 82 | 
            +
                      ::Appium::Core::Base::Bridge.class_eval do
         | 
| 87 83 | 
             
                        undef_method method if method_defined? method
         | 
| 88 84 | 
             
                        block_given? ? class_eval(&block) : define_method(method) { execute method }
         | 
| 89 85 | 
             
                      end
         | 
| @@ -15,6 +15,9 @@ | |
| 15 15 | 
             
            require 'uri'
         | 
| 16 16 |  | 
| 17 17 | 
             
            module Appium
         | 
| 18 | 
            +
              # The struct for 'location'
         | 
| 19 | 
            +
              Location = Struct.new(:latitude, :longitude, :altitude)
         | 
| 20 | 
            +
             | 
| 18 21 | 
             
              module Core
         | 
| 19 22 | 
             
                module Android
         | 
| 20 23 | 
             
                  autoload :Uiautomator1, 'appium_lib_core/android'
         | 
| @@ -23,10 +26,11 @@ module Appium | |
| 23 26 | 
             
                end
         | 
| 24 27 |  | 
| 25 28 | 
             
                module Ios
         | 
| 26 | 
            -
                  autoload :Uiautomation, 'appium_lib_core/ios'
         | 
| 27 29 | 
             
                  autoload :Xcuitest, 'appium_lib_core/ios_xcuitest'
         | 
| 28 30 | 
             
                end
         | 
| 29 31 |  | 
| 32 | 
            +
                autoload :Mac2, 'appium_lib_core/mac2'
         | 
| 33 | 
            +
             | 
| 30 34 | 
             
                autoload :Windows, 'appium_lib_core/windows'
         | 
| 31 35 |  | 
| 32 36 | 
             
                # This options affects only client side as <code>:appium_lib</code> key.<br>
         | 
| @@ -38,18 +42,18 @@ module Appium | |
| 38 42 |  | 
| 39 43 | 
             
                  def initialize(appium_lib_opts)
         | 
| 40 44 | 
             
                    @custom_url = appium_lib_opts.fetch :server_url, nil
         | 
| 41 | 
            -
                    @default_wait = appium_lib_opts.fetch :wait,  | 
| 45 | 
            +
                    @default_wait = appium_lib_opts.fetch :wait, nil
         | 
| 42 46 | 
             
                    @enable_idempotency_header = appium_lib_opts.fetch :enable_idempotency_header, true
         | 
| 43 47 |  | 
| 44 48 | 
             
                    # bump current session id into a particular file
         | 
| 45 49 | 
             
                    @export_session = appium_lib_opts.fetch :export_session, false
         | 
| 46 50 | 
             
                    @export_session_path = appium_lib_opts.fetch :export_session_path, default_tmp_appium_lib_session
         | 
| 47 51 |  | 
| 48 | 
            -
                    @direct_connect = appium_lib_opts.fetch :direct_connect,  | 
| 52 | 
            +
                    @direct_connect = appium_lib_opts.fetch :direct_connect, true
         | 
| 49 53 |  | 
| 50 54 | 
             
                    @port = appium_lib_opts.fetch :port, Driver::DEFAULT_APPIUM_PORT
         | 
| 51 55 |  | 
| 52 | 
            -
                    # timeout and interval used in ::Appium:: | 
| 56 | 
            +
                    # timeout and interval used in ::Appium::Commn.wait/wait_true
         | 
| 53 57 | 
             
                    @wait_timeout  = appium_lib_opts.fetch :wait_timeout, ::Appium::Core::Wait::DEFAULT_TIMEOUT
         | 
| 54 58 | 
             
                    @wait_interval = appium_lib_opts.fetch :wait_interval, ::Appium::Core::Wait::DEFAULT_INTERVAL
         | 
| 55 59 |  | 
| @@ -74,6 +78,13 @@ module Appium | |
| 74 78 | 
             
                    path: 'directConnectPath'
         | 
| 75 79 | 
             
                  }.freeze
         | 
| 76 80 |  | 
| 81 | 
            +
                  W3C_KEYS = {
         | 
| 82 | 
            +
                    protocol: 'appium:directConnectProtocol',
         | 
| 83 | 
            +
                    host: 'appium:directConnectHost',
         | 
| 84 | 
            +
                    port: 'appium:directConnectPort',
         | 
| 85 | 
            +
                    path: 'appium:directConnectPath'
         | 
| 86 | 
            +
                  }.freeze
         | 
| 87 | 
            +
             | 
| 77 88 | 
             
                  # @return [string] Returns a protocol such as http/https
         | 
| 78 89 | 
             
                  attr_reader :protocol
         | 
| 79 90 |  | 
| @@ -87,10 +98,10 @@ module Appium | |
| 87 98 | 
             
                  attr_reader :path
         | 
| 88 99 |  | 
| 89 100 | 
             
                  def initialize(capabilities)
         | 
| 90 | 
            -
                    @protocol = capabilities[KEYS[:protocol]]
         | 
| 91 | 
            -
                    @host = capabilities[KEYS[:host]]
         | 
| 92 | 
            -
                    @port = capabilities[KEYS[:port]]
         | 
| 93 | 
            -
                    @path = capabilities[KEYS[:path]]
         | 
| 101 | 
            +
                    @protocol = capabilities[W3C_KEYS[:protocol]] || capabilities[KEYS[:protocol]]
         | 
| 102 | 
            +
                    @host = capabilities[W3C_KEYS[:host]] || capabilities[KEYS[:host]]
         | 
| 103 | 
            +
                    @port = capabilities[W3C_KEYS[:port]] || capabilities[KEYS[:port]]
         | 
| 104 | 
            +
                    @path = capabilities[W3C_KEYS[:path]] || capabilities[KEYS[:path]]
         | 
| 94 105 | 
             
                  end
         | 
| 95 106 | 
             
                end
         | 
| 96 107 |  | 
| @@ -133,11 +144,9 @@ module Appium | |
| 133 144 | 
             
                  attr_reader :export_session_path
         | 
| 134 145 |  | 
| 135 146 | 
             
                  # Default wait time for elements to appear in Appium server side.
         | 
| 136 | 
            -
                  # Defaults to {::Appium::Core::Driver::DEFAULT_IMPLICIT_WAIT}.<br>
         | 
| 137 147 | 
             
                  # Provide <code>{ appium_lib: { wait: 30 } }</code> to {::Appium::Core.for}
         | 
| 138 148 | 
             
                  # @return [Integer]
         | 
| 139 149 | 
             
                  attr_reader :default_wait
         | 
| 140 | 
            -
                  DEFAULT_IMPLICIT_WAIT = 0
         | 
| 141 150 |  | 
| 142 151 | 
             
                  # Appium's server port. 4723 is by default. Defaults to {::Appium::Core::Driver::DEFAULT_APPIUM_PORT}.<br>
         | 
| 143 152 | 
             
                  # Provide <code>{ appium_lib: { port: 8080 } }</code> to {::Appium::Core.for}.
         | 
| @@ -175,7 +184,8 @@ module Appium | |
| 175 184 | 
             
                  # - <code>directConnectPort</code>
         | 
| 176 185 | 
             
                  # - <code>directConnectPath</code>
         | 
| 177 186 | 
             
                  #
         | 
| 178 | 
            -
                  #  | 
| 187 | 
            +
                  # ignore them if this parameter is <code>false</code>. Defaults to true.
         | 
| 188 | 
            +
                  # These keys can have <code>appium:</code> prefix.
         | 
| 179 189 | 
             
                  #
         | 
| 180 190 | 
             
                  # @return [Bool]
         | 
| 181 191 | 
             
                  attr_reader :direct_connect
         | 
| @@ -185,8 +195,6 @@ module Appium | |
| 185 195 | 
             
                  # @option opts [Hash] :caps Appium capabilities.
         | 
| 186 196 | 
             
                  # @option opts [Hash] :capabilities The same as :caps.
         | 
| 187 197 | 
             
                  #                                   This param is for compatibility with Selenium WebDriver format
         | 
| 188 | 
            -
                  # @option opts [Hash] :desired_capabilities The same as :caps.
         | 
| 189 | 
            -
                  #                                           This param is for compatibility with Selenium WebDriver format
         | 
| 190 198 | 
             
                  # @option opts [Appium::Core::Options] :appium_lib Capabilities affect only ruby client
         | 
| 191 199 | 
             
                  # @option opts [String] :url The same as :custom_url in :appium_lib.
         | 
| 192 200 | 
             
                  #                            This param is for compatibility with Selenium WebDriver format
         | 
| @@ -197,10 +205,8 @@ module Appium | |
| 197 205 | 
             
                  #
         | 
| 198 206 | 
             
                  #     # format 1
         | 
| 199 207 | 
             
                  #     @core = Appium::Core.for caps: {...}, appium_lib: {...}
         | 
| 200 | 
            -
                  #     # format 2. 'capabilities:'  | 
| 208 | 
            +
                  #     # format 2. 'capabilities:' is also available instead of 'caps:'.
         | 
| 201 209 | 
             
                  #     @core = Appium::Core.for url: "http://127.0.0.1:8080/wd/hub", capabilities: {...}, appium_lib: {...}
         | 
| 202 | 
            -
                  #     # format 3. 'appium_lib: {...}' can be blank
         | 
| 203 | 
            -
                  #     @core = Appium::Core.for url: "http://127.0.0.1:8080/wd/hub", desired_capabilities: {...}
         | 
| 204 210 | 
             
                  #
         | 
| 205 211 | 
             
                  #
         | 
| 206 212 | 
             
                  #     require 'rubygems'
         | 
| @@ -228,7 +234,7 @@ module Appium | |
| 228 234 | 
             
                  #     @core.start_driver # Connect to 'http://127.0.0.1:8080/wd/hub' because of 'port: 8080'
         | 
| 229 235 | 
             
                  #
         | 
| 230 236 | 
             
                  #     # Start iOS driver with .zip file over HTTP
         | 
| 231 | 
            -
                  #     # | 
| 237 | 
            +
                  #     # 'capabilities:' is also available instead of 'caps:'. Either is fine.
         | 
| 232 238 | 
             
                  #     opts = {
         | 
| 233 239 | 
             
                  #              capabilities: {
         | 
| 234 240 | 
             
                  #                platformName: :ios,
         | 
| @@ -252,7 +258,7 @@ module Appium | |
| 252 258 | 
             
                  #     # Start iOS driver as another format. 'url' is available like below
         | 
| 253 259 | 
             
                  #     opts = {
         | 
| 254 260 | 
             
                  #              url: "http://custom-host:8080/wd/hub.com",
         | 
| 255 | 
            -
                  #               | 
| 261 | 
            +
                  #              capabilities: {
         | 
| 256 262 | 
             
                  #                platformName: :ios,
         | 
| 257 263 | 
             
                  #                platformVersion: '11.0',
         | 
| 258 264 | 
             
                  #                deviceName: 'iPhone Simulator',
         | 
| @@ -271,7 +277,40 @@ module Appium | |
| 271 277 | 
             
                  #     @core.start_driver # start driver with 'url'. Connect to 'http://custom-host:8080/wd/hub.com'
         | 
| 272 278 | 
             
                  #
         | 
| 273 279 | 
             
                  def self.for(opts = {})
         | 
| 274 | 
            -
                    new(opts)
         | 
| 280 | 
            +
                    new.setup_for_new_session(opts)
         | 
| 281 | 
            +
                  end
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                  # Attach to an existing session. The main usage of this method is to attach to
         | 
| 284 | 
            +
                  # an existing session for debugging. The generated driver instance has the capabilities which
         | 
| 285 | 
            +
                  # has the given automationName and platformName only since the W3C WebDriver spec does not provide
         | 
| 286 | 
            +
                  # an endpoint to get running session's capabilities.
         | 
| 287 | 
            +
                  #
         | 
| 288 | 
            +
                  #
         | 
| 289 | 
            +
                  # @param [String] The session id to attach to.
         | 
| 290 | 
            +
                  # @param [String] url The WebDriver URL to attach to with the session_id.
         | 
| 291 | 
            +
                  # @param [String] automation_name The platform name to keep in the dummy capabilities
         | 
| 292 | 
            +
                  # @param [String] platform_name The automation name to keep in the dummy capabilities
         | 
| 293 | 
            +
                  # @return [Selenium::WebDriver] A new driver instance with the given session id.
         | 
| 294 | 
            +
                  #
         | 
| 295 | 
            +
                  # @example
         | 
| 296 | 
            +
                  #
         | 
| 297 | 
            +
                  #   new_driver = ::Appium::Core::Driver.attach_to(
         | 
| 298 | 
            +
                  #     driver.session_id,  # The 'driver' has an existing session id
         | 
| 299 | 
            +
                  #     url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
         | 
| 300 | 
            +
                  #   )
         | 
| 301 | 
            +
                  #   new_driver.page_source # for example
         | 
| 302 | 
            +
                  #
         | 
| 303 | 
            +
                  def self.attach_to(
         | 
| 304 | 
            +
                    session_id, url: nil, automation_name: nil, platform_name: nil,
         | 
| 305 | 
            +
                    http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 }
         | 
| 306 | 
            +
                  )
         | 
| 307 | 
            +
                    new.attach_to(
         | 
| 308 | 
            +
                      session_id,
         | 
| 309 | 
            +
                      automation_name: automation_name,
         | 
| 310 | 
            +
                      platform_name: platform_name,
         | 
| 311 | 
            +
                      url: url,
         | 
| 312 | 
            +
                      http_client_ops: http_client_ops
         | 
| 313 | 
            +
                    )
         | 
| 275 314 | 
             
                  end
         | 
| 276 315 |  | 
| 277 316 | 
             
                  private
         | 
| @@ -282,17 +321,25 @@ module Appium | |
| 282 321 | 
             
                    @delegate_target
         | 
| 283 322 | 
             
                  end
         | 
| 284 323 |  | 
| 285 | 
            -
                  public
         | 
| 286 | 
            -
             | 
| 287 324 | 
             
                  # @private
         | 
| 288 | 
            -
                  def initialize | 
| 325 | 
            +
                  def initialize
         | 
| 289 326 | 
             
                    @delegate_target = self # for testing purpose
         | 
| 290 327 | 
             
                    @automation_name = nil # initialise before 'set_automation_name'
         | 
| 328 | 
            +
                  end
         | 
| 291 329 |  | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 330 | 
            +
                  public
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                  # @private
         | 
| 333 | 
            +
                  # Set up for a new session
         | 
| 334 | 
            +
                  def setup_for_new_session(opts = {})
         | 
| 335 | 
            +
                    @custom_url = opts.delete :url # to set the custom url as :url
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                    # TODO: Remove when we implement Options
         | 
| 338 | 
            +
                    # The symbolize_keys is to keep compatiility for the legacy code, which allows capabilities to give 'string' as the key.
         | 
| 339 | 
            +
                    # The toplevel `caps`, `capabilities` and `appium_lib` are expected to be symbol.
         | 
| 340 | 
            +
                    # FIXME: First, please try to remove `nested: true` to `nested: false`.
         | 
| 341 | 
            +
                    opts = Appium.symbolize_keys(opts, nested: true)
         | 
| 294 342 |  | 
| 295 | 
            -
                    @custom_url = opts.delete :url
         | 
| 296 343 | 
             
                    @caps = get_caps(opts)
         | 
| 297 344 |  | 
| 298 345 | 
             
                    set_appium_lib_specific_values(get_appium_lib_opts(opts))
         | 
| @@ -301,8 +348,7 @@ module Appium | |
| 301 348 | 
             
                    set_automation_name
         | 
| 302 349 |  | 
| 303 350 | 
             
                    extend_for(device: @device, automation_name: @automation_name)
         | 
| 304 | 
            -
             | 
| 305 | 
            -
                    self # rubocop:disable Lint/Void
         | 
| 351 | 
            +
                    self
         | 
| 306 352 | 
             
                  end
         | 
| 307 353 |  | 
| 308 354 | 
             
                  # Creates a new global driver and quits the old one if it exists.
         | 
| @@ -313,7 +359,7 @@ module Appium | |
| 313 359 | 
             
                  # @option http_client_ops [Hash] :http_client Custom HTTP Client
         | 
| 314 360 | 
             
                  # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
         | 
| 315 361 | 
             
                  # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
         | 
| 316 | 
            -
                  # @return [Selenium::WebDriver]  | 
| 362 | 
            +
                  # @return [Selenium::WebDriver] A new driver instance
         | 
| 317 363 | 
             
                  #
         | 
| 318 364 | 
             
                  # @example
         | 
| 319 365 | 
             
                  #
         | 
| @@ -324,7 +370,7 @@ module Appium | |
| 324 370 | 
             
                  #
         | 
| 325 371 | 
             
                  #     # Start iOS driver
         | 
| 326 372 | 
             
                  #     opts = {
         | 
| 327 | 
            -
                  #               | 
| 373 | 
            +
                  #              capabilities: {
         | 
| 328 374 | 
             
                  #                platformName: :ios,
         | 
| 329 375 | 
             
                  #                platformVersion: '11.0',
         | 
| 330 376 | 
             
                  #                deviceName: 'iPhone Simulator',
         | 
| @@ -365,11 +411,12 @@ module Appium | |
| 365 411 | 
             
                    end
         | 
| 366 412 |  | 
| 367 413 | 
             
                    begin
         | 
| 368 | 
            -
                       | 
| 369 | 
            -
             | 
| 370 | 
            -
                                                                  | 
| 414 | 
            +
                      @driver = ::Appium::Core::Base::Driver.new(listener: @listener,
         | 
| 415 | 
            +
                                                                 http_client: @http_client,
         | 
| 416 | 
            +
                                                                 capabilities: @caps, # ::Appium::Core::Base::Capabilities
         | 
| 371 417 | 
             
                                                                 url: @custom_url,
         | 
| 372 | 
            -
                                                                  | 
| 418 | 
            +
                                                                 wait_timeout: @wait_timeout,
         | 
| 419 | 
            +
                                                                 wait_interval: @wait_interval)
         | 
| 373 420 |  | 
| 374 421 | 
             
                      if @direct_connect
         | 
| 375 422 | 
             
                        d_c = DirectConnections.new(@driver.capabilities)
         | 
| @@ -387,6 +434,8 @@ module Appium | |
| 387 434 | 
             
                      @http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
         | 
| 388 435 | 
             
                    end
         | 
| 389 436 |  | 
| 437 | 
            +
                    # TODO: this method can be removed after releasing Appium 2.0, and after a while
         | 
| 438 | 
            +
                    # since Appium 2.0 reuqires 'automationName'. This method won't help anymore then.
         | 
| 390 439 | 
             
                    # If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
         | 
| 391 440 | 
             
                    # Since @automation_name is set only client side before start_driver is called.
         | 
| 392 441 | 
             
                    set_automation_name_if_nil
         | 
| @@ -396,7 +445,47 @@ module Appium | |
| 396 445 | 
             
                    @driver
         | 
| 397 446 | 
             
                  end
         | 
| 398 447 |  | 
| 399 | 
            -
                  private
         | 
| 448 | 
            +
                  # @private
         | 
| 449 | 
            +
                  # Attach to an existing session
         | 
| 450 | 
            +
                  def attach_to(session_id, url: nil, automation_name: nil, platform_name: nil,
         | 
| 451 | 
            +
                                http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })
         | 
| 452 | 
            +
             | 
| 453 | 
            +
                    raise ::Appium::Core::Error::ArgumentError, 'The :url must not be nil' if url.nil?
         | 
| 454 | 
            +
                    raise ::Appium::Core::Error::ArgumentError, 'The :automation_name must not be nil' if automation_name.nil?
         | 
| 455 | 
            +
                    raise ::Appium::Core::Error::ArgumentError, 'The :platform_name must not be nil' if platform_name.nil?
         | 
| 456 | 
            +
             | 
| 457 | 
            +
                    @custom_url = url
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                    # use lowercase internally
         | 
| 460 | 
            +
                    @automation_name = convert_downcase(automation_name)
         | 
| 461 | 
            +
                    @device = convert_downcase(platform_name)
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                    extend_for(device: @device, automation_name: @automation_name)
         | 
| 464 | 
            +
             | 
| 465 | 
            +
                    @http_client = get_http_client http_client: http_client_ops.delete(:http_client),
         | 
| 466 | 
            +
                                                   open_timeout: http_client_ops.delete(:open_timeout),
         | 
| 467 | 
            +
                                                   read_timeout: http_client_ops.delete(:read_timeout)
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                    # Note that 'enable_idempotency_header' works only a new session reqeust. The attach_to method skips
         | 
| 470 | 
            +
                    # the new session request, this it does not needed.
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                    begin
         | 
| 473 | 
            +
                      # included https://github.com/SeleniumHQ/selenium/blob/43f8b3f66e7e01124eff6a5805269ee441f65707/rb/lib/selenium/webdriver/remote/driver.rb#L29
         | 
| 474 | 
            +
                      @driver = ::Appium::Core::Base::Driver.new(http_client: @http_client,
         | 
| 475 | 
            +
                                                                 url: @custom_url,
         | 
| 476 | 
            +
                                                                 listener: @listener,
         | 
| 477 | 
            +
                                                                 existing_session_id: session_id,
         | 
| 478 | 
            +
                                                                 automation_name: automation_name,
         | 
| 479 | 
            +
                                                                 platform_name: platform_name)
         | 
| 480 | 
            +
             | 
| 481 | 
            +
                      # export session
         | 
| 482 | 
            +
                      write_session_id(@driver.session_id, @export_session_path) if @export_session
         | 
| 483 | 
            +
                    rescue Errno::ECONNREFUSED
         | 
| 484 | 
            +
                      raise "ERROR: Unable to connect to Appium. Is the server running on #{@custom_url}?"
         | 
| 485 | 
            +
                    end
         | 
| 486 | 
            +
             | 
| 487 | 
            +
                    @driver
         | 
| 488 | 
            +
                  end
         | 
| 400 489 |  | 
| 401 490 | 
             
                  def get_http_client(http_client: nil, open_timeout: nil, read_timeout: nil)
         | 
| 402 491 | 
             
                    client = http_client || Appium::Core::Base::Http::Default.new
         | 
| @@ -410,6 +499,8 @@ module Appium | |
| 410 499 |  | 
| 411 500 | 
             
                  # Ignore setting default wait if the target driver has no implementation
         | 
| 412 501 | 
             
                  def set_implicit_wait_by_default(wait)
         | 
| 502 | 
            +
                    return if @default_wait.nil?
         | 
| 503 | 
            +
             | 
| 413 504 | 
             
                    @driver.manage.timeouts.implicit_wait = wait
         | 
| 414 505 | 
             
                  rescue ::Selenium::WebDriver::Error::UnknownError => e
         | 
| 415 506 | 
             
                    unless e.message.include?('The operation requested is not yet implemented')
         | 
| @@ -420,9 +511,7 @@ module Appium | |
| 420 511 | 
             
                    {}
         | 
| 421 512 | 
             
                  end
         | 
| 422 513 |  | 
| 423 | 
            -
                   | 
| 424 | 
            -
             | 
| 425 | 
            -
                  # Quits the driver
         | 
| 514 | 
            +
                  # [Deprecated] Quits the driver. This method is the same as @driver.quit
         | 
| 426 515 | 
             
                  # @return [void]
         | 
| 427 516 | 
             
                  #
         | 
| 428 517 | 
             
                  # @example
         | 
| @@ -430,12 +519,14 @@ module Appium | |
| 430 519 | 
             
                  #   @core.quit_driver
         | 
| 431 520 | 
             
                  #
         | 
| 432 521 | 
             
                  def quit_driver
         | 
| 522 | 
            +
                    ::Appium::Logger.warn('[DEPRECATION] quit_driver will be removed. Please use @driver.quit instead.')
         | 
| 433 523 | 
             
                    @driver.quit
         | 
| 434 524 | 
             
                  rescue # rubocop:disable Style/RescueStandardError
         | 
| 435 525 | 
             
                    nil
         | 
| 436 526 | 
             
                  end
         | 
| 437 527 |  | 
| 438 | 
            -
                  # Returns the server's version info
         | 
| 528 | 
            +
                  # Returns the server's version info. This method calls +driver.remote_status+ internally
         | 
| 529 | 
            +
                  #
         | 
| 439 530 | 
             
                  # @return [Hash]
         | 
| 440 531 | 
             
                  #
         | 
| 441 532 | 
             
                  # @example
         | 
| @@ -449,18 +540,20 @@ module Appium | |
| 449 540 | 
             
                  #         }
         | 
| 450 541 | 
             
                  #     }
         | 
| 451 542 | 
             
                  #
         | 
| 452 | 
            -
                  # Returns blank hash  | 
| 543 | 
            +
                  # Returns blank hash in a case +driver.remote_status+ got an error
         | 
| 544 | 
            +
                  # such as Selenium Grid. It returns 500 error against 'remote_status'.
         | 
| 453 545 | 
             
                  #
         | 
| 454 546 | 
             
                  # @example
         | 
| 455 547 | 
             
                  #
         | 
| 456 548 | 
             
                  #   @core.appium_server_version #=> {}
         | 
| 457 549 | 
             
                  #
         | 
| 458 550 | 
             
                  def appium_server_version
         | 
| 459 | 
            -
                    @driver. | 
| 460 | 
            -
                  rescue Selenium::WebDriver::Error::ServerError => e
         | 
| 461 | 
            -
                    raise ::Appium::Core::Error::ServerError unless e.message.include?('status code 500')
         | 
| 551 | 
            +
                    return {} if @driver.nil?
         | 
| 462 552 |  | 
| 463 | 
            -
                     | 
| 553 | 
            +
                    @driver.remote_status
         | 
| 554 | 
            +
                  rescue StandardError
         | 
| 555 | 
            +
                    # Ignore error case in a case the target appium server
         | 
| 556 | 
            +
                    # does not support `/status` API.
         | 
| 464 557 | 
             
                    {}
         | 
| 465 558 | 
             
                  end
         | 
| 466 559 |  | 
| @@ -472,35 +565,35 @@ module Appium | |
| 472 565 | 
             
                  #     @core.platform_version #=> [10,1,1]
         | 
| 473 566 | 
             
                  #
         | 
| 474 567 | 
             
                  def platform_version
         | 
| 568 | 
            +
                    ::Appium::Logger.warn(
         | 
| 569 | 
            +
                      '[DEPRECATION] platform_version method will be. ' \
         | 
| 570 | 
            +
                      'Please check the platformVersion via @driver.capabilities["platformVersion"] instead.'
         | 
| 571 | 
            +
                    )
         | 
| 572 | 
            +
             | 
| 475 573 | 
             
                    p_version = @driver.capabilities['platformVersion'] || @driver.session_capabilities['platformVersion']
         | 
| 476 574 | 
             
                    p_version.split('.').map(&:to_i)
         | 
| 477 575 | 
             
                  end
         | 
| 478 576 |  | 
| 479 | 
            -
                  # Takes a png screenshot and saves to the target path.
         | 
| 480 | 
            -
                  #
         | 
| 481 | 
            -
                  # @param png_save_path [String] the full path to save the png
         | 
| 482 | 
            -
                  # @return [File]
         | 
| 483 | 
            -
                  #
         | 
| 484 | 
            -
                  # @example
         | 
| 485 | 
            -
                  #
         | 
| 486 | 
            -
                  #   @core.screenshot '/tmp/hi.png' #=> nil
         | 
| 487 | 
            -
                  #   # same as '@driver.save_screenshot png_save_path'
         | 
| 488 | 
            -
                  #
         | 
| 489 | 
            -
                  def screenshot(png_save_path)
         | 
| 490 | 
            -
                    ::Appium::Logger.warn '[DEPRECATION] screenshot will be removed. Please use driver.save_screenshot instead.'
         | 
| 491 | 
            -
                    @driver.save_screenshot png_save_path
         | 
| 492 | 
            -
                  end
         | 
| 493 | 
            -
             | 
| 494 577 | 
             
                  private
         | 
| 495 578 |  | 
| 579 | 
            +
                  def convert_to_symbol(value)
         | 
| 580 | 
            +
                    if value.nil?
         | 
| 581 | 
            +
                      value
         | 
| 582 | 
            +
                    else
         | 
| 583 | 
            +
                      value.to_sym
         | 
| 584 | 
            +
                    end
         | 
| 585 | 
            +
                  end
         | 
| 586 | 
            +
             | 
| 496 587 | 
             
                  # @private
         | 
| 497 588 | 
             
                  def extend_for(device:, automation_name:) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 498 589 | 
             
                    extend Appium::Core
         | 
| 499 590 | 
             
                    extend Appium::Core::Device
         | 
| 500 591 |  | 
| 501 | 
            -
                     | 
| 592 | 
            +
                    sym_automation_name = convert_to_symbol(automation_name)
         | 
| 593 | 
            +
             | 
| 594 | 
            +
                    case convert_to_symbol(device)
         | 
| 502 595 | 
             
                    when :android
         | 
| 503 | 
            -
                      case  | 
| 596 | 
            +
                      case sym_automation_name
         | 
| 504 597 | 
             
                      when :espresso
         | 
| 505 598 | 
             
                        ::Appium::Core::Android::Espresso::Bridge.for self
         | 
| 506 599 | 
             
                      when :uiautomator2
         | 
| @@ -511,28 +604,26 @@ module Appium | |
| 511 604 | 
             
                        ::Appium::Core::Android::Uiautomator1::Bridge.for self
         | 
| 512 605 | 
             
                      end
         | 
| 513 606 | 
             
                    when :ios, :tvos
         | 
| 514 | 
            -
                      case  | 
| 607 | 
            +
                      case sym_automation_name
         | 
| 515 608 | 
             
                      when :safari
         | 
| 516 609 | 
             
                        ::Appium::Logger.debug('SafariDriver for iOS')
         | 
| 517 | 
            -
                       | 
| 610 | 
            +
                      else # XCUITest
         | 
| 518 611 | 
             
                        ::Appium::Core::Ios::Xcuitest::Bridge.for self
         | 
| 519 | 
            -
                      else # default and UIAutomation
         | 
| 520 | 
            -
                        ::Appium::Core::Ios::Uiautomation::Bridge.for self
         | 
| 521 612 | 
             
                      end
         | 
| 522 613 | 
             
                    when :mac
         | 
| 523 | 
            -
                      case  | 
| 614 | 
            +
                      case sym_automation_name
         | 
| 524 615 | 
             
                      when :safari
         | 
| 525 616 | 
             
                        ::Appium::Logger.debug('SafariDriver for macOS')
         | 
| 526 617 | 
             
                      when :gecko
         | 
| 527 618 | 
             
                        ::Appium::Logger.debug('Gecko Driver for macOS')
         | 
| 528 619 | 
             
                      when :mac2
         | 
| 529 | 
            -
                        ::Appium:: | 
| 620 | 
            +
                        ::Appium::Core::Mac2::Bridge.for self
         | 
| 530 621 | 
             
                      else
         | 
| 531 622 | 
             
                        # no Mac specific extentions
         | 
| 532 623 | 
             
                        ::Appium::Logger.debug('macOS Native')
         | 
| 533 624 | 
             
                      end
         | 
| 534 625 | 
             
                    when :windows
         | 
| 535 | 
            -
                      case  | 
| 626 | 
            +
                      case sym_automation_name
         | 
| 536 627 | 
             
                      when :gecko
         | 
| 537 628 | 
             
                        ::Appium::Logger.debug('Gecko Driver for Windows')
         | 
| 538 629 | 
             
                      else
         | 
| @@ -542,7 +633,7 @@ module Appium | |
| 542 633 | 
             
                      # https://github.com/Samsung/appium-tizen-driver
         | 
| 543 634 | 
             
                      ::Appium::Logger.debug('tizen')
         | 
| 544 635 | 
             
                    else
         | 
| 545 | 
            -
                      case  | 
| 636 | 
            +
                      case sym_automation_name
         | 
| 546 637 | 
             
                      when :youiengine
         | 
| 547 638 | 
             
                        # https://github.com/YOU-i-Labs/appium-youiengine-driver
         | 
| 548 639 | 
             
                        ::Appium::Logger.debug('YouiEngine')
         | 
| @@ -559,36 +650,9 @@ module Appium | |
| 559 650 | 
             
                    self
         | 
| 560 651 | 
             
                  end
         | 
| 561 652 |  | 
| 562 | 
            -
                  # @private
         | 
| 563 | 
            -
                  def validate_keys(opts)
         | 
| 564 | 
            -
                    flatten_ops = flatten_hash_keys(opts)
         | 
| 565 | 
            -
             | 
| 566 | 
            -
                    # FIXME: Remove 'desired_capabilities' in the next major Selenium update
         | 
| 567 | 
            -
                    unless opts.member?(:caps) || opts.member?(:capabilities) || opts.member?(:desired_capabilities)
         | 
| 568 | 
            -
                      raise Error::NoCapabilityError
         | 
| 569 | 
            -
                    end
         | 
| 570 | 
            -
             | 
| 571 | 
            -
                    if !opts.member?(:appium_lib) && flatten_ops.member?(:appium_lib)
         | 
| 572 | 
            -
                      raise Error::CapabilityStructureError, 'Please check the value of appium_lib in the capability'
         | 
| 573 | 
            -
                    end
         | 
| 574 | 
            -
             | 
| 575 | 
            -
                    true
         | 
| 576 | 
            -
                  end
         | 
| 577 | 
            -
             | 
| 578 | 
            -
                  # @private
         | 
| 579 | 
            -
                  def flatten_hash_keys(hash, flatten_keys_result = [])
         | 
| 580 | 
            -
                    hash.each do |key, value|
         | 
| 581 | 
            -
                      flatten_keys_result << key
         | 
| 582 | 
            -
                      flatten_hash_keys(value, flatten_keys_result) if value.is_a?(Hash)
         | 
| 583 | 
            -
                    end
         | 
| 584 | 
            -
             | 
| 585 | 
            -
                    flatten_keys_result
         | 
| 586 | 
            -
                  end
         | 
| 587 | 
            -
             | 
| 588 653 | 
             
                  # @private
         | 
| 589 654 | 
             
                  def get_caps(opts)
         | 
| 590 | 
            -
                     | 
| 591 | 
            -
                    Core::Base::Capabilities.create_capabilities(opts[:caps] || opts[:capabilities] || opts[:desired_capabilities] || {})
         | 
| 655 | 
            +
                    Core::Base::Capabilities.new(opts[:caps] || opts[:capabilities] || {})
         | 
| 592 656 | 
             
                  end
         | 
| 593 657 |  | 
| 594 658 | 
             
                  # @private
         | 
| @@ -601,6 +665,7 @@ module Appium | |
| 601 665 | 
             
                  # The path can be local, HTTP/S, Windows Share and other path like 'sauce-storage:'.
         | 
| 602 666 | 
             
                  # Use @caps[:app] without modifications if the path isn't HTTP/S or local path.
         | 
| 603 667 | 
             
                  def set_app_path
         | 
| 668 | 
            +
                    # FIXME: maybe `:app` should check `app` as well.
         | 
| 604 669 | 
             
                    return unless @caps && @caps[:app] && !@caps[:app].empty?
         | 
| 605 670 | 
             
                    return if @caps[:app] =~ URI::DEFAULT_PARSER.make_regexp
         | 
| 606 671 |  | 
| @@ -639,18 +704,24 @@ module Appium | |
| 639 704 | 
             
                  # @private
         | 
| 640 705 | 
             
                  def set_appium_device
         | 
| 641 706 | 
             
                    # https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
         | 
| 642 | 
            -
                     | 
| 707 | 
            +
                    # TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
         | 
| 708 | 
            +
                    @device = @caps[:platformName] || @caps['platformName']
         | 
| 643 709 | 
             
                    return @device unless @device
         | 
| 644 710 |  | 
| 645 | 
            -
                    @device =  | 
| 711 | 
            +
                    @device = convert_downcase @device
         | 
| 646 712 | 
             
                  end
         | 
| 647 713 |  | 
| 648 714 | 
             
                  # @private
         | 
| 649 715 | 
             
                  def set_automation_name
         | 
| 650 | 
            -
                     | 
| 651 | 
            -
                     | 
| 652 | 
            -
             | 
| 653 | 
            -
             | 
| 716 | 
            +
                    # TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
         | 
| 717 | 
            +
                    candidate = @caps[:automationName] || @caps['automationName']
         | 
| 718 | 
            +
                    @automation_name = candidate if candidate
         | 
| 719 | 
            +
                    @automation_name = convert_downcase @automation_name if @automation_name
         | 
| 720 | 
            +
                  end
         | 
| 721 | 
            +
             | 
| 722 | 
            +
                  # @private
         | 
| 723 | 
            +
                  def convert_downcase(value)
         | 
| 724 | 
            +
                    value.is_a?(Symbol) ? value.downcase : value.downcase.strip.intern
         | 
| 654 725 | 
             
                  end
         | 
| 655 726 |  | 
| 656 727 | 
             
                  # @private
         | 
| @@ -664,6 +735,10 @@ module Appium | |
| 664 735 |  | 
| 665 736 | 
             
                  # @private
         | 
| 666 737 | 
             
                  def write_session_id(session_id, export_path = '/tmp/appium_lib_session')
         | 
| 738 | 
            +
                    ::Appium::Logger.warn(
         | 
| 739 | 
            +
                      '[DEPRECATION] export_session option will be removed. ' \
         | 
| 740 | 
            +
                      'Please save the session id by yourself with #session_id method like @driver.session_id.'
         | 
| 741 | 
            +
                    )
         | 
| 667 742 | 
             
                    export_path = export_path.tr('/', '\\') if ::Appium::Core::Base.platform.windows?
         | 
| 668 743 | 
             
                    File.write(export_path, session_id)
         | 
| 669 744 | 
             
                  rescue IOError => e
         |