selenium-selenese 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/README.markdown +308 -0
  2. data/examples/script/google.rb +15 -0
  3. data/lib/nautilus/shell.rb +32 -0
  4. data/lib/selenium.rb +14 -0
  5. data/lib/selenium/client/base.rb +140 -0
  6. data/lib/selenium/client/driver.rb +11 -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 +131 -0
  14. data/lib/selenium/client/selenium_helper.rb +36 -0
  15. data/lib/selenium/command_error.rb +4 -0
  16. data/lib/selenium/protocol_error.rb +4 -0
  17. data/lib/selenium/rake/default_tasks.rb +16 -0
  18. data/lib/selenium/rake/remote_control_start_task.rb +71 -0
  19. data/lib/selenium/rake/remote_control_stop_task.rb +44 -0
  20. data/lib/selenium/rake/tasks.rb +6 -0
  21. data/lib/selenium/remote_control/remote_control.rb +35 -0
  22. data/lib/selenium/rspec/reporting/file_path_strategy.rb +78 -0
  23. data/lib/selenium/rspec/reporting/html_report.rb +123 -0
  24. data/lib/selenium/rspec/reporting/selenium_test_report_formatter.rb +87 -0
  25. data/lib/selenium/rspec/reporting/system_capture.rb +72 -0
  26. data/lib/selenium/rspec/rspec_extensions.rb +96 -0
  27. data/lib/selenium/rspec/spec_helper.rb +34 -0
  28. data/lib/selenium/selenese.rb +24 -0
  29. data/lib/tcp_socket_extension.rb +32 -0
  30. data/vendor/selenium-server.jar +0 -0
  31. metadata +101 -0
@@ -0,0 +1,131 @@
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
+
9
+ $commands = []
10
+
11
+ attr_reader :session_id
12
+
13
+ def remote_control_command(verb, args=[])
14
+ timeout(@default_timeout_in_seconds) do
15
+ status, response = http_post(http_request_for(verb, args))
16
+ raise Selenium::CommandError, response unless status == "OK"
17
+ response[3..-1] # strip "OK," from response
18
+ end
19
+ end
20
+
21
+ def string_command(verb, args=[])
22
+ remote_control_command(verb, args)
23
+ end
24
+
25
+ def string_array_command(verb, args=[])
26
+ csv = string_command(verb, args)
27
+ token = ""
28
+ tokens = []
29
+ escape = false
30
+ csv.split(//).each do |letter|
31
+ if escape
32
+ token += letter
33
+ escape = false
34
+ next
35
+ end
36
+ case letter
37
+ when '\\'
38
+ escape = true
39
+ when ','
40
+ tokens << token
41
+ token = ""
42
+ else
43
+ token += letter
44
+ end
45
+ end
46
+ tokens << token
47
+ return tokens
48
+ end
49
+
50
+ def number_command(verb, args)
51
+ string_command verb, args
52
+ end
53
+
54
+ def number_array_command(verb, args)
55
+ string_array_command verb, args
56
+ end
57
+
58
+ def boolean_command(verb, args=[])
59
+ parse_boolean_value string_command(verb, args)
60
+ end
61
+
62
+ def boolean_array_command(verb, args)
63
+ string_array_command(verb, args).collect {|value| parse_boolean_value(value)}
64
+ end
65
+
66
+ protected
67
+
68
+ def parse_boolean_value(value)
69
+ if ("true" == value)
70
+ return true
71
+ elsif ("false" == value)
72
+ return false
73
+ end
74
+ raise ProtocolError, "Invalid Selenese boolean value that is neither 'true' nor 'false': got '#{value}'"
75
+ end
76
+
77
+ def http_request_for(verb, args)
78
+ data = "cmd=#{CGI::escape(verb)}"
79
+ args.each_with_index do |arg, index|
80
+ data << "&#{index.succ}=#{CGI::escape(arg.to_s)}"
81
+ end
82
+ data << "&sessionId=#{session_id}" unless session_id.nil?
83
+ data
84
+ end
85
+
86
+ def http_post(data)
87
+ dummy_data = data
88
+ start = Time.now
89
+ called_from = caller.detect{|line| line !~ /(selenium-client|vendor|usr\/lib\/ruby|\(eval\))/i}
90
+ http = Net::HTTP.new(@host, @port)
91
+ http.open_timeout = default_timeout_in_seconds
92
+ http.read_timeout = default_timeout_in_seconds
93
+ response = http.post('/selenium-server/driver/', data, HTTP_HEADERS)
94
+ if response.body !~ /^OK/
95
+ puts "#{start} selenium-client received failure from selenium server:"
96
+ puts "requested:"
97
+ puts "\t" + CGI::unescape(data.split('&').join("\n\t"))
98
+ puts "received:"
99
+ puts "\t#{response.body.inspect}"
100
+ puts "\tcalled from #{called_from}"
101
+ end
102
+ cmd = []
103
+ dummy_data = "" if dummy_data.include?("getNewBrowserSession")
104
+ if dummy_data != ""
105
+ command = dummy_data.split('&')
106
+ command.delete_if{|str| str.include?("sessionId")}
107
+ command.collect{|str|
108
+ cmd << str.gsub!("cmd=","") if str.include?("cmd=")
109
+ cmd << CGI::unescape(str.gsub!("1=",""))if str.include?("1=")
110
+ cmd << CGI::unescape(str.gsub!("2=","")) if str.include?("2=")
111
+ }
112
+ $commands << cmd
113
+ end
114
+ [ response.body[0..1], response.body ]
115
+ end
116
+
117
+ def selenese_script
118
+
119
+ selenese_commands = ""
120
+ $commands.collect do |command|
121
+ selenese_commands << "<tr><td>#{command[0]}</td><td>#{command[1]}</td><td>#{command[2]}</td></tr>"
122
+ end
123
+
124
+ script = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://selenium-ide.openqa.org/profiles/test-case"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="selenium.base" href="http://www.google.co.in/" /><title>myscript<title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">myscript</td></tr></thead><tbody>'+selenese_commands+'</tbody></table></body></html>'
125
+ return script
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,36 @@
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
+ puts "Inside Help Open"
13
+ @selenium.open url
14
+ end
15
+
16
+ # Overrides default type method to actually delegates to @selenium
17
+ def type(locator, value)
18
+ puts "Inside Help type"
19
+ @selenium.type locator, value
20
+ end
21
+
22
+ # Overrides default select method to actually delegates to @selenium
23
+ def select(input_locator, option_locator)
24
+ @selenium.select input_locator, option_locator
25
+ end
26
+
27
+ # Delegates to @selenium on method missing
28
+ def method_missing(method_name, *args)
29
+ return super unless @selenium.respond_to?(method_name)
30
+
31
+ @selenium.send(method_name, *args)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module Selenium
2
+ class CommandError < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Selenium
2
+ class ProtocolError < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ require 'selenium/rake/tasks'
2
+
3
+ Selenium::Rake::RemoteControlStartTask.new do |rc|
4
+ rc.timeout_in_seconds = 3 * 60
5
+ rc.background = true
6
+ rc.wait_until_up_and_running = true
7
+ rc.additional_args << "-singleWindow"
8
+ end
9
+
10
+ Selenium::Rake::RemoteControlStopTask.new
11
+
12
+ desc "Restart Selenium Remote Control"
13
+ task :'selenium:rc:restart' do
14
+ Rake::Task[:'selenium:rc:stop'].execute [] rescue nil
15
+ Rake::Task[:'selenium:rc:start'].execute []
16
+ end
@@ -0,0 +1,71 @@
1
+ module Selenium
2
+ module Rake
3
+
4
+ # Rake tasks to start a Remote Control server.
5
+ #
6
+ # require 'selenium/rake/tasks'
7
+ #
8
+ # Selenium::Rake::RemoteControlStartTask.new do |rc|
9
+ # rc.port = 4444
10
+ # rc.timeout_in_seconds = 3 * 60
11
+ # rc.background = true
12
+ # rc.wait_until_up_and_running = true
13
+ # rc.jar_file = "/path/to/where/selenium-rc-standalone-jar-is-installed"
14
+ # rc.additional_args << "-singleWindow"
15
+ # end
16
+ #
17
+ # If you do not explicitly specify the path to selenium remote control jar
18
+ # it will be "auto-discovered" in `vendor` directory using the following
19
+ # path : `vendor/selenium-remote-control/selenium-server*-standalone.jar`
20
+ #
21
+ # To leverage the latest selenium-client capabilities, you may need to download
22
+ # a recent nightly build of a standalone packaging of Selenium Remote
23
+ # Control. You will find the nightly build at
24
+ # http://nexus.openqa.org/content/repositories/snapshots/org/seleniumhq/selenium/server/selenium-server/
25
+ class RemoteControlStartTask
26
+ attr_accessor :host, :port, :timeout_in_seconds, :background,
27
+ :wait_until_up_and_running, :additional_args,
28
+ :log_to
29
+ attr_reader :jar_file
30
+
31
+ JAR_FILE_PATTERN = "vendor/selenium-remote-control/selenium-server-*.jar"
32
+
33
+ def initialize(name = :'selenium:rc:start')
34
+ @name = name
35
+ @host = "localhost"
36
+ @port = 4444
37
+ @timeout_in_seconds = 5
38
+ project_specific_jar = Dir[JAR_FILE_PATTERN].first
39
+ @jar_file = project_specific_jar
40
+ @additional_args = []
41
+ @background = false
42
+ @wait_until_up_and_running = false
43
+ yield self if block_given?
44
+ define
45
+ end
46
+
47
+ def jar_file=(new_jar_file)
48
+ @jar_file = File.expand_path(new_jar_file)
49
+ end
50
+
51
+ def define
52
+ desc "Launch Selenium Remote Control"
53
+ task @name do
54
+ puts "Starting Selenium Remote Control at 0.0.0.0:#{@port}..."
55
+ raise "Could not find jar file '#{@jar_file}'. Expected it under #{JAR_FILE_PATTERN}" unless @jar_file && File.exists?(@jar_file)
56
+ remote_control = Selenium::RemoteControl::RemoteControl.new("0.0.0.0", @port, :timeout => @timeout_in_seconds)
57
+ remote_control.jar_file = @jar_file
58
+ remote_control.additional_args = @additional_args
59
+ remote_control.log_to = @log_to
60
+ remote_control.start :background => @background
61
+ if @background && @wait_until_up_and_running
62
+ puts "Waiting for Remote Control to be up and running..."
63
+ TCPSocket.wait_for_service :host => @host, :port => @port
64
+ end
65
+ puts "Selenium Remote Control at 0.0.0.0:#{@port} ready"
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ module Selenium
2
+ module Rake
3
+
4
+ # Rake task to stop a Selenium Remote Control Server
5
+ #
6
+ # Selenium::Rake::RemoteControlStopTask.new do |rc|
7
+ # rc.host = "localhost"
8
+ # rc.port = 4444
9
+ # rc.timeout_in_seconds = 3 * 60
10
+ # end
11
+ #
12
+ class RemoteControlStopTask
13
+ attr_accessor :host, :port, :timeout_in_seconds, :wait_until_stopped,
14
+ :shutdown_command
15
+
16
+ def initialize(name = :'selenium:rc:stop')
17
+ @host = "localhost"
18
+ @name = name
19
+ @port = 4444
20
+ @timeout_in_seconds = nil
21
+ @shutdown_command = nil
22
+ @wait_until_stopped = true
23
+ yield self if block_given?
24
+ define
25
+ end
26
+
27
+ def define
28
+ desc "Stop Selenium Remote Control running"
29
+ task @name do
30
+ puts "Stopping Selenium Remote Control running at #{host}:#{port}..."
31
+ remote_control = Selenium::RemoteControl::RemoteControl.new(
32
+ host, port, :timeout => timeout_in_seconds,
33
+ :shutdown_command => shutdown_command)
34
+ remote_control.stop
35
+ if @wait_until_stopped
36
+ TCPSocket.wait_for_service_termination :host => host, :port => port
37
+ end
38
+ puts "Stopped Selenium Remote Control running at #{host}:#{port}"
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,6 @@
1
+ require "net/http"
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../nautilus/shell')
3
+ require File.expand_path(File.dirname(__FILE__) + '/../../tcp_socket_extension')
4
+ require File.expand_path(File.dirname(__FILE__) + '/../remote_control/remote_control')
5
+ require File.expand_path(File.dirname(__FILE__) + '/remote_control_start_task')
6
+ require File.expand_path(File.dirname(__FILE__) + '/remote_control_stop_task')
@@ -0,0 +1,35 @@
1
+ module Selenium
2
+ module RemoteControl
3
+
4
+ class RemoteControl
5
+ attr_reader :host, :port, :timeout_in_seconds, :firefox_profile, :shutdown_command
6
+ attr_accessor :additional_args, :jar_file, :log_to
7
+
8
+ def initialize(host, port, options={})
9
+ @host, @port = host, port
10
+ @timeout_in_seconds = options[:timeout] || (2 * 60)
11
+ @shutdown_command = options[:shutdown_command] || "shutDownSeleniumServer"
12
+ @firefox_profile = options[:firefox_profile]
13
+ @additional_args = options[:additional_args] || []
14
+ @shell = Nautilus::Shell.new
15
+ end
16
+
17
+ def start(options = {})
18
+ command = "java -jar \"#{jar_file}\""
19
+ command << " -port #{@port}"
20
+ command << " -timeout #{@timeout_in_seconds}"
21
+ command << " -firefoxProfileTemplate '#{@firefox_profile}'" if @firefox_profile
22
+ command << " #{additional_args.join(' ')}" unless additional_args.empty?
23
+ command << " > #{log_to}" if log_to
24
+
25
+ @shell.run command, {:background => options[:background]}
26
+ end
27
+
28
+ def stop
29
+ Net::HTTP.get(@host, "/selenium-server/driver/?cmd=#{shutdown_command}", @port)
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,78 @@
1
+ module Selenium
2
+ module RSpec
3
+ module Reporting
4
+
5
+ class FilePathStrategy
6
+ attr_reader :final_report_file_path
7
+
8
+ REPORT_DEFAULT_FILE_PATH = File.join(Dir::tmpdir, "selenium_test_report", "index.html")
9
+
10
+ def initialize(final_report_file_path)
11
+ @final_report_file_path = final_report_file_path || REPORT_DEFAULT_FILE_PATH
12
+ @relative_dir = nil
13
+ end
14
+
15
+ def base_report_dir
16
+ @base_report_dir ||= File.dirname(File.expand_path(@final_report_file_path))
17
+ end
18
+
19
+ def relative_dir
20
+ return @relative_dir if @relative_dir
21
+
22
+ file_name_without_extension = File.basename(@final_report_file_path).sub(/\.[^\.]*$/, "")
23
+ @relative_dir ||= "resources/" + file_name_without_extension
24
+ end
25
+
26
+ def relative_file_path_for_html_capture(example)
27
+ "#{relative_dir}/example_#{example.reporting_uid}.html"
28
+ end
29
+
30
+ def relative_file_path_for_system_screenshot(example)
31
+ "#{relative_dir}/example_#{example.reporting_uid}_system_screenshot.png"
32
+ end
33
+
34
+ def relative_file_path_for_page_screenshot(example)
35
+ "#{relative_dir}/example_#{example.reporting_uid}_page_screenshot.png"
36
+ end
37
+
38
+ def relative_file_path_for_remote_control_logs(example)
39
+ "#{relative_dir}/example_#{example.reporting_uid}_remote_control.log"
40
+ end
41
+
42
+ def relative_file_path_for_browser_network_traffic(example)
43
+ "#{relative_dir}/example_#{example.reporting_uid}_browser_network_traffic.log"
44
+ end
45
+
46
+ def file_path_for_html_capture(example)
47
+ file_path relative_file_path_for_html_capture(example)
48
+ end
49
+
50
+ def file_path_for_system_screenshot(example)
51
+ file_path relative_file_path_for_system_screenshot(example)
52
+ end
53
+
54
+ def file_path_for_page_screenshot(example)
55
+ file_path relative_file_path_for_page_screenshot(example)
56
+ end
57
+
58
+ def file_path_for_remote_control_logs(example)
59
+ file_path relative_file_path_for_remote_control_logs(example)
60
+ end
61
+
62
+ def file_path_for_browser_network_traffic(example)
63
+ file_path relative_file_path_for_browser_network_traffic(example)
64
+ end
65
+
66
+ def file_path(relative_file_path)
67
+ the_file_path = base_report_dir + "/" + relative_file_path
68
+ parent_dir = File.dirname(the_file_path)
69
+ FileUtils.mkdir_p(parent_dir) unless File.directory?(parent_dir)
70
+ the_file_path
71
+ end
72
+
73
+
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,123 @@
1
+ module Selenium
2
+ module RSpec
3
+ module Reporting
4
+
5
+ class HtmlReport
6
+
7
+ PLACEHOLDER = "<<placeholder>>"
8
+
9
+ def initialize(file_path_strategy)
10
+ @file_path_strategy = file_path_strategy
11
+ end
12
+
13
+ def self.inject_placeholder(content)
14
+ content + Selenium::RSpec::Reporting::HtmlReport::PLACEHOLDER
15
+ end
16
+
17
+ def replace_placeholder_with_system_state_content(result, example)
18
+ result.gsub! PLACEHOLDER, logs_and_screenshot_sections(example)
19
+ end
20
+
21
+ def logs_and_screenshot_sections(example)
22
+ dom_id = "example_" + example.reporting_uid
23
+ system_screenshot_url = @file_path_strategy.relative_file_path_for_system_screenshot(example)
24
+ page_screenshot_url = @file_path_strategy.relative_file_path_for_page_screenshot(example)
25
+ snapshot_url = @file_path_strategy.relative_file_path_for_html_capture(example)
26
+ remote_control_logs_url = @file_path_strategy.relative_file_path_for_remote_control_logs(example)
27
+
28
+ html = ""
29
+ if File.exists? @file_path_strategy.file_path_for_html_capture(example)
30
+ html << toggable_section(dom_id, :id => "snapshot", :url=> snapshot_url, :name => "Dynamic HTML Snapshot")
31
+ end
32
+ if File.exists? @file_path_strategy.file_path_for_remote_control_logs(example)
33
+ html << toggable_section(dom_id, :id => "rc_logs", :url=> remote_control_logs_url, :name => "Remote Control Logs")
34
+ end
35
+ if File.exists? @file_path_strategy.file_path_for_page_screenshot(example)
36
+ html << toggable_image_section(dom_id, :id => "page_screenshot", :name => "Page Screenshot", :url => page_screenshot_url)
37
+ end
38
+ if File.exists? @file_path_strategy.file_path_for_system_screenshot(example)
39
+ html << toggable_image_section(dom_id, :id => "system_screenshot", :name => "System Screenshot", :url => system_screenshot_url)
40
+ end
41
+
42
+ return html
43
+ end
44
+
45
+ def self.append_javascript(global_scripts)
46
+ global_scripts + <<-EOF
47
+ function toggleVisilibility(id, description) {
48
+ var section;
49
+ var link;
50
+
51
+ section = document.getElementById(id);
52
+ link = document.getElementById(id + "_link");
53
+
54
+ if (section.style.display == "block") {
55
+ section.style.display = "none"
56
+ link.innerHTML = "Show " + description
57
+ } else {
58
+ section.style.display = "block"
59
+ link.innerHTML = "Hide " + description
60
+ }
61
+ }
62
+ EOF
63
+ end
64
+
65
+ def self.append_css(global_styles)
66
+ global_styles + <<-EOF
67
+
68
+ div.rspec-report textarea {
69
+ width: 100%;
70
+ }
71
+
72
+ div.rspec-report .dyn-source {
73
+ background: #FFFFEE none repeat scroll 0%;
74
+ border:1px dotted black;
75
+ color: #000000;
76
+ display: none;
77
+ margin: 0.5em 2em;
78
+ padding: 0.5em;
79
+ }
80
+
81
+ EOF
82
+ end
83
+
84
+ def toggable_section(dom_id, options)
85
+ <<-EOS
86
+
87
+ <div>[
88
+ <a id="#{dom_id}_#{options[:id]}_link"
89
+ href=\"javascript:toggleVisilibility('#{dom_id}_#{options[:id]}', '#{options[:name]}')\">Show #{options[:name]}</a>
90
+ ]</div>
91
+ <br/><br/>
92
+ <div id="#{dom_id}_#{options[:id]}" class="dyn-source">
93
+ <a href="#{options[:url]}">Full screen</a><br/><br/>
94
+ <iframe src="#{options[:url]}" width="100%" height="600px" ></iframe>
95
+ </div>
96
+
97
+ EOS
98
+ end
99
+
100
+ def toggable_image_section(dom_id, options)
101
+ <<-EOS
102
+
103
+ <div>[<a id="#{dom_id}_#{options[:id]}_link" href="javascript:toggleVisilibility('#{dom_id}_#{options[:id]}', '#{options[:name]}');">Show #{options[:name]}</a>]</div>
104
+ <br/>
105
+ <div id="#{dom_id}_#{options[:id]}" style="display: none">
106
+ <a href="#{options[:url]}">
107
+ <img width="80%" src="#{options[:url]}" />
108
+ </a>
109
+ </div>
110
+ <br/>
111
+
112
+ EOS
113
+ end
114
+
115
+ def report_header
116
+ super + "\n<script type=\"text/javascript\">moveProgressBar('100.0');</script>"
117
+ end
118
+
119
+ end
120
+ end
121
+
122
+ end
123
+ end