rspec-webdriver 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +17 -0
- data/Rakefile +19 -0
- data/lib/rspec/reporting/file_path_strategy.rb +78 -0
- data/lib/rspec/reporting/html_report.rb +123 -0
- data/lib/rspec/reporting/selenium_test_report_formatter.rb +82 -0
- data/lib/rspec/reporting/system_capture.rb +39 -0
- data/lib/rspec/rspec_extensions.rb +75 -0
- data/lib/rspec/spec_helper.rb +18 -0
- data/rspec-webdriver.gemspec +21 -0
- data/spec/example_run.rb +26 -0
- data/spec/report_spec.rb +24 -0
- data/spec/spec_results_for_comparison.html +356 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#Rspec-Webdriver
|
2
|
+
|
3
|
+
Just some reporting if you are using rspec and webdriver
|
4
|
+
|
5
|
+
##Credit where credit is due
|
6
|
+
|
7
|
+
This is project is not much more than a port of the reporting from ph7's selenium-client. I added updates for rspec 2.0 and selenium-webdriver.
|
8
|
+
|
9
|
+
##How to play
|
10
|
+
|
11
|
+
Name your webdriver @driver in your specs. Do not close it at the end of your spec (the spec_helper will do that for you).
|
12
|
+
|
13
|
+
rspec --require 'rspec/reporting/selenium_test_report_formatter'
|
14
|
+
--require 'rspec/spec_helper' --format 'SeleniumTestReportFormatter'
|
15
|
+
-o './test_results.html' <your_spec.rb>
|
16
|
+
|
17
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
Bundler.setup
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
require "rake"
|
7
|
+
require "rspec/core/rake_task"
|
8
|
+
require "rspec/core/version"
|
9
|
+
|
10
|
+
|
11
|
+
desc "Run all examples"
|
12
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
13
|
+
t.rspec_opts = %w[--color]
|
14
|
+
t.verbose = false
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
task :default => [:spec]
|
19
|
+
|
@@ -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) rescue @final_report_file_path.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(/\.[^\.]*$/, "") rescue File.basename(@final_report_file_path.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
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#
|
2
|
+
# Explicit requires in this file so that we can invoke RSpec runner with a
|
3
|
+
# single:
|
4
|
+
# --require 'lib/selenium/rspec/reporting/selenium_test_report_formatter'
|
5
|
+
#
|
6
|
+
require "digest/md5"
|
7
|
+
require "base64"
|
8
|
+
require 'tmpdir'
|
9
|
+
require "rubygems"
|
10
|
+
gem "rspec", ">=2.0"
|
11
|
+
require 'rspec/core'
|
12
|
+
require 'rspec/core/formatters/html_formatter'
|
13
|
+
require File.expand_path(File.dirname(__FILE__) + "/file_path_strategy")
|
14
|
+
require File.expand_path(File.dirname(__FILE__) + "/system_capture")
|
15
|
+
require File.expand_path(File.dirname(__FILE__) + "/html_report")
|
16
|
+
|
17
|
+
class SeleniumTestReportFormatter < RSpec::Core::Formatters::HtmlFormatter
|
18
|
+
|
19
|
+
def initialize(output)
|
20
|
+
super
|
21
|
+
raise "Unexpected output type #{output.inspect}" unless output.kind_of?(String) || output.kind_of?(File)
|
22
|
+
@@file_path_strategy = Selenium::RSpec::Reporting::FilePathStrategy.new(output)
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(example_count)
|
26
|
+
super
|
27
|
+
# ensure there's at least 1 example group header (normally 0 with deep_test)
|
28
|
+
# prevents js and html validity errors
|
29
|
+
example_group = Object.new
|
30
|
+
def example_group.description; ""; end
|
31
|
+
#example_group_started example_group
|
32
|
+
end
|
33
|
+
|
34
|
+
def move_progress
|
35
|
+
# we don't have current_example_number, and we don't really care about the progress bar
|
36
|
+
end
|
37
|
+
|
38
|
+
def extra_failure_content(failure)
|
39
|
+
Selenium::RSpec::Reporting::HtmlReport.inject_placeholder(super)
|
40
|
+
end
|
41
|
+
|
42
|
+
def example_pending(example_proxy)
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def example_failed(example)
|
47
|
+
old_output = @output
|
48
|
+
@output = StringIO.new
|
49
|
+
super
|
50
|
+
|
51
|
+
result = @output.string
|
52
|
+
report = Selenium::RSpec::Reporting::HtmlReport.new(@@file_path_strategy)
|
53
|
+
report.replace_placeholder_with_system_state_content(result, example)
|
54
|
+
old_output.puts result
|
55
|
+
old_output.flush
|
56
|
+
ensure
|
57
|
+
@output = old_output
|
58
|
+
end
|
59
|
+
|
60
|
+
# Should be called from config.after(:each) in spec helper
|
61
|
+
def self.capture_system_state(selenium_driver, example)
|
62
|
+
system_capture = Selenium::RSpec::Reporting::SystemCapture.new(selenium_driver, example, file_path_strategy)
|
63
|
+
system_capture.capture_system_state
|
64
|
+
end
|
65
|
+
|
66
|
+
def global_scripts
|
67
|
+
Selenium::RSpec::Reporting::HtmlReport.append_javascript(super)
|
68
|
+
end
|
69
|
+
|
70
|
+
def global_styles
|
71
|
+
Selenium::RSpec::Reporting::HtmlReport.append_css(super)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.file_path_strategy
|
75
|
+
### HACK ####
|
76
|
+
# When running with DeepTest the class instance variable could not have been set
|
77
|
+
# For now you must set the env variable before launching the tests. We need to revisit the way DeepTest
|
78
|
+
# and RSpec reporting work for a proper fix.
|
79
|
+
@@file_path_strategy ||= Selenium::RSpec::Reporting::FilePathStrategy.new(ENV["SELENIUM_TEST_REPORT_FILE"])
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Selenium
|
2
|
+
module RSpec
|
3
|
+
module Reporting
|
4
|
+
|
5
|
+
class SystemCapture
|
6
|
+
|
7
|
+
def initialize(selenium_driver, example, file_path_strategy)
|
8
|
+
@webdriver = selenium_driver
|
9
|
+
@example = example
|
10
|
+
@file_path_strategy = file_path_strategy
|
11
|
+
end
|
12
|
+
|
13
|
+
def capture_system_state
|
14
|
+
begin
|
15
|
+
capture_html_snapshot
|
16
|
+
rescue Exception => e
|
17
|
+
STDERR.puts "WARNING: Could not capture HTML snapshot: #{e}"
|
18
|
+
end
|
19
|
+
begin
|
20
|
+
capture_page_screenshot
|
21
|
+
rescue Exception => e
|
22
|
+
STDERR.puts "WARNING: Could not capture page screenshot: #{e}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def capture_html_snapshot
|
27
|
+
html = @webdriver.page_source
|
28
|
+
File.open(@file_path_strategy.file_path_for_html_capture(@example), "w") { |f| f.write html }
|
29
|
+
end
|
30
|
+
|
31
|
+
def capture_page_screenshot
|
32
|
+
@webdriver.save_screenshot(@file_path_strategy.file_path_for_page_screenshot(@example))
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
gem "rspec", ">=2.0"
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/example'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Monkey-patch RSpec Example Group so that we can track whether an
|
8
|
+
# example already failed or not in an after(:each) block
|
9
|
+
#
|
10
|
+
# Useful to only capture Selenium screenshots when a test fails
|
11
|
+
#
|
12
|
+
# * Changed execution_error to be an instance variable (in lieu of
|
13
|
+
# a local variable).
|
14
|
+
#
|
15
|
+
# * Introduced an unique id (example_uid) that is the same for
|
16
|
+
# a real Example (passed in after(:each) when screenshot is
|
17
|
+
# taken) as well as the corresponding ExampleProxy
|
18
|
+
# (passed to the HTML formatter). This unique id gives us
|
19
|
+
# a way to correlate file names between generation and
|
20
|
+
# reporting time.
|
21
|
+
#
|
22
|
+
module RSpec
|
23
|
+
module Core
|
24
|
+
class ExampleGroup
|
25
|
+
|
26
|
+
|
27
|
+
def actual_failure?
|
28
|
+
case example.exception
|
29
|
+
when nil
|
30
|
+
false
|
31
|
+
when RSpec::Core::PendingExampleFixedError
|
32
|
+
#RSpec::Example::ExamplePendingError,
|
33
|
+
#RSpec::Example::PendingExampleFixedError,
|
34
|
+
#RSpec::Example::NoDescriptionError
|
35
|
+
false
|
36
|
+
else
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Example
|
43
|
+
|
44
|
+
attr_reader :exception
|
45
|
+
|
46
|
+
def reporting_uid
|
47
|
+
# backtrace is not reliable anymore using the implementation proc
|
48
|
+
Digest::MD5.hexdigest(metadata[:execution_result][:started_at].to_s+metadata[:full_description].to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def pending_for_browsers(*browser_regexps, &block)
|
52
|
+
actual_browser = selenium_driver.browser_string
|
53
|
+
match_browser_regexps = browser_regexps.inject(false) do |match, regexp|
|
54
|
+
match ||= actual_browser =~ Regexp.new(regexp.source, Regexp::IGNORECASE)
|
55
|
+
end
|
56
|
+
if match_browser_regexps
|
57
|
+
pending "#{actual_browser.gsub(/\*/, '').capitalize} does not support this feature yet"
|
58
|
+
else
|
59
|
+
yield
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
class ExampleProxy
|
66
|
+
|
67
|
+
def reporting_uid
|
68
|
+
options[:actual_example].reporting_uid
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'base64'
|
4
|
+
require 'fileutils'
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "/rspec_extensions")
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + "/reporting/selenium_test_report_formatter")
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
|
10
|
+
config.after(:each) do
|
11
|
+
if actual_failure?
|
12
|
+
SeleniumTestReportFormatter.capture_system_state(@driver, self.example)
|
13
|
+
end
|
14
|
+
@driver.quit
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "rspec-webdriver"
|
6
|
+
s.version = "0.0.1"
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Brian Faherty"]
|
9
|
+
s.email = "anothergenericuser+ruby@gmail.com"
|
10
|
+
s.summary = "rspec-webdriver-0.0.1"
|
11
|
+
s.description = "RSpec reporting for selenium-webdriver"
|
12
|
+
|
13
|
+
s.rubygems_version = "1.3.7"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
17
|
+
#s.extra_rdoc_files = [ "README.md" ]
|
18
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
s.require_path = "lib"
|
20
|
+
end
|
21
|
+
|
data/spec/example_run.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "selenium-webdriver"
|
2
|
+
require "test/unit/assertions"
|
3
|
+
include Test::Unit::Assertions
|
4
|
+
|
5
|
+
describe "Report" do
|
6
|
+
attr_reader :driver
|
7
|
+
|
8
|
+
it "Generates a clean report when needed" do
|
9
|
+
@driver = Selenium::WebDriver.for :firefox
|
10
|
+
@driver.navigate.to "http://google.com"
|
11
|
+
element = @driver.find_element(:name, 'q')
|
12
|
+
element.send_keys "Hello Web@driver!"
|
13
|
+
element.submit
|
14
|
+
puts @driver.title
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Generates a clean report when needed" do
|
18
|
+
@driver = Selenium::WebDriver.for :firefox
|
19
|
+
@driver.navigate.to "http://google.com"
|
20
|
+
element = @driver.find_element(:name, 'q')
|
21
|
+
assert false
|
22
|
+
element.send_keys "Hello Web@driver!"
|
23
|
+
element.submit
|
24
|
+
puts @driver.title
|
25
|
+
end
|
26
|
+
end
|
data/spec/report_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#require "nokogiri"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
describe "Report" do
|
5
|
+
it "Generates a clean report when needed" do
|
6
|
+
RSpec::Core::RakeTask.new(:test_for_specs) do |t|
|
7
|
+
t.pattern = File.expand_path(File.dirname(__FILE__) + "/example_run.rb")
|
8
|
+
t.rspec_opts = "--require 'lib/rspec/reporting/selenium_test_report_formatter' "
|
9
|
+
t.rspec_opts << "--require 'lib/rspec/spec_helper' "
|
10
|
+
t.rspec_opts << "--format SeleniumTestReportFormatter "
|
11
|
+
t.rspec_opts << "-o ./spec_test_report.html "
|
12
|
+
t.verbose = false
|
13
|
+
end
|
14
|
+
Rake::Task[:test_for_specs].invoke rescue nil
|
15
|
+
out = File.read(File.expand_path(File.dirname(__FILE__) + "/../spec_test_report.html")).to_s
|
16
|
+
out.gsub! /\d+\.\d+ seconds/, 'x seconds'
|
17
|
+
out.match /example_([a-z0-9]+)_snapshot/
|
18
|
+
reporting_uid = $1
|
19
|
+
2.times{out.gsub! reporting_uid.to_s, "ZASDF"}
|
20
|
+
expected = File.read(File.expand_path(File.dirname(__FILE__) + "/spec_results_for_comparison.html")).to_s
|
21
|
+
STDOUT.puts "The reporteding_uid was #{reporting_uid}"
|
22
|
+
out.should == expected
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,356 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<title>RSpec results</title>
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
9
|
+
<meta http-equiv="Expires" content="-1" />
|
10
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
11
|
+
<style type="text/css">
|
12
|
+
body {
|
13
|
+
margin: 0;
|
14
|
+
padding: 0;
|
15
|
+
background: #fff;
|
16
|
+
font-size: 80%;
|
17
|
+
}
|
18
|
+
</style>
|
19
|
+
<script type="text/javascript">
|
20
|
+
// <![CDATA[
|
21
|
+
|
22
|
+
function addClass(element_id, classname) {
|
23
|
+
document.getElementById(element_id).className += (" " + classname);
|
24
|
+
}
|
25
|
+
|
26
|
+
function removeClass(element_id, classname) {
|
27
|
+
var elem = document.getElementById(element_id);
|
28
|
+
var classlist = elem.className.replace(classname,'');
|
29
|
+
elem.className = classlist;
|
30
|
+
}
|
31
|
+
|
32
|
+
function moveProgressBar(percentDone) {
|
33
|
+
document.getElementById("rspec-header").style.width = percentDone +"%";
|
34
|
+
}
|
35
|
+
|
36
|
+
function makeRed(element_id) {
|
37
|
+
removeClass(element_id, 'passed');
|
38
|
+
removeClass(element_id, 'not_implemented');
|
39
|
+
addClass(element_id,'failed');
|
40
|
+
}
|
41
|
+
|
42
|
+
function makeYellow(element_id) {
|
43
|
+
var elem = document.getElementById(element_id);
|
44
|
+
if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed
|
45
|
+
if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented
|
46
|
+
removeClass(element_id, 'passed');
|
47
|
+
addClass(element_id,'not_implemented');
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
function apply_filters() {
|
53
|
+
var passed_filter = document.getElementById('passed_checkbox').checked;
|
54
|
+
var failed_filter = document.getElementById('failed_checkbox').checked;
|
55
|
+
var pending_filter = document.getElementById('pending_checkbox').checked;
|
56
|
+
|
57
|
+
assign_display_style("example passed", passed_filter);
|
58
|
+
assign_display_style("example failed", failed_filter);
|
59
|
+
assign_display_style("example not_implemented", pending_filter);
|
60
|
+
|
61
|
+
assign_display_style_for_group("example_group passed", passed_filter);
|
62
|
+
assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter);
|
63
|
+
assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter);
|
64
|
+
}
|
65
|
+
|
66
|
+
function get_display_style(display_flag) {
|
67
|
+
var style_mode = 'none';
|
68
|
+
if (display_flag == true) {
|
69
|
+
style_mode = 'block';
|
70
|
+
}
|
71
|
+
return style_mode;
|
72
|
+
}
|
73
|
+
|
74
|
+
function assign_display_style(classname, display_flag) {
|
75
|
+
var style_mode = get_display_style(display_flag);
|
76
|
+
var elems = document.getElementsByClassName(classname)
|
77
|
+
for (var i=0; i<elems.length;i++) {
|
78
|
+
elems[i].style.display = style_mode;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
function assign_display_style_for_group(classname, display_flag, subgroup_flag) {
|
83
|
+
var display_style_mode = get_display_style(display_flag);
|
84
|
+
var subgroup_style_mode = get_display_style(subgroup_flag);
|
85
|
+
var elems = document.getElementsByClassName(classname)
|
86
|
+
for (var i=0; i<elems.length;i++) {
|
87
|
+
var style_mode = display_style_mode;
|
88
|
+
if ((display_flag != subgroup_flag) && (elems[i].getElementsByTagName('dt')[0].innerHTML.indexOf(", ") != -1)) {
|
89
|
+
elems[i].style.display = subgroup_style_mode;
|
90
|
+
} else {
|
91
|
+
elems[i].style.display = display_style_mode;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
function toggleVisilibility(id, description) {
|
96
|
+
var section;
|
97
|
+
var link;
|
98
|
+
|
99
|
+
section = document.getElementById(id);
|
100
|
+
link = document.getElementById(id + "_link");
|
101
|
+
|
102
|
+
if (section.style.display == "block") {
|
103
|
+
section.style.display = "none"
|
104
|
+
link.innerHTML = "Show " + description
|
105
|
+
} else {
|
106
|
+
section.style.display = "block"
|
107
|
+
link.innerHTML = "Hide " + description
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
// ]]>
|
112
|
+
</script>
|
113
|
+
<style type="text/css">
|
114
|
+
#rspec-header {
|
115
|
+
background: #65C400; color: #fff; height: 4em;
|
116
|
+
}
|
117
|
+
|
118
|
+
.rspec-report h1 {
|
119
|
+
margin: 0px 10px 0px 10px;
|
120
|
+
padding: 10px;
|
121
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
122
|
+
font-size: 1.8em;
|
123
|
+
position: absolute;
|
124
|
+
}
|
125
|
+
|
126
|
+
#label {
|
127
|
+
float:left;
|
128
|
+
}
|
129
|
+
|
130
|
+
#display-filters {
|
131
|
+
float:left;
|
132
|
+
padding: 28px 0 0 40%;
|
133
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
134
|
+
}
|
135
|
+
|
136
|
+
#summary {
|
137
|
+
float:right;
|
138
|
+
padding: 5px 10px;
|
139
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
140
|
+
text-align: right;
|
141
|
+
}
|
142
|
+
|
143
|
+
#summary p {
|
144
|
+
margin: 0 0 0 2px;
|
145
|
+
}
|
146
|
+
|
147
|
+
#summary #totals {
|
148
|
+
font-size: 1.2em;
|
149
|
+
}
|
150
|
+
|
151
|
+
.example_group {
|
152
|
+
margin: 0 10px 5px;
|
153
|
+
background: #fff;
|
154
|
+
}
|
155
|
+
|
156
|
+
dl {
|
157
|
+
margin: 0; padding: 0 0 5px;
|
158
|
+
font: normal 11px "Lucida Grande", Helvetica, sans-serif;
|
159
|
+
}
|
160
|
+
|
161
|
+
dt {
|
162
|
+
padding: 3px;
|
163
|
+
background: #65C400;
|
164
|
+
color: #fff;
|
165
|
+
font-weight: bold;
|
166
|
+
}
|
167
|
+
|
168
|
+
dd {
|
169
|
+
margin: 5px 0 5px 5px;
|
170
|
+
padding: 3px 3px 3px 18px;
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
dd.example.passed {
|
175
|
+
border-left: 5px solid #65C400;
|
176
|
+
border-bottom: 1px solid #65C400;
|
177
|
+
background: #DBFFB4; color: #3D7700;
|
178
|
+
}
|
179
|
+
|
180
|
+
dd.example.not_implemented {
|
181
|
+
border-left: 5px solid #FAF834;
|
182
|
+
border-bottom: 1px solid #FAF834;
|
183
|
+
background: #FCFB98; color: #131313;
|
184
|
+
}
|
185
|
+
|
186
|
+
dd.example.pending_fixed {
|
187
|
+
border-left: 5px solid #0000C2;
|
188
|
+
border-bottom: 1px solid #0000C2;
|
189
|
+
color: #0000C2; background: #D3FBFF;
|
190
|
+
}
|
191
|
+
|
192
|
+
dd.example.failed {
|
193
|
+
border-left: 5px solid #C20000;
|
194
|
+
border-bottom: 1px solid #C20000;
|
195
|
+
color: #C20000; background: #FFFBD3;
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
dt.not_implemented {
|
200
|
+
color: #000000; background: #FAF834;
|
201
|
+
}
|
202
|
+
|
203
|
+
dt.pending_fixed {
|
204
|
+
color: #FFFFFF; background: #C40D0D;
|
205
|
+
}
|
206
|
+
|
207
|
+
dt.failed {
|
208
|
+
color: #FFFFFF; background: #C40D0D;
|
209
|
+
}
|
210
|
+
|
211
|
+
|
212
|
+
#rspec-header.not_implemented {
|
213
|
+
color: #000000; background: #FAF834;
|
214
|
+
}
|
215
|
+
|
216
|
+
#rspec-header.pending_fixed {
|
217
|
+
color: #FFFFFF; background: #C40D0D;
|
218
|
+
}
|
219
|
+
|
220
|
+
#rspec-header.failed {
|
221
|
+
color: #FFFFFF; background: #C40D0D;
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
.backtrace {
|
226
|
+
color: #000;
|
227
|
+
font-size: 12px;
|
228
|
+
}
|
229
|
+
|
230
|
+
a {
|
231
|
+
color: #BE5C00;
|
232
|
+
}
|
233
|
+
|
234
|
+
/* Ruby code, style similar to vibrant ink */
|
235
|
+
.ruby {
|
236
|
+
font-size: 12px;
|
237
|
+
font-family: monospace;
|
238
|
+
color: white;
|
239
|
+
background-color: black;
|
240
|
+
padding: 0.1em 0 0.2em 0;
|
241
|
+
}
|
242
|
+
|
243
|
+
.ruby .keyword { color: #FF6600; }
|
244
|
+
.ruby .constant { color: #339999; }
|
245
|
+
.ruby .attribute { color: white; }
|
246
|
+
.ruby .global { color: white; }
|
247
|
+
.ruby .module { color: white; }
|
248
|
+
.ruby .class { color: white; }
|
249
|
+
.ruby .string { color: #66FF00; }
|
250
|
+
.ruby .ident { color: white; }
|
251
|
+
.ruby .method { color: #FFCC00; }
|
252
|
+
.ruby .number { color: white; }
|
253
|
+
.ruby .char { color: white; }
|
254
|
+
.ruby .comment { color: #9933CC; }
|
255
|
+
.ruby .symbol { color: white; }
|
256
|
+
.ruby .regex { color: #44B4CC; }
|
257
|
+
.ruby .punct { color: white; }
|
258
|
+
.ruby .escape { color: white; }
|
259
|
+
.ruby .interp { color: white; }
|
260
|
+
.ruby .expr { color: white; }
|
261
|
+
|
262
|
+
.ruby .offending { background-color: gray; }
|
263
|
+
.ruby .linenum {
|
264
|
+
width: 75px;
|
265
|
+
padding: 0.1em 1em 0.2em 0;
|
266
|
+
color: #000000;
|
267
|
+
background-color: #FFFBD3;
|
268
|
+
}
|
269
|
+
|
270
|
+
div.rspec-report textarea {
|
271
|
+
width: 100%;
|
272
|
+
}
|
273
|
+
|
274
|
+
div.rspec-report .dyn-source {
|
275
|
+
background: #FFFFEE none repeat scroll 0%;
|
276
|
+
border:1px dotted black;
|
277
|
+
color: #000000;
|
278
|
+
display: none;
|
279
|
+
margin: 0.5em 2em;
|
280
|
+
padding: 0.5em;
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
</style>
|
285
|
+
</head>
|
286
|
+
<body>
|
287
|
+
<div class="rspec-report">
|
288
|
+
|
289
|
+
<div id="rspec-header">
|
290
|
+
<div id="label">
|
291
|
+
<h1>RSpec Code Examples</h1>
|
292
|
+
</div>
|
293
|
+
|
294
|
+
<div id="display-filters">
|
295
|
+
<input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked onchange="apply_filters()" value="1"> <label for="passed_checkbox">Passed</label>
|
296
|
+
<input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked onchange="apply_filters()" value="2"> <label for="failed_checkbox">Failed</label>
|
297
|
+
<input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked onchange="apply_filters()" value="3"> <label for="pending_checkbox">Pending</label>
|
298
|
+
</div>
|
299
|
+
|
300
|
+
<div id="summary">
|
301
|
+
<p id="totals"> </p>
|
302
|
+
<p id="duration"> </p>
|
303
|
+
</div>
|
304
|
+
</div>
|
305
|
+
|
306
|
+
|
307
|
+
<div class="results">
|
308
|
+
<div id="div_group_1" class="example_group passed">
|
309
|
+
<dl style="margin-left: 0px;">
|
310
|
+
<dt id="example_group_1" class="passed">Report</dt>
|
311
|
+
<dd class="example passed"><span class="passed_spec_name">Generates a clean report when needed</span></dd>
|
312
|
+
<script type="text/javascript">makeRed('rspec-header');</script>
|
313
|
+
<script type="text/javascript">makeRed('div_group_1');</script>
|
314
|
+
<script type="text/javascript">makeRed('example_group_1');</script>
|
315
|
+
<dd class="example failed">
|
316
|
+
<span class="failed_spec_name">Generates a clean report when needed</span>
|
317
|
+
<div class="failure" id="failure_1">
|
318
|
+
<div class="message"><pre><false> is not true.</pre></div>
|
319
|
+
<div class="backtrace"><pre>./spec/example_run.rb:21</pre></div>
|
320
|
+
<pre class="ruby"><code><span class="linenum">19</span> @driver.navigate.to "http://google.com"
|
321
|
+
<span class="linenum">20</span> element = @driver.find_element(:name, 'q')
|
322
|
+
<span class="offending"><span class="linenum">21</span> assert false</span>
|
323
|
+
<span class="linenum">22</span> element.send_keys "Hello Web@driver!"
|
324
|
+
<span class="linenum">23</span> element.submit
|
325
|
+
<span class="linenum">24</span><span class="comment"># gem install syntax to get syntax highlighting</span></code></pre>
|
326
|
+
<div>[
|
327
|
+
<a id="example_ZASDF_snapshot_link"
|
328
|
+
href="javascript:toggleVisilibility('example_ZASDF_snapshot', 'Dynamic HTML Snapshot')">Show Dynamic HTML Snapshot</a>
|
329
|
+
]</div>
|
330
|
+
<br/><br/>
|
331
|
+
<div id="example_ZASDF_snapshot" class="dyn-source">
|
332
|
+
<a href="resources/spec_test_report/example_ZASDF.html">Full screen</a><br/><br/>
|
333
|
+
<iframe src="resources/spec_test_report/example_ZASDF.html" width="100%" height="600px" ></iframe>
|
334
|
+
</div>
|
335
|
+
|
336
|
+
|
337
|
+
<div>[<a id="example_ZASDF_page_screenshot_link" href="javascript:toggleVisilibility('example_ZASDF_page_screenshot', 'Page Screenshot');">Show Page Screenshot</a>]</div>
|
338
|
+
<br/>
|
339
|
+
<div id="example_ZASDF_page_screenshot" style="display: none">
|
340
|
+
<a href="resources/spec_test_report/example_ZASDF_page_screenshot.png">
|
341
|
+
<img width="80%" src="resources/spec_test_report/example_ZASDF_page_screenshot.png" />
|
342
|
+
</a>
|
343
|
+
</div>
|
344
|
+
<br/>
|
345
|
+
|
346
|
+
|
347
|
+
</div>
|
348
|
+
</dd>
|
349
|
+
</dl>
|
350
|
+
</div>
|
351
|
+
<script type="text/javascript">document.getElementById('duration').innerHTML = "Finished in <strong>x seconds</strong>";</script>
|
352
|
+
<script type="text/javascript">document.getElementById('totals').innerHTML = "2 examples, 1 failure";</script>
|
353
|
+
</div>
|
354
|
+
</div>
|
355
|
+
</body>
|
356
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-webdriver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Brian Faherty
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-08 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: RSpec reporting for selenium-webdriver
|
23
|
+
email: anothergenericuser+ruby@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- lib/rspec/reporting/file_path_strategy.rb
|
36
|
+
- lib/rspec/reporting/html_report.rb
|
37
|
+
- lib/rspec/reporting/selenium_test_report_formatter.rb
|
38
|
+
- lib/rspec/reporting/system_capture.rb
|
39
|
+
- lib/rspec/rspec_extensions.rb
|
40
|
+
- lib/rspec/spec_helper.rb
|
41
|
+
- rspec-webdriver.gemspec
|
42
|
+
- spec/example_run.rb
|
43
|
+
- spec/report_spec.rb
|
44
|
+
- spec/spec_results_for_comparison.html
|
45
|
+
has_rdoc: true
|
46
|
+
homepage:
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: rspec-webdriver-0.0.1
|
79
|
+
test_files: []
|
80
|
+
|