File: //lib/ruby/vendor_ruby/selenium/webdriver/remote/w3c/capabilities.rb
# 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