selenium-webdriver 4.0.0.beta3 → 4.0.0.rc3

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +1953 -0
  3. data/Gemfile +6 -0
  4. data/LICENSE +202 -0
  5. data/NOTICE +2 -0
  6. data/README.md +34 -0
  7. data/lib/selenium/webdriver/atoms/findElements.js +0 -0
  8. data/lib/selenium/webdriver/atoms/getAttribute.js +25 -25
  9. data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
  10. data/lib/selenium/webdriver/chrome/driver.rb +6 -5
  11. data/lib/selenium/webdriver/chrome/features.rb +44 -4
  12. data/lib/selenium/webdriver/chrome/options.rb +25 -2
  13. data/lib/selenium/webdriver/chrome/profile.rb +0 -0
  14. data/lib/selenium/webdriver/common/driver.rb +5 -1
  15. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  16. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  17. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  18. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
  19. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  20. data/lib/selenium/{devtools.rb → webdriver/common/driver_extensions/has_launching.rb} +16 -8
  21. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -6
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +8 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +87 -18
  24. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  25. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  26. data/lib/selenium/webdriver/common/driver_extensions/prints_page.rb +1 -1
  27. data/lib/selenium/webdriver/common/element.rb +17 -8
  28. data/lib/selenium/webdriver/common/error.rb +12 -0
  29. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  30. data/lib/selenium/webdriver/common/manager.rb +3 -13
  31. data/lib/selenium/webdriver/common/options.rb +20 -6
  32. data/lib/selenium/webdriver/common/proxy.rb +2 -2
  33. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  34. data/lib/selenium/webdriver/common/takes_screenshot.rb +9 -6
  35. data/lib/selenium/webdriver/common/target_locator.rb +28 -0
  36. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  37. data/lib/selenium/webdriver/common/window.rb +0 -4
  38. data/lib/selenium/webdriver/common.rb +8 -0
  39. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  40. data/lib/selenium/webdriver/devtools/request.rb +27 -17
  41. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  42. data/lib/selenium/webdriver/devtools.rb +50 -12
  43. data/lib/selenium/webdriver/edge/features.rb +5 -0
  44. data/lib/selenium/webdriver/edge/options.rb +0 -0
  45. data/lib/selenium/webdriver/edge/profile.rb +0 -0
  46. data/lib/selenium/webdriver/firefox/driver.rb +6 -0
  47. data/lib/selenium/webdriver/firefox/features.rb +20 -1
  48. data/lib/selenium/webdriver/firefox/options.rb +24 -1
  49. data/lib/selenium/webdriver/firefox.rb +0 -1
  50. data/lib/selenium/webdriver/ie/options.rb +3 -1
  51. data/lib/selenium/webdriver/ie/service.rb +1 -1
  52. data/lib/selenium/webdriver/remote/bridge.rb +39 -23
  53. data/lib/selenium/webdriver/remote/capabilities.rb +4 -13
  54. data/lib/selenium/webdriver/remote/commands.rb +4 -0
  55. data/lib/selenium/webdriver/remote/driver.rb +3 -1
  56. data/lib/selenium/webdriver/remote.rb +1 -1
  57. data/lib/selenium/webdriver/safari/driver.rb +1 -1
  58. data/lib/selenium/webdriver/safari/options.rb +7 -0
  59. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  60. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  61. data/lib/selenium/webdriver/support/event_firing_bridge.rb +2 -2
  62. data/lib/selenium/webdriver/version.rb +1 -1
  63. data/lib/selenium/webdriver.rb +1 -1
  64. data/selenium-webdriver.gemspec +63 -0
  65. metadata +60 -44
@@ -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
- "#{level} #{time}: #{message}"
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].freeze
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.select { |key, _val| W3C_OPTIONS.include?(key) }
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 unless capability_value.nil?
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
@@ -167,6 +179,8 @@ module Selenium
167
179
  def camel_case(str)
168
180
  str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
169
181
  end
170
- end # Options
182
+ end
183
+
184
+ # Options
171
185
  end # WebDriver
172
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
@@ -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
- screenshot.unpack1('m')
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
  #
@@ -24,22 +24,49 @@ module Selenium
24
24
  @bridge = bridge
25
25
  end
26
26
 
27
+ #
28
+ # Gets the amount of time the driver should wait when searching for elements.
29
+ #
30
+
31
+ def implicit_wait
32
+ Float(@bridge.timeouts['implicit']) / 1000
33
+ end
34
+
27
35
  #
28
36
  # Set the amount of time the driver should wait when searching for elements.
29
37
  #
30
38
 
31
39
  def implicit_wait=(seconds)
32
- @bridge.implicit_wait_timeout = Integer(seconds * 1000)
40
+ @bridge.timeouts = {'implicit' => Integer(seconds * 1000)}
33
41
  end
34
42
 
43
+ #
44
+ # Gets the amount of time to wait for an asynchronous script to finish
45
+ # execution before throwing an error.
46
+ #
47
+
48
+ def script
49
+ Float(@bridge.timeouts['script']) / 1000
50
+ end
51
+ alias_method :script_timeout, :script
52
+
35
53
  #
36
54
  # Sets the amount of time to wait for an asynchronous script to finish
37
55
  # execution before throwing an error. If the timeout is negative, then the
38
56
  # script will be allowed to run indefinitely.
39
57
  #
40
58
 
41
- def script_timeout=(seconds)
42
- @bridge.script_timeout = Integer(seconds * 1000)
59
+ def script=(seconds)
60
+ @bridge.timeouts = {'script' => Integer(seconds * 1000)}
61
+ end
62
+ alias_method :script_timeout=, :script=
63
+
64
+ #
65
+ # Gets the amount of time to wait for a page load to complete before throwing an error.
66
+ #
67
+
68
+ def page_load
69
+ Float(@bridge.timeouts['pageLoad']) / 1000
43
70
  end
44
71
 
45
72
  #
@@ -48,7 +75,7 @@ module Selenium
48
75
  #
49
76
 
50
77
  def page_load=(seconds)
51
- @bridge.timeout 'page load', Integer(seconds * 1000)
78
+ @bridge.timeouts = {'pageLoad' => Integer(seconds * 1000)}
52
79
  end
53
80
  end # Timeouts
54
81
  end # WebDriver
@@ -19,10 +19,6 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- #
23
- # @api beta This API may be changed or removed in a future release.
24
- #
25
-
26
22
  class Window
27
23
  #
28
24
  # @api private
@@ -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
- attr_reader :url, :method, :headers
25
+ attr_accessor :url, :method, :headers, :post_data
26
+ attr_reader :id
26
27
 
27
- def initialize(devtools:, id:, url:, method:, headers:)
28
- @devtools = devtools
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 continue
36
- @devtools.fetch.continue_request(request_id: @id)
37
- end
38
-
39
- def respond(code: 200, headers: {}, body: '')
40
- @devtools.fetch.fulfill_request(
41
- request_id: @id,
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
@@ -0,0 +1,66 @@
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 Response
24
+
25
+ attr_accessor :code, :body, :headers
26
+ attr_reader :id
27
+
28
+ #
29
+ # Creates response from DevTools message.
30
+ # @api private
31
+ #
32
+
33
+ def self.from(id, encoded_body, params)
34
+ new(
35
+ id: id,
36
+ code: params['responseStatusCode'],
37
+ body: (Base64.strict_decode64(encoded_body) if encoded_body),
38
+ headers: params['responseHeaders'].each_with_object({}) do |header, hash|
39
+ hash[header['name']] = header['value']
40
+ end
41
+ )
42
+ end
43
+
44
+ def initialize(id:, code:, body:, headers:)
45
+ @id = id
46
+ @code = code
47
+ @body = body
48
+ @headers = headers
49
+ end
50
+
51
+ def ==(other)
52
+ self.class == other.class &&
53
+ id == other.id &&
54
+ code == other.code &&
55
+ body == other.body &&
56
+ headers == other.headers
57
+ end
58
+
59
+ def inspect
60
+ %(#<#{self.class.name} @id="#{id}" @code="#{code}")
61
+ end
62
+
63
+ end # Response
64
+ end # DevTools
65
+ end # WebDriver
66
+ end # Selenium