selenium-webdriver 0.1.4 → 0.2.0.dev

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 CHANGED
@@ -1,5 +1,12 @@
1
+ 0.2.0 (???)
2
+ ==================
3
+
4
+ * Update Ruby bindings to use the new Chrome driver (http://code.google.com/p/selenium/wiki/ChromeDriver).
5
+ * Add deprecation warning for WebDriver::Element#value.
6
+ * Change the default timeout for Wait instances to 5 seconds.
7
+
1
8
  0.1.4 (2011-03-21)
2
- ===========
9
+ ==================
3
10
 
4
11
  * Support for Firefox 4.
5
12
  * Search PATH for Firefox / Chrome on OS X as well.
@@ -1,17 +1,15 @@
1
- require "selenium/webdriver/chrome/launcher"
2
- require "selenium/webdriver/chrome/command_executor"
1
+ require 'net/http'
2
+
3
+ require "selenium/webdriver/chrome/service"
3
4
  require "selenium/webdriver/chrome/bridge"
4
5
 
5
- require "fileutils"
6
- require "thread"
7
- require "socket"
8
6
 
9
7
  module Selenium
10
8
  module WebDriver
11
9
 
12
10
  module Chrome
13
11
  def self.path=(path)
14
- Launcher.binary_path = path
12
+ Service.executable_path = path
15
13
  end
16
14
  end
17
15
 
@@ -6,13 +6,24 @@ module Selenium
6
6
  class Bridge < Remote::Bridge
7
7
 
8
8
  def initialize(opts = {})
9
- @launcher = Launcher.new(
10
- :default_profile => opts[:default_profile],
11
- :secure_ssl => opts[:secure_ssl]
12
- )
9
+ # TODO: pass options to Chrome::Service
10
+ http_client = opts.delete(:http_client)
13
11
 
14
- @executor = CommandExecutor.new
15
- @launcher.launch(@executor.uri)
12
+ unless opts.empty?
13
+ raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
14
+ end
15
+
16
+ @service = Service.default_service
17
+ @service.start
18
+
19
+ remote_opts = {
20
+ :url => @service.uri,
21
+ :desired_capabilities => :chrome
22
+ }
23
+
24
+ remote_opts.merge!(:http_client => http_client) if http_client
25
+
26
+ super(remote_opts)
16
27
  end
17
28
 
18
29
  def browser
@@ -20,7 +31,7 @@ module Selenium
20
31
  end
21
32
 
22
33
  def driver_extensions
23
- [DriverExtensions::TakesScreenshot]
34
+ []
24
35
  end
25
36
 
26
37
  def capabilities
@@ -28,81 +39,9 @@ module Selenium
28
39
  end
29
40
 
30
41
  def quit
31
- begin
32
- super
33
- rescue IOError
34
- end
35
-
36
- @executor.close
37
- @launcher.quit
38
- end
39
-
40
- def getAllCookies
41
- execute :getCookies
42
- end
43
-
44
- def deleteCookie(name)
45
- execute :deleteCookie, :name => name
46
- end
47
-
48
- def setImplicitWaitTimeout(milliseconds)
49
- execute :implicitlyWait, :ms => milliseconds
50
- end
51
-
52
- def elementEquals(element, other)
53
- element.ref == other.ref
54
- end
55
-
56
- %w[acceptAlert dismissAlert setAlertValue getAlertText].each do |m|
57
- define_method(m) { |*args| raise NotImplementedError }
58
- end
59
-
60
- private
61
-
62
- def execute(command_name, opts = {}, args = nil)
63
- command = {:request => command_name}.merge(opts)
64
- command.merge!(args) if args
65
-
66
- command = camel_case_keys_in(command)
67
-
68
- puts "--> #{command.inspect}" if $DEBUG
69
- resp = raw_execute command
70
- puts "<-- #{resp.inspect}" if $DEBUG
71
-
72
- code = resp['status']
73
- if e = Error.for_code(code)
74
- msg = resp['value']['message'] if resp['value']
75
- msg ||= "unknown exception for #{command.inspect}"
76
- msg << " (#{code})"
77
-
78
- raise e, msg
79
- end
80
-
81
- resp['value']
82
- end
83
-
84
- def raw_execute(command)
85
- @executor.execute command
86
- end
87
-
88
- #
89
- # TODO(jari): fix this in the remote driver
90
- #
91
-
92
- def camel_case(string)
93
- parts = string.split('_')
94
- parts[1..-1].map { |e| e.capitalize! }
95
- parts.join
96
- end
97
-
98
- def camel_case_keys_in(hash)
99
- h = {}
100
-
101
- hash.each do |key, value|
102
- h[camel_case(key.to_s)] = value
103
- end
104
-
105
- h
42
+ super
43
+ ensure
44
+ @service.stop
106
45
  end
107
46
 
108
47
  end # Bridge
@@ -0,0 +1,62 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Chrome
4
+
5
+ #
6
+ # @api private
7
+ #
8
+
9
+ class Service
10
+ START_TIMEOUT = 20
11
+ STOP_TIMEOUT = 5
12
+ MISSING_TEXT = "Unable to find the chromedriver executable. Please download the server from http://code.google.com/p/selenium/downloads/list and place it somewhere on your PATH. More info at http://code.google.com/p/selenium/wiki/ChromeDriver."
13
+
14
+ attr_reader :uri
15
+
16
+ def self.executable_path
17
+ @executable_path ||= (
18
+ Platform.find_binary "chromedriver" or raise Error::WebDriverError, MISSING_TEXT
19
+ )
20
+ end
21
+
22
+ def self.executable_path=(path)
23
+ Platform.assert_executable path
24
+ @executable_path = path
25
+ end
26
+
27
+ def self.default_service
28
+ new executable_path, PortProber.random
29
+ end
30
+
31
+ def initialize(executable_path, port)
32
+ @uri = URI.parse "http://#{Platform.localhost}:#{port}"
33
+ server_command = [executable_path, "--port=#{port}"]
34
+
35
+ @process = ChildProcess.build(*server_command)
36
+ @socket_poller = SocketPoller.new Platform.localhost, port, START_TIMEOUT
37
+
38
+ @process.io.inherit! if $DEBUG == true
39
+ end
40
+
41
+ def start
42
+ @process.start
43
+
44
+ unless @socket_poller.connected?
45
+ raise Error::WebDriverError, "unable to connect to chromedriver #{@uri}"
46
+ end
47
+ end
48
+
49
+ def stop
50
+ return if @process.nil? || @process.exited?
51
+
52
+ Net::HTTP.get uri.host, '/shutdown', uri.port
53
+ @process.poll_for_exit STOP_TIMEOUT
54
+ rescue ChildProcess::TimeoutError
55
+ # ok, force quit
56
+ @process.stop STOP_TIMEOUT
57
+ end
58
+ end # Service
59
+
60
+ end # Chrome
61
+ end # WebDriver
62
+ end # Service
@@ -5,6 +5,7 @@ require "selenium/webdriver/common/platform"
5
5
  require "selenium/webdriver/common/proxy"
6
6
  require "selenium/webdriver/common/file_reaper"
7
7
  require "selenium/webdriver/common/socket_poller"
8
+ require "selenium/webdriver/common/port_prober"
8
9
  require "selenium/webdriver/common/zipper"
9
10
  require "selenium/webdriver/common/wait"
10
11
  require "selenium/webdriver/common/alert"
@@ -53,6 +53,7 @@ module Selenium
53
53
  #
54
54
 
55
55
  def value
56
+ warn "#{self.class}#value is deprecated, please use #{self.class}#attribute('value')"
56
57
  bridge.getElementValue @id
57
58
  end
58
59
 
@@ -0,0 +1,25 @@
1
+ module Selenium
2
+ module WebDriver
3
+ class PortProber
4
+ def self.above(port)
5
+ port += 1 until free? port
6
+ port
7
+ end
8
+
9
+ def self.random
10
+ server = TCPServer.new(Platform.localhost, 0)
11
+ port = server.addr[1]
12
+ server.close
13
+
14
+ port
15
+ end
16
+
17
+ def self.free?(port)
18
+ TCPServer.new(Platform.localhost, port).close
19
+ true
20
+ rescue SocketError, Errno::EADDRINUSE
21
+ false
22
+ end
23
+ end # PortProber
24
+ end # WebDriver
25
+ end # Selenium
@@ -2,14 +2,14 @@ module Selenium
2
2
  module WebDriver
3
3
  class Wait
4
4
 
5
- DEFAULT_TIMEOUT = 30
5
+ DEFAULT_TIMEOUT = 5
6
6
  DEFAULT_INTERVAL = 0.5
7
7
 
8
8
  #
9
9
  # Create a new Wait instance
10
10
  #
11
11
  # @param [Hash] opts Options for this instance
12
- # @option opts [Numeric] :timeout (30) Seconds to wait before timing out.
12
+ # @option opts [Numeric] :timeout (5) Seconds to wait before timing out.
13
13
  # @option opts [Numeric] :interval (0.5) Seconds to sleep between polls.
14
14
  # @option opts [String] :message Exception mesage if timed out.
15
15
 
@@ -11,7 +11,8 @@ module Selenium
11
11
  ["#{WebDriver.root}/selenium/webdriver/firefox/native/linux/x86/#{NO_FOCUS_LIBRARY_NAME}", "x86/#{NO_FOCUS_LIBRARY_NAME}"],
12
12
  ]
13
13
 
14
- WAIT_TIMEOUT = 90
14
+ WAIT_TIMEOUT = 90
15
+ QUIT_TIMEOUT = 5
15
16
 
16
17
  def start_with(profile, profile_path, *args)
17
18
  profile_path = profile_path.gsub("/", "\\") if Platform.win?
@@ -32,10 +33,10 @@ module Selenium
32
33
 
33
34
  def quit
34
35
  return unless @process
35
- @process.poll_for_exit 5
36
+ @process.poll_for_exit QUIT_TIMEOUT
36
37
  rescue ChildProcess::TimeoutError
37
38
  # ok, force quit
38
- @process.stop 5
39
+ @process.stop QUIT_TIMEOUT
39
40
  end
40
41
 
41
42
  def wait
@@ -46,13 +46,7 @@ module Selenium
46
46
  end
47
47
 
48
48
  def find_free_port
49
- port = @port
50
-
51
- until free_port?(port)
52
- port += 1
53
- end
54
-
55
- @port = port
49
+ @port = PortProber.above @port
56
50
  end
57
51
 
58
52
  def create_profile
@@ -82,14 +76,6 @@ module Selenium
82
76
  end
83
77
  end
84
78
 
85
- def free_port?(port)
86
- s = TCPServer.new(@host, port)
87
- s.close
88
- true
89
- rescue SocketError, Errno::EADDRINUSE
90
- false
91
- end
92
-
93
79
  def fetch_profile
94
80
  if @profile_name
95
81
  @profile = Profile.from_name @profile_name
@@ -59,7 +59,7 @@ module Selenium
59
59
  desired_capabilities = Capabilities.send(desired_capabilities)
60
60
  end
61
61
 
62
- uri = URI.parse(url)
62
+ uri = url.kind_of?(URI) ? url : URI.parse(url)
63
63
  uri.path += "/" unless uri.path =~ /\/$/
64
64
 
65
65
  http_client.server_url = uri
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selenium-webdriver
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.1.4
4
+ prerelease: 6
5
+ version: 0.2.0.dev
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jari Bakken
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-21 00:00:00 +01:00
13
+ date: 2011-04-06 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -116,9 +116,7 @@ files:
116
116
  - lib/selenium/webdriver/android/bridge.rb
117
117
  - lib/selenium/webdriver/android.rb
118
118
  - lib/selenium/webdriver/chrome/bridge.rb
119
- - lib/selenium/webdriver/chrome/command_executor.rb
120
- - lib/selenium/webdriver/chrome/extension.zip
121
- - lib/selenium/webdriver/chrome/launcher.rb
119
+ - lib/selenium/webdriver/chrome/service.rb
122
120
  - lib/selenium/webdriver/chrome.rb
123
121
  - lib/selenium/webdriver/common/action_builder.rb
124
122
  - lib/selenium/webdriver/common/alert.rb
@@ -138,6 +136,7 @@ files:
138
136
  - lib/selenium/webdriver/common/navigation.rb
139
137
  - lib/selenium/webdriver/common/options.rb
140
138
  - lib/selenium/webdriver/common/platform.rb
139
+ - lib/selenium/webdriver/common/port_prober.rb
141
140
  - lib/selenium/webdriver/common/proxy.rb
142
141
  - lib/selenium/webdriver/common/search_context.rb
143
142
  - lib/selenium/webdriver/common/socket_poller.rb
@@ -198,9 +197,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
197
  required_rubygems_version: !ruby/object:Gem::Requirement
199
198
  none: false
200
199
  requirements:
201
- - - ">="
200
+ - - ">"
202
201
  - !ruby/object:Gem::Version
203
- version: "0"
202
+ version: 1.3.1
204
203
  requirements: []
205
204
 
206
205
  rubyforge_project:
@@ -1,126 +0,0 @@
1
- module Selenium
2
- module WebDriver
3
- module Chrome
4
-
5
- # @api private
6
- class CommandExecutor
7
- HTML_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s"
8
- JSON_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n%s"
9
-
10
- def initialize
11
- @server = TCPServer.new(localhost, 0)
12
- @queue = Queue.new
13
-
14
- @accepted_any = false
15
- @next_socket = nil
16
- @listening = true
17
-
18
- Thread.new { start_run_loop }
19
- end
20
-
21
- def execute(command)
22
- until accepted_any?
23
- Thread.pass
24
- sleep 0.01
25
- end
26
-
27
- json = command.to_json
28
- data = JSON_TEMPLATE % [json.length, json]
29
-
30
- @next_socket.write data
31
- @next_socket.close
32
-
33
- JSON.parse read_response(@queue.pop)
34
- end
35
-
36
- def close
37
- stop_listening
38
- close_sockets
39
- @server.close unless @server.closed?
40
- rescue IOError
41
- nil
42
- end
43
-
44
- def port
45
- @server.addr[1]
46
- end
47
-
48
- def uri
49
- "http://#{Platform.localhost}:#{port}/chromeCommandExecutor"
50
- end
51
-
52
- private
53
-
54
- def localhost
55
- Platform.ironruby? ? Platform.localhost : "0.0.0.0" # yeah, weird..
56
- end
57
-
58
- def start_run_loop
59
- while(@listening) do
60
- socket = @server.accept
61
-
62
- if socket.read(1) == "G" # initial GET(s)
63
- write_holding_page_to socket
64
- else
65
- if accepted_any?
66
- @queue << socket
67
- else
68
- read_response(socket)
69
- @accepted_any = true
70
- end
71
- end
72
- end
73
- rescue IOError, Errno::EBADF
74
- raise if @listening
75
- end
76
-
77
- def read_response(socket)
78
- result = ''
79
- seen_double_crlf = false
80
-
81
- while line = next_line(socket)
82
- seen_double_crlf = true if line.empty?
83
- result << "#{line}\n" if seen_double_crlf
84
- end
85
-
86
- @next_socket = socket
87
-
88
- result.strip!
89
- end
90
-
91
- def accepted_any?
92
- @accepted_any
93
- end
94
-
95
- def close_sockets
96
- @next_socket.close if @next_socket
97
- @queue.pop.close until @queue.empty?
98
- end
99
-
100
- def stop_listening
101
- @listening = false
102
- end
103
-
104
- def next_line(socket)
105
- return if socket.closed?
106
- input = socket.gets
107
-
108
- raise Error::WebDriverError, "unexpected EOF from Chrome" if input.nil?
109
-
110
- line = input.chomp
111
- return if line == "EOResponse"
112
-
113
- line
114
- end
115
-
116
- def write_holding_page_to(socket)
117
- msg = %[<html><head><script type='text/javascript'>if (window.location.search == '') { setTimeout("window.location = window.location.href + '?reloaded'", 5000); }</script></head><body><p>ChromeDriver server started and connected. Please leave this tab open.</p></body></html>]
118
-
119
- socket.write HTML_TEMPLATE % [msg.length, msg]
120
- socket.close
121
- end
122
-
123
- end # CommandExecutor
124
- end # Chrome
125
- end # WebDriver
126
- end # Selenium
@@ -1,175 +0,0 @@
1
- module Selenium
2
- module WebDriver
3
- module Chrome
4
-
5
- # @api private
6
- class Launcher
7
- include FileUtils
8
-
9
- attr_reader :pid
10
-
11
- def initialize(opts = {})
12
- @default_profile = opts[:default_profile]
13
- @secure_ssl = !!opts[:secure_ssl]
14
- end
15
-
16
- def self.binary_path
17
- @binary_path ||= (
18
- path = possible_paths.find { |f| File.exist?(f) }
19
- path || raise(Error::WebDriverError, "Could not find Chrome binary. Make sure Chrome is installed (OS: #{Platform.os})")
20
- )
21
- end
22
-
23
- #
24
- # @api private
25
- #
26
- # @see Chrome.path=
27
- #
28
-
29
- def self.binary_path=(path)
30
- Platform.assert_executable(path)
31
- @binary_path = path
32
- end
33
-
34
- def launch(server_url)
35
- create_extension
36
- create_profile
37
- launch_chrome server_url
38
-
39
- pid
40
- end
41
-
42
- def quit
43
- @process.stop
44
- end
45
-
46
- private
47
-
48
- def create_extension
49
- # TODO: find a better way to do this
50
- rm_rf tmp_extension_dir
51
- mkdir_p File.dirname(tmp_extension_dir), :mode => 0700
52
- cp_r ext_path, tmp_extension_dir
53
- end
54
-
55
- def create_profile
56
- touch "#{tmp_profile_dir}/First Run"
57
- touch "#{tmp_profile_dir}/First Run Dev"
58
- end
59
-
60
- def launch_chrome(server_url)
61
- path = self.class.binary_path
62
-
63
- args = [
64
- Platform.wrap_in_quotes_if_necessary(path),
65
- "--load-extension=#{Platform.wrap_in_quotes_if_necessary(tmp_extension_dir)}",
66
- "--activate-on-launch",
67
- "--disable-hang-monitor",
68
- "--disable-popup-blocking",
69
- "--disable-prompt-on-repost"
70
- ]
71
-
72
- unless @default_profile
73
- args << "--user-data-dir=#{Platform.wrap_in_quotes_if_necessary(tmp_profile_dir)}"
74
- end
75
-
76
- unless @secure_ssl
77
- args << "--ignore-certificate-errors"
78
- end
79
-
80
- args << server_url
81
-
82
- @process = ChildProcess.build(*args)
83
- @process.io.inherit! if $DEBUG
84
-
85
- @process.start
86
- end
87
-
88
- def ext_path
89
- @ext_path ||= Zipper.unzip("#{WebDriver.root}/selenium/webdriver/chrome/extension.zip")
90
- end
91
-
92
- def tmp_extension_dir
93
- @tmp_extension_dir ||= (
94
- dir = Dir.mktmpdir("webdriver-chrome-extension")
95
- Platform.make_writable(dir)
96
- FileReaper << dir
97
-
98
- dir
99
- )
100
- end
101
-
102
- def tmp_profile_dir
103
- @tmp_profile_dir ||= (
104
- dir = Dir.mktmpdir("webdriver-chrome-profile")
105
- Platform.make_writable(dir)
106
- FileReaper << dir
107
-
108
- dir
109
- )
110
- end
111
-
112
- class << self
113
- def possible_paths
114
- case Platform.os
115
- when :windows
116
- windows_paths
117
- when :macosx
118
- macosx_paths
119
- when :unix, :linux
120
- unix_paths
121
- else
122
- raise "unknown OS: #{Platform.os}"
123
- end
124
- end
125
-
126
- def unix_paths
127
- [
128
- Platform.find_binary("google-chrome"),
129
- Platform.find_binary("chromium"),
130
- Platform.find_binary("chromium-browser"),
131
- "/usr/bin/google-chrome"
132
- ].compact
133
- end
134
-
135
- def macosx_paths
136
- [
137
- "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
138
- "#{Platform.home}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
139
- Platform.find_binary("Google Chrome")
140
- ]
141
- end
142
-
143
- def windows_paths
144
- paths = [
145
- windows_registry_path,
146
- "#{ENV['USERPROFILE']}\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe",
147
- "#{ENV['USERPROFILE']}\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
148
- "#{Platform.home}\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe",
149
- "#{Platform.home}\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe",
150
- ].compact
151
-
152
- paths.map! { |path| Platform.cygwin_path(path) } if Platform.cygwin?
153
-
154
- paths
155
- end
156
-
157
- def windows_registry_path
158
- require "win32/registry"
159
-
160
- reg = Win32::Registry::HKEY_LOCAL_MACHINE.open(
161
- "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe")
162
-
163
- reg[""]
164
- rescue LoadError
165
- # older JRuby and IronRuby does not have win32/registry
166
- nil
167
- rescue Win32::Registry::Error
168
- nil
169
- end
170
- end # class << self
171
-
172
- end # Launcher
173
- end # Chrome
174
- end # WebDriver
175
- end # Selenium