File: capabilities.rb

package info (click to toggle)
ruby-selenium-webdriver 3.142.7%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,592 kB
  • sloc: ruby: 6,740; javascript: 85; makefile: 3
file content (310 lines) | stat: -rwxr-xr-x 10,898 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

module Selenium
  module WebDriver
    module Remote
      module W3C

        #
        # Specification of the desired and/or actual capabilities of the browser that the
        # server is being asked to create.
        #
        # @api private
        #

        class Capabilities

          EXTENSION_CAPABILITY_PATTERN = /\A[\w-]+:.*\z/.freeze

          KNOWN = [
            :browser_name,
            :browser_version,
            :platform_name,
            :accept_insecure_certs,
            :page_load_strategy,
            :proxy,
            :set_window_rect,
            :timeouts,
            :unhandled_prompt_behavior,
            :strict_file_interactability,

            # remote-specific
            :remote_session_id,

            # TODO: (alex) deprecate in favor of Firefox::Options?
            :accessibility_checks,
            :device,

            # TODO: (alex) deprecate compatibility with OSS-capabilities
            :implicit_timeout,
            :page_load_timeout,
            :script_timeout
          ].freeze

          KNOWN.each do |key|
            define_method key do
              @capabilities.fetch(key)
            end

            next if key == :proxy

            define_method "#{key}=" do |value|
              case key
              when :accessibility_checks
                WebDriver.logger.deprecate(":accessibility_checks capability")
              when :device
                WebDriver.logger.deprecate(":device capability")
              end
              @capabilities[key] = value
            end
          end

          #
          # Backward compatibility
          #

          alias_method :version, :browser_version
          alias_method :version=, :browser_version=
          alias_method :platform, :platform_name
          alias_method :platform=, :platform_name=

          #
          # Convenience methods for the common choices.
          #

          class << self
            def edge(opts = {})
              WebDriver.logger.deprecate('Selenium::WebDriver::Remote::W3C::Capabilities.edge',
                                         'Selenium::WebDriver::Remote::Capabilities.edge')
              Remote::Capabilities.edge(opts)
            end

            def firefox(opts = {})
              WebDriver.logger.deprecate('Selenium::WebDriver::Remote::W3C::Capabilities.firefox',
                                         'Selenium::WebDriver::Remote::Capabilities.firefox')
              Remote::Capabilities.firefox(opts)
            end

            alias_method :ff, :firefox

            #
            # @api private
            #

            def json_create(data)
              data = data.dup

              caps = new
              caps.browser_name = data.delete('browserName')
              caps.browser_version = data.delete('browserVersion')
              caps.platform_name = data.delete('platformName')
              caps.accept_insecure_certs = data.delete('acceptInsecureCerts') if data.key?('acceptInsecureCerts')
              caps.page_load_strategy = data.delete('pageLoadStrategy')
              timeouts = data.delete('timeouts')
              caps.implicit_timeout = timeouts['implicit'] if timeouts
              caps.page_load_timeout = timeouts['pageLoad'] if timeouts
              caps.script_timeout = timeouts['script'] if timeouts

              proxy = data.delete('proxy')
              caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?

              # Remote Server Specific
              caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')

              # Marionette Specific
              caps[:accessibility_checks] = data.delete('moz:accessibilityChecks')
              caps[:profile] = data.delete('moz:profile')
              caps[:rotatable] = data.delete('rotatable')
              caps[:device] = data.delete('device')

              # any remaining pairs will be added as is, with no conversion
              caps.merge!(data)

              caps
            end

            #
            # Creates W3C compliant capabilities from OSS ones.
            # @param oss_capabilities [Hash, Remote::Capabilities]
            #

            def from_oss(oss_capabilities) # rubocop:disable Metrics/MethodLength
              w3c_capabilities = new

              # TODO: (alex) make capabilities enumerable?
              oss_capabilities = oss_capabilities.__send__(:capabilities) unless oss_capabilities.is_a?(Hash)
              oss_capabilities.each do |name, value|
                next if value.nil?
                next if value.is_a?(String) && value.empty?

                capability_name = name.to_s

                snake_cased_capability_names = KNOWN.map(&:to_s)
                camel_cased_capability_names = snake_cased_capability_names.map(&w3c_capabilities.method(:camel_case))

                next unless snake_cased_capability_names.include?(capability_name) ||
                            camel_cased_capability_names.include?(capability_name) ||
                            capability_name.match(EXTENSION_CAPABILITY_PATTERN)

                w3c_capabilities[name] = value
              end

              # User can pass :firefox_options or :firefox_profile.
              #
              # TODO: (alex) Refactor this whole method into converter class.
              firefox_options = oss_capabilities['firefoxOptions'] || oss_capabilities['firefox_options'] || oss_capabilities[:firefox_options]
              firefox_profile = oss_capabilities['firefox_profile'] || oss_capabilities[:firefox_profile]
              firefox_binary  = oss_capabilities['firefox_binary'] || oss_capabilities[:firefox_binary]

              if firefox_options
                WebDriver.logger.deprecate(':firefox_options capabilitiy', 'Selenium::WebDriver::Firefox::Options')
              end

              if firefox_profile
                WebDriver.logger.deprecate(':firefox_profile capabilitiy', 'Selenium::WebDriver::Firefox::Options#profile')
              end

              if firefox_binary
                WebDriver.logger.deprecate(':firefox_binary capabilitiy', 'Selenium::WebDriver::Firefox::Options#binary')
              end

              if firefox_profile && firefox_options
                second_profile = firefox_options['profile'] || firefox_options[:profile]
                if second_profile && firefox_profile != second_profile
                  raise Error::WebDriverError, 'You cannot pass 2 different Firefox profiles'
                end
              end

              if firefox_options || firefox_profile || firefox_binary
                options = WebDriver::Firefox::Options.new(firefox_options || {})
                options.binary = firefox_binary if firefox_binary
                options.profile = firefox_profile if firefox_profile
                w3c_capabilities.merge!(options.as_json)
              end

              w3c_capabilities
            end
          end

          #
          # @param [Hash] opts
          # @option :browser_name             [String] required browser name
          # @option :browser_version          [String] required browser version number
          # @option :platform_name            [Symbol] one of :any, :win, :mac, or :x
          # @option :accept_insecure_certs    [Boolean] does the driver accept insecure SSL certifications?
          # @option :proxy                    [Selenium::WebDriver::Proxy, Hash] proxy configuration
          #
          # @api public
          #

          def initialize(opts = {})
            @capabilities = opts
            self.proxy = opts.delete(:proxy)
          end

          #
          # Allows setting arbitrary capabilities.
          #

          def []=(key, value)
            @capabilities[key] = value
          end

          def [](key)
            @capabilities[key]
          end

          def merge!(other)
            if other.respond_to?(:capabilities, true) && other.capabilities.is_a?(Hash)
              @capabilities.merge! other.capabilities
            elsif other.is_a? Hash
              @capabilities.merge! other
            else
              raise ArgumentError, 'argument should be a Hash or implement #capabilities'
            end
          end

          def proxy=(proxy)
            case proxy
            when Hash
              @capabilities[:proxy] = Proxy.new(proxy)
            when Proxy, nil
              @capabilities[:proxy] = proxy
            else
              raise TypeError, "expected Hash or #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}"
            end
          end

          #
          # @api private
          #

          def as_json(*)
            hash = {}

            @capabilities.each do |key, value|
              case key
              when :platform
                hash['platform'] = value.to_s.upcase
              when :proxy
                if value
                  hash['proxy'] = value.as_json
                  hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
                  hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ') if hash['proxy']['noProxy'].is_a?(String)
                end
              when String, :firefox_binary
                hash[key.to_s] = value
              when Symbol
                hash[camel_case(key.to_s)] = value
              else
                raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
              end
            end

            hash
          end

          def to_json(*)
            JSON.generate as_json
          end

          def ==(other)
            return false unless other.is_a? self.class

            as_json == other.as_json
          end

          alias_method :eql?, :==

          protected

          attr_reader :capabilities

          private

          def camel_case(str)
            str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
          end

        end # Capabilities
      end # W3c
    end # Remote
  end # WebDriver
end # Selenium