selenium-webdriver 0.0.28 → 0.0.29

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 +25 -0
  2. data/lib/selenium/webdriver.rb +6 -29
  3. data/lib/selenium/webdriver/chrome.rb +4 -2
  4. data/lib/selenium/webdriver/chrome/extension.zip +0 -0
  5. data/lib/selenium/webdriver/chrome/launcher.rb +15 -16
  6. data/lib/selenium/webdriver/common.rb +18 -0
  7. data/lib/selenium/webdriver/{bridge_helper.rb → common/bridge_helper.rb} +0 -0
  8. data/lib/selenium/webdriver/{core_ext → common/core_ext}/dir.rb +0 -0
  9. data/lib/selenium/webdriver/{core_ext → common/core_ext}/string.rb +0 -0
  10. data/lib/selenium/webdriver/{driver.rb → common/driver.rb} +19 -7
  11. data/lib/selenium/webdriver/{driver_extensions → common/driver_extensions}/takes_screenshot.rb +2 -2
  12. data/lib/selenium/webdriver/{element.rb → common/element.rb} +30 -3
  13. data/lib/selenium/webdriver/{error.rb → common/error.rb} +0 -0
  14. data/lib/selenium/webdriver/{file_reaper.rb → common/file_reaper.rb} +0 -0
  15. data/lib/selenium/webdriver/{find.rb → common/find.rb} +9 -1
  16. data/lib/selenium/webdriver/{keys.rb → common/keys.rb} +0 -0
  17. data/lib/selenium/webdriver/{navigation.rb → common/navigation.rb} +3 -3
  18. data/lib/selenium/webdriver/{options.rb → common/options.rb} +47 -5
  19. data/lib/selenium/webdriver/{platform.rb → common/platform.rb} +10 -0
  20. data/lib/selenium/webdriver/common/socket_poller.rb +47 -0
  21. data/lib/selenium/webdriver/{target_locator.rb → common/target_locator.rb} +11 -8
  22. data/lib/selenium/webdriver/{timeouts.rb → common/timeouts.rb} +0 -0
  23. data/lib/selenium/webdriver/common/wait.rb +60 -0
  24. data/lib/selenium/webdriver/common/zipper.rb +54 -0
  25. data/lib/selenium/webdriver/firefox.rb +6 -3
  26. data/lib/selenium/webdriver/firefox/binary.rb +46 -43
  27. data/lib/selenium/webdriver/firefox/bridge.rb +2 -10
  28. data/lib/selenium/webdriver/firefox/extension.rb +51 -0
  29. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  30. data/lib/selenium/webdriver/firefox/launcher.rb +25 -69
  31. data/lib/selenium/webdriver/firefox/profile.rb +123 -89
  32. data/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -1
  33. data/lib/selenium/webdriver/firefox/socket_lock.rb +77 -0
  34. data/lib/selenium/webdriver/ie/bridge.rb +25 -38
  35. data/lib/selenium/webdriver/ie/lib.rb +11 -1
  36. data/lib/selenium/webdriver/ie/native/win32/InternetExplorerDriver.dll +0 -0
  37. data/lib/selenium/webdriver/ie/native/x64/InternetExplorerDriver.dll +0 -0
  38. data/lib/selenium/webdriver/ie/util.rb +3 -17
  39. data/lib/selenium/webdriver/remote/bridge.rb +9 -1
  40. data/lib/selenium/webdriver/remote/capabilities.rb +53 -20
  41. data/lib/selenium/webdriver/remote/http/default.rb +2 -2
  42. metadata +52 -31
  43. data/lib/selenium/webdriver/child_process.rb +0 -243
  44. 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(driver)
10
- @bridge = driver.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
- yield
36
+ begin
37
+ returned = yield
38
+ ensure
39
+ current_handles = @bridge.getWindowHandles
37
40
 
38
- current_handles = @bridge.getWindowHandles
41
+ if current_handles.size == 1
42
+ original = current_handles.shift
43
+ end
39
44
 
40
- if current_handles.size == 1
41
- original = current_handles.shift
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
@@ -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
- def create_base_profile(name)
15
- execute("-CreateProfile", name)
14
+ WAIT_TIMEOUT = 90
16
15
 
17
- status = nil
18
- Timeout.timeout(15, Error::TimeOutError) do
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
- def start_with(profile, *args)
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 profile
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.new(*args).start
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.ugly_death?
48
- # process crashed, trying a restart. sleeping 5 seconds shorter than the java driver
49
- sleep 5
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.ugly_death?
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 quit
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
- attr_writer :path
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 || "#{ ENV['PROGRAMFILES'] || "\\Program Files" }\\Mozilla Firefox\\firefox.exe"
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) || DEFAULT_PORT,
13
- opts.delete(:profile) || DEFAULT_PROFILE_NAME
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