selenium-webdriver 0.0.29 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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