Path: blob/trunk/rb/lib/selenium/webdriver/remote/capabilities.rb
1865 views
# frozen_string_literal: true12# Licensed to the Software Freedom Conservancy (SFC) under one3# or more contributor license agreements. See the NOTICE file4# distributed with this work for additional information5# regarding copyright ownership. The SFC licenses this file6# to you under the Apache License, Version 2.0 (the7# "License"); you may not use this file except in compliance8# with the License. You may obtain a copy of the License at9#10# http://www.apache.org/licenses/LICENSE-2.011#12# Unless required by applicable law or agreed to in writing,13# software distributed under the License is distributed on an14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15# KIND, either express or implied. See the License for the16# specific language governing permissions and limitations17# under the License.1819module Selenium20module WebDriver21module Remote22#23# Specification of the desired and/or actual capabilities of the browser that the24# server is being asked to create.25#2627class Capabilities28KNOWN = [29:browser_name,30:browser_version,31:platform_name,32:accept_insecure_certs,33:page_load_strategy,34:proxy,35:set_window_rect,36:timeouts,37:unhandled_prompt_behavior,38:strict_file_interactability,39:web_socket_url,4041# remote-specific (webdriver.remote.sessionid)42:remote_session_id43].freeze4445(KNOWN - %i[proxy timeouts]).each do |key|46define_method key do47@capabilities[key]48end4950define_method :"#{key}=" do |value|51@capabilities[key] = value52end53end5455#56# Convenience methods for the common choices.57#5859class << self60def always_match(capabilities)61new(always_match: capabilities)62end6364def first_match(*capabilities)65new(first_match: capabilities)66end6768#69# @api private70#7172def json_create(data)73data = data.dup74caps = new7576process_timeouts(caps, data.delete('timeouts'))7778if data.key?('proxy')79proxy = data.delete('proxy')80caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?81end8283# Remote Server Specific84if data.key?('webdriver.remote.sessionid')85caps[:remote_session_id] =86data.delete('webdriver.remote.sessionid')87end8889KNOWN.each do |cap|90data_value = camel_case(cap)91caps[cap] = data.delete(data_value) if data.key?(data_value)92end9394# any remaining pairs will be added as is, with no conversion95caps.merge!(data)9697caps98end99100def camel_case(str_or_sym)101str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }102end103104private105106def process_timeouts(caps, timeouts)107return if timeouts.nil?108109caps.implicit_timeout = timeouts['implicit']110caps.page_load_timeout = timeouts['pageLoad']111caps.script_timeout = timeouts['script']112end113end114115#116# @param [Hash] opts117# @option :browser_name [String] required browser name118# @option :browser_version [String] required browser version number119# @option :platform_name [Symbol] one of :any, :win, :mac, or :x120# @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?121# @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration122#123# @api public124#125126def initialize(opts = {})127@capabilities = {}128self.proxy = opts.delete(:proxy) if opts[:proxy]129@capabilities.merge!(opts)130end131132#133# Allows setting arbitrary capabilities.134#135136def []=(key, value)137@capabilities[key] = value138end139140def [](key)141@capabilities[key]142end143144def merge!(other)145if other.respond_to?(:capabilities, true) && other.capabilities.is_a?(Hash)146@capabilities.merge! other.capabilities147elsif other.is_a? Hash148@capabilities.merge! other149else150raise ArgumentError, 'argument should be a Hash or implement #capabilities'151end152end153154def proxy155@capabilities[:proxy]156end157158def proxy=(proxy)159case proxy160when Hash161@capabilities[:proxy] = Proxy.new(proxy)162when Proxy, nil163@capabilities[:proxy] = proxy164else165raise TypeError, "expected Hash or #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}"166end167end168169def timeouts170@capabilities[:timeouts] ||= {}171end172173def timeouts=(timeouts)174@capabilities[:timeouts] = timeouts175end176177def implicit_timeout178timeouts[:implicit]179end180181def implicit_timeout=(timeout)182timeouts[:implicit] = timeout183end184185def page_load_timeout186timeouts[:page_load] || timeouts[:pageLoad]187end188189def page_load_timeout=(timeout)190timeouts[:page_load] = timeout191end192193def script_timeout194timeouts[:script]195end196197def script_timeout=(timeout)198timeouts[:script] = timeout199end200201#202# @api private203#204205def as_json(*)206@capabilities.each_with_object({}) do |(key, value), hash|207hash[convert_key(key)] = process_capabilities(key, value, hash)208end209end210211def to_json(*)212JSON.generate as_json213end214215def ==(other)216return false unless other.is_a? self.class217218as_json == other.as_json219end220221alias eql? ==222223protected224225attr_reader :capabilities226227private228229def process_capabilities(key, value, hash)230case value231when Array232value.map { |v| process_capabilities(key, v, hash) }233when Hash234value.each_with_object({}) do |(k, v), h|235h[convert_key(k)] = process_capabilities(k, v, h)236end237when Capabilities, Options238value.as_json239else240convert_value(key, value)241end242end243244def convert_key(key)245case key246when String247key.to_s248when Symbol249self.class.camel_case(key)250else251raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"252end253end254255def convert_value(key, value)256case key257when :platform258value.to_s.upcase259when :proxy260value&.as_json261when :unhandled_prompt_behavior262value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value263else264value265end266end267end # Capabilities268end # Remote269end # WebDriver270end # Selenium271272273