appium_lib_core 4.1.0 → 8.0.2
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 +316 -270
- data/README.md +65 -15
- data/Rakefile +5 -22
- data/appium_lib_core.gemspec +6 -9
- data/bin/console +0 -4
- data/lib/appium_lib_core/android/device/auth_finger_print.rb +4 -1
- data/lib/appium_lib_core/android/device/network.rb +10 -0
- data/lib/appium_lib_core/android/device/performance.rb +3 -0
- data/lib/appium_lib_core/android/device/screen.rb +2 -0
- data/lib/appium_lib_core/android/device.rb +80 -17
- data/lib/appium_lib_core/common/base/bridge.rb +309 -93
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
- data/lib/appium_lib_core/common/{command/mjsonwp.rb → base/device_ime.rb} +33 -12
- data/lib/appium_lib_core/common/base/driver.rb +258 -331
- 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 +15 -38
- 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 +62 -0
- data/lib/appium_lib_core/common/base/screenshot.rb +8 -8
- data/lib/appium_lib_core/common/base/search_context.rb +13 -17
- data/lib/appium_lib_core/common/base.rb +1 -5
- data/lib/appium_lib_core/common/command.rb +244 -4
- data/lib/appium_lib_core/common/device/app_management.rb +2 -26
- data/lib/appium_lib_core/common/device/context.rb +1 -5
- 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/device/{touch_actions.rb → orientation.rb} +6 -10
- data/lib/appium_lib_core/common/error.rb +4 -5
- data/lib/appium_lib_core/common/log.rb +5 -4
- data/lib/appium_lib_core/common/wait.rb +38 -6
- data/lib/appium_lib_core/device.rb +3 -9
- data/lib/appium_lib_core/driver.rb +182 -148
- data/lib/appium_lib_core/{patch.rb → element.rb} +62 -25
- data/lib/appium_lib_core/ios/xcuitest/device.rb +2 -0
- 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/support/event_firing_bridge.rb +57 -0
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core.rb +21 -10
- metadata +28 -94
- 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/common/device/value.rb +0 -52
- data/lib/appium_lib_core/common/touch_action/multi_touch.rb +0 -56
- data/lib/appium_lib_core/common/touch_action/touch_actions.rb +0 -203
- 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
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            # you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            # You may obtain a copy of the License at
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
            # Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            # See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            # limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module Appium
         | 
| 16 | 
            +
              module Core
         | 
| 17 | 
            +
                class Base
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  class DriverSettings
         | 
| 22 | 
            +
                    # @private this class is private
         | 
| 23 | 
            +
                    def initialize(bridge)
         | 
| 24 | 
            +
                      @bridge = bridge
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    # Get appium Settings for current test session.
         | 
| 28 | 
            +
                    #
         | 
| 29 | 
            +
                    # @example
         | 
| 30 | 
            +
                    #
         | 
| 31 | 
            +
                    #   @driver.settings.get
         | 
| 32 | 
            +
                    #
         | 
| 33 | 
            +
                    def get
         | 
| 34 | 
            +
                      @bridge.get_settings
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    # Update Appium Settings for current test session
         | 
| 38 | 
            +
                    #
         | 
| 39 | 
            +
                    # @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
         | 
| 40 | 
            +
                    #
         | 
| 41 | 
            +
                    # @example
         | 
| 42 | 
            +
                    #
         | 
| 43 | 
            +
                    #   @driver.settings.update({'allowInvisibleElements': true})
         | 
| 44 | 
            +
                    #
         | 
| 45 | 
            +
                    def update(settings)
         | 
| 46 | 
            +
                      @bridge.update_settings(settings)
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            # you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            # You may obtain a copy of the License at
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
            # Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            # See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            # limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module Appium
         | 
| 16 | 
            +
              module Core
         | 
| 17 | 
            +
                class Base
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  module HasLocation
         | 
| 22 | 
            +
                    # Get the location of the device.
         | 
| 23 | 
            +
                    #
         | 
| 24 | 
            +
                    # @return [::Appium::Location]
         | 
| 25 | 
            +
                    #
         | 
| 26 | 
            +
                    # @example
         | 
| 27 | 
            +
                    #
         | 
| 28 | 
            +
                    #   driver.location #=> ::Appium::Location.new(10, 10, 10)
         | 
| 29 | 
            +
                    #
         | 
| 30 | 
            +
                    def location
         | 
| 31 | 
            +
                      @bridge.location
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    # Set the location of the device.
         | 
| 35 | 
            +
                    #
         | 
| 36 | 
            +
                    # @param [::Appium::Location] location Set the location.
         | 
| 37 | 
            +
                    #
         | 
| 38 | 
            +
                    # @example
         | 
| 39 | 
            +
                    #
         | 
| 40 | 
            +
                    #   driver.location = ::Appium::Location.new(10, 10, 10)
         | 
| 41 | 
            +
                    #
         | 
| 42 | 
            +
                    def location=(location)
         | 
| 43 | 
            +
                      unless location.is_a?(::Appium::Location)
         | 
| 44 | 
            +
                        raise TypeError, "expected #{::Appium::Location}, got #{location.inspect}:#{location.class}"
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      @bridge.set_location location.latitude, location.longitude, location.altitude
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    # Set the location of the device.
         | 
| 51 | 
            +
                    #
         | 
| 52 | 
            +
                    # @param [String, Number] latitude Set the latitude.
         | 
| 53 | 
            +
                    # @param [String, Number] longitude Set the longitude.
         | 
| 54 | 
            +
                    # @param [String, Number] altitude Set the altitude.
         | 
| 55 | 
            +
                    # @param [String, Number] speed Set the speed to apply the location on Android real devices
         | 
| 56 | 
            +
                    #                               in meters/second @since Appium 1.21.0 and in knots for emulators @since Appium 1.22.0.
         | 
| 57 | 
            +
                    # @param [String, Number] satellites Sets the count of geo satellites being tracked in range 1..12 @since Appium 1.22.0.
         | 
| 58 | 
            +
                    #                                    This number is respected on Emulators.
         | 
| 59 | 
            +
                    # @param [::Appium::Location]
         | 
| 60 | 
            +
                    #
         | 
| 61 | 
            +
                    # @example
         | 
| 62 | 
            +
                    #
         | 
| 63 | 
            +
                    #   driver.location = ::Appium::Location.new(10, 10, 10)
         | 
| 64 | 
            +
                    #
         | 
| 65 | 
            +
                    def set_location(latitude, longitude, altitude, speed: nil, satellites: nil)
         | 
| 66 | 
            +
                      if speed.nil? && satellites.nil?
         | 
| 67 | 
            +
                        self.location = ::Appium::Location.new(Float(latitude), Float(longitude), Float(altitude))
         | 
| 68 | 
            +
                      else
         | 
| 69 | 
            +
                        loc = ::Appium::Location.new(Float(latitude), Float(longitude), Float(altitude))
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                        speed = Float(speed) unless speed.nil?
         | 
| 72 | 
            +
                        satellites = Integer(satellites) unless satellites.nil?
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                        @bridge.set_location loc.latitude, loc.longitude, loc.altitude, speed: speed, satellites: satellites
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            # you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            # You may obtain a copy of the License at
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
            # Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            # See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            # limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module Appium
         | 
| 16 | 
            +
              module Core
         | 
| 17 | 
            +
                class Base
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  module HasNetworkConnection
         | 
| 22 | 
            +
                    def network_connection_type
         | 
| 23 | 
            +
                      connection_value = @bridge.network_connection
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                      connection_type = values_to_type[connection_value]
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                      # In case the connection type is not recognized return the
         | 
| 28 | 
            +
                      # connection value.
         | 
| 29 | 
            +
                      connection_type || connection_value
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    def network_connection_type=(connection_type)
         | 
| 33 | 
            +
                      raise ::Appium::Core::Error::ArgumentError, 'Invalid connection type' unless valid_type? connection_type
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                      connection_value = type_to_values[connection_type]
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      @bridge.network_connection = connection_value
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    private
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    def type_to_values
         | 
| 43 | 
            +
                      { airplane_mode: 1, wifi: 2, data: 4, all: 6, none: 0 }
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    def values_to_type
         | 
| 47 | 
            +
                      type_to_values.invert
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    def valid_type?(type)
         | 
| 51 | 
            +
                      type_to_values.keys.include? type
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -13,6 +13,8 @@ | |
| 13 13 | 
             
            # limitations under the License.
         | 
| 14 14 |  | 
| 15 15 | 
             
            require 'securerandom'
         | 
| 16 | 
            +
            # to avoid mysterious resolution error 'uninitialized constant Selenium::WebDriver::Remote::Http::Default::Net (NameError)'
         | 
| 17 | 
            +
            require 'net/http'
         | 
| 16 18 |  | 
| 17 19 | 
             
            require_relative '../../version'
         | 
| 18 20 |  | 
| @@ -26,21 +28,15 @@ module Appium | |
| 26 28 | 
             
                      }.freeze
         | 
| 27 29 | 
             
                    end
         | 
| 28 30 |  | 
| 29 | 
            -
                    class Default < Selenium::WebDriver::Remote::Http::Default
         | 
| 30 | 
            -
                      DEFAULT_HEADERS = {
         | 
| 31 | 
            -
                        'Accept' => CONTENT_TYPE,
         | 
| 32 | 
            -
                        'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8",
         | 
| 33 | 
            -
                        'User-Agent' =>
         | 
| 34 | 
            -
                          "appium/ruby_lib_core/#{VERSION} (#{::Selenium::WebDriver::Remote::Http::Common::DEFAULT_HEADERS['User-Agent']})"
         | 
| 35 | 
            -
                      }.freeze
         | 
| 36 | 
            -
             | 
| 31 | 
            +
                    class Default < ::Selenium::WebDriver::Remote::Http::Default
         | 
| 37 32 | 
             
                      attr_reader :additional_headers
         | 
| 38 33 |  | 
| 39 34 | 
             
                      # override
         | 
| 40 | 
            -
                      def initialize(open_timeout: nil, read_timeout: nil) | 
| 35 | 
            +
                      def initialize(open_timeout: nil, read_timeout: nil)
         | 
| 41 36 | 
             
                        @open_timeout = open_timeout
         | 
| 42 37 | 
             
                        @read_timeout = read_timeout
         | 
| 43 38 | 
             
                        @additional_headers = {}
         | 
| 39 | 
            +
                        super
         | 
| 44 40 | 
             
                      end
         | 
| 45 41 |  | 
| 46 42 | 
             
                      # Update <code>server_url</code> provided when ruby_lib _core created a default http client.
         | 
| @@ -55,49 +51,30 @@ module Appium | |
| 55 51 | 
             
                      def update_sending_request_to(scheme:, host:, port:, path:)
         | 
| 56 52 | 
             
                        return @server_url unless validate_url_param(scheme, host, port, path)
         | 
| 57 53 |  | 
| 58 | 
            -
                        ::Appium::Logger.debug("[experimental] This feature, #{__method__}, is an experimental")
         | 
| 59 | 
            -
             | 
| 60 54 | 
             
                        # Add / if 'path' does not have it
         | 
| 61 | 
            -
                        path = path.start_with?('/') | 
| 62 | 
            -
                        path = path.end_with?('/') | 
| 55 | 
            +
                        path = "/#{path}" unless path.start_with?('/')
         | 
| 56 | 
            +
                        path = "#{path}/" unless path.end_with?('/')
         | 
| 63 57 |  | 
| 64 58 | 
             
                        @http = nil
         | 
| 65 59 | 
             
                        @server_url = URI.parse "#{scheme}://#{host}:#{port}#{path}"
         | 
| 66 60 | 
             
                      end
         | 
| 67 61 |  | 
| 62 | 
            +
                      def request(verb, url, headers, payload, redirects = 0)
         | 
| 63 | 
            +
                        headers['User-Agent'] = "appium/ruby_lib_core/#{VERSION} (#{headers['User-Agent']})"
         | 
| 64 | 
            +
                        headers = headers.merge @additional_headers unless @additional_headers.empty?
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                        super(verb, url, headers, payload, redirects)
         | 
| 67 | 
            +
                      end
         | 
| 68 | 
            +
             | 
| 68 69 | 
             
                      private
         | 
| 69 70 |  | 
| 70 71 | 
             
                      def validate_url_param(scheme, host, port, path)
         | 
| 71 72 | 
             
                        return true unless [scheme, host, port, path].include?(nil)
         | 
| 72 73 |  | 
| 73 74 | 
             
                        message = "Given parameters are scheme: '#{scheme}', host: '#{host}', port: '#{port}', path: '#{path}'"
         | 
| 74 | 
            -
                        ::Appium::Logger. | 
| 75 | 
            +
                        ::Appium::Logger.debug(message)
         | 
| 75 76 | 
             
                        false
         | 
| 76 77 | 
             
                      end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                      public
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                      # override to use default header
         | 
| 81 | 
            -
                      # https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/remote/http/common.rb#L46
         | 
| 82 | 
            -
                      def call(verb, url, command_hash)
         | 
| 83 | 
            -
                        url      = server_url.merge(url) unless url.is_a?(URI)
         | 
| 84 | 
            -
                        headers  = DEFAULT_HEADERS.dup
         | 
| 85 | 
            -
                        headers  = headers.merge @additional_headers unless @additional_headers.empty?
         | 
| 86 | 
            -
                        headers['Cache-Control'] = 'no-cache' if verb == :get
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                        if command_hash
         | 
| 89 | 
            -
                          payload                   = JSON.generate(command_hash)
         | 
| 90 | 
            -
                          headers['Content-Length'] = payload.bytesize.to_s if [:post, :put].include?(verb)
         | 
| 91 | 
            -
                        elsif verb == :post
         | 
| 92 | 
            -
                          payload = '{}'
         | 
| 93 | 
            -
                          headers['Content-Length'] = '2'
         | 
| 94 | 
            -
                        end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                        ::Appium::Logger.info("   >>> #{url} | #{payload}")
         | 
| 97 | 
            -
                        ::Appium::Logger.info("     > #{headers.inspect}")
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                        request verb, url, headers, payload
         | 
| 100 | 
            -
                      end
         | 
| 101 78 | 
             
                    end
         | 
| 102 79 | 
             
                  end
         | 
| 103 80 | 
             
                end
         | 
| @@ -14,15 +14,16 @@ | |
| 14 14 |  | 
| 15 15 | 
             
            module Appium
         | 
| 16 16 | 
             
              module Core
         | 
| 17 | 
            -
                 | 
| 18 | 
            -
                   | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                        target.extend Appium::Core::Ios::Device
         | 
| 17 | 
            +
                class Base
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  #
         | 
| 22 21 |  | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 22 | 
            +
                  module HasRemoteStatus
         | 
| 23 | 
            +
                    # Selenium binding has this ability only in Remote Binding,
         | 
| 24 | 
            +
                    # so this library has this method by own for safe.
         | 
| 25 | 
            +
                    def remote_status
         | 
| 26 | 
            +
                      bridge.status
         | 
| 26 27 | 
             
                    end
         | 
| 27 28 | 
             
                  end
         | 
| 28 29 | 
             
                end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            # you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            # You may obtain a copy of the License at
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
            # Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            # See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            # limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module Appium
         | 
| 16 | 
            +
              module Core
         | 
| 17 | 
            +
                class Base
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  module Rotatable
         | 
| 23 | 
            +
                    ORIENTATIONS = %i[
         | 
| 24 | 
            +
                      landscape
         | 
| 25 | 
            +
                      portrait
         | 
| 26 | 
            +
                      uia_device_orientation_landscaperight
         | 
| 27 | 
            +
                      uia_device_orientation_portrait_upsidedown
         | 
| 28 | 
            +
                    ].freeze
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    #
         | 
| 31 | 
            +
                    # Change the screen orientation
         | 
| 32 | 
            +
                    #
         | 
| 33 | 
            +
                    # @param [:landscape, :portrait,
         | 
| 34 | 
            +
                    #         :uia_device_orientation_landscaperight, :uia_device_orientation_portrait_upsidedown] orientation
         | 
| 35 | 
            +
                    #
         | 
| 36 | 
            +
                    #
         | 
| 37 | 
            +
                    def rotation=(orientation)
         | 
| 38 | 
            +
                      unless ORIENTATIONS.include?(orientation)
         | 
| 39 | 
            +
                        raise ::Appium::Core::Error::ArgumentError, "expected #{ORIENTATIONS.inspect}, got #{orientation.inspect}"
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      bridge.screen_orientation = orientation.to_s.upcase
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                    alias rotate rotation=
         | 
| 45 | 
            +
                    alias orientation= rotation=
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    #
         | 
| 48 | 
            +
                    # Get the current screen orientation
         | 
| 49 | 
            +
                    #
         | 
| 50 | 
            +
                    # @return [:landscape, :portrait,
         | 
| 51 | 
            +
                    #          :uia_device_orientation_landscaperight, :uia_device_orientation_portrait_upsidedown] orientation
         | 
| 52 | 
            +
                    #
         | 
| 53 | 
            +
                    # @api public
         | 
| 54 | 
            +
                    #
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def orientation
         | 
| 57 | 
            +
                      bridge.screen_orientation.to_sym.downcase
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -15,7 +15,7 @@ | |
| 15 15 | 
             
            module Appium
         | 
| 16 16 | 
             
              module Core
         | 
| 17 17 | 
             
                class Base
         | 
| 18 | 
            -
                  module  | 
| 18 | 
            +
                  module TakesScreenshot
         | 
| 19 19 | 
             
                    #
         | 
| 20 20 | 
             
                    # Save a PNG screenshot to the given path
         | 
| 21 21 | 
             
                    #
         | 
| @@ -24,7 +24,7 @@ module Appium | |
| 24 24 | 
             
                    def save_screenshot(png_path)
         | 
| 25 25 | 
             
                      extension = File.extname(png_path).downcase
         | 
| 26 26 | 
             
                      if extension != '.png'
         | 
| 27 | 
            -
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
         | 
| 27 | 
            +
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. ' \
         | 
| 28 28 | 
             
                                              'It should end with .png extension'
         | 
| 29 29 | 
             
                      end
         | 
| 30 30 | 
             
                      File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
         | 
| @@ -63,8 +63,8 @@ module Appium | |
| 63 63 | 
             
                    def save_element_screenshot(element, png_path)
         | 
| 64 64 | 
             
                      extension = File.extname(png_path).downcase
         | 
| 65 65 | 
             
                      if extension != '.png'
         | 
| 66 | 
            -
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
         | 
| 67 | 
            -
             | 
| 66 | 
            +
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. ' \
         | 
| 67 | 
            +
                                              'It should end with .png extension'
         | 
| 68 68 | 
             
                      end
         | 
| 69 69 | 
             
                      File.open(png_path, 'wb') { |f| f << element_screenshot_as(element, :png) }
         | 
| 70 70 | 
             
                    end
         | 
| @@ -84,9 +84,9 @@ module Appium | |
| 84 84 | 
             
                    def element_screenshot_as(element, format)
         | 
| 85 85 | 
             
                      case format
         | 
| 86 86 | 
             
                      when :base64
         | 
| 87 | 
            -
                        bridge. | 
| 87 | 
            +
                        bridge.element_screenshot element.id
         | 
| 88 88 | 
             
                      when :png
         | 
| 89 | 
            -
                        bridge. | 
| 89 | 
            +
                        bridge.element_screenshot(element.id).unpack('m')[0]
         | 
| 90 90 | 
             
                      else
         | 
| 91 91 | 
             
                        raise Core::Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
         | 
| 92 92 | 
             
                      end
         | 
| @@ -103,10 +103,10 @@ module Appium | |
| 103 103 | 
             
                    def save_viewport_screenshot(png_path)
         | 
| 104 104 | 
             
                      extension = File.extname(png_path).downcase
         | 
| 105 105 | 
             
                      if extension != '.png'
         | 
| 106 | 
            -
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
         | 
| 106 | 
            +
                        ::Appium::Logger.warn 'name used for saved screenshot does not match file type. ' \
         | 
| 107 107 | 
             
                                              'It should end with .png extension'
         | 
| 108 108 | 
             
                      end
         | 
| 109 | 
            -
                      viewport_screenshot_encode64 = bridge. | 
| 109 | 
            +
                      viewport_screenshot_encode64 = bridge.viewport_screenshot
         | 
| 110 110 | 
             
                      File.open(png_path, 'wb') { |f| f << viewport_screenshot_encode64.unpack('m')[0] }
         | 
| 111 111 | 
             
                    end
         | 
| 112 112 | 
             
                  end
         | 
| @@ -28,13 +28,8 @@ module Appium | |
| 28 28 | 
             
                      data_matcher:         '-android datamatcher', # Available in Espresso
         | 
| 29 29 | 
             
                      view_matcher:         '-android viewmatcher', # Available in Espresso
         | 
| 30 30 | 
             
                      # iOS
         | 
| 31 | 
            -
                      uiautomation:         '-ios uiautomation',
         | 
| 32 31 | 
             
                      predicate:            '-ios predicate string',
         | 
| 33 | 
            -
                      class_chain:          '-ios class chain' | 
| 34 | 
            -
                      # Windows with windows prefix
         | 
| 35 | 
            -
                      windows_uiautomation: '-windows uiautomation',
         | 
| 36 | 
            -
                      # Tizen with Tizen prefix
         | 
| 37 | 
            -
                      tizen_uiautomation:   '-tizen uiautomation'
         | 
| 32 | 
            +
                      class_chain:          '-ios class chain'
         | 
| 38 33 | 
             
                    )
         | 
| 39 34 |  | 
| 40 35 | 
             
                    # rubocop:disable Layout/LineLength
         | 
| @@ -47,7 +42,7 @@ module Appium | |
| 47 42 | 
             
                    #
         | 
| 48 43 | 
             
                    # == Find with image
         | 
| 49 44 | 
             
                    # Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
         | 
| 50 | 
            -
                    # {https://github.com/appium/appium/blob/ | 
| 45 | 
            +
                    # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
         | 
| 51 46 | 
             
                    #
         | 
| 52 47 | 
             
                    # You can handle settings for the comparision following {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 here}
         | 
| 53 48 | 
             
                    #
         | 
| @@ -121,12 +116,6 @@ module Appium | |
| 121 116 | 
             
                    #     e = find_element :class_chain, "**/XCUIElementTypeStaticText[$name == 'Buttons'$]"
         | 
| 122 117 | 
             
                    #     e.tag_name #=> "XCUIElementTypeStaticText"
         | 
| 123 118 | 
             
                    #
         | 
| 124 | 
            -
                    #     # For Windows
         | 
| 125 | 
            -
                    #     @driver.find_elements :windows_uiautomation, '....'
         | 
| 126 | 
            -
                    #
         | 
| 127 | 
            -
                    #     # For Tizen
         | 
| 128 | 
            -
                    #     @driver.find_elements :tizen_uiautomation, '....'
         | 
| 129 | 
            -
                    #
         | 
| 130 119 | 
             
                    # rubocop:enable Layout/LineLength
         | 
| 131 120 | 
             
                    def find_element(*args)
         | 
| 132 121 | 
             
                      how, what = extract_args(args)
         | 
| @@ -141,6 +130,8 @@ module Appium | |
| 141 130 | 
             
                    #
         | 
| 142 131 | 
             
                    # Find all elements matching the given arguments
         | 
| 143 132 | 
             
                    #
         | 
| 133 | 
            +
                    # @return [Array<Selenium::WebDriver::Element>]
         | 
| 134 | 
            +
                    #
         | 
| 144 135 | 
             
                    # @see SearchContext#find_elements
         | 
| 145 136 | 
             
                    #
         | 
| 146 137 | 
             
                    def find_elements(*args)
         | 
| @@ -157,7 +148,10 @@ module Appium | |
| 157 148 |  | 
| 158 149 | 
             
                    def _set_by_from_finders(how)
         | 
| 159 150 | 
             
                      by = FINDERS[how.to_sym]
         | 
| 160 | 
            -
                       | 
| 151 | 
            +
                      unless by
         | 
| 152 | 
            +
                        raise ::Appium::Core::Error::ArgumentError,
         | 
| 153 | 
            +
                              "cannot find element by #{how.inspect}. Available finders are #{FINDERS.keys}."
         | 
| 154 | 
            +
                      end
         | 
| 161 155 |  | 
| 162 156 | 
             
                      by
         | 
| 163 157 | 
             
                    end
         | 
| @@ -169,16 +163,18 @@ module Appium | |
| 169 163 | 
             
                      when 1
         | 
| 170 164 | 
             
                        arg = args.first
         | 
| 171 165 |  | 
| 172 | 
            -
                         | 
| 166 | 
            +
                        unless arg.respond_to?(:shift)
         | 
| 167 | 
            +
                          raise ::Appium::Core::Error::ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
         | 
| 168 | 
            +
                        end
         | 
| 173 169 |  | 
| 174 170 | 
             
                        # this will be a single-entry hash, so use #shift over #first or #[]
         | 
| 175 171 | 
             
                        arr = arg.dup.shift
         | 
| 176 172 |  | 
| 177 | 
            -
                        raise ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
         | 
| 173 | 
            +
                        raise ::Appium::Core::Error::ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
         | 
| 178 174 |  | 
| 179 175 | 
             
                        arr
         | 
| 180 176 | 
             
                      else
         | 
| 181 | 
            -
                        raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
         | 
| 177 | 
            +
                        raise ::Appium::Core::Error::ArgumentError, "wrong number of arguments (#{args.size} for 2)"
         | 
| 182 178 | 
             
                      end
         | 
| 183 179 | 
             
                    end
         | 
| 184 180 | 
             
                  end # module SearchContext
         | 
| @@ -17,7 +17,6 @@ require_relative 'device/keyboard' | |
| 17 17 | 
             
            require_relative 'device/ime_actions'
         | 
| 18 18 | 
             
            require_relative 'device/setting'
         | 
| 19 19 | 
             
            require_relative 'device/context'
         | 
| 20 | 
            -
            require_relative 'device/value'
         | 
| 21 20 | 
             
            require_relative 'device/file_management'
         | 
| 22 21 | 
             
            require_relative 'device/keyevent'
         | 
| 23 22 | 
             
            require_relative 'device/image_comparison'
         | 
| @@ -27,16 +26,13 @@ require_relative 'device/screen_record' | |
| 27 26 | 
             
            require_relative 'device/battery_status'
         | 
| 28 27 | 
             
            require_relative 'device/clipboard_content_type'
         | 
| 29 28 | 
             
            require_relative 'device/device'
         | 
| 30 | 
            -
            require_relative 'device/touch_actions'
         | 
| 31 29 | 
             
            require_relative 'device/execute_driver'
         | 
| 30 | 
            +
            require_relative 'device/orientation'
         | 
| 32 31 |  | 
| 33 32 | 
             
            # The following files have selenium-webdriver related stuff.
         | 
| 34 33 | 
             
            require_relative 'base/driver'
         | 
| 35 34 | 
             
            require_relative 'base/bridge'
         | 
| 36 | 
            -
            require_relative 'base/bridge/mjsonwp'
         | 
| 37 | 
            -
            require_relative 'base/bridge/w3c'
         | 
| 38 35 | 
             
            require_relative 'base/capabilities'
         | 
| 39 36 | 
             
            require_relative 'base/http_default'
         | 
| 40 37 | 
             
            require_relative 'base/search_context'
         | 
| 41 | 
            -
            require_relative 'base/command'
         | 
| 42 38 | 
             
            require_relative 'base/platform'
         |