selenium-webdriver 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +17 -0
- data/lib/selenium/webdriver/chrome.rb +13 -13
- data/lib/selenium/webdriver/chrome/bridge.rb +4 -3
- data/lib/selenium/webdriver/chrome/service.rb +6 -4
- data/lib/selenium/webdriver/common.rb +1 -0
- data/lib/selenium/webdriver/common/driver.rb +1 -1
- data/lib/selenium/webdriver/common/element.rb +14 -0
- data/lib/selenium/webdriver/common/options.rb +12 -10
- data/lib/selenium/webdriver/common/port_prober.rb +2 -1
- data/lib/selenium/webdriver/common/service.rb +23 -8
- data/lib/selenium/webdriver/common/w3c_options.rb +45 -0
- data/lib/selenium/webdriver/edge.rb +13 -13
- data/lib/selenium/webdriver/edge/bridge.rb +98 -1
- data/lib/selenium/webdriver/edge/service.rb +6 -4
- data/lib/selenium/webdriver/firefox.rb +13 -13
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/service.rb +10 -4
- data/lib/selenium/webdriver/firefox/w3c_bridge.rb +2 -1
- data/lib/selenium/webdriver/ie.rb +13 -13
- data/lib/selenium/webdriver/ie/bridge.rb +3 -1
- data/lib/selenium/webdriver/ie/service.rb +6 -4
- data/lib/selenium/webdriver/phantomjs.rb +13 -9
- data/lib/selenium/webdriver/phantomjs/bridge.rb +2 -1
- data/lib/selenium/webdriver/phantomjs/service.rb +2 -4
- data/lib/selenium/webdriver/remote/bridge.rb +102 -108
- data/lib/selenium/webdriver/remote/commands.rb +188 -185
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +75 -94
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +3 -3
- data/lib/selenium/webdriver/remote/w3c_commands.rb +108 -104
- data/lib/selenium/webdriver/safari.rb +14 -13
- data/lib/selenium/webdriver/safari/bridge.rb +2 -1
- data/lib/selenium/webdriver/safari/service.rb +16 -4
- data/selenium-webdriver.gemspec +1 -1
- metadata +3 -4
- data/Gemfile.lock +0 -53
- data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
data/CHANGES
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
3.0.2 (2016-11-25)
|
2
|
+
===================
|
3
|
+
|
4
|
+
Ruby:
|
5
|
+
* Implement #driver_path as parameter when initializing a driver (thanks lmtierney)
|
6
|
+
* Improve Ruby syntax in driver commands (thanks joe_schulte)
|
7
|
+
* Improve performance when shutting down drivers (thanks lmtierney)
|
8
|
+
* Fix bug for finding open ports on Windows (thanks kou1okada)
|
9
|
+
* Fix bug in auto detection of drivers which allowed selection of non-executable binaries
|
10
|
+
|
11
|
+
W3C:
|
12
|
+
* Implement #cookie_named and #delete_all_cookies methods (thanks lmtierney)
|
13
|
+
* Implement element #property method (thanks lmtierney)
|
14
|
+
|
15
|
+
Chrome:
|
16
|
+
* Fix bug in switches (thanks danvine)
|
17
|
+
|
1
18
|
3.0.1 (2016-11-06)
|
2
19
|
===================
|
3
20
|
|
@@ -26,25 +26,25 @@ require 'selenium/webdriver/chrome/profile'
|
|
26
26
|
module Selenium
|
27
27
|
module WebDriver
|
28
28
|
module Chrome
|
29
|
-
MISSING_TEXT = <<-ERROR.tr("\n", '').freeze
|
30
|
-
Unable to find chromedriver. Please download the server from
|
31
|
-
http://chromedriver.storage.googleapis.com/index.html and place it
|
32
|
-
somewhere on your PATH. More info at https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver.
|
33
|
-
ERROR
|
34
|
-
|
35
29
|
def self.driver_path=(path)
|
30
|
+
warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
|
31
|
+
[DEPRECATION] `driver_path=` is deprecated. Pass the driver path as an option instead.
|
32
|
+
e.g. Selenium::WebDriver.for :chrome, driver_path: '/path'
|
33
|
+
DEPRECATE
|
34
|
+
|
36
35
|
Platform.assert_executable path
|
37
36
|
@driver_path = path
|
38
37
|
end
|
39
38
|
|
40
|
-
def self.driver_path
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
path
|
39
|
+
def self.driver_path(warning = true)
|
40
|
+
if warning
|
41
|
+
warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
|
42
|
+
[DEPRECATION] `driver_path` is deprecated. Pass the driver path as an option instead.
|
43
|
+
e.g. Selenium::WebDriver.for :chrome, driver_path: '/path'
|
44
|
+
DEPRECATE
|
47
45
|
end
|
46
|
+
|
47
|
+
@driver_path ||= nil
|
48
48
|
end
|
49
49
|
|
50
50
|
def self.path=(path)
|
@@ -31,7 +31,8 @@ module Selenium
|
|
31
31
|
end
|
32
32
|
|
33
33
|
unless opts.key?(:url)
|
34
|
-
|
34
|
+
driver_path = opts.delete(:driver_path) || Chrome.driver_path(false)
|
35
|
+
@service = Service.new(driver_path, port, *extract_service_args(service_args))
|
35
36
|
@service.start
|
36
37
|
opts[:url] = @service.uri
|
37
38
|
end
|
@@ -100,8 +101,8 @@ module Selenium
|
|
100
101
|
service_args << "--url-base=#{args.delete(:url_base)}" if args.key?(:url_base)
|
101
102
|
service_args << "--port-server=#{args.delete(:port_server)}" if args.key?(:port_server)
|
102
103
|
service_args << "--whitelisted-ips=#{args.delete(:whitelisted_ips)}" if args.key?(:whitelisted_ips)
|
103
|
-
service_args << "--verbose=#{args.delete(:verbose)}" if args.key?(:
|
104
|
-
service_args << "--silent=#{args.delete(:silent)}" if args.key?(:
|
104
|
+
service_args << "--verbose=#{args.delete(:verbose)}" if args.key?(:verbose)
|
105
|
+
service_args << "--silent=#{args.delete(:silent)}" if args.key?(:silent)
|
105
106
|
service_args
|
106
107
|
end
|
107
108
|
end # Bridge
|
@@ -26,6 +26,12 @@ module Selenium
|
|
26
26
|
|
27
27
|
class Service < WebDriver::Service
|
28
28
|
DEFAULT_PORT = 9515
|
29
|
+
@executable = 'chromedriver'.freeze
|
30
|
+
@missing_text = <<-ERROR.gsub(/\n +| {2,}/, ' ').freeze
|
31
|
+
Unable to find chromedriver. Please download the server from
|
32
|
+
http://chromedriver.storage.googleapis.com/index.html and place it somewhere on your PATH.
|
33
|
+
More info at https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver.
|
34
|
+
ERROR
|
29
35
|
|
30
36
|
private
|
31
37
|
|
@@ -37,10 +43,6 @@ module Selenium
|
|
37
43
|
@process.start
|
38
44
|
end
|
39
45
|
|
40
|
-
def stop_server
|
41
|
-
connect_to_server { |http| http.get('/shutdown') }
|
42
|
-
end
|
43
|
-
|
44
46
|
def cannot_connect_error_text
|
45
47
|
"unable to connect to chromedriver #{@host}:#{@port}"
|
46
48
|
end
|
@@ -39,6 +39,7 @@ require 'selenium/webdriver/common/timeouts'
|
|
39
39
|
require 'selenium/webdriver/common/window'
|
40
40
|
require 'selenium/webdriver/common/logs'
|
41
41
|
require 'selenium/webdriver/common/options'
|
42
|
+
require 'selenium/webdriver/common/w3c_options'
|
42
43
|
require 'selenium/webdriver/common/search_context'
|
43
44
|
require 'selenium/webdriver/common/action_builder'
|
44
45
|
require 'selenium/webdriver/common/touch_action_builder'
|
@@ -118,6 +118,20 @@ module Selenium
|
|
118
118
|
bridge.element_attribute self, name
|
119
119
|
end
|
120
120
|
|
121
|
+
#
|
122
|
+
# Get the value of a the given property with the same name of the element. If the value is not
|
123
|
+
# set, nil is returned.
|
124
|
+
#
|
125
|
+
# @param [String]
|
126
|
+
# property name
|
127
|
+
# @return [String,nil]
|
128
|
+
# property value
|
129
|
+
#
|
130
|
+
|
131
|
+
def property(name)
|
132
|
+
bridge.element_property self, name
|
133
|
+
end
|
134
|
+
|
121
135
|
#
|
122
136
|
# Get the text content of this element
|
123
137
|
#
|
@@ -90,16 +90,7 @@ module Selenium
|
|
90
90
|
#
|
91
91
|
|
92
92
|
def all_cookies
|
93
|
-
@bridge.cookies.map
|
94
|
-
{
|
95
|
-
name: cookie['name'],
|
96
|
-
value: cookie['value'],
|
97
|
-
path: cookie['path'],
|
98
|
-
domain: cookie['domain'] && strip_port(cookie['domain']),
|
99
|
-
expires: cookie['expiry'] && datetime_at(cookie['expiry']),
|
100
|
-
secure: cookie['secure']
|
101
|
-
}
|
102
|
-
end
|
93
|
+
@bridge.cookies.map { |cookie| convert_cookie(cookie) }
|
103
94
|
end
|
104
95
|
|
105
96
|
def timeouts
|
@@ -146,6 +137,17 @@ module Selenium
|
|
146
137
|
def strip_port(str)
|
147
138
|
str.split(':', 2).first
|
148
139
|
end
|
140
|
+
|
141
|
+
def convert_cookie(cookie)
|
142
|
+
{
|
143
|
+
name: cookie['name'],
|
144
|
+
value: cookie['value'],
|
145
|
+
path: cookie['path'],
|
146
|
+
domain: cookie['domain'] && strip_port(cookie['domain']),
|
147
|
+
expires: cookie['expiry'] && datetime_at(cookie['expiry']),
|
148
|
+
secure: cookie['secure']
|
149
|
+
}
|
150
|
+
end
|
149
151
|
end # Options
|
150
152
|
end # WebDriver
|
151
153
|
end # Selenium
|
@@ -38,8 +38,9 @@ module Selenium
|
|
38
38
|
port
|
39
39
|
end
|
40
40
|
|
41
|
-
IGNORED_ERRORS = [Errno::EADDRNOTAVAIL]
|
41
|
+
IGNORED_ERRORS = [Errno::EADDRNOTAVAIL]
|
42
42
|
IGNORED_ERRORS << Errno::EBADF if Platform.cygwin?
|
43
|
+
IGNORED_ERRORS.freeze
|
43
44
|
|
44
45
|
def self.free?(port)
|
45
46
|
Platform.interfaces.each do |host|
|
@@ -36,10 +36,17 @@ module Selenium
|
|
36
36
|
SOCKET_LOCK_TIMEOUT = 45
|
37
37
|
STOP_TIMEOUT = 20
|
38
38
|
|
39
|
+
@executable = nil
|
40
|
+
@missing_text = nil
|
41
|
+
|
42
|
+
class << self
|
43
|
+
attr_reader :executable, :missing_text
|
44
|
+
end
|
45
|
+
|
39
46
|
attr_accessor :host
|
40
47
|
|
41
48
|
def initialize(executable_path, port, *extra_args)
|
42
|
-
@executable_path = executable_path
|
49
|
+
@executable_path = binary_path(executable_path)
|
43
50
|
@host = Platform.localhost
|
44
51
|
@port = Integer(port)
|
45
52
|
@extra_args = extra_args
|
@@ -47,6 +54,13 @@ module Selenium
|
|
47
54
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
48
55
|
end
|
49
56
|
|
57
|
+
def binary_path(path)
|
58
|
+
path = Platform.find_binary(self.class.executable) if path.nil?
|
59
|
+
raise Error::WebDriverError, self.class.missing_text unless path
|
60
|
+
Platform.assert_executable path
|
61
|
+
path
|
62
|
+
end
|
63
|
+
|
50
64
|
def start
|
51
65
|
if process_running?
|
52
66
|
raise "already started: #{uri.inspect} #{@executable_path.inspect}"
|
@@ -62,8 +76,9 @@ module Selenium
|
|
62
76
|
end
|
63
77
|
|
64
78
|
def stop
|
65
|
-
return if process_exited?
|
66
79
|
stop_server
|
80
|
+
@process.poll_for_exit STOP_TIMEOUT
|
81
|
+
rescue ChildProcess::TimeoutError
|
67
82
|
ensure
|
68
83
|
stop_process
|
69
84
|
end
|
@@ -91,16 +106,16 @@ module Selenium
|
|
91
106
|
raise NotImplementedError, 'subclass responsibility'
|
92
107
|
end
|
93
108
|
|
94
|
-
def stop_server
|
95
|
-
raise NotImplementedError, 'subclass responsibility'
|
96
|
-
end
|
97
|
-
|
98
109
|
def stop_process
|
99
|
-
|
100
|
-
rescue ChildProcess::TimeoutError
|
110
|
+
return if process_exited?
|
101
111
|
@process.stop STOP_TIMEOUT
|
102
112
|
end
|
103
113
|
|
114
|
+
def stop_server
|
115
|
+
return if process_exited?
|
116
|
+
connect_to_server { |http| http.get('/shutdown') }
|
117
|
+
end
|
118
|
+
|
104
119
|
def process_running?
|
105
120
|
@process && @process.alive?
|
106
121
|
end
|
@@ -0,0 +1,45 @@
|
|
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
|
+
class W3COptions < Options
|
23
|
+
|
24
|
+
#
|
25
|
+
# Get the cookie with the given name
|
26
|
+
#
|
27
|
+
# @param [String] name the name of the cookie
|
28
|
+
# @return [Hash, nil] the cookie, or nil if it wasn't found.
|
29
|
+
#
|
30
|
+
|
31
|
+
def cookie_named(name)
|
32
|
+
convert_cookie(@bridge.cookie(name))
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Delete all cookies
|
37
|
+
#
|
38
|
+
|
39
|
+
def delete_all_cookies
|
40
|
+
@bridge.delete_all_cookies
|
41
|
+
end
|
42
|
+
|
43
|
+
end # WC3Options
|
44
|
+
end # WebDriver
|
45
|
+
end # Selenium
|
@@ -25,25 +25,25 @@ require 'selenium/webdriver/edge/bridge'
|
|
25
25
|
module Selenium
|
26
26
|
module WebDriver
|
27
27
|
module Edge
|
28
|
-
MISSING_TEXT = <<-ERROR.tr("\n", '').freeze
|
29
|
-
Unable to find MicrosoftWebDriver. Please download the server from
|
30
|
-
https://www.microsoft.com/en-us/download/details.aspx?id=48212 and place it
|
31
|
-
somewhere on your PATH. More info at https://github.com/SeleniumHQ/selenium/wiki/MicrosoftWebDriver.
|
32
|
-
ERROR
|
33
|
-
|
34
28
|
def self.driver_path=(path)
|
29
|
+
warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
|
30
|
+
[DEPRECATION] `driver_path=` is deprecated. Pass the driver path as an option instead.
|
31
|
+
e.g. Selenium::WebDriver.for :edge, driver_path: '/path'
|
32
|
+
DEPRECATE
|
33
|
+
|
35
34
|
Platform.assert_executable path
|
36
35
|
@driver_path = path
|
37
36
|
end
|
38
37
|
|
39
|
-
def self.driver_path
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
path
|
38
|
+
def self.driver_path(warning = true)
|
39
|
+
if warning
|
40
|
+
warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
|
41
|
+
[DEPRECATION] `driver_path` is deprecated. Pass the driver path as an option instead.
|
42
|
+
e.g. Selenium::WebDriver.for :edge, driver_path: '/path'
|
43
|
+
DEPRECATE
|
46
44
|
end
|
45
|
+
|
46
|
+
@driver_path ||= nil
|
47
47
|
end
|
48
48
|
end # Edge
|
49
49
|
end # WebDriver
|
@@ -28,8 +28,10 @@ module Selenium
|
|
28
28
|
def initialize(opts = {})
|
29
29
|
port = opts.delete(:port) || Service::DEFAULT_PORT
|
30
30
|
service_args = opts.delete(:service_args) || {}
|
31
|
+
|
31
32
|
unless opts.key?(:url)
|
32
|
-
|
33
|
+
driver_path = opts.delete(:driver_path) || Edge.driver_path(false)
|
34
|
+
@service = Service.new(driver_path, port, *extract_service_args(service_args))
|
33
35
|
@service.host = 'localhost' if @service.host == '127.0.0.1'
|
34
36
|
@service.start
|
35
37
|
opts[:url] = @service.uri
|
@@ -51,6 +53,20 @@ module Selenium
|
|
51
53
|
]
|
52
54
|
end
|
53
55
|
|
56
|
+
def commands(command)
|
57
|
+
unsupported = %i[execute_script execute_async_script submit_element double_click
|
58
|
+
mouse_down mouse_up mouse_move_to click
|
59
|
+
send_keys_to_active_element get_window_handles get_current_window_handle
|
60
|
+
get_window_size set_window_size get_window_position set_window_position
|
61
|
+
maximize_window get_alert_text accept_alert dismiss_alert]
|
62
|
+
if unsupported.include? command
|
63
|
+
Remote::Bridge::COMMANDS[command]
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
54
70
|
def capabilities
|
55
71
|
@capabilities ||= Remote::Capabilities.edge
|
56
72
|
end
|
@@ -61,6 +77,87 @@ module Selenium
|
|
61
77
|
@service.stop if @service
|
62
78
|
end
|
63
79
|
|
80
|
+
def execute_script(script, *args)
|
81
|
+
result = execute :execute_script, {}, {script: script, args: args}
|
82
|
+
unwrap_script_result result
|
83
|
+
end
|
84
|
+
|
85
|
+
def execute_async_script(script, *args)
|
86
|
+
result = execute :execute_async_script, {}, {script: script, args: args}
|
87
|
+
unwrap_script_result result
|
88
|
+
end
|
89
|
+
|
90
|
+
def submit_element(element)
|
91
|
+
execute :submit_element, id: element['ELEMENT']
|
92
|
+
end
|
93
|
+
|
94
|
+
def double_click
|
95
|
+
execute :double_click
|
96
|
+
end
|
97
|
+
|
98
|
+
def click
|
99
|
+
execute :click, {}, {button: 0}
|
100
|
+
end
|
101
|
+
|
102
|
+
def context_click
|
103
|
+
execute :click, {}, {button: 2}
|
104
|
+
end
|
105
|
+
|
106
|
+
def mouse_down
|
107
|
+
execute :mouse_down
|
108
|
+
end
|
109
|
+
|
110
|
+
def mouse_up
|
111
|
+
execute :mouse_up
|
112
|
+
end
|
113
|
+
|
114
|
+
def mouse_move_to(element, x = nil, y = nil)
|
115
|
+
element_id = element['ELEMENT'] if element
|
116
|
+
params = {element: element_id}
|
117
|
+
|
118
|
+
if x && y
|
119
|
+
params[:xoffset] = x
|
120
|
+
params[:yoffset] = y
|
121
|
+
end
|
122
|
+
|
123
|
+
execute :mouse_move_to, {}, params
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_keys_to_active_element(key)
|
127
|
+
execute :send_keys_to_active_element, {}, {value: key}
|
128
|
+
end
|
129
|
+
|
130
|
+
def window_handle
|
131
|
+
execute :get_current_window_handle
|
132
|
+
end
|
133
|
+
|
134
|
+
def window_size(handle = :current)
|
135
|
+
data = execute :get_window_size, window_handle: handle
|
136
|
+
|
137
|
+
Dimension.new data['width'], data['height']
|
138
|
+
end
|
139
|
+
|
140
|
+
def resize_window(width, height, handle = :current)
|
141
|
+
execute :set_window_size, {window_handle: handle},
|
142
|
+
{width: width,
|
143
|
+
height: height}
|
144
|
+
end
|
145
|
+
|
146
|
+
def window_position(handle = :current)
|
147
|
+
data = execute :get_window_position, window_handle: handle
|
148
|
+
|
149
|
+
Point.new data['x'], data['y']
|
150
|
+
end
|
151
|
+
|
152
|
+
def reposition_window(x, y, handle = :current)
|
153
|
+
execute :set_window_position, {window_handle: handle},
|
154
|
+
{x: x, y: y}
|
155
|
+
end
|
156
|
+
|
157
|
+
def maximize_window(handle = :current)
|
158
|
+
execute :maximize_window, window_handle: handle
|
159
|
+
end
|
160
|
+
|
64
161
|
private
|
65
162
|
|
66
163
|
def extract_service_args(args = {})
|