selenium-webdriver 0.0.29 → 0.1.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.
Files changed (45) hide show
  1. data/CHANGES +15 -1
  2. data/lib/selenium-client.rb +2 -0
  3. data/lib/selenium/client.rb +30 -0
  4. data/lib/selenium/client/base.rb +118 -0
  5. data/lib/selenium/client/driver.rb +10 -0
  6. data/lib/selenium/client/errors.rb +9 -0
  7. data/lib/selenium/client/extensions.rb +118 -0
  8. data/lib/selenium/client/idiomatic.rb +488 -0
  9. data/lib/selenium/client/javascript_expression_builder.rb +116 -0
  10. data/lib/selenium/client/javascript_frameworks/jquery.rb +13 -0
  11. data/lib/selenium/client/javascript_frameworks/prototype.rb +13 -0
  12. data/lib/selenium/client/legacy_driver.rb +1711 -0
  13. data/lib/selenium/client/protocol.rb +104 -0
  14. data/lib/selenium/client/selenium_helper.rb +34 -0
  15. data/lib/selenium/rake/server_task.rb +131 -0
  16. data/lib/selenium/server.rb +114 -0
  17. data/lib/selenium/webdriver.rb +3 -2
  18. data/lib/selenium/webdriver/android.rb +9 -0
  19. data/lib/selenium/webdriver/android/bridge.rb +45 -0
  20. data/lib/selenium/webdriver/chrome/extension.zip +0 -0
  21. data/lib/selenium/webdriver/chrome/launcher.rb +6 -3
  22. data/lib/selenium/webdriver/common.rb +2 -0
  23. data/lib/selenium/webdriver/common/driver.rb +8 -4
  24. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +28 -0
  25. data/lib/selenium/webdriver/common/file_reaper.rb +10 -0
  26. data/lib/selenium/webdriver/common/proxy.rb +119 -0
  27. data/lib/selenium/webdriver/common/socket_poller.rb +27 -9
  28. data/lib/selenium/webdriver/firefox/binary.rb +8 -5
  29. data/lib/selenium/webdriver/firefox/bridge.rb +2 -3
  30. data/lib/selenium/webdriver/firefox/extension.rb +17 -14
  31. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  32. data/lib/selenium/webdriver/firefox/launcher.rb +8 -2
  33. data/lib/selenium/webdriver/firefox/profile.rb +45 -1
  34. data/lib/selenium/webdriver/firefox/socket_lock.rb +1 -5
  35. data/lib/selenium/webdriver/ie/bridge.rb +3 -3
  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/iphone.rb +9 -0
  39. data/lib/selenium/webdriver/iphone/bridge.rb +34 -0
  40. data/lib/selenium/webdriver/remote/bridge.rb +0 -1
  41. data/lib/selenium/webdriver/remote/capabilities.rb +46 -13
  42. data/lib/selenium/webdriver/remote/commands.rb +3 -4
  43. data/lib/selenium/webdriver/remote/http/common.rb +1 -1
  44. data/lib/selenium/webdriver/remote/http/default.rb +7 -1
  45. metadata +42 -7
@@ -75,7 +75,7 @@ module Selenium
75
75
  def launch_chrome(server_url)
76
76
  args = [
77
77
  Platform.wrap_in_quotes_if_necessary(self.class.binary_path),
78
- "--load-extension=#{Platform.wrap_in_quotes_if_necessary tmp_extension_dir}",
78
+ "--load-extension=#{Platform.wrap_in_quotes_if_necessary(tmp_extension_dir)}",
79
79
  "--activate-on-launch",
80
80
  "--disable-hang-monitor",
81
81
  "--disable-popup-blocking",
@@ -83,7 +83,7 @@ module Selenium
83
83
  ]
84
84
 
85
85
  unless @default_profile
86
- args << "--user-data-dir=#{Platform.wrap_in_quotes_if_necessary tmp_profile_dir}"
86
+ args << "--user-data-dir=#{Platform.wrap_in_quotes_if_necessary(tmp_profile_dir)}"
87
87
  end
88
88
 
89
89
  unless @secure_ssl
@@ -92,7 +92,10 @@ module Selenium
92
92
 
93
93
  args << server_url
94
94
 
95
- @process = ChildProcess.build(*args).start
95
+ @process = ChildProcess.build(*args)
96
+ @process.io.inherit! if $DEBUG
97
+
98
+ @process.start
96
99
  end
97
100
 
98
101
  def ext_path
@@ -2,6 +2,7 @@ require "selenium/webdriver/common/core_ext/dir"
2
2
  require "selenium/webdriver/common/core_ext/string"
3
3
  require "selenium/webdriver/common/error"
4
4
  require "selenium/webdriver/common/platform"
5
+ require "selenium/webdriver/common/proxy"
5
6
  require "selenium/webdriver/common/file_reaper"
6
7
  require "selenium/webdriver/common/socket_poller"
7
8
  require "selenium/webdriver/common/zipper"
@@ -12,6 +13,7 @@ require "selenium/webdriver/common/timeouts"
12
13
  require "selenium/webdriver/common/options"
13
14
  require "selenium/webdriver/common/find"
14
15
  require "selenium/webdriver/common/driver_extensions/takes_screenshot"
16
+ require "selenium/webdriver/common/driver_extensions/rotatable"
15
17
  require "selenium/webdriver/common/keys"
16
18
  require "selenium/webdriver/common/bridge_helper"
17
19
  require "selenium/webdriver/common/driver"
@@ -34,14 +34,18 @@ module Selenium
34
34
 
35
35
  def for(browser, *args)
36
36
  bridge = case browser
37
- when :ie, :internet_explorer
38
- IE::Bridge.new(*args)
37
+ when :firefox, :ff
38
+ Firefox::Bridge.new(*args)
39
39
  when :remote
40
40
  Remote::Bridge.new(*args)
41
+ when :ie, :internet_explorer
42
+ IE::Bridge.new(*args)
41
43
  when :chrome
42
44
  Chrome::Bridge.new(*args)
43
- when :firefox, :ff
44
- Firefox::Bridge.new(*args)
45
+ when :android
46
+ Android::Bridge.new(*args)
47
+ when :iphone
48
+ IPhone::Bridge.new(*args)
45
49
  else
46
50
  raise ArgumentError, "unknown driver: #{browser.inspect}"
47
51
  end
@@ -0,0 +1,28 @@
1
+ module Selenium
2
+ module WebDriver
3
+
4
+ #
5
+ # @private
6
+ #
7
+
8
+ module DriverExtensions
9
+ module Rotatable
10
+
11
+ ORIENTATIONS = [:landscape, :portrait]
12
+
13
+ def rotate(orientation)
14
+ unless ORIENTATIONS.include?(orientation)
15
+ raise ArgumentError, "expected #{ORIENTATIONS.inspect}, got #{orientation.inspect}"
16
+ end
17
+
18
+ bridge.setScreenOrientation(orientation.to_s.upcase)
19
+ end
20
+
21
+ def orientation
22
+ bridge.getScreenOrientation.to_sym.downcase
23
+ end
24
+
25
+ end # Rotatable
26
+ end # DriverExtensions
27
+ end # WebDriver
28
+ end # Selenium
@@ -20,6 +20,16 @@ module Selenium
20
20
  tmp_files << file
21
21
  end
22
22
 
23
+ def reap(file)
24
+ return unless reap?
25
+
26
+ unless tmp_files.include?(file)
27
+ raise Error::WebDriverError, "file not added for reaping: #{file.inspect}"
28
+ end
29
+
30
+ FileUtils.rm_rf tmp_files.delete(file)
31
+ end
32
+
23
33
  def reap!
24
34
  tmp_files.each { |file| FileUtils.rm_rf(file) } if reap?
25
35
  end
@@ -0,0 +1,119 @@
1
+ module Selenium
2
+ module WebDriver
3
+ class Proxy
4
+ TYPES = {
5
+ :direct => "DIRECT", # Direct connection, no proxy (default on Windows).
6
+ :manual => "MANUAL", # Manual proxy settings (e.g., for httpProxy).
7
+ :pac => "PAC", # Proxy autoconfiguration from URL.
8
+ :auto_detect => "AUTODETECT", # Proxy autodetection (presumably with WPAD).
9
+ :system => "SYSTEM" # Use system settings (default on Linux).
10
+ }
11
+
12
+ attr_reader :type,
13
+ :ftp,
14
+ :http,
15
+ :no_proxy,
16
+ :pac,
17
+ :ssl,
18
+ :auto_detect
19
+
20
+ def initialize(opts = {})
21
+ opts = opts.dup
22
+
23
+ self.type = opts.delete(:type) if opts.has_key? :type
24
+ self.ftp = opts.delete(:ftp) if opts.has_key? :ftp
25
+ self.http = opts.delete(:http) if opts.has_key? :http
26
+ self.no_proxy = opts.delete(:no_proxy) if opts.has_key? :no_proxy
27
+ self.ssl = opts.delete(:ssl) if opts.has_key? :ssl
28
+ self.pac = opts.delete(:pac) if opts.has_key? :pac
29
+ self.auto_detect = opts.delete(:auto_detect) if opts.has_key? :auto_detect
30
+
31
+ unless opts.empty?
32
+ raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
33
+ end
34
+ end
35
+
36
+ def ==(other)
37
+ return false unless other.kind_of? self.class
38
+ as_json == other.as_json
39
+ end
40
+ alias_method :eql?, :==
41
+
42
+
43
+ def ftp=(value)
44
+ self.type = :manual
45
+ @ftp = value
46
+ end
47
+
48
+ def http=(value)
49
+ self.type = :manual
50
+ @http = value
51
+ end
52
+
53
+ def no_proxy=(value)
54
+ self.type = :manual
55
+ @no_proxy = value
56
+ end
57
+
58
+ def ssl=(value)
59
+ self.type = :manual
60
+ @ssl = value
61
+ end
62
+
63
+ def pac=(url)
64
+ self.type = :pac
65
+ @pac = url
66
+ end
67
+
68
+ def auto_detect=(bool)
69
+ self.type = :auto_detect
70
+ @auto_detect = bool
71
+ end
72
+
73
+ def type=(type)
74
+ unless TYPES.has_key? type
75
+ raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
76
+ end
77
+
78
+ if @type && type != @type
79
+ raise ArgumentError, "incompatible proxy type #{type.inspect} (already set to #{@type.inspect})"
80
+ end
81
+
82
+ @type = type
83
+ end
84
+
85
+ def as_json(opts = nil)
86
+ json_result = {
87
+ "proxyType" => TYPES[type]
88
+ }
89
+
90
+ json_result["ftpProxy"] = ftp if ftp
91
+ json_result["httpProxy"] = http if http
92
+ json_result["noProxy"] = no_proxy if no_proxy
93
+ json_result["proxyAutoconfigUrl"] = pac if pac
94
+ json_result["sslProxy"] = ssl if ssl
95
+ json_result["autodetect"] = auto_detect if auto_detect
96
+
97
+ json_result if json_result.length > 1
98
+ end
99
+
100
+ class << self
101
+ def json_create(data)
102
+ proxy = new
103
+
104
+ proxy.type = data['proxyType'].downcase.to_sym if data.has_key? 'proxyType'
105
+ proxy.ftp = data['ftpProxy'] if data.has_key? 'ftpProxy'
106
+ proxy.http = data['httpProxy'] if data.has_key? 'httpProxy'
107
+ proxy.no_proxy = data['noProxy'] if data.has_key? 'noProxy'
108
+ proxy.pac = data['proxyAutoconfigUrl'] if data.has_key? 'proxyAutoconfigUrl'
109
+ proxy.ssl = data['sslProxy'] if data.has_key? 'sslProxy'
110
+ proxy.auto_detect = data['autodetect'] if data.has_key? 'autodetect'
111
+
112
+ proxy
113
+ end
114
+
115
+ end # class << self
116
+
117
+ end # Proxy
118
+ end # WebDriver
119
+ end # Selenium
@@ -12,23 +12,30 @@ module Selenium
12
12
  end
13
13
 
14
14
  #
15
- # @return true if the socket can be connected to
15
+ # Returns true if the server is listening within the given timeout,
16
+ # false otherwise.
17
+ #
18
+ # @return [Boolean]
16
19
  #
17
20
 
18
- def success?
19
- max_time = Time.now + @timeout
21
+ def connected?
22
+ with_timeout { listening? }
23
+ end
20
24
 
21
- (
22
- return true if can_connect?
23
- wait
24
- ) until Time.now >= max_time
25
+ #
26
+ # Returns true if the server has stopped listening within the given timeout,
27
+ # false otherwise.
28
+ #
29
+ # @return [Boolean]
30
+ #
25
31
 
26
- false
32
+ def closed?
33
+ with_timeout { not listening? }
27
34
  end
28
35
 
29
36
  private
30
37
 
31
- def can_connect?
38
+ def listening?
32
39
  # There's a bug in 1.9.1 on Windows where this will succeed even if no
33
40
  # one is listening. Users who hit that should upgrade their Ruby.
34
41
  TCPSocket.new(@host, @port).close
@@ -38,6 +45,17 @@ module Selenium
38
45
  false
39
46
  end
40
47
 
48
+ def with_timeout(&blk)
49
+ max_time = Time.now + @timeout
50
+
51
+ (
52
+ return true if yield
53
+ wait
54
+ ) until Time.now > max_time
55
+
56
+ false
57
+ end
58
+
41
59
  def wait
42
60
  sleep @interval
43
61
  end
@@ -16,15 +16,16 @@ module Selenium
16
16
  def start_with(profile, profile_path, *args)
17
17
  profile_path = profile_path.gsub("/", "\\") if Platform.win?
18
18
 
19
- ENV['XRE_PROFILE_PATH'] = profile_path
20
- ENV['MOZ_NO_REMOTE'] = '1' # able to launch multiple instances
19
+ ENV['XRE_CONSOLE_LOG'] = profile.log_file if profile.log_file
20
+ ENV['XRE_PROFILE_PATH'] = profile_path
21
+ ENV['MOZ_NO_REMOTE'] = '1' # able to launch multiple instances
22
+ ENV['MOZ_CRASHREPORTER_DISABLE'] = '1' # disable breakpad
23
+ ENV['NO_EM_RESTART'] = '1' # prevent the binary from detaching from the console
21
24
 
22
25
  if Platform.linux? && (profile.native_events? || profile.load_no_focus_lib?)
23
26
  modify_link_library_path profile_path
24
27
  end
25
28
 
26
- ENV['XRE_CONSOLE_LOG'] = profile.log_file if profile.log_file
27
-
28
29
  execute(*args)
29
30
  cope_with_mac_strangeness(args) if Platform.mac?
30
31
  end
@@ -45,7 +46,9 @@ module Selenium
45
46
 
46
47
  def execute(*extra_args)
47
48
  args = [self.class.path, "-no-remote", "--verbose"] + extra_args
48
- @process = ChildProcess.build(*args).start
49
+ @process = ChildProcess.build(*args)
50
+ @process.io.inherit! if $DEBUG
51
+ @process.start
49
52
  end
50
53
 
51
54
  def cope_with_mac_strangeness(args)
@@ -6,9 +6,8 @@ module Selenium
6
6
  class Bridge < Remote::Bridge
7
7
 
8
8
  def initialize(opts = {})
9
- @binary = Binary.new
10
9
  @launcher = Launcher.new(
11
- @binary,
10
+ Binary.new,
12
11
  opts.delete(:port) || DEFAULT_PORT,
13
12
  opts.delete(:profile)
14
13
  )
@@ -41,7 +40,7 @@ module Selenium
41
40
 
42
41
  def quit
43
42
  super
44
- @binary.quit
43
+ @launcher.quit
45
44
 
46
45
  nil
47
46
  end
@@ -11,31 +11,34 @@ module Selenium
11
11
  raise Error::WebDriverError, "could not find extension at #{path.inspect}"
12
12
  end
13
13
 
14
- @path = path
14
+ @path = path
15
+ @should_reap_root = false
15
16
  end
16
17
 
17
18
  def write_to(extensions_dir)
18
- ext_path = File.join extensions_dir, read_id_from_install_rdf(root)
19
+ root_dir = create_root
20
+ ext_path = File.join extensions_dir, read_id_from_install_rdf(root_dir)
19
21
 
20
22
  FileUtils.rm_rf ext_path
21
23
  FileUtils.mkdir_p File.dirname(ext_path), :mode => 0700
22
- FileUtils.cp_r root, ext_path
24
+ FileUtils.cp_r root_dir, ext_path
25
+
26
+ FileReaper.reap(root_dir) if @should_reap_root
23
27
  end
24
28
 
25
29
  private
26
30
 
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)
31
+ def create_root
32
+ if File.directory? @path
33
+ @path
34
+ else
35
+ unless Zipper::EXTENSIONS.include? File.extname(@path)
36
+ raise Error::WebDriverError, "expected #{Zipper::EXTENSIONS.join(" or ")}, got #{@path.inspect}"
37
37
  end
38
- )
38
+
39
+ @should_reap_root = true
40
+ Zipper.unzip(@path)
41
+ end
39
42
  end
40
43
 
41
44
  def read_id_from_install_rdf(directory)
@@ -40,6 +40,11 @@ module Selenium
40
40
  self
41
41
  end
42
42
 
43
+ def quit
44
+ @binary.quit
45
+ FileReaper.reap(@profile_dir) if @profile_dir
46
+ end
47
+
43
48
  def find_free_port
44
49
  port = @port
45
50
 
@@ -65,13 +70,14 @@ module Selenium
65
70
 
66
71
  def start_silent_and_wait
67
72
  assert_profile
68
- @binary.start_with @profile, @profile_dir, "--silent"
73
+ @binary.start_with @profile, @profile_dir, "-silent"
69
74
  @binary.wait
70
75
  end
71
76
 
72
77
  def connect_until_stable
73
78
  poller = SocketPoller.new(@host, @port, STABLE_CONNECTION_TIMEOUT)
74
- unless poller.success?
79
+ unless poller.connected?
80
+ @binary.quit
75
81
  raise Error::WebDriverError, "unable to obtain stable firefox connection in #{STABLE_CONNECTION_TIMEOUT} seconds"
76
82
  end
77
83
  end
@@ -156,8 +156,47 @@ module Selenium
156
156
  @untrusted_issuer = bool
157
157
  end
158
158
 
159
+ def proxy=(proxy)
160
+ unless proxy.kind_of? Proxy
161
+ raise TypeError, "expected #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}"
162
+ end
163
+
164
+ case proxy.type
165
+ when :manual
166
+ self['network.proxy.type'] = 1
167
+
168
+ set_manual_proxy_preference "ftp", proxy.ftp
169
+ set_manual_proxy_preference "http", proxy.http
170
+ set_manual_proxy_preference "ssl", proxy.ssl
171
+
172
+ if proxy.no_proxy
173
+ self["network.proxy.no_proxies_on"] = proxy.no_proxy
174
+ else
175
+ self["network.proxy.no_proxies_on"] = ""
176
+ end
177
+ when :pac
178
+ self['network.proxy.type'] = 2
179
+ self['network.proxy.autoconfig_url'] = proxy.pac
180
+ when :auto_detect
181
+ self['network.proxy.type'] = 4
182
+ else
183
+ raise ArgumentError, "unsupported proxy type #{proxy.type}"
184
+ end
185
+
186
+ proxy
187
+ end
188
+
159
189
  private
160
190
 
191
+ def set_manual_proxy_preference(key, value)
192
+ return unless value
193
+
194
+ host, port = value.to_s.split(":", 2)
195
+
196
+ self["network.proxy.#{key}"] = host
197
+ self["network.proxy.#{key}_port"] = Integer(port) if port
198
+ end
199
+
161
200
  def install_extensions(directory)
162
201
  destination = File.join(directory, "extensions")
163
202
 
@@ -267,7 +306,10 @@ module Selenium
267
306
  "browser.shell.checkDefaultBrowser" => 'false',
268
307
  "browser.tabs.warnOnClose" => 'false',
269
308
  "browser.tabs.warnOnOpen" => 'false',
309
+ "devtools.errorconsole.enabled" => 'true',
270
310
  "dom.disable_open_during_load" => 'false',
311
+ "dom.max_script_run_time" => '30',
312
+ "extensions.logging.enabled" => 'true',
271
313
  "extensions.update.enabled" => 'false',
272
314
  "extensions.update.notifyUser" => 'false',
273
315
  "network.manage-offline-status" => 'false',
@@ -283,8 +325,10 @@ module Selenium
283
325
  "security.warn_viewing_mixed" => 'false',
284
326
  "security.warn_viewing_mixed.show_once" => 'false',
285
327
  "signon.rememberSignons" => 'false',
328
+ "toolkit.networkmanager.disable" => 'true',
286
329
  "javascript.options.showInConsole" => 'true',
287
- "browser.dom.window.dump.enabled" => 'true'
330
+ "browser.dom.window.dump.enabled" => 'true',
331
+ "dom.report_all_js_exceptions" => "true"
288
332
  }.freeze
289
333
 
290
334
  end # Profile