Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/remote/capabilities.rb
1865 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
module Selenium
21
module WebDriver
22
module Remote
23
#
24
# Specification of the desired and/or actual capabilities of the browser that the
25
# server is being asked to create.
26
#
27
28
class Capabilities
29
KNOWN = [
30
:browser_name,
31
:browser_version,
32
:platform_name,
33
:accept_insecure_certs,
34
:page_load_strategy,
35
:proxy,
36
:set_window_rect,
37
:timeouts,
38
:unhandled_prompt_behavior,
39
:strict_file_interactability,
40
:web_socket_url,
41
42
# remote-specific (webdriver.remote.sessionid)
43
:remote_session_id
44
].freeze
45
46
(KNOWN - %i[proxy timeouts]).each do |key|
47
define_method key do
48
@capabilities[key]
49
end
50
51
define_method :"#{key}=" do |value|
52
@capabilities[key] = value
53
end
54
end
55
56
#
57
# Convenience methods for the common choices.
58
#
59
60
class << self
61
def always_match(capabilities)
62
new(always_match: capabilities)
63
end
64
65
def first_match(*capabilities)
66
new(first_match: capabilities)
67
end
68
69
#
70
# @api private
71
#
72
73
def json_create(data)
74
data = data.dup
75
caps = new
76
77
process_timeouts(caps, data.delete('timeouts'))
78
79
if data.key?('proxy')
80
proxy = data.delete('proxy')
81
caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
82
end
83
84
# Remote Server Specific
85
if data.key?('webdriver.remote.sessionid')
86
caps[:remote_session_id] =
87
data.delete('webdriver.remote.sessionid')
88
end
89
90
KNOWN.each do |cap|
91
data_value = camel_case(cap)
92
caps[cap] = data.delete(data_value) if data.key?(data_value)
93
end
94
95
# any remaining pairs will be added as is, with no conversion
96
caps.merge!(data)
97
98
caps
99
end
100
101
def camel_case(str_or_sym)
102
str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }
103
end
104
105
private
106
107
def process_timeouts(caps, timeouts)
108
return if timeouts.nil?
109
110
caps.implicit_timeout = timeouts['implicit']
111
caps.page_load_timeout = timeouts['pageLoad']
112
caps.script_timeout = timeouts['script']
113
end
114
end
115
116
#
117
# @param [Hash] opts
118
# @option :browser_name [String] required browser name
119
# @option :browser_version [String] required browser version number
120
# @option :platform_name [Symbol] one of :any, :win, :mac, or :x
121
# @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
122
# @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
123
#
124
# @api public
125
#
126
127
def initialize(opts = {})
128
@capabilities = {}
129
self.proxy = opts.delete(:proxy) if opts[:proxy]
130
@capabilities.merge!(opts)
131
end
132
133
#
134
# Allows setting arbitrary capabilities.
135
#
136
137
def []=(key, value)
138
@capabilities[key] = value
139
end
140
141
def [](key)
142
@capabilities[key]
143
end
144
145
def merge!(other)
146
if other.respond_to?(:capabilities, true) && other.capabilities.is_a?(Hash)
147
@capabilities.merge! other.capabilities
148
elsif other.is_a? Hash
149
@capabilities.merge! other
150
else
151
raise ArgumentError, 'argument should be a Hash or implement #capabilities'
152
end
153
end
154
155
def proxy
156
@capabilities[:proxy]
157
end
158
159
def proxy=(proxy)
160
case proxy
161
when Hash
162
@capabilities[:proxy] = Proxy.new(proxy)
163
when Proxy, nil
164
@capabilities[:proxy] = proxy
165
else
166
raise TypeError, "expected Hash or #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}"
167
end
168
end
169
170
def timeouts
171
@capabilities[:timeouts] ||= {}
172
end
173
174
def timeouts=(timeouts)
175
@capabilities[:timeouts] = timeouts
176
end
177
178
def implicit_timeout
179
timeouts[:implicit]
180
end
181
182
def implicit_timeout=(timeout)
183
timeouts[:implicit] = timeout
184
end
185
186
def page_load_timeout
187
timeouts[:page_load] || timeouts[:pageLoad]
188
end
189
190
def page_load_timeout=(timeout)
191
timeouts[:page_load] = timeout
192
end
193
194
def script_timeout
195
timeouts[:script]
196
end
197
198
def script_timeout=(timeout)
199
timeouts[:script] = timeout
200
end
201
202
#
203
# @api private
204
#
205
206
def as_json(*)
207
@capabilities.each_with_object({}) do |(key, value), hash|
208
hash[convert_key(key)] = process_capabilities(key, value, hash)
209
end
210
end
211
212
def to_json(*)
213
JSON.generate as_json
214
end
215
216
def ==(other)
217
return false unless other.is_a? self.class
218
219
as_json == other.as_json
220
end
221
222
alias eql? ==
223
224
protected
225
226
attr_reader :capabilities
227
228
private
229
230
def process_capabilities(key, value, hash)
231
case value
232
when Array
233
value.map { |v| process_capabilities(key, v, hash) }
234
when Hash
235
value.each_with_object({}) do |(k, v), h|
236
h[convert_key(k)] = process_capabilities(k, v, h)
237
end
238
when Capabilities, Options
239
value.as_json
240
else
241
convert_value(key, value)
242
end
243
end
244
245
def convert_key(key)
246
case key
247
when String
248
key.to_s
249
when Symbol
250
self.class.camel_case(key)
251
else
252
raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
253
end
254
end
255
256
def convert_value(key, value)
257
case key
258
when :platform
259
value.to_s.upcase
260
when :proxy
261
value&.as_json
262
when :unhandled_prompt_behavior
263
value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
264
else
265
value
266
end
267
end
268
end # Capabilities
269
end # Remote
270
end # WebDriver
271
end # Selenium
272
273