selenium-webdriver 0.0.28 → 0.0.29
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.
- data/CHANGES +25 -0
- data/lib/selenium/webdriver.rb +6 -29
- data/lib/selenium/webdriver/chrome.rb +4 -2
- data/lib/selenium/webdriver/chrome/extension.zip +0 -0
- data/lib/selenium/webdriver/chrome/launcher.rb +15 -16
- data/lib/selenium/webdriver/common.rb +18 -0
- data/lib/selenium/webdriver/{bridge_helper.rb → common/bridge_helper.rb} +0 -0
- data/lib/selenium/webdriver/{core_ext → common/core_ext}/dir.rb +0 -0
- data/lib/selenium/webdriver/{core_ext → common/core_ext}/string.rb +0 -0
- data/lib/selenium/webdriver/{driver.rb → common/driver.rb} +19 -7
- data/lib/selenium/webdriver/{driver_extensions → common/driver_extensions}/takes_screenshot.rb +2 -2
- data/lib/selenium/webdriver/{element.rb → common/element.rb} +30 -3
- data/lib/selenium/webdriver/{error.rb → common/error.rb} +0 -0
- data/lib/selenium/webdriver/{file_reaper.rb → common/file_reaper.rb} +0 -0
- data/lib/selenium/webdriver/{find.rb → common/find.rb} +9 -1
- data/lib/selenium/webdriver/{keys.rb → common/keys.rb} +0 -0
- data/lib/selenium/webdriver/{navigation.rb → common/navigation.rb} +3 -3
- data/lib/selenium/webdriver/{options.rb → common/options.rb} +47 -5
- data/lib/selenium/webdriver/{platform.rb → common/platform.rb} +10 -0
- data/lib/selenium/webdriver/common/socket_poller.rb +47 -0
- data/lib/selenium/webdriver/{target_locator.rb → common/target_locator.rb} +11 -8
- data/lib/selenium/webdriver/{timeouts.rb → common/timeouts.rb} +0 -0
- data/lib/selenium/webdriver/common/wait.rb +60 -0
- data/lib/selenium/webdriver/common/zipper.rb +54 -0
- data/lib/selenium/webdriver/firefox.rb +6 -3
- data/lib/selenium/webdriver/firefox/binary.rb +46 -43
- data/lib/selenium/webdriver/firefox/bridge.rb +2 -10
- data/lib/selenium/webdriver/firefox/extension.rb +51 -0
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +25 -69
- data/lib/selenium/webdriver/firefox/profile.rb +123 -89
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -1
- data/lib/selenium/webdriver/firefox/socket_lock.rb +77 -0
- data/lib/selenium/webdriver/ie/bridge.rb +25 -38
- data/lib/selenium/webdriver/ie/lib.rb +11 -1
- data/lib/selenium/webdriver/ie/native/win32/InternetExplorerDriver.dll +0 -0
- data/lib/selenium/webdriver/ie/native/x64/InternetExplorerDriver.dll +0 -0
- data/lib/selenium/webdriver/ie/util.rb +3 -17
- data/lib/selenium/webdriver/remote/bridge.rb +9 -1
- data/lib/selenium/webdriver/remote/capabilities.rb +53 -20
- data/lib/selenium/webdriver/remote/http/default.rb +2 -2
- metadata +52 -31
- data/lib/selenium/webdriver/child_process.rb +0 -243
- data/lib/selenium/webdriver/zip_helper.rb +0 -27
@@ -91,6 +91,16 @@ module Selenium
|
|
91
91
|
File.chmod 0766, file
|
92
92
|
end
|
93
93
|
|
94
|
+
def assert_executable(path)
|
95
|
+
unless File.file? path
|
96
|
+
raise Error::WebDriverError, "not a file: #{path.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
unless File.executable? path
|
100
|
+
raise Error::WebDriverError, "not executable: #{path.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
94
104
|
def find_binary(*binary_names)
|
95
105
|
paths = ENV['PATH'].split(File::PATH_SEPARATOR)
|
96
106
|
binary_names.map! { |n| "#{n}.exe" } if win?
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module Selenium
|
4
|
+
module WebDriver
|
5
|
+
class SocketPoller
|
6
|
+
|
7
|
+
def initialize(host, port, timeout = 0, interval = 0.25)
|
8
|
+
@host = host
|
9
|
+
@port = Integer(port)
|
10
|
+
@timeout = Integer(timeout)
|
11
|
+
@interval = interval
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# @return true if the socket can be connected to
|
16
|
+
#
|
17
|
+
|
18
|
+
def success?
|
19
|
+
max_time = Time.now + @timeout
|
20
|
+
|
21
|
+
(
|
22
|
+
return true if can_connect?
|
23
|
+
wait
|
24
|
+
) until Time.now >= max_time
|
25
|
+
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def can_connect?
|
32
|
+
# There's a bug in 1.9.1 on Windows where this will succeed even if no
|
33
|
+
# one is listening. Users who hit that should upgrade their Ruby.
|
34
|
+
TCPSocket.new(@host, @port).close
|
35
|
+
true
|
36
|
+
rescue Errno::ECONNREFUSED, Errno::ENOTCONN, SocketError => e
|
37
|
+
$stderr.puts [@host, @port].inspect if $DEBUG
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def wait
|
42
|
+
sleep @interval
|
43
|
+
end
|
44
|
+
|
45
|
+
end # SocketPoller
|
46
|
+
end # WebDriver
|
47
|
+
end # Selenium
|
@@ -6,8 +6,8 @@ module Selenium
|
|
6
6
|
# @api private
|
7
7
|
#
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@bridge =
|
9
|
+
def initialize(bridge)
|
10
|
+
@bridge = bridge
|
11
11
|
end
|
12
12
|
|
13
13
|
#
|
@@ -33,15 +33,18 @@ module Selenium
|
|
33
33
|
original = @bridge.getCurrentWindowHandle
|
34
34
|
@bridge.switchToWindow id
|
35
35
|
|
36
|
-
|
36
|
+
begin
|
37
|
+
returned = yield
|
38
|
+
ensure
|
39
|
+
current_handles = @bridge.getWindowHandles
|
37
40
|
|
38
|
-
|
41
|
+
if current_handles.size == 1
|
42
|
+
original = current_handles.shift
|
43
|
+
end
|
39
44
|
|
40
|
-
|
41
|
-
|
45
|
+
@bridge.switchToWindow original
|
46
|
+
returned
|
42
47
|
end
|
43
|
-
|
44
|
-
@bridge.switchToWindow original
|
45
48
|
else
|
46
49
|
@bridge.switchToWindow id
|
47
50
|
end
|
File without changes
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
class Wait
|
4
|
+
|
5
|
+
DEFAULT_TIMEOUT = 30
|
6
|
+
DEFAULT_INTERVAL = 0.5
|
7
|
+
|
8
|
+
#
|
9
|
+
# Create a new Wait instance
|
10
|
+
#
|
11
|
+
# @param [Hash] opts Options for this instance
|
12
|
+
# @option opts [Numeric] :timeout (30) Seconds to wait before timing out.
|
13
|
+
# @option opts [Numeric] :interval (0.5) Seconds to sleep between polls.
|
14
|
+
# @option opts [String] :message Exception mesage if timed out.
|
15
|
+
|
16
|
+
def initialize(opts = {})
|
17
|
+
@timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT)
|
18
|
+
@interval = opts.fetch(:interval, DEFAULT_INTERVAL)
|
19
|
+
@message = opts[:message]
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
#
|
24
|
+
# Wait until the given block returns a true value.
|
25
|
+
#
|
26
|
+
# @raise [Error::TimeOutError]
|
27
|
+
# @return [Object] the result of the block
|
28
|
+
#
|
29
|
+
|
30
|
+
def until(&blk)
|
31
|
+
end_time = Time.now + @timeout
|
32
|
+
last_error = nil
|
33
|
+
|
34
|
+
until Time.now > end_time
|
35
|
+
begin
|
36
|
+
result = yield
|
37
|
+
return result if result
|
38
|
+
rescue Error::NoSuchElementError => last_error
|
39
|
+
# swallowed
|
40
|
+
end
|
41
|
+
|
42
|
+
sleep @interval
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
if @message
|
47
|
+
msg = @message.dup
|
48
|
+
else
|
49
|
+
msg = "timed out after #{@timeout} seconds"
|
50
|
+
end
|
51
|
+
|
52
|
+
msg << " (#{last_error.message})}" if last_error
|
53
|
+
|
54
|
+
raise Error::TimeOutError, msg
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Wait
|
58
|
+
end # WebDriver
|
59
|
+
end # Selenium
|
60
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'zip/zip'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'find'
|
4
|
+
|
5
|
+
module Selenium
|
6
|
+
module WebDriver
|
7
|
+
module Zipper
|
8
|
+
|
9
|
+
EXTENSIONS = %w[.zip .xpi]
|
10
|
+
|
11
|
+
def self.unzip(path)
|
12
|
+
destination = Dir.mktmpdir("unzip")
|
13
|
+
FileReaper << destination
|
14
|
+
|
15
|
+
Zip::ZipFile.open(path) do |zip|
|
16
|
+
zip.each do |entry|
|
17
|
+
to = File.join(destination, entry.name)
|
18
|
+
dirname = File.dirname(to)
|
19
|
+
|
20
|
+
FileUtils.mkdir_p dirname unless File.exist? dirname
|
21
|
+
zip.extract(entry, to)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
destination
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.zip(path)
|
29
|
+
tmp_zip = Tempfile.new("webdriver-zip")
|
30
|
+
|
31
|
+
begin
|
32
|
+
zos = Zip::ZipOutputStream.new(tmp_zip.path)
|
33
|
+
|
34
|
+
::Find.find(path) do |file|
|
35
|
+
next if File.directory?(file)
|
36
|
+
entry = file.sub("#{path}/", '')
|
37
|
+
|
38
|
+
zos.put_next_entry(entry)
|
39
|
+
zos << File.read(file)
|
40
|
+
p :added => file, :as => entry
|
41
|
+
end
|
42
|
+
|
43
|
+
zos.close
|
44
|
+
tmp_zip.rewind
|
45
|
+
|
46
|
+
[tmp_zip.read].pack("m")
|
47
|
+
ensure
|
48
|
+
tmp_zip.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end # Zipper
|
53
|
+
end # WebDriver
|
54
|
+
end # Selenium
|
@@ -3,6 +3,8 @@ require "socket"
|
|
3
3
|
require "rexml/document"
|
4
4
|
|
5
5
|
require "selenium/webdriver/firefox/util"
|
6
|
+
require "selenium/webdriver/firefox/extension"
|
7
|
+
require "selenium/webdriver/firefox/socket_lock"
|
6
8
|
require "selenium/webdriver/firefox/binary"
|
7
9
|
require "selenium/webdriver/firefox/profiles_ini"
|
8
10
|
require "selenium/webdriver/firefox/profile"
|
@@ -11,17 +13,18 @@ require "selenium/webdriver/firefox/bridge"
|
|
11
13
|
|
12
14
|
module Selenium
|
13
15
|
module WebDriver
|
14
|
-
|
15
|
-
# @private
|
16
16
|
module Firefox
|
17
17
|
|
18
|
-
DEFAULT_PROFILE_NAME = "WebDriver".freeze
|
19
18
|
DEFAULT_PORT = 7055
|
20
19
|
DEFAULT_ENABLE_NATIVE_EVENTS = Platform.os == :windows
|
21
20
|
DEFAULT_SECURE_SSL = false
|
22
21
|
DEFAULT_ASSUME_UNTRUSTED_ISSUER = true
|
23
22
|
DEFAULT_LOAD_NO_FOCUS_LIB = false
|
24
23
|
|
24
|
+
def self.path=(path)
|
25
|
+
Binary.path = path
|
26
|
+
end
|
27
|
+
|
25
28
|
end
|
26
29
|
end
|
27
30
|
end
|
@@ -6,78 +6,66 @@ module Selenium
|
|
6
6
|
class Binary
|
7
7
|
|
8
8
|
NO_FOCUS_LIBRARY_NAME = "x_ignore_nofocus.so"
|
9
|
-
NO_FOCUS_LIBRARIES
|
9
|
+
NO_FOCUS_LIBRARIES = [
|
10
10
|
["#{WebDriver.root}/selenium/webdriver/firefox/native/linux/amd64/#{NO_FOCUS_LIBRARY_NAME}", "amd64/#{NO_FOCUS_LIBRARY_NAME}"],
|
11
11
|
["#{WebDriver.root}/selenium/webdriver/firefox/native/linux/x86/#{NO_FOCUS_LIBRARY_NAME}", "x86/#{NO_FOCUS_LIBRARY_NAME}"],
|
12
12
|
]
|
13
13
|
|
14
|
-
|
15
|
-
execute("-CreateProfile", name)
|
14
|
+
WAIT_TIMEOUT = 90
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
_, status = wait
|
20
|
-
end
|
21
|
-
|
22
|
-
if status && status.to_i != 0
|
23
|
-
raise Error::WebDriverError, "could not create base profile: (exit status: #{status})"
|
24
|
-
end
|
25
|
-
end
|
16
|
+
def start_with(profile, profile_path, *args)
|
17
|
+
profile_path = profile_path.gsub("/", "\\") if Platform.win?
|
26
18
|
|
27
|
-
|
28
|
-
ENV['XRE_PROFILE_PATH'] = profile.absolute_path
|
19
|
+
ENV['XRE_PROFILE_PATH'] = profile_path
|
29
20
|
ENV['MOZ_NO_REMOTE'] = '1' # able to launch multiple instances
|
30
21
|
|
31
22
|
if Platform.linux? && (profile.native_events? || profile.load_no_focus_lib?)
|
32
|
-
modify_link_library_path
|
23
|
+
modify_link_library_path profile_path
|
33
24
|
end
|
34
25
|
|
26
|
+
ENV['XRE_CONSOLE_LOG'] = profile.log_file if profile.log_file
|
27
|
+
|
35
28
|
execute(*args)
|
36
29
|
cope_with_mac_strangeness(args) if Platform.mac?
|
37
30
|
end
|
38
31
|
|
32
|
+
def quit
|
33
|
+
return unless @process
|
34
|
+
@process.poll_for_exit 5
|
35
|
+
rescue ChildProcess::TimeoutError
|
36
|
+
# ok, force quit
|
37
|
+
@process.stop 5
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait
|
41
|
+
@process.poll_for_exit(WAIT_TIMEOUT) if @process
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
39
46
|
def execute(*extra_args)
|
40
47
|
args = [self.class.path, "-no-remote", "--verbose"] + extra_args
|
41
|
-
@process = ChildProcess.
|
48
|
+
@process = ChildProcess.build(*args).start
|
42
49
|
end
|
43
50
|
|
44
51
|
def cope_with_mac_strangeness(args)
|
45
52
|
sleep 0.3
|
46
53
|
|
47
|
-
if @process.
|
48
|
-
#
|
49
|
-
sleep
|
54
|
+
if @process.crashed?
|
55
|
+
# ok, trying a restart
|
56
|
+
sleep 7
|
50
57
|
execute(*args)
|
51
58
|
end
|
52
59
|
|
53
60
|
# ensure we're ok
|
54
61
|
sleep 0.3
|
55
|
-
if @process.
|
62
|
+
if @process.crashed?
|
56
63
|
raise Error::WebDriverError, "unable to start Firefox cleanly, args: #{args.inspect}"
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
60
|
-
def
|
61
|
-
@process.ensure_death if @process
|
62
|
-
end
|
63
|
-
|
64
|
-
def kill
|
65
|
-
@process.kill if @process
|
66
|
-
end
|
67
|
-
|
68
|
-
def wait
|
69
|
-
@process.wait if @process
|
70
|
-
end
|
71
|
-
|
72
|
-
def pid
|
73
|
-
@process.pid if @process
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def modify_link_library_path(profile)
|
67
|
+
def modify_link_library_path(profile_path)
|
79
68
|
paths = []
|
80
|
-
profile_path = profile.absolute_path
|
81
69
|
|
82
70
|
NO_FOCUS_LIBRARIES.each do |from, to|
|
83
71
|
dest = File.join(profile_path, to)
|
@@ -94,7 +82,17 @@ module Selenium
|
|
94
82
|
end
|
95
83
|
|
96
84
|
class << self
|
97
|
-
|
85
|
+
|
86
|
+
#
|
87
|
+
# @private
|
88
|
+
#
|
89
|
+
# @see Firefox.path=
|
90
|
+
#
|
91
|
+
|
92
|
+
def path=(path)
|
93
|
+
Platform.assert_executable(path)
|
94
|
+
@path = path
|
95
|
+
end
|
98
96
|
|
99
97
|
def path
|
100
98
|
@path ||= case Platform.os
|
@@ -108,7 +106,7 @@ module Selenium
|
|
108
106
|
raise Error::WebDriverError, "unknown platform: #{Platform.os}"
|
109
107
|
end
|
110
108
|
|
111
|
-
unless File.file?(@path)
|
109
|
+
unless File.file?(@path.to_s)
|
112
110
|
raise Error::WebDriverError, "Could not find Firefox binary (os=#{Platform.os}). Make sure Firefox is installed or set the path manually with #{self}.path="
|
113
111
|
end
|
114
112
|
|
@@ -118,7 +116,7 @@ module Selenium
|
|
118
116
|
private
|
119
117
|
|
120
118
|
def windows_path
|
121
|
-
windows_registry_path ||
|
119
|
+
windows_registry_path || likely_windows_path || Platform.find_binary("firefox")
|
122
120
|
end
|
123
121
|
|
124
122
|
def windows_registry_path
|
@@ -135,6 +133,11 @@ module Selenium
|
|
135
133
|
# older JRuby or IronRuby does not have win32/registry
|
136
134
|
rescue Win32::Registry::Error
|
137
135
|
end
|
136
|
+
|
137
|
+
def likely_windows_path
|
138
|
+
path = "#{ ENV['PROGRAMFILES'] || "\\Program Files" }\\Mozilla Firefox\\firefox.exe"
|
139
|
+
path if File.executable?(path)
|
140
|
+
end
|
138
141
|
end # class << self
|
139
142
|
|
140
143
|
end # Binary
|
@@ -9,8 +9,8 @@ module Selenium
|
|
9
9
|
@binary = Binary.new
|
10
10
|
@launcher = Launcher.new(
|
11
11
|
@binary,
|
12
|
-
opts.delete(:port)
|
13
|
-
opts.delete(:profile)
|
12
|
+
opts.delete(:port) || DEFAULT_PORT,
|
13
|
+
opts.delete(:profile)
|
14
14
|
)
|
15
15
|
|
16
16
|
http_client = opts.delete(:http_client)
|
@@ -50,14 +50,6 @@ module Selenium
|
|
50
50
|
execute :screenshot
|
51
51
|
end
|
52
52
|
|
53
|
-
def findElementByCssSelector(parent, selector)
|
54
|
-
find_element_by 'css selector', selector, parent
|
55
|
-
end
|
56
|
-
|
57
|
-
def findElementsByCssSelector(parent, selector)
|
58
|
-
find_elements_by 'css selector', selector, parent
|
59
|
-
end
|
60
|
-
|
61
53
|
end # Bridge
|
62
54
|
end # Firefox
|
63
55
|
end # WebDriver
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module Firefox
|
4
|
+
|
5
|
+
# @private
|
6
|
+
class Extension
|
7
|
+
EM_NAMESPACE_URI = "http://www.mozilla.org/2004/em-rdf#" # not used?
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
unless File.exist?(path)
|
11
|
+
raise Error::WebDriverError, "could not find extension at #{path.inspect}"
|
12
|
+
end
|
13
|
+
|
14
|
+
@path = path
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_to(extensions_dir)
|
18
|
+
ext_path = File.join extensions_dir, read_id_from_install_rdf(root)
|
19
|
+
|
20
|
+
FileUtils.rm_rf ext_path
|
21
|
+
FileUtils.mkdir_p File.dirname(ext_path), :mode => 0700
|
22
|
+
FileUtils.cp_r root, ext_path
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def root
|
28
|
+
@root ||= (
|
29
|
+
if File.directory? @path
|
30
|
+
@path
|
31
|
+
else
|
32
|
+
unless Zipper::EXTENSIONS.include? File.extname(@path)
|
33
|
+
raise Error::WebDriverError, "expected #{Zipper::EXTENSIONS.join(" or ")}, got #{@path.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
Zipper.unzip(@path)
|
37
|
+
end
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_id_from_install_rdf(directory)
|
42
|
+
rdf_path = File.join(directory, "install.rdf")
|
43
|
+
doc = REXML::Document.new(File.read(rdf_path))
|
44
|
+
|
45
|
+
REXML::XPath.first(doc, "//em:id").text
|
46
|
+
end
|
47
|
+
|
48
|
+
end # Extension
|
49
|
+
end # Firefox
|
50
|
+
end # WebDriver
|
51
|
+
end # Selenium
|