selenium-webdriver 3.4.0 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGES +35 -1
  2. data/Gemfile.lock +54 -0
  3. data/lib/selenium/webdriver.rb +8 -10
  4. data/lib/selenium/webdriver/chrome.rb +2 -1
  5. data/lib/selenium/webdriver/chrome/{bridge.rb → driver.rb} +47 -32
  6. data/lib/selenium/webdriver/chrome/options.rb +170 -0
  7. data/lib/selenium/webdriver/common/driver.rb +20 -39
  8. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +5 -0
  9. data/lib/selenium/webdriver/common/element.rb +5 -1
  10. data/lib/selenium/webdriver/common/logger.rb +10 -0
  11. data/lib/selenium/webdriver/common/w3c_error.rb +2 -2
  12. data/lib/selenium/webdriver/edge.rb +2 -1
  13. data/lib/selenium/webdriver/edge/bridge.rb +2 -91
  14. data/lib/selenium/webdriver/edge/driver.rb +80 -0
  15. data/lib/selenium/webdriver/firefox.rb +6 -3
  16. data/lib/selenium/webdriver/firefox/driver.rb +50 -0
  17. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  18. data/lib/selenium/webdriver/firefox/legacy/driver.rb +81 -0
  19. data/lib/selenium/webdriver/firefox/marionette/driver.rb +101 -0
  20. data/lib/selenium/webdriver/firefox/options.rb +139 -0
  21. data/lib/selenium/webdriver/ie.rb +1 -1
  22. data/lib/selenium/webdriver/ie/{bridge.rb → driver.rb} +13 -13
  23. data/lib/selenium/webdriver/phantomjs.rb +1 -1
  24. data/lib/selenium/webdriver/phantomjs/{bridge.rb → driver.rb} +10 -13
  25. data/lib/selenium/webdriver/remote.rb +11 -13
  26. data/lib/selenium/webdriver/remote/bridge.rb +87 -586
  27. data/lib/selenium/webdriver/remote/capabilities.rb +3 -1
  28. data/lib/selenium/webdriver/remote/driver.rb +44 -0
  29. data/lib/selenium/webdriver/remote/http/default.rb +1 -1
  30. data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
  31. data/lib/selenium/webdriver/remote/{commands.rb → oss/commands.rb} +9 -5
  32. data/lib/selenium/webdriver/remote/oss/driver.rb +44 -0
  33. data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
  34. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +266 -0
  35. data/lib/selenium/webdriver/remote/{w3c_commands.rb → w3c/commands.rb} +9 -4
  36. data/lib/selenium/webdriver/remote/w3c/driver.rb +41 -0
  37. data/lib/selenium/webdriver/safari.rb +3 -6
  38. data/lib/selenium/webdriver/safari/{bridge.rb → driver.rb} +14 -6
  39. data/selenium-webdriver.gemspec +1 -3
  40. metadata +29 -45
  41. data/lib/selenium/webdriver/firefox/bridge.rb +0 -70
  42. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +0 -114
  43. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -663
  44. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -231
@@ -32,6 +32,11 @@ module Selenium
32
32
  #
33
33
 
34
34
  def save_screenshot(png_path)
35
+ extension = File.extname(png_path).downcase
36
+ if extension != '.png'
37
+ WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
38
+ "It should end with .png extension"
39
+ end
35
40
  File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
36
41
  end
37
42
 
@@ -312,7 +312,11 @@ module Selenium
312
312
  #
313
313
 
314
314
  def as_json(*)
315
- key = bridge.is_a?(Remote::W3CBridge) ? 'element-6066-11e4-a52e-4f735466cecf' : 'ELEMENT'
315
+ key = if bridge.dialect == :w3c
316
+ 'element-6066-11e4-a52e-4f735466cecf'
317
+ else
318
+ 'ELEMENT'
319
+ end
316
320
  @id.is_a?(Hash) ? @id : {key => @id}
317
321
  end
318
322
 
@@ -104,6 +104,16 @@ module Selenium
104
104
  end
105
105
  end
106
106
 
107
+ #
108
+ # Marks code as deprecated with replacement.
109
+ #
110
+ # @param [String] old
111
+ # @param [String] new
112
+ #
113
+ def deprecate(old, new)
114
+ warn "[DEPRECATION] #{old} is deprecated. Use #{new} instead."
115
+ end
116
+
107
117
  private
108
118
 
109
119
  def create_logger(output)
@@ -183,13 +183,13 @@ module Selenium
183
183
  # is obscuring the element that was requested clicked.
184
184
  #
185
185
 
186
- class ElementClickIntercepted < WebDriverError; end
186
+ class ElementClickInterceptedError < WebDriverError; end
187
187
 
188
188
  #
189
189
  # Indicates that a command could not be completed because the element is not pointer or keyboard interactable.
190
190
  #
191
191
 
192
- class ElementNotInteractable < WebDriverError; end
192
+ class ElementNotInteractableError < WebDriverError; end
193
193
 
194
194
  # aliased for backwards compatibility
195
195
  NoAlertPresentError = NoSuchAlertError
@@ -19,8 +19,9 @@
19
19
 
20
20
  require 'net/http'
21
21
 
22
- require 'selenium/webdriver/edge/service'
23
22
  require 'selenium/webdriver/edge/bridge'
23
+ require 'selenium/webdriver/edge/driver'
24
+ require 'selenium/webdriver/edge/service'
24
25
 
25
26
  module Selenium
26
27
  module WebDriver
@@ -20,42 +20,7 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Edge
23
- #
24
- # @api private
25
- #
26
-
27
- class Bridge < Remote::W3CBridge
28
- def initialize(opts = {})
29
- opts[:desired_capabilities] ||= Remote::W3CCapabilities.edge
30
-
31
- unless opts.key?(:url)
32
- driver_path = opts.delete(:driver_path) || Edge.driver_path
33
- port = opts.delete(:port) || Service::DEFAULT_PORT
34
-
35
- opts[:driver_opts] ||= {}
36
- if opts.key? :service_args
37
- WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
38
- [DEPRECATION] `:service_args` is deprecated. Pass switches using `driver_opts`
39
- DEPRECATE
40
- opts[:driver_opts][:args] = opts.delete(:service_args)
41
- end
42
-
43
- @service = Service.new(driver_path, port, opts.delete(:driver_opts))
44
- @service.host = 'localhost' if @service.host == '127.0.0.1'
45
- @service.start
46
- opts[:url] = @service.uri
47
- end
48
-
49
- super(opts)
50
- end
51
-
52
- def browser
53
- :edge
54
- end
55
-
56
- def driver_extensions
57
- [DriverExtensions::TakesScreenshot]
58
- end
23
+ module Bridge
59
24
 
60
25
  def commands(command)
61
26
  unsupported = %i[execute_script execute_async_script submit_element double_click
@@ -64,21 +29,10 @@ module Selenium
64
29
  get_window_size set_window_size get_window_position set_window_position
65
30
  maximize_window get_alert_text accept_alert dismiss_alert]
66
31
  if unsupported.include? command
67
- Remote::Bridge::COMMANDS[command]
32
+ Remote::OSS::Bridge::COMMANDS[command]
68
33
  else
69
34
  super
70
35
  end
71
-
72
- end
73
-
74
- def capabilities
75
- @capabilities ||= Remote::Capabilities.edge
76
- end
77
-
78
- def quit
79
- super
80
- ensure
81
- @service.stop if @service
82
36
  end
83
37
 
84
38
  def send_keys_to_active_element(key)
@@ -116,49 +70,6 @@ module Selenium
116
70
  execute :maximize_window, window_handle: handle
117
71
  end
118
72
 
119
- def create_session(desired_capabilities)
120
- resp = raw_execute :new_session, {}, {desiredCapabilities: desired_capabilities}
121
- @session_id = resp['sessionId']
122
- return Remote::W3CCapabilities.json_create resp['value'] if @session_id
123
-
124
- raise Error::WebDriverError, 'no sessionId in returned payload'
125
- end
126
-
127
- #
128
- # executes a command on the remote server.
129
- #
130
- #
131
- # Returns the 'value' of the returned payload
132
- #
133
-
134
- def execute(*args)
135
- result = raw_execute(*args)
136
- result.payload.key?('value') ? result['value'] : result
137
- end
138
-
139
- #
140
- # executes a command on the remote server.
141
- #
142
- # @return [WebDriver::Remote::Response]
143
- #
144
-
145
- def raw_execute(command, opts = {}, command_hash = nil)
146
- verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
147
- path = path.dup
148
-
149
- path[':session_id'] = @session_id if path.include?(':session_id')
150
-
151
- begin
152
- opts.each do |key, value|
153
- path[key.inspect] = escaper.escape(value.to_s)
154
- end
155
- rescue IndexError
156
- raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
157
- end
158
-
159
- WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
160
- http.call verb, path, command_hash
161
- end
162
73
  end # Bridge
163
74
  end # Edge
164
75
  end # WebDriver
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
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 Edge
23
+
24
+ #
25
+ # Driver implementation for Microsoft Edge.
26
+ # @api private
27
+ #
28
+
29
+ class Driver < WebDriver::Driver
30
+ include DriverExtensions::TakesScreenshot
31
+
32
+ def initialize(opts = {})
33
+ opts[:desired_capabilities] ||= Remote::W3C::Capabilities.edge
34
+
35
+ unless opts.key?(:url)
36
+ driver_path = opts.delete(:driver_path) || Edge.driver_path
37
+ port = opts.delete(:port) || Service::DEFAULT_PORT
38
+
39
+ opts[:driver_opts] ||= {}
40
+ if opts.key? :service_args
41
+ WebDriver.logger.deprecate ':service_args', "driver_opts: {args: #{opts[:service_args]}}"
42
+ opts[:driver_opts][:args] = opts.delete(:service_args)
43
+ end
44
+
45
+ @service = Service.new(driver_path, port, opts.delete(:driver_opts))
46
+ @service.host = 'localhost' if @service.host == '127.0.0.1'
47
+ @service.start
48
+ opts[:url] = @service.uri
49
+ end
50
+
51
+ listener = opts.delete(:listener)
52
+
53
+ # Edge is mostly using W3C dialect, but a request to
54
+ # create session responds with OSS-like body,
55
+ # so we need to force W3C implementation.
56
+ desired_capabilities = opts.delete(:desired_capabilities)
57
+ bridge = Remote::Bridge.new(opts)
58
+ capabilities = bridge.create_session(desired_capabilities)
59
+
60
+ WebDriver.logger.info 'Forcing W3C dialect.'
61
+ @bridge = Remote::W3C::Bridge.new(capabilities, bridge.session_id, opts)
62
+ @bridge.extend Edge::Bridge
63
+
64
+ super(@bridge, listener: listener)
65
+ end
66
+
67
+ def browser
68
+ :edge
69
+ end
70
+
71
+ def quit
72
+ super
73
+ ensure
74
+ @service.stop if @service
75
+ end
76
+
77
+ end # Driver
78
+ end # Edge
79
+ end # WebDriver
80
+ end # Selenium
@@ -21,15 +21,18 @@ require 'timeout'
21
21
  require 'socket'
22
22
  require 'rexml/document'
23
23
 
24
+ require 'selenium/webdriver/firefox/driver'
25
+
24
26
  require 'selenium/webdriver/firefox/util'
25
27
  require 'selenium/webdriver/firefox/extension'
26
28
  require 'selenium/webdriver/firefox/binary'
27
29
  require 'selenium/webdriver/firefox/profiles_ini'
28
30
  require 'selenium/webdriver/firefox/profile'
29
31
  require 'selenium/webdriver/firefox/launcher'
30
- require 'selenium/webdriver/firefox/bridge'
31
- require 'selenium/webdriver/firefox/w3c_bridge'
32
- require 'selenium/webdriver/firefox/binary'
32
+ require 'selenium/webdriver/firefox/legacy/driver'
33
+
34
+ require 'selenium/webdriver/firefox/marionette/driver'
35
+ require 'selenium/webdriver/firefox/options'
33
36
  require 'selenium/webdriver/firefox/service'
34
37
 
35
38
  module Selenium
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
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 Firefox
23
+ module Driver
24
+ class << self
25
+
26
+ #
27
+ # Instantiates correct Firefox driver implementation
28
+ # @return [Marionette::Driver, Legacy::Driver]
29
+ #
30
+
31
+ def new(**opts)
32
+ if marionette?(opts)
33
+ Firefox::Marionette::Driver.new(opts)
34
+ else
35
+ Firefox::Legacy::Driver.new(opts)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def marionette?(opts)
42
+ opts.delete(:marionette) != false &&
43
+ (!opts[:desired_capabilities] || opts[:desired_capabilities][:marionette] != false)
44
+ end
45
+ end
46
+
47
+ end # Driver
48
+ end # Firefox
49
+ end # WebDriver
50
+ end # Selenium
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
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 Firefox
23
+ module Legacy
24
+
25
+ #
26
+ # Driver implementation for Firefox using legacy extension.
27
+ # @api private
28
+ #
29
+
30
+ class Driver < WebDriver::Driver
31
+ include DriverExtensions::TakesScreenshot
32
+
33
+ def initialize(opts = {})
34
+ opts[:desired_capabilities] ||= Remote::Capabilities.firefox
35
+
36
+ if opts.key? :proxy
37
+ WebDriver.logger.deprecate ':proxy', "Selenium::WebDriver::Remote::Capabilities.firefox(proxy: #{opts[:proxy]})"
38
+ opts[:desired_capabilities].proxy = opts.delete(:proxy)
39
+ end
40
+
41
+ unless opts.key?(:url)
42
+ port = opts.delete(:port) || DEFAULT_PORT
43
+ profile = opts.delete(:profile)
44
+
45
+ Binary.path = opts[:desired_capabilities][:firefox_binary] if opts[:desired_capabilities][:firefox_binary]
46
+ @launcher = Launcher.new Binary.new, port, profile
47
+ @launcher.launch
48
+ opts[:url] = @launcher.url
49
+ end
50
+
51
+ listener = opts.delete(:listener)
52
+ WebDriver.logger.info 'Skipping handshake as we know it is OSS.'
53
+ desired_capabilities = opts.delete(:desired_capabilities)
54
+ bridge = Remote::Bridge.new(opts)
55
+ capabilities = bridge.create_session(desired_capabilities)
56
+ @bridge = Remote::OSS::Bridge.new(capabilities, bridge.session_id, opts)
57
+
58
+ begin
59
+ super(@bridge, listener: listener)
60
+ rescue
61
+ @launcher.quit if @launcher
62
+ raise
63
+ end
64
+ end
65
+
66
+ def browser
67
+ :firefox
68
+ end
69
+
70
+ def quit
71
+ super
72
+ nil
73
+ ensure
74
+ @launcher.quit
75
+ end
76
+
77
+ end # Driver
78
+ end # Legacy
79
+ end # Firefox
80
+ end # WebDriver
81
+ end # Selenium
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
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 Firefox
23
+ module Marionette
24
+
25
+ #
26
+ # Driver implementation for Firefox using GeckoDriver.
27
+ # @api private
28
+ #
29
+
30
+ class Driver < WebDriver::Driver
31
+ include DriverExtensions::HasWebStorage
32
+ include DriverExtensions::TakesScreenshot
33
+
34
+ def initialize(opts = {})
35
+ opts[:desired_capabilities] = create_capabilities(opts)
36
+
37
+ unless opts.key?(:url)
38
+ driver_path = opts.delete(:driver_path) || Firefox.driver_path
39
+ port = opts.delete(:port) || Service::DEFAULT_PORT
40
+
41
+ opts[:driver_opts] ||= {}
42
+ if opts.key? :service_args
43
+ WebDriver.logger.deprecate ':service_args', "driver_opts: {args: #{opts[:service_args]}}"
44
+ opts[:driver_opts][:args] = opts.delete(:service_args)
45
+ end
46
+
47
+ @service = Service.new(driver_path, port, opts.delete(:driver_opts))
48
+ @service.start
49
+ opts[:url] = @service.uri
50
+ end
51
+
52
+ listener = opts.delete(:listener)
53
+ WebDriver.logger.info 'Skipping handshake as we know it is W3C.'
54
+ desired_capabilities = opts.delete(:desired_capabilities)
55
+ bridge = Remote::Bridge.new(opts)
56
+ capabilities = bridge.create_session(desired_capabilities)
57
+ @bridge = Remote::W3C::Bridge.new(capabilities, bridge.session_id, opts)
58
+
59
+ super(@bridge, listener: listener)
60
+ end
61
+
62
+ def browser
63
+ :firefox
64
+ end
65
+
66
+ def quit
67
+ super
68
+ ensure
69
+ @service.stop if @service
70
+ end
71
+
72
+ private
73
+
74
+ def create_capabilities(opts)
75
+ caps = opts.delete(:desired_capabilities) { Remote::W3C::Capabilities.firefox }
76
+ options = opts.delete(:options) { Options.new }
77
+
78
+ firefox_options = opts.delete(:firefox_options)
79
+ if firefox_options
80
+ WebDriver.logger.deprecate ':firefox_options', 'Selenium::WebDriver::Firefox::Options'
81
+ firefox_options.each do |key, value|
82
+ options.add_option(key, value)
83
+ end
84
+ end
85
+
86
+ profile = opts.delete(:profile)
87
+ if profile
88
+ WebDriver.logger.deprecate ':profile', 'Selenium::WebDriver::Firefox::Options#profile='
89
+ options.profile = profile
90
+ end
91
+
92
+ options = options.as_json
93
+ caps.merge!(options) unless options.empty?
94
+
95
+ caps
96
+ end
97
+ end # Driver
98
+ end # Marionette
99
+ end # Firefox
100
+ end # WebDriver
101
+ end # Selenium