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
@@ -0,0 +1,104 @@
1
+ module Selenium
2
+ module Client
3
+
4
+ HTTP_HEADERS = { 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8' }
5
+
6
+ # Module in charge of handling Selenium over-the-wire HTTP protocol
7
+ module Protocol
8
+ attr_reader :session_id
9
+
10
+ def remote_control_command(verb, args=[])
11
+ timeout(@default_timeout_in_seconds) do
12
+ status, response = http_post(http_request_for(verb, args))
13
+ raise CommandError, response unless status == "OK"
14
+ response[3..-1] # strip "OK," from response
15
+ end
16
+ end
17
+
18
+ def string_command(verb, args=[])
19
+ remote_control_command(verb, args)
20
+ end
21
+
22
+ def string_array_command(verb, args=[])
23
+ csv = string_command(verb, args)
24
+ token = ""
25
+ tokens = []
26
+ escape = false
27
+ csv.split(//).each do |letter|
28
+ if escape
29
+ token += letter
30
+ escape = false
31
+ next
32
+ end
33
+ case letter
34
+ when '\\'
35
+ escape = true
36
+ when ','
37
+ tokens << token
38
+ token = ""
39
+ else
40
+ token += letter
41
+ end
42
+ end
43
+ tokens << token
44
+ return tokens
45
+ end
46
+
47
+ def number_command(verb, args)
48
+ string_command verb, args
49
+ end
50
+
51
+ def number_array_command(verb, args)
52
+ string_array_command verb, args
53
+ end
54
+
55
+ def boolean_command(verb, args=[])
56
+ parse_boolean_value string_command(verb, args)
57
+ end
58
+
59
+ def boolean_array_command(verb, args)
60
+ string_array_command(verb, args).collect {|value| parse_boolean_value(value)}
61
+ end
62
+
63
+ protected
64
+
65
+ def parse_boolean_value(value)
66
+ if ("true" == value)
67
+ return true
68
+ elsif ("false" == value)
69
+ return false
70
+ end
71
+ raise ProtocolError, "Invalid Selenese boolean value that is neither 'true' nor 'false': got '#{value}'"
72
+ end
73
+
74
+ def http_request_for(verb, args)
75
+ data = "cmd=#{CGI::escape(verb)}"
76
+ args.each_with_index do |arg, index|
77
+ data << "&#{index.succ}=#{CGI::escape(arg.to_s)}"
78
+ end
79
+ data << "&sessionId=#{session_id}" unless session_id.nil?
80
+ data
81
+ end
82
+
83
+ def http_post(data)
84
+ start = Time.now
85
+ called_from = caller.detect{|line| line !~ /(selenium-client|vendor|usr\/lib\/ruby|\(eval\))/i}
86
+ http = Net::HTTP.new(@host, @port)
87
+ http.open_timeout = default_timeout_in_seconds
88
+ http.read_timeout = default_timeout_in_seconds
89
+ response = http.post('/selenium-server/driver/', data, HTTP_HEADERS)
90
+ if response.body !~ /^OK/
91
+ puts "#{start} selenium-client received failure from selenium server:"
92
+ puts "requested:"
93
+ puts "\t" + CGI::unescape(data.split('&').join("\n\t"))
94
+ puts "received:"
95
+ puts "\t#{response.body.inspect}"
96
+ puts "\tcalled from #{called_from}"
97
+ end
98
+ [ response.body[0..1], response.body ]
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,34 @@
1
+ # Defines a mixin module that you can use to write Selenium tests
2
+ # without typing "@selenium." in front of every command. Every
3
+ # call to a missing method will be automatically sent to the @selenium
4
+ # object.
5
+ module Selenium
6
+ module Client
7
+
8
+ module SeleniumHelper
9
+
10
+ # Overrides default open method to actually delegates to @selenium
11
+ def open(url)
12
+ @selenium.open url
13
+ end
14
+
15
+ # Overrides default type method to actually delegates to @selenium
16
+ def type(locator, value)
17
+ @selenium.type locator, value
18
+ end
19
+
20
+ # Overrides default select method to actually delegates to @selenium
21
+ def select(input_locator, option_locator)
22
+ @selenium.select input_locator, option_locator
23
+ end
24
+
25
+ # Delegates to @selenium on method missing
26
+ def method_missing(method_name, *args)
27
+ return super unless @selenium.respond_to?(method_name)
28
+
29
+ @selenium.send(method_name, *args)
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,131 @@
1
+ require 'selenium/server'
2
+ require 'rake'
3
+
4
+ module Selenium
5
+ module Rake
6
+
7
+ class MissingJarFileError < StandardError
8
+ end
9
+
10
+
11
+ #
12
+ # Defines rake tasks for starting, stopping and restarting the Selenium server.
13
+ #
14
+ # Usage:
15
+ #
16
+ # Selenium::Rake::ServerTask.new do |t|
17
+ # t.jar = "/path/to/selenium-server-standalone.jar"
18
+ # t.port = 4444
19
+ # t.opts = %w[-some options]
20
+ # end
21
+ #
22
+ # Tasks defined:
23
+ #
24
+ # rake selenium:server:start
25
+ # rake selenium:server:stop
26
+ # rake selenium:server:restart
27
+ #
28
+
29
+ class ServerTask
30
+
31
+ #
32
+ # Path to the selenium server jar
33
+ #
34
+
35
+ attr_accessor :jar
36
+
37
+ #
38
+ # Port to use for the server.
39
+ # Default: 4444
40
+ #
41
+ #
42
+
43
+ attr_accessor :port
44
+
45
+ #
46
+ # Timeout in seconds for the server to start/stop.
47
+ # Default: 30
48
+ #
49
+
50
+ attr_accessor :timeout
51
+
52
+ #
53
+ # Whether we should detach from the server process.
54
+ # Default: true
55
+ #
56
+
57
+ attr_accessor :background
58
+ alias_method :background?, :background
59
+
60
+ #
61
+ # Configure logging. Pass a log file path or a boolean.
62
+ # Default: true
63
+ #
64
+ # true - log to stdout/stderr
65
+ # false - no logging
66
+ # String - log to the specified file
67
+ #
68
+
69
+ attr_accessor :log
70
+
71
+ #
72
+ # Add additional options passed to the server jar.
73
+ #
74
+
75
+ attr_accessor :opts
76
+
77
+
78
+ def initialize(prefix = "selenium:server")
79
+ @jar = nil
80
+ @prefix = prefix
81
+ @port = 4444
82
+ @timeout = 30
83
+ @background = true
84
+ @log = true
85
+ @opts = []
86
+
87
+ yield self if block_given?
88
+
89
+ unless @jar
90
+ raise MissingJarFileError, "must provide path to the selenium server jar"
91
+ end
92
+
93
+ @server = Selenium::Server.new(@jar, :port => @port,
94
+ :timeout => @timeout,
95
+ :background => @background,
96
+ :log => @log )
97
+
98
+ @server << @opts
99
+
100
+ define_start_task
101
+ define_stop_task
102
+ define_restart_task
103
+ end
104
+
105
+ private
106
+
107
+ def define_start_task
108
+ desc "Start the Selenium server"
109
+ task "#{@prefix}:start" do
110
+ @server.start
111
+ end
112
+ end
113
+
114
+ def define_stop_task
115
+ desc 'Stop the Selenium server'
116
+ task "#{@prefix}:stop" do
117
+ @server.stop
118
+ end
119
+ end
120
+
121
+ def define_restart_task
122
+ desc 'Restart the Selenium server'
123
+ task "#{@prefix}:restart" do
124
+ @server.stop
125
+ @server.start
126
+ end
127
+ end
128
+
129
+ end # ServerTask
130
+ end # Rake
131
+ end # Selenium
@@ -0,0 +1,114 @@
1
+ require "childprocess"
2
+ require "selenium/webdriver/common/socket_poller"
3
+ require "net/http"
4
+
5
+ module Selenium
6
+
7
+ #
8
+ # Wraps the remote server jar
9
+ #
10
+
11
+ class Server
12
+
13
+ def initialize(jar, opts = {})
14
+ raise Errno::ENOENT, jar unless File.exist?(jar)
15
+
16
+ @jar = jar
17
+ @host = "127.0.0.1"
18
+ @port = opts.fetch(:port, 4444)
19
+ @timeout = opts.fetch(:timeout, 30)
20
+ @background = opts.fetch(:background, false)
21
+ @log = opts[:log]
22
+
23
+ @additional_args = []
24
+ end
25
+
26
+ def start
27
+ process.start
28
+ poll_for_service
29
+
30
+ unless @background
31
+ begin
32
+ sleep 1 while process.alive?
33
+ rescue Errno::ECHILD
34
+ # no longer alive
35
+ end
36
+ end
37
+ end
38
+
39
+ def stop
40
+ begin
41
+ Net::HTTP.get(@host, "/selenium-server/driver/?cmd=shutDownSeleniumServer", @port)
42
+ rescue Errno::ECONNREFUSED
43
+ end
44
+
45
+ stop_process if @process
46
+ poll_for_shutdown
47
+
48
+ @log_file.close if @log_file
49
+ end
50
+
51
+ def webdriver_url
52
+ "http://#{@host}:#{@port}/wd/hub"
53
+ end
54
+
55
+ def <<(arg)
56
+ if arg.kind_of?(Array)
57
+ @additional_args += arg
58
+ else
59
+ @additional_args << arg.to_s
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def stop_process
66
+ return unless @process.alive?
67
+
68
+ begin
69
+ @process.poll_for_exit(5)
70
+ rescue ChildProcess::TimeoutError
71
+ @process.stop
72
+ end
73
+ rescue Errno::ECHILD
74
+ # already dead
75
+ ensure
76
+ @process = nil
77
+ end
78
+
79
+ def process
80
+ @process ||= (
81
+ cp = ChildProcess.build("java", "-jar", @jar, "-port", @port.to_s, *@additional_args)
82
+ io = cp.io
83
+
84
+ if @log.kind_of?(String) && !@background
85
+ @log_file = File.open(@log, "w")
86
+ io.stdout = io.stderr = @log_file
87
+ elsif @log
88
+ io.inherit!
89
+ end
90
+
91
+ cp.detach = @background
92
+
93
+ cp
94
+ )
95
+ end
96
+
97
+ def poll_for_service
98
+ unless socket.connected?
99
+ raise "remote server not launched in #{@timeout} seconds"
100
+ end
101
+ end
102
+
103
+ def poll_for_shutdown
104
+ unless socket.closed?
105
+ raise "remote server not stopped in #{@timeout} seconds"
106
+ end
107
+ end
108
+
109
+ def socket
110
+ @socket ||= WebDriver::SocketPoller.new(@host, @port, @timeout)
111
+ end
112
+
113
+ end # Server
114
+ end # Selenium
@@ -27,15 +27,16 @@ end
27
27
 
28
28
  require "selenium/webdriver/common"
29
29
 
30
-
31
30
  module Selenium
32
31
  module WebDriver
33
32
  Point = Struct.new(:x, :y)
34
33
  Dimension = Struct.new(:width, :height)
35
34
 
35
+ autoload :Android, 'selenium/webdriver/android'
36
+ autoload :Chrome, 'selenium/webdriver/chrome'
36
37
  autoload :IE, 'selenium/webdriver/ie'
38
+ autoload :IPhone, 'selenium/webdriver/iphone'
37
39
  autoload :Remote, 'selenium/webdriver/remote'
38
- autoload :Chrome, 'selenium/webdriver/chrome'
39
40
  autoload :Firefox, 'selenium/webdriver/firefox'
40
41
 
41
42
  def self.root
@@ -0,0 +1,9 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Android
4
+
5
+ end # Android
6
+ end # WebDriver
7
+ end # Selenium
8
+
9
+ require "selenium/webdriver/android/bridge"
@@ -0,0 +1,45 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Android
4
+ class Bridge < Remote::Bridge
5
+
6
+ DEFAULT_URL = "http://localhost:8080/hub"
7
+
8
+ def initialize(opts = nil)
9
+ if opts
10
+ super
11
+ else
12
+ super(
13
+ :url => DEFAULT_URL,
14
+ :desired_capabilities => capabilities
15
+ )
16
+ end
17
+ end
18
+
19
+ def browser
20
+ :android
21
+ end
22
+
23
+ def driver_extensions
24
+ [
25
+ DriverExtensions::TakesScreenshot,
26
+ DriverExtensions::Rotatable
27
+ ]
28
+ end
29
+
30
+ def setScreenOrientation(orientation)
31
+ execute :setScreenOrientation, {}, :orientation => orientation
32
+ end
33
+
34
+ def getScreenOrientation
35
+ execute :getScreenOrientation
36
+ end
37
+
38
+ def capabilities
39
+ @capabilities ||= Remote::Capabilities.android
40
+ end
41
+
42
+ end # Bridge
43
+ end # Android
44
+ end # WebDriver
45
+ end # Selenium