selenium-webdriver 4.0.0.beta2 → 4.0.0.rc2
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/CHANGES +1947 -0
- data/Gemfile +6 -0
- data/LICENSE +202 -0
- data/NOTICE +2 -0
- data/README.md +34 -0
- data/lib/selenium/webdriver/atoms/findElements.js +0 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +25 -25
- data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
- data/lib/selenium/webdriver/chrome/driver.rb +16 -4
- data/lib/selenium/webdriver/chrome/features.rb +44 -4
- data/lib/selenium/webdriver/chrome/options.rb +25 -2
- data/lib/selenium/webdriver/chrome/profile.rb +5 -2
- data/lib/selenium/webdriver/common/driver.rb +5 -1
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -17
- data/lib/selenium/{devtools.rb → webdriver/common/driver_extensions/has_launching.rb} +16 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -6
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +8 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +87 -18
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/prints_page.rb +28 -1
- data/lib/selenium/webdriver/common/element.rb +35 -6
- data/lib/selenium/webdriver/common/error.rb +12 -0
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/manager.rb +3 -13
- data/lib/selenium/webdriver/common/options.rb +31 -12
- data/lib/selenium/webdriver/common/proxy.rb +2 -2
- data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
- data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
- data/lib/selenium/webdriver/common/takes_screenshot.rb +9 -6
- data/lib/selenium/webdriver/common/target_locator.rb +28 -0
- data/lib/selenium/webdriver/common/window.rb +0 -4
- data/lib/selenium/webdriver/common.rb +8 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
- data/lib/selenium/webdriver/devtools/request.rb +27 -17
- data/lib/selenium/webdriver/devtools/response.rb +66 -0
- data/lib/selenium/webdriver/devtools.rb +50 -12
- data/lib/selenium/webdriver/edge/features.rb +5 -0
- data/lib/selenium/webdriver/edge/options.rb +0 -0
- data/lib/selenium/webdriver/edge/profile.rb +0 -0
- data/lib/selenium/webdriver/firefox/driver.rb +15 -2
- data/lib/selenium/webdriver/firefox/features.rb +20 -1
- data/lib/selenium/webdriver/firefox/options.rb +24 -1
- data/lib/selenium/webdriver/firefox.rb +0 -1
- data/lib/selenium/webdriver/ie/options.rb +3 -1
- data/lib/selenium/webdriver/ie/service.rb +1 -1
- data/lib/selenium/webdriver/remote/bridge.rb +43 -13
- data/lib/selenium/webdriver/remote/capabilities.rb +97 -53
- data/lib/selenium/webdriver/remote/commands.rb +5 -0
- data/lib/selenium/webdriver/remote/driver.rb +7 -7
- data/lib/selenium/webdriver/remote.rb +1 -1
- data/lib/selenium/webdriver/safari/driver.rb +1 -1
- data/lib/selenium/webdriver/safari/options.rb +7 -0
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +2 -2
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +1 -1
- data/selenium-webdriver.gemspec +63 -0
- metadata +60 -44
@@ -143,7 +143,7 @@ module Selenium
|
|
143
143
|
#
|
144
144
|
|
145
145
|
def dom_attribute(name)
|
146
|
-
bridge.element_dom_attribute
|
146
|
+
bridge.element_dom_attribute @id, name
|
147
147
|
end
|
148
148
|
|
149
149
|
#
|
@@ -157,7 +157,27 @@ module Selenium
|
|
157
157
|
#
|
158
158
|
|
159
159
|
def property(name)
|
160
|
-
bridge.element_property
|
160
|
+
bridge.element_property @id, name
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Gets the computed WAI-ARIA role of element
|
165
|
+
#
|
166
|
+
# @return [String]
|
167
|
+
#
|
168
|
+
|
169
|
+
def aria_role
|
170
|
+
bridge.element_aria_role @id
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Gets the computed WAI-ARIA label of element.
|
175
|
+
#
|
176
|
+
# @return [String]
|
177
|
+
#
|
178
|
+
|
179
|
+
def accessible_name
|
180
|
+
bridge.element_aria_label @id
|
161
181
|
end
|
162
182
|
|
163
183
|
#
|
@@ -297,6 +317,16 @@ module Selenium
|
|
297
317
|
bridge.element_size @id
|
298
318
|
end
|
299
319
|
|
320
|
+
#
|
321
|
+
# Returns the shadow root of an element.
|
322
|
+
#
|
323
|
+
# @return [WebDriver::ShadowRoot]
|
324
|
+
#
|
325
|
+
|
326
|
+
def shadow_root
|
327
|
+
bridge.shadow_root @id
|
328
|
+
end
|
329
|
+
|
300
330
|
#-------------------------------- sugar --------------------------------
|
301
331
|
|
302
332
|
#
|
@@ -316,14 +346,13 @@ module Selenium
|
|
316
346
|
#
|
317
347
|
alias_method :[], :attribute
|
318
348
|
|
319
|
-
#
|
320
|
-
# for SearchContext and execute_script
|
321
349
|
#
|
322
350
|
# @api private
|
351
|
+
# @see SearchContext
|
323
352
|
#
|
324
353
|
|
325
354
|
def ref
|
326
|
-
@id
|
355
|
+
[:element, @id]
|
327
356
|
end
|
328
357
|
|
329
358
|
#
|
@@ -359,7 +388,7 @@ module Selenium
|
|
359
388
|
end
|
360
389
|
|
361
390
|
def screenshot
|
362
|
-
bridge.element_screenshot(
|
391
|
+
bridge.element_screenshot(@id)
|
363
392
|
end
|
364
393
|
end # Element
|
365
394
|
end # WebDriver
|
@@ -61,6 +61,12 @@ module Selenium
|
|
61
61
|
|
62
62
|
class StaleElementReferenceError < WebDriverError; end
|
63
63
|
|
64
|
+
#
|
65
|
+
# A command failed because the referenced shadow root is no longer attached to the DOM.
|
66
|
+
#
|
67
|
+
|
68
|
+
class DetachedShadowRootError < WebDriverError; end
|
69
|
+
|
64
70
|
#
|
65
71
|
# The target element is in an invalid state, rendering it impossible to interact with, for
|
66
72
|
# example if you click a disabled element.
|
@@ -93,6 +99,12 @@ module Selenium
|
|
93
99
|
|
94
100
|
class NoSuchWindowError < WebDriverError; end
|
95
101
|
|
102
|
+
#
|
103
|
+
# The element does not have a shadow root.
|
104
|
+
#
|
105
|
+
|
106
|
+
class NoSuchShadowRootError < WebDriverError; end
|
107
|
+
|
96
108
|
#
|
97
109
|
# An illegal attempt was made to set a cookie under a different domain than the current page.
|
98
110
|
#
|
@@ -30,14 +30,14 @@ module Selenium
|
|
30
30
|
|
31
31
|
def as_json(*)
|
32
32
|
{
|
33
|
-
'level' => level,
|
34
33
|
'timestamp' => timestamp,
|
34
|
+
'level' => level,
|
35
35
|
'message' => message
|
36
36
|
}
|
37
37
|
end
|
38
38
|
|
39
39
|
def to_s
|
40
|
-
"#{
|
40
|
+
"#{time} #{level}: #{message}"
|
41
41
|
end
|
42
42
|
|
43
43
|
def time
|
@@ -104,25 +104,19 @@ module Selenium
|
|
104
104
|
@timeouts ||= Timeouts.new(@bridge)
|
105
105
|
end
|
106
106
|
|
107
|
-
#
|
108
|
-
# @api beta This API may be changed or removed in a future release.
|
109
|
-
#
|
110
|
-
|
111
107
|
def logs
|
112
108
|
WebDriver.logger.deprecate('Manager#logs', 'Chrome::Driver#logs')
|
113
109
|
@logs ||= Logs.new(@bridge)
|
114
110
|
end
|
115
111
|
|
116
112
|
#
|
117
|
-
# Create a new top-level browsing context
|
118
|
-
# https://w3c.github.io/webdriver/#new-window
|
119
113
|
# @param type [Symbol] Supports two values: :tab and :window.
|
120
|
-
# Use :tab if you'd like the new window to share an OS-level window
|
121
|
-
# with the current browsing context.
|
122
|
-
# Use :window otherwise
|
123
114
|
# @return [String] The value of the window handle
|
124
115
|
#
|
125
116
|
def new_window(type = :tab)
|
117
|
+
WebDriver.logger.deprecate('Manager#new_window', 'TargetLocator#new_window', id: :new_window) do
|
118
|
+
'e.g., `driver.switch_to.new_window(:tab)`'
|
119
|
+
end
|
126
120
|
case type
|
127
121
|
when :tab, :window
|
128
122
|
result = @bridge.new_window(type)
|
@@ -137,10 +131,6 @@ module Selenium
|
|
137
131
|
end
|
138
132
|
end
|
139
133
|
|
140
|
-
#
|
141
|
-
# @api beta This API may be changed or removed in a future release.
|
142
|
-
#
|
143
|
-
|
144
134
|
def window
|
145
135
|
@window ||= Window.new(@bridge)
|
146
136
|
end
|
@@ -21,7 +21,8 @@ module Selenium
|
|
21
21
|
module WebDriver
|
22
22
|
class Options
|
23
23
|
W3C_OPTIONS = %i[browser_name browser_version platform_name accept_insecure_certs page_load_strategy proxy
|
24
|
-
set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability
|
24
|
+
set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability
|
25
|
+
web_socket_url].freeze
|
25
26
|
|
26
27
|
class << self
|
27
28
|
attr_reader :driver_path
|
@@ -90,7 +91,8 @@ module Selenium
|
|
90
91
|
# @param [Boolean, String, Integer] value Value of the option
|
91
92
|
#
|
92
93
|
|
93
|
-
def add_option(name, value)
|
94
|
+
def add_option(name, value = nil)
|
95
|
+
@options[name.keys.first] = name.values.first if value.nil? && name.is_a?(Hash)
|
94
96
|
@options[name] = value
|
95
97
|
end
|
96
98
|
|
@@ -109,12 +111,11 @@ module Selenium
|
|
109
111
|
def as_json(*)
|
110
112
|
options = @options.dup
|
111
113
|
|
112
|
-
w3c_options = options
|
113
|
-
options.delete_if { |key, _val| W3C_OPTIONS.include?(key) }
|
114
|
+
w3c_options = process_w3c_options(options)
|
114
115
|
|
115
116
|
self.class::CAPABILITIES.each do |capability_alias, capability_name|
|
116
117
|
capability_value = options.delete(capability_alias)
|
117
|
-
options[capability_name] = capability_value
|
118
|
+
options[capability_name] = capability_value if !capability_value.nil? && !options.key?(capability_name)
|
118
119
|
end
|
119
120
|
browser_options = defined?(self.class::KEY) ? {self.class::KEY => options} : options
|
120
121
|
|
@@ -124,6 +125,17 @@ module Selenium
|
|
124
125
|
|
125
126
|
private
|
126
127
|
|
128
|
+
def w3c?(key)
|
129
|
+
W3C_OPTIONS.include?(key) || key.to_s.include?(':')
|
130
|
+
end
|
131
|
+
|
132
|
+
def process_w3c_options(options)
|
133
|
+
w3c_options = options.select { |key, _val| w3c?(key) }
|
134
|
+
w3c_options[:unhandled_prompt_behavior] &&= w3c_options[:unhandled_prompt_behavior]&.to_s&.tr('_', ' ')
|
135
|
+
options.delete_if { |key, _val| w3c?(key) }
|
136
|
+
w3c_options
|
137
|
+
end
|
138
|
+
|
127
139
|
def process_browser_options(_browser_options)
|
128
140
|
nil
|
129
141
|
end
|
@@ -134,12 +146,7 @@ module Selenium
|
|
134
146
|
|
135
147
|
def generate_as_json(value, camelize_keys: true)
|
136
148
|
if value.is_a?(Hash)
|
137
|
-
value
|
138
|
-
next if val.respond_to?(:empty?) && val.empty?
|
139
|
-
|
140
|
-
key = convert_json_key(key, camelize: camelize_keys)
|
141
|
-
hash[key] = generate_as_json(val, camelize_keys: camelize?(key))
|
142
|
-
end
|
149
|
+
process_json_hash(value, camelize_keys)
|
143
150
|
elsif value.respond_to?(:as_json)
|
144
151
|
value.as_json
|
145
152
|
elsif value.is_a?(Array)
|
@@ -151,6 +158,16 @@ module Selenium
|
|
151
158
|
end
|
152
159
|
end
|
153
160
|
|
161
|
+
def process_json_hash(value, camelize_keys)
|
162
|
+
value.each_with_object({}) do |(key, val), hash|
|
163
|
+
next if val.respond_to?(:empty?) && val.empty?
|
164
|
+
|
165
|
+
camelize = camelize_keys ? camelize?(key) : false
|
166
|
+
key = convert_json_key(key, camelize: camelize)
|
167
|
+
hash[key] = generate_as_json(val, camelize_keys: camelize)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
154
171
|
def convert_json_key(key, camelize: true)
|
155
172
|
key = key.to_s if key.is_a?(Symbol)
|
156
173
|
key = camel_case(key) if camelize
|
@@ -162,6 +179,8 @@ module Selenium
|
|
162
179
|
def camel_case(str)
|
163
180
|
str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
|
164
181
|
end
|
165
|
-
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Options
|
166
185
|
end # WebDriver
|
167
186
|
end # Selenium
|
@@ -141,10 +141,10 @@ module Selenium
|
|
141
141
|
|
142
142
|
def as_json(*)
|
143
143
|
json_result = {
|
144
|
-
'proxyType' => TYPES[type],
|
144
|
+
'proxyType' => TYPES[type].downcase,
|
145
145
|
'ftpProxy' => ftp,
|
146
146
|
'httpProxy' => http,
|
147
|
-
'noProxy' => no_proxy,
|
147
|
+
'noProxy' => no_proxy.is_a?(String) ? no_proxy.split(', ') : no_proxy,
|
148
148
|
'proxyAutoconfigUrl' => pac,
|
149
149
|
'sslProxy' => ssl,
|
150
150
|
'autodetect' => auto_detect,
|
@@ -0,0 +1,87 @@
|
|
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
|
+
class ShadowRoot
|
23
|
+
ROOT_KEY = 'shadow-6066-11e4-a52e-4f735466cecf'
|
24
|
+
|
25
|
+
include SearchContext
|
26
|
+
|
27
|
+
#
|
28
|
+
# Creates a new shadow root
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
|
33
|
+
def initialize(bridge, id)
|
34
|
+
@bridge = bridge
|
35
|
+
@id = id
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
format '#<%<class>s:0x%<hash>x id=%<id>s>', class: self.class, hash: hash * 2, id: @id.inspect
|
40
|
+
end
|
41
|
+
|
42
|
+
def ==(other)
|
43
|
+
other.is_a?(self.class) && ref == other.ref
|
44
|
+
end
|
45
|
+
alias_method :eql?, :==
|
46
|
+
|
47
|
+
def hash
|
48
|
+
@id.hash ^ @bridge.hash
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
# @see SearchContext
|
54
|
+
#
|
55
|
+
|
56
|
+
def ref
|
57
|
+
[:shadow_root, @id]
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Convert to a ShadowRoot JSON Object for transmission over the wire.
|
62
|
+
# @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#basic-terms-and-concepts
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
#
|
66
|
+
|
67
|
+
def to_json(*)
|
68
|
+
JSON.generate as_json
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# For Rails 3 - http://jonathanjulian.com/2010/04/rails-to_json-or-as_json/
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
|
77
|
+
def as_json(*)
|
78
|
+
{ROOT_KEY => @id}
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
attr_reader :bridge
|
84
|
+
|
85
|
+
end # ShadowRoot
|
86
|
+
end # WebDriver
|
87
|
+
end # Selenium
|
@@ -65,37 +65,26 @@ module Selenium
|
|
65
65
|
arr << Errno::EALREADY if Platform.wsl?
|
66
66
|
}.freeze
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
81
|
-
sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
|
82
|
-
|
83
|
-
begin
|
84
|
-
sock.connect_nonblock sockaddr
|
85
|
-
rescue Errno::EINPROGRESS
|
86
|
-
retry if socket_writable?(sock) && conn_completed?(sock)
|
87
|
-
raise Errno::ECONNREFUSED
|
88
|
-
rescue *CONNECTED_ERRORS
|
89
|
-
# yay!
|
90
|
-
end
|
91
|
-
|
92
|
-
sock.close
|
93
|
-
true
|
94
|
-
rescue *NOT_CONNECTED_ERRORS
|
95
|
-
sock&.close
|
96
|
-
WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
|
97
|
-
false
|
68
|
+
def listening?
|
69
|
+
addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
|
70
|
+
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
71
|
+
sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
|
72
|
+
|
73
|
+
begin
|
74
|
+
sock.connect_nonblock sockaddr
|
75
|
+
rescue Errno::EINPROGRESS
|
76
|
+
retry if socket_writable?(sock) && conn_completed?(sock)
|
77
|
+
raise Errno::ECONNREFUSED
|
78
|
+
rescue *CONNECTED_ERRORS
|
79
|
+
# yay!
|
98
80
|
end
|
81
|
+
|
82
|
+
sock.close
|
83
|
+
true
|
84
|
+
rescue *NOT_CONNECTED_ERRORS
|
85
|
+
sock&.close
|
86
|
+
WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
|
87
|
+
false
|
99
88
|
end
|
100
89
|
|
101
90
|
def socket_writable?(sock)
|
@@ -24,38 +24,41 @@ module Selenium
|
|
24
24
|
#
|
25
25
|
module TakesScreenshot
|
26
26
|
#
|
27
|
-
# Save a PNG screenshot to the given path
|
27
|
+
# Save a PNG screenshot of the viewport to the given path
|
28
28
|
#
|
29
29
|
# @api public
|
30
30
|
#
|
31
31
|
|
32
|
-
def save_screenshot(png_path)
|
32
|
+
def save_screenshot(png_path, full_page: false)
|
33
33
|
extension = File.extname(png_path).downcase
|
34
34
|
if extension != '.png'
|
35
35
|
WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
|
36
36
|
"It should end with .png extension",
|
37
37
|
id: :screenshot
|
38
38
|
end
|
39
|
-
File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
|
39
|
+
File.open(png_path, 'wb') { |f| f << screenshot_as(:png, full_page: full_page) }
|
40
40
|
end
|
41
41
|
|
42
42
|
#
|
43
43
|
# Return a PNG screenshot in the given format as a string
|
44
44
|
#
|
45
45
|
# @param [:base64, :png] format
|
46
|
+
# @param [Boolean] full_page allows taking full page screenshots if supported
|
46
47
|
# @return String screenshot
|
47
48
|
#
|
48
49
|
# @api public
|
49
50
|
|
50
|
-
def screenshot_as(format)
|
51
|
+
def screenshot_as(format, full_page: false)
|
51
52
|
case format
|
52
53
|
when :base64
|
53
|
-
screenshot
|
54
|
+
full_page ? full_screenshot : screenshot
|
54
55
|
when :png
|
55
|
-
|
56
|
+
screenshot_as(:base64, full_page: full_page).unpack1('m')
|
56
57
|
else
|
57
58
|
raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
|
58
59
|
end
|
60
|
+
rescue NameError
|
61
|
+
raise Error::UnsupportedOperationError, "Full Page Screenshots are not supported for #{inspect}"
|
59
62
|
end
|
60
63
|
|
61
64
|
end # TakesScreenshot
|
@@ -44,6 +44,34 @@ module Selenium
|
|
44
44
|
@bridge.switch_to_parent_frame
|
45
45
|
end
|
46
46
|
|
47
|
+
#
|
48
|
+
# Switch to a new top-level browsing context
|
49
|
+
#
|
50
|
+
# @param type either :tab or :window
|
51
|
+
#
|
52
|
+
|
53
|
+
def new_window(type = :window)
|
54
|
+
unless %i[window tab].include?(type)
|
55
|
+
raise ArgumentError, "Valid types are :tab and :window, received: #{type.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
handle = @bridge.new_window(type)['handle']
|
59
|
+
|
60
|
+
if block_given?
|
61
|
+
execute_and_close = proc do
|
62
|
+
yield(self)
|
63
|
+
begin
|
64
|
+
@bridge.close
|
65
|
+
rescue Error::NoSuchWindowError
|
66
|
+
# window already closed
|
67
|
+
end
|
68
|
+
end
|
69
|
+
window(handle, &execute_and_close)
|
70
|
+
else
|
71
|
+
window(handle)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
47
75
|
#
|
48
76
|
# switch to the given window handle
|
49
77
|
#
|
@@ -58,18 +58,26 @@ require 'selenium/webdriver/common/driver_extensions/has_remote_status'
|
|
58
58
|
require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
|
59
59
|
require 'selenium/webdriver/common/driver_extensions/has_network_connection'
|
60
60
|
require 'selenium/webdriver/common/driver_extensions/has_network_interception'
|
61
|
+
require 'selenium/webdriver/common/driver_extensions/has_apple_permissions'
|
61
62
|
require 'selenium/webdriver/common/driver_extensions/has_permissions'
|
62
63
|
require 'selenium/webdriver/common/driver_extensions/has_debugger'
|
64
|
+
require 'selenium/webdriver/common/driver_extensions/has_context'
|
63
65
|
require 'selenium/webdriver/common/driver_extensions/prints_page'
|
64
66
|
require 'selenium/webdriver/common/driver_extensions/uploads_files'
|
67
|
+
require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
|
65
68
|
require 'selenium/webdriver/common/driver_extensions/has_addons'
|
66
69
|
require 'selenium/webdriver/common/driver_extensions/has_devtools'
|
67
70
|
require 'selenium/webdriver/common/driver_extensions/has_authentication'
|
68
71
|
require 'selenium/webdriver/common/driver_extensions/has_logs'
|
69
72
|
require 'selenium/webdriver/common/driver_extensions/has_log_events'
|
73
|
+
require 'selenium/webdriver/common/driver_extensions/has_pinned_scripts'
|
74
|
+
require 'selenium/webdriver/common/driver_extensions/has_cdp'
|
75
|
+
require 'selenium/webdriver/common/driver_extensions/has_casting'
|
76
|
+
require 'selenium/webdriver/common/driver_extensions/has_launching'
|
70
77
|
require 'selenium/webdriver/common/keys'
|
71
78
|
require 'selenium/webdriver/common/profile_helper'
|
72
79
|
require 'selenium/webdriver/common/options'
|
73
80
|
require 'selenium/webdriver/common/takes_screenshot'
|
74
81
|
require 'selenium/webdriver/common/driver'
|
75
82
|
require 'selenium/webdriver/common/element'
|
83
|
+
require 'selenium/webdriver/common/shadow_root'
|
@@ -0,0 +1,59 @@
|
|
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
|
+
class DevTools
|
23
|
+
class PinnedScript
|
24
|
+
|
25
|
+
attr_accessor :key, :devtools_identifier, :script
|
26
|
+
|
27
|
+
def initialize(script)
|
28
|
+
@key = SecureRandom.alphanumeric
|
29
|
+
@script = script
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
|
36
|
+
def callable
|
37
|
+
"function __webdriver_#{key}(arguments) { #{script} }"
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
|
44
|
+
def to_json(*)
|
45
|
+
%{"return __webdriver_#{key}(arguments)"}
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
|
52
|
+
def remove
|
53
|
+
"__webdriver_#{key} = undefined"
|
54
|
+
end
|
55
|
+
|
56
|
+
end # PinnedScript
|
57
|
+
end # DevTools
|
58
|
+
end # WebDriver
|
59
|
+
end # Selenium
|
@@ -22,33 +22,43 @@ module Selenium
|
|
22
22
|
class DevTools
|
23
23
|
class Request
|
24
24
|
|
25
|
-
|
25
|
+
attr_accessor :url, :method, :headers, :post_data
|
26
|
+
attr_reader :id
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
#
|
29
|
+
# Creates request from DevTools message.
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
|
33
|
+
def self.from(id, params)
|
34
|
+
new(
|
35
|
+
id: id,
|
36
|
+
url: params.dig('request', 'url'),
|
37
|
+
method: params.dig('request', 'method'),
|
38
|
+
headers: params.dig('request', 'headers'),
|
39
|
+
post_data: params.dig('request', 'postData')
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(id:, url:, method:, headers:, post_data:)
|
29
44
|
@id = id
|
30
45
|
@url = url
|
31
46
|
@method = method
|
32
47
|
@headers = headers
|
48
|
+
@post_data = post_data
|
33
49
|
end
|
34
50
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
body: Base64.strict_encode64(body),
|
43
|
-
response_code: code,
|
44
|
-
response_headers: headers.map do |k, v|
|
45
|
-
{name: k, value: v}
|
46
|
-
end
|
47
|
-
)
|
51
|
+
def ==(other)
|
52
|
+
self.class == other.class &&
|
53
|
+
id == other.id &&
|
54
|
+
url == other.url &&
|
55
|
+
method == other.method &&
|
56
|
+
headers == other.headers &&
|
57
|
+
post_data == other.post_data
|
48
58
|
end
|
49
59
|
|
50
60
|
def inspect
|
51
|
-
%(#<#{self.class.name} @method="#{method}" @url="#{url}")
|
61
|
+
%(#<#{self.class.name} @id="#{id}" @method="#{method}" @url="#{url}")
|
52
62
|
end
|
53
63
|
|
54
64
|
end # Request
|