selenium-webdriver 2.20.0 → 2.21.0

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,3 +1,20 @@
1
+ 2.21.0 (2012-04-11)
2
+ ===================
3
+
4
+ * Add Selenium::WebDriver::Window#maximize (#3489)
5
+ * Safari:
6
+ * New driver! See http://code.google.com/p/selenium/wiki/SafariDriver.
7
+ * Firefox:
8
+ * Significant stability improvements.
9
+ * Native events support for Firefox 11
10
+ * Dropped native events support for Firefox 4-9
11
+ * Window maximize implementation.
12
+ * IE:
13
+ * Ignore invisible dialogs (#3360).
14
+ * Window maximize implementation.
15
+ * Android:
16
+ * Accept SSL certificates (#3504).
17
+
1
18
  2.20.0 (2012-02-28)
2
19
  ===================
3
20
 
@@ -101,6 +101,30 @@ module Selenium
101
101
  end
102
102
  end
103
103
 
104
+ #
105
+ # The server port
106
+ #
107
+
108
+ attr_accessor :port
109
+
110
+ #
111
+ # The server timeout
112
+ #
113
+
114
+ attr_accessor :timeout
115
+
116
+ #
117
+ # Whether to launch the server in the background
118
+ #
119
+
120
+ attr_accessor :background
121
+
122
+ #
123
+ # Path to log file, or 'true' for stdout.
124
+ #
125
+
126
+ attr_accessor :log
127
+
104
128
  #
105
129
  # @param [String] jar Path to the server jar.
106
130
  # @param [Hash] opts the options to create the server process with
@@ -190,7 +214,7 @@ module Selenium
190
214
  cp = ChildProcess.build("java", "-jar", @jar, "-port", @port.to_s, *@additional_args)
191
215
  io = cp.io
192
216
 
193
- if @log.kind_of?(String) && !@background
217
+ if @log.kind_of?(String)
194
218
  @log_file = File.open(@log, "w")
195
219
  io.stdout = io.stderr = @log_file
196
220
  elsif @log
@@ -19,6 +19,7 @@ module Selenium
19
19
  autoload :IPhone, 'selenium/webdriver/iphone'
20
20
  autoload :Opera, 'selenium/webdriver/opera'
21
21
  autoload :Remote, 'selenium/webdriver/remote'
22
+ autoload :Safari, 'selenium/webdriver/safari'
22
23
  autoload :Support, 'selenium/webdriver/support'
23
24
 
24
25
  # @api private
@@ -41,6 +41,8 @@ module Selenium
41
41
  IPhone::Bridge.new(opts)
42
42
  when :opera
43
43
  Opera::Bridge.new(opts)
44
+ when :safari
45
+ Safari::Bridge.new(opts)
44
46
  else
45
47
  raise ArgumentError, "unknown driver: #{browser.inspect}"
46
48
  end
@@ -27,17 +27,41 @@ module Selenium
27
27
  end
28
28
 
29
29
  #
30
- # Click the element
30
+ # Click this element. If this causes a new page to load, this method will
31
+ # attempt to block until the page has loaded. At this point, you should
32
+ # discard all references to this element and any further operations
33
+ # performed on this element will raise a StaleElementReferenceError
34
+ # unless you know that the element and the page will still be present. If
35
+ # click() causes a new page to be loaded via an event or is done by
36
+ # sending a native event then the method will *not* wait for it to be
37
+ # loaded and the caller should verify that a new page has been loaded.
31
38
  #
32
-
39
+ # There are some preconditions for an element to be clicked. The element
40
+ # must be visible and it must have a height and width greater then 0.
41
+ #
42
+ # Equivalent to:
43
+ # driver.action.click(element)
44
+ #
45
+ # @example Click on a button
46
+ #
47
+ # driver.find_element(:tag_name, "button").click
48
+ #
49
+ # @raise [StaleElementReferenceError] if the element no longer exists as
50
+ # defined
51
+ #
52
+
33
53
  def click
34
54
  bridge.clickElement @id
35
55
  end
36
56
 
37
57
  #
38
- # Get the tag name of this element
58
+ # Get the tag name of the element.
39
59
  #
40
- # @return [String]
60
+ # @example Get the tagname of an INPUT element(returns "input")
61
+ #
62
+ # driver.find_element(:xpath, "//input").tag_name
63
+ #
64
+ # @return [String] The tag name of this element.
41
65
  #
42
66
 
43
67
  def tag_name
@@ -90,6 +90,14 @@ module Selenium
90
90
  @bridge.setWindowPosition Integer(x), Integer(y)
91
91
  end
92
92
 
93
+ #
94
+ # Maximize the current window
95
+ #
96
+
97
+ def maximize
98
+ @bridge.maximizeWindow
99
+ end
100
+
93
101
 
94
102
  end
95
103
  end
@@ -21,9 +21,7 @@
21
21
  "extensions.logging.enabled": true,
22
22
  "extensions.update.enabled": false,
23
23
  "extensions.update.notifyUser": false,
24
- "focusmanager.testmode": true,
25
24
  "network.manage-offline-status": false,
26
- "network.http.max-connections-per-server": 10,
27
25
  "network.http.phishy-userpass-length": 255,
28
26
  "offline-apps.allow_by_default": true,
29
27
  "prompts.tab_modal.enabled": false,
@@ -51,6 +49,7 @@
51
49
  "dom.max_script_run_time": 30,
52
50
  "dom.report_all_js_exceptions": true,
53
51
  "javascript.options.showInConsole": true,
52
+ "network.http.max-connections-per-server": 10,
54
53
  "webdriver_accept_untrusted_certs": true,
55
54
  "webdriver_assume_untrusted_issuer": true
56
55
  }
@@ -16,25 +16,26 @@ module Selenium
16
16
  timeout = opts.delete(:timeout) { DEFAULT_TIMEOUT }
17
17
  port = opts.delete(:port) { DEFAULT_PORT }
18
18
  http_client = opts.delete(:http_client)
19
+ ignore_mode = opts.delete(:introduce_flakiness_by_ignoring_security_domains)
19
20
 
20
21
  unless opts.empty?
21
22
  raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
22
23
  end
23
24
 
24
25
  @server = Server.new
25
- @port = @server.start Integer(port)
26
+ @port = @server.start Integer(port), timeout
26
27
 
27
- host = Platform.localhost
28
- unless SocketPoller.new(host, @port, timeout).connected?
29
- raise Error::WebDriverError, "unable to connect to IE server within #{timeout} seconds"
28
+ caps = Remote::Capabilities.internet_explorer
29
+ if ignore_mode
30
+ caps['ignoreProtectedModeSettings'] = true
30
31
  end
31
32
 
32
33
  remote_opts = {
33
- :url => "http://#{host}:#{@port}",
34
- :desired_capabilities => :internet_explorer
34
+ :url => @server.uri,
35
+ :desired_capabilities => caps
35
36
  }
36
37
 
37
- remote_opts.merge!(:http_client => http_client) if http_client
38
+ remote_opts[:http_client] = http_client if http_client
38
39
 
39
40
  super(remote_opts)
40
41
  end
@@ -31,10 +31,14 @@ module Selenium
31
31
  # Starts the server, communicating on the specified port, if it is not already running
32
32
  #
33
33
 
34
- def start(start_port)
34
+ def start(start_port, timeout)
35
35
  return port if running?
36
36
  @handle = self.class.start_server(start_port)
37
37
 
38
+ unless SocketPoller.new(Platform.localhost, start_port, timeout).connected?
39
+ raise Error::WebDriverError, "unable to connect to IE server within #{timeout} seconds"
40
+ end
41
+
38
42
  start_port
39
43
  end
40
44
 
@@ -52,6 +56,10 @@ module Selenium
52
56
  self.class.current_port
53
57
  end
54
58
 
59
+ def uri
60
+ "http://#{Platform.localhost}:#{port}"
61
+ end
62
+
55
63
  private
56
64
 
57
65
  def session_count
@@ -104,7 +104,7 @@ module Selenium
104
104
  end
105
105
 
106
106
  def setImplicitWaitTimeout(milliseconds)
107
- execute :setImplicitWaitTimeout, {}, :ms => milliseconds
107
+ execute :implicitlyWait, {}, :ms => milliseconds
108
108
  end
109
109
 
110
110
  def setScriptTimeout(milliseconds)
@@ -217,6 +217,10 @@ module Selenium
217
217
  :height => height
218
218
  end
219
219
 
220
+ def maximizeWindow(handle = :current)
221
+ execute :maximizeWindow, :window_handle => handle
222
+ end
223
+
220
224
  def getWindowSize(handle = :current)
221
225
  data = execute :getWindowSize, :window_handle => handle
222
226
 
@@ -335,11 +339,11 @@ module Selenium
335
339
  end
336
340
 
337
341
  def deleteCookie(name)
338
- execute :deleteCookieNamed, :name => name
342
+ execute :deleteCookie, :name => name
339
343
  end
340
344
 
341
345
  def getAllCookies
342
- execute :getAllCookies
346
+ execute :getCookies
343
347
  end
344
348
 
345
349
  def deleteAllCookies
@@ -562,7 +566,7 @@ module Selenium
562
566
  end
563
567
 
564
568
  #
565
- # executes a command on the remote server via the REST / JSON API.
569
+ # executes a command on the remote server.
566
570
  #
567
571
  #
568
572
  # Returns the 'value' of the returned payload
@@ -573,7 +577,7 @@ module Selenium
573
577
  end
574
578
 
575
579
  #
576
- # executes a command on the remote server via the REST / JSON API.
580
+ # executes a command on the remote server.
577
581
  #
578
582
  # @return [WebDriver::Remote::Response]
579
583
  #
@@ -108,6 +108,15 @@ module Selenium
108
108
  }.merge(opts))
109
109
  end
110
110
 
111
+ def safari(opts = {})
112
+ new({
113
+ :browser_name => "safari",
114
+ :javascript_enabled => true,
115
+ :takes_screenshot => true,
116
+ :css_selectors_enabled => true
117
+ }.merge(opts))
118
+ end
119
+
111
120
  #
112
121
  # @api private
113
122
  #
@@ -37,6 +37,7 @@ class Selenium::WebDriver::Remote::Bridge
37
37
  command :setWindowPosition, :post, "session/:session_id/window/:window_handle/position"
38
38
  command :getWindowSize, :get, "session/:session_id/window/:window_handle/size"
39
39
  command :getWindowPosition, :get, "session/:session_id/window/:window_handle/position"
40
+ command :maximizeWindow, :post, "session/:session_id/window/:window_handle/maximize"
40
41
 
41
42
  #
42
43
  # script execution
@@ -71,16 +72,16 @@ class Selenium::WebDriver::Remote::Bridge
71
72
  # options
72
73
  #
73
74
 
74
- command :getAllCookies, :get, "session/:session_id/cookie"
75
+ command :getCookies, :get, "session/:session_id/cookie"
75
76
  command :addCookie, :post, "session/:session_id/cookie"
76
77
  command :deleteAllCookies, :delete, "session/:session_id/cookie"
77
- command :deleteCookieNamed, :delete, "session/:session_id/cookie/:name"
78
+ command :deleteCookie, :delete, "session/:session_id/cookie/:name"
78
79
 
79
80
  #
80
81
  # timeouts
81
82
  #
82
83
 
83
- command :setImplicitWaitTimeout, :post, "session/:session_id/timeouts/implicit_wait"
84
+ command :implicitlyWait, :post, "session/:session_id/timeouts/implicit_wait"
84
85
  command :setScriptTimeout, :post, "session/:session_id/timeouts/async_script"
85
86
  command :setTimeout, :post, "session/:session_id/timeouts"
86
87
 
@@ -0,0 +1,41 @@
1
+ require 'libwebsocket'
2
+
3
+ module Selenium
4
+ module WebDriver
5
+ module Safari
6
+
7
+ class << self
8
+ def path=(path)
9
+ Platform.assert_executable(path)
10
+ @path = path
11
+ end
12
+
13
+ def path
14
+ @path ||= (
15
+ path = case Platform.os
16
+ when :windows
17
+ # TODO: improve this
18
+ File.join(ENV['ProgramFiles'], 'Safari', 'Safari.exe')
19
+ when :macosx
20
+ "/Applications/Safari.app/Contents/MacOS/Safari"
21
+ else
22
+ Platform.find_binary("Safari")
23
+ end
24
+
25
+ unless File.file?(path) && File.executable?(path)
26
+ raise Error::WebDriverError, "unable to find the Safari executable, please set Selenium::WebDriver::Safari.path= or add it to your PATH."
27
+ end
28
+
29
+ path
30
+ )
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+
38
+ require 'selenium/webdriver/safari/browser'
39
+ require 'selenium/webdriver/safari/server'
40
+ require 'selenium/webdriver/safari/bridge'
41
+
@@ -0,0 +1,96 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Bridge < Remote::Bridge
6
+ COMMAND_TIMEOUT = 60
7
+
8
+ def initialize(opts = {})
9
+ port = Integer(opts[:port] || PortProber.random)
10
+ timeout = Integer(opts[:timeout] || COMMAND_TIMEOUT)
11
+
12
+ @command_id ||= 0
13
+
14
+ @server = Server.new(port, timeout)
15
+ @server.start
16
+
17
+ @browser = Browser.new
18
+ @browser.start(prepare_connect_file)
19
+
20
+ @server.wait_for_connection
21
+
22
+ super(:desired_capabilities => :safari)
23
+ end
24
+
25
+ def quit
26
+ super
27
+
28
+ @server.stop
29
+ @browser.stop
30
+ end
31
+
32
+ def driver_extensions
33
+ []
34
+ end
35
+
36
+ private
37
+
38
+ def create_session(desired_capabilities)
39
+ resp = raw_execute :newSession, {}, :desiredCapabilities => desired_capabilities
40
+ Remote::Capabilities.json_create resp.fetch('value')
41
+ end
42
+
43
+ def raw_execute(command, opts = {}, command_hash = nil)
44
+ @command_id += 1
45
+
46
+ params = {}
47
+ opts.each do |key, value|
48
+ params[camel_case(key.to_s)] = value
49
+ end
50
+
51
+ params.merge!(command_hash) if command_hash
52
+
53
+ @server.send :id => @command_id.to_s,
54
+ :name => command,
55
+ :parameters => params
56
+
57
+ response = @server.receive
58
+
59
+ status_code = response['status']
60
+ if status_code != 0
61
+ raise Error.for_code(status_code), response['value']['message']
62
+ end
63
+
64
+ if response['id'] != @command_id.to_s
65
+ raise Error::WebDriverError, "response id does not match command id"
66
+ end
67
+
68
+ response
69
+ end
70
+
71
+ def camel_case(str)
72
+ parts = str.split('_')
73
+ parts[1..-1].map { |e| e.capitalize! }
74
+
75
+ parts.join
76
+ end
77
+
78
+ def prepare_connect_file
79
+ # TODO: use tempfile?
80
+ path = File.join(Dir.tmpdir, "safaridriver-#{Time.now.to_i}.html")
81
+
82
+ File.open(path, 'w') do |io|
83
+ io << "<!DOCTYPE html><script>window.location = '#{@server.uri}';</script>"
84
+ end
85
+
86
+ FileReaper << path
87
+ path.gsub! "/", "\\" if Platform.windows?
88
+
89
+ path
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,20 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Browser
6
+ def start(*args)
7
+ @process = ChildProcess.new(Safari.path, *args)
8
+ @process.io.inherit! if $DEBUG
9
+ @process.start
10
+ end
11
+
12
+ def stop
13
+ @process.stop if @process
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,138 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Safari
4
+
5
+ class Server
6
+ def initialize(port, command_timeout)
7
+ @port = port
8
+ @command_timeout = command_timeout
9
+ @frame = LibWebSocket::Frame.new
10
+ end
11
+
12
+ def start
13
+ @server = TCPServer.new(Platform.localhost, @port)
14
+ end
15
+
16
+ def stop
17
+ @server.close if @server && !@server.closed?
18
+ @ws.close if @ws && !@ws.closed?
19
+ end
20
+
21
+ def send(command)
22
+ json = MultiJson.encode(command)
23
+ puts ">>> #{json}" if $DEBUG
24
+
25
+ frame = LibWebSocket::Frame.new(json).to_s
26
+
27
+ @ws.write frame
28
+ @ws.flush
29
+ end
30
+
31
+ def receive
32
+ until msg = @frame.next
33
+ end_time = Time.now + @command_timeout
34
+
35
+ begin
36
+ data = @ws.read_nonblock(1)
37
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
38
+ now = Time.now
39
+ if now >= end_time
40
+ raise Error::TimeOutError, "timed out waiting for Safari to respond"
41
+ end
42
+
43
+ IO.select([@ws], nil, nil, end_time - now)
44
+ retry
45
+ end
46
+
47
+ @frame.append(data)
48
+ end
49
+
50
+ puts "<<< #{msg}" if $DEBUG
51
+
52
+ MultiJson.decode msg
53
+ end
54
+
55
+ def ws_uri
56
+ "ws://#{Platform.localhost}:#{@port}/wd"
57
+ end
58
+
59
+ def uri
60
+ "http://#{Platform.localhost}:#{@port}"
61
+ end
62
+
63
+ def wait_for_connection
64
+ # TODO: timeouts / non-blocking accept
65
+ process_initial_http_request
66
+ process_handshake
67
+ end
68
+
69
+ HEADERS = <<-HEADERS
70
+ HTTP/1.1 200 OK
71
+ Content-Type: text/html; charset=utf-8
72
+ Server: safaridriver-ruby
73
+ HEADERS
74
+
75
+ HEADERS.gsub!("\n", "\r\n")
76
+
77
+ HTML = <<-HTML
78
+ <!DOCTYPE html>
79
+ <h2>SafariDriver requesting connection at %s</h2>
80
+ <script>
81
+ // Must wait for onload so the injected script is loaded by the
82
+ // SafariDriver extension.
83
+ window.onload = function() {
84
+ window.postMessage({
85
+ 'message': 'connect',
86
+ 'source': 'webdriver',
87
+ 'url': '%s'
88
+ }, '*');
89
+ };
90
+ </script>
91
+ HTML
92
+
93
+ def process_initial_http_request
94
+ http = @server.accept
95
+
96
+ req = ''
97
+ until req.include?("\r\n\r\n")
98
+ req << http.read(1)
99
+ end
100
+
101
+ http << HEADERS
102
+ http << "\r\n\r\n"
103
+ http << HTML % [ws_uri, ws_uri]
104
+
105
+ http.close
106
+ end
107
+
108
+ def process_handshake
109
+ @ws = @server.accept
110
+ hs = LibWebSocket::OpeningHandshake::Server.new
111
+
112
+ req = ''
113
+ until hs.done?
114
+ data = @ws.getc || next
115
+ req << data.chr
116
+
117
+ unless hs.parse(data.chr)
118
+ if req.include? "favicon.ico"
119
+ @ws.close
120
+ process_handshake
121
+ return
122
+ else
123
+ raise Error::WebDriverError, "#{hs.error}: #{req}"
124
+ end
125
+ end
126
+ end
127
+
128
+ @ws.write(hs.to_s)
129
+ @ws.flush
130
+
131
+ puts "handshake complete" if $DEBUG
132
+ @server.close
133
+ end
134
+ end
135
+
136
+ end
137
+ end
138
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: selenium-webdriver
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.20.0
5
+ version: 2.21.0
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: 2012-02-28 00:00:00 -08:00
13
+ date: 2012-04-11 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -58,49 +58,60 @@ dependencies:
58
58
  type: :runtime
59
59
  version_requirements: *id004
60
60
  - !ruby/object:Gem::Dependency
61
- name: rspec
61
+ name: libwebsocket
62
62
  prerelease: false
63
63
  requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.3
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
64
75
  none: false
65
76
  requirements:
66
77
  - - ~>
67
78
  - !ruby/object:Gem::Version
68
79
  version: "2.0"
69
80
  type: :development
70
- version_requirements: *id005
81
+ version_requirements: *id006
71
82
  - !ruby/object:Gem::Dependency
72
83
  name: rack
73
84
  prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
85
+ requirement: &id007 !ruby/object:Gem::Requirement
75
86
  none: false
76
87
  requirements:
77
88
  - - ~>
78
89
  - !ruby/object:Gem::Version
79
90
  version: "1.0"
80
91
  type: :development
81
- version_requirements: *id006
92
+ version_requirements: *id007
82
93
  - !ruby/object:Gem::Dependency
83
94
  name: ci_reporter
84
95
  prerelease: false
85
- requirement: &id007 !ruby/object:Gem::Requirement
96
+ requirement: &id008 !ruby/object:Gem::Requirement
86
97
  none: false
87
98
  requirements:
88
99
  - - ~>
89
100
  - !ruby/object:Gem::Version
90
101
  version: 1.6.2
91
102
  type: :development
92
- version_requirements: *id007
103
+ version_requirements: *id008
93
104
  - !ruby/object:Gem::Dependency
94
105
  name: webmock
95
106
  prerelease: false
96
- requirement: &id008 !ruby/object:Gem::Requirement
107
+ requirement: &id009 !ruby/object:Gem::Requirement
97
108
  none: false
98
109
  requirements:
99
110
  - - ~>
100
111
  - !ruby/object:Gem::Version
101
112
  version: 1.7.5
102
113
  type: :development
103
- version_requirements: *id008
114
+ version_requirements: *id009
104
115
  description: WebDriver is a tool for writing automated tests of websites. It aims to mimic the behaviour of a real user, and as such interacts with the HTML of the application.
105
116
  email: jari.bakken@gmail.com
106
117
  executables: []
@@ -135,6 +146,7 @@ files:
135
146
  - lib/selenium/webdriver/iphone.rb
136
147
  - lib/selenium/webdriver/opera.rb
137
148
  - lib/selenium/webdriver/remote.rb
149
+ - lib/selenium/webdriver/safari.rb
138
150
  - lib/selenium/webdriver/support.rb
139
151
  - lib/selenium/webdriver/android/bridge.rb
140
152
  - lib/selenium/webdriver/chrome/bridge.rb
@@ -208,6 +220,9 @@ files:
208
220
  - lib/selenium/webdriver/remote/http/curb.rb
209
221
  - lib/selenium/webdriver/remote/http/default.rb
210
222
  - lib/selenium/webdriver/remote/http/persistent.rb
223
+ - lib/selenium/webdriver/safari/bridge.rb
224
+ - lib/selenium/webdriver/safari/browser.rb
225
+ - lib/selenium/webdriver/safari/server.rb
211
226
  - lib/selenium/webdriver/support/abstract_event_listener.rb
212
227
  - lib/selenium/webdriver/support/block_event_listener.rb
213
228
  - lib/selenium/webdriver/support/event_firing_bridge.rb