pretty_face 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/ChangeLog +2 -0
- data/Gemfile +12 -0
- data/Guardfile +17 -0
- data/README.md +21 -0
- data/Rakefile +18 -0
- data/cucumber.yml +3 -0
- data/features/pretty_face_report.feature +63 -0
- data/features/support/env.rb +9 -0
- data/features/support/hooks.rb +6 -0
- data/fixtures/advanced.feature +14 -0
- data/fixtures/basic.feature +17 -0
- data/fixtures/step_definitions/advanced_steps.rb +12 -0
- data/fixtures/step_definitions/basic_steps.rb +19 -0
- data/fixtures/support/env.rb +3 -0
- data/lib/pretty_face.rb +6 -0
- data/lib/pretty_face/formatter/html.rb +140 -0
- data/lib/pretty_face/formatter/report.rb +68 -0
- data/lib/pretty_face/formatter/view_helper.rb +60 -0
- data/lib/pretty_face/templates/face.jpg +0 -0
- data/lib/pretty_face/templates/failed.jpg +0 -0
- data/lib/pretty_face/templates/main.erb +194 -0
- data/lib/pretty_face/templates/passed.jpg +0 -0
- data/lib/pretty_face/templates/pending.jpg +0 -0
- data/lib/pretty_face/templates/skipped.jpg +0 -0
- data/lib/pretty_face/templates/undefined.jpg +0 -0
- data/lib/pretty_face/version.rb +3 -0
- data/pretty_face.gemspec +26 -0
- data/sample_report/LisaCrispin1.png +0 -0
- data/sample_report/LisaCrispin2.png +0 -0
- data/sample_report/blue_s.jpeg +0 -0
- data/sample_report/green_bar.jpeg +0 -0
- data/sample_report/green_check.jpg +0 -0
- data/sample_report/red_bar.gif +0 -0
- data/sample_report/red_x.jpg +0 -0
- data/sample_report/sample_report.html +167 -0
- data/sample_report/some_code/gherkin_formatter_adapter.rb +87 -0
- data/sample_report/some_code/html.rb +655 -0
- data/sample_report/some_code/ordered_xml_markup.rb +24 -0
- data/sample_report/some_code/summary.rb +35 -0
- data/sample_report/yellow_o.jpg +0 -0
- data/spec/lib/html_formatter_spec.rb +111 -0
- data/spec/spec_helper.rb +5 -0
- metadata +168 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/ChangeLog
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'rake'
|
4
|
+
gem 'fuubar'
|
5
|
+
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
6
|
+
gem 'growl'
|
7
|
+
gem 'guard-rspec'
|
8
|
+
gem 'guard-cucumber'
|
9
|
+
|
10
|
+
|
11
|
+
# Specify your gem's dependencies in pretty_face.gemspec
|
12
|
+
gemspec
|
data/Guardfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :cli => '--color --format Fuubar' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { "spec" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
9
|
+
|
10
|
+
guard 'cucumber', :notification => true, :all_after_pass => false, :cli => '--profile focus' do
|
11
|
+
watch(%r{^features/.+\.feature$})
|
12
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
13
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
14
|
+
watch(%r{^lib/.+\.rb$}) { "features" }
|
15
|
+
watch(%r{^lib/.+\.erb$}) { "features" }
|
16
|
+
end
|
17
|
+
|
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# pretty_face
|
2
|
+
|
3
|
+
HTML report for cucumber and rspec. You can customzie the report by editing an erb file.
|
4
|
+
|
5
|
+
## Known Issues
|
6
|
+
|
7
|
+
See [http://github.com/cheezy/pretty_face/issues](http://github.com/cheezy/pretty_face/issues)
|
8
|
+
|
9
|
+
## Contribute
|
10
|
+
|
11
|
+
* Fork the project.
|
12
|
+
* Test drive your feature addition or bug fix. Adding specs is important and I will not accept a pull request that does not have tests.
|
13
|
+
* Make sure you describe your new feature with a cucumber scenario.
|
14
|
+
* Make sure you provide RDoc comments for any new public method you add. Remember, others will be using this gem.
|
15
|
+
* Commit, do not mess with Rakefile, version, or ChangeLog.
|
16
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
17
|
+
* Send me a pull request. Bonus points for topic branches.
|
18
|
+
|
19
|
+
## Copyright
|
20
|
+
|
21
|
+
Copyright (c) 2012 Jeffrey S. Morgan. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'cucumber'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
Cucumber::Rake::Task.new(:features, "Run all features") do |t|
|
7
|
+
t.profile = 'default'
|
8
|
+
end
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
10
|
+
spec.ruby_opts = "-I lib:spec"
|
11
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
12
|
+
end
|
13
|
+
task :spec
|
14
|
+
|
15
|
+
desc 'Run all specs and features'
|
16
|
+
task :test => %w[spec features]
|
17
|
+
|
18
|
+
task :default => :test
|
data/cucumber.yml
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
Feature: pretty face report
|
2
|
+
|
3
|
+
Background:
|
4
|
+
When I run `cucumber fixtures --profile fixture`
|
5
|
+
|
6
|
+
Scenario: Cucumber crefates an html report
|
7
|
+
Then the following files should exist:
|
8
|
+
| fixture.html |
|
9
|
+
|
10
|
+
Scenario: Generating the basic html page from the erb
|
11
|
+
Then the file "fixture.html" should contain "DOCTYPE html PUBLIC"
|
12
|
+
And the file "fixture.html" should contain "<html xmlns='http://www.w3.org/1999/xhtml'>"
|
13
|
+
And the file "fixture.html" should contain "<head>"
|
14
|
+
And the file "fixture.html" should contain "<body"
|
15
|
+
And the file "fixture.html" should contain "<title>Test Results</title>"
|
16
|
+
|
17
|
+
Scenario: Generating some basic stats from the erb
|
18
|
+
Then the file "fixture.html" should contain "<th>Executed<"
|
19
|
+
And the file "fixture.html" should contain "<th>Average<br/>Duration"
|
20
|
+
And the file "fixture.html" should contain "Scenarios"
|
21
|
+
And the file "fixture.html" should contain "Steps"
|
22
|
+
|
23
|
+
Scenario: Including the styles for the main page
|
24
|
+
Then the file "fixture.html" should contain "<style type='text/css'>"
|
25
|
+
And the file "fixture.html" should contain "</style>"
|
26
|
+
|
27
|
+
Scenario: Including an image / logo
|
28
|
+
Then the file "fixture.html" should contain "<img src="
|
29
|
+
And the file "fixture.html" should contain "images/face.jpg"
|
30
|
+
|
31
|
+
Scenario: It should copy the logo image to the images directory
|
32
|
+
Then the following files should exist:
|
33
|
+
| images/face.jpg |
|
34
|
+
|
35
|
+
Scenario: It should show start time and duration in the header
|
36
|
+
Then the file "fixture.html" should contain "Tests started:"
|
37
|
+
And the file "fixture.html" should contain "Duration:"
|
38
|
+
|
39
|
+
Scenario: It should capture scenario and step statuses
|
40
|
+
Then the file "fixture.html" should contain "Passed"
|
41
|
+
And the file "fixture.html" should contain "Failed"
|
42
|
+
And the file "fixture.html" should contain "Pending"
|
43
|
+
And the file "fixture.html" should contain "Undefined"
|
44
|
+
And the file "fixture.html" should contain "Skipped"
|
45
|
+
|
46
|
+
Scenario: It should display all of the tests with failures
|
47
|
+
Then the file "fixture.html" should contain "Tests With Failures:"
|
48
|
+
|
49
|
+
Scenario: It should display a list of all features / scenarios
|
50
|
+
Then the file "fixture.html" should contain "Scenario Overview:"
|
51
|
+
|
52
|
+
Scenario: It should display useful information about each scenario
|
53
|
+
Then the file "fixture.html" should contain "Result"
|
54
|
+
And the file "fixture.html" should contain "Name"
|
55
|
+
And the file "fixture.html" should contain "# Steps"
|
56
|
+
And the file "fixture.html" should contain "Duration"
|
57
|
+
|
58
|
+
Scenario: It should display the data from scenario outlines
|
59
|
+
Then the file "fixture.html" should contain "| aaa | bbb |"
|
60
|
+
And the file "fixture.html" should contain "| ccc | ddd |"
|
61
|
+
|
62
|
+
Scenario: It should display the scenario name for scenario outlines
|
63
|
+
Then the file "fixture.html" should contain "A scenario outline"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: Advanced scenarios
|
2
|
+
|
3
|
+
Scenario Outline: A scenario outline
|
4
|
+
Given I am using a scenario outline
|
5
|
+
When I use <first>
|
6
|
+
And I use <second>
|
7
|
+
Then the examples should work
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
| first | second |
|
11
|
+
| aaa | bbb |
|
12
|
+
| ccc | ddd |
|
13
|
+
| eee | fff |
|
14
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Basic scenarios
|
2
|
+
|
3
|
+
Scenario: A passing scenario
|
4
|
+
When Cucumber puts "hello"
|
5
|
+
Then it should say hello
|
6
|
+
|
7
|
+
Scenario: A failing scenario
|
8
|
+
When the first step fails
|
9
|
+
Then the second step should not execute
|
10
|
+
|
11
|
+
Scenario: A pending scenario
|
12
|
+
When the first step is pending
|
13
|
+
Then the second step is undefined
|
14
|
+
|
15
|
+
Scenario: A undefined scenario
|
16
|
+
When all steps are undefined
|
17
|
+
Then the scenario is undefined
|
@@ -0,0 +1,19 @@
|
|
1
|
+
When /^Cucumber puts "(.*?)"$/ do |some_string|
|
2
|
+
puts some_string
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^it should say hello$/ do
|
6
|
+
puts "It said hello"
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^the first step fails$/ do
|
10
|
+
true.should == false
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the second step should not execute$/ do
|
14
|
+
puts "Should not execute"
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^the first step is pending$/ do
|
18
|
+
pending
|
19
|
+
end
|
data/lib/pretty_face.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'cucumber/formatter/io'
|
4
|
+
require 'cucumber/formatter/duration'
|
5
|
+
require 'cucumber/ast/scenario'
|
6
|
+
require 'cucumber/ast/table'
|
7
|
+
require 'cucumber/ast/outline_table'
|
8
|
+
require File.join(File.dirname(__FILE__), 'view_helper')
|
9
|
+
require File.join(File.dirname(__FILE__), 'report')
|
10
|
+
|
11
|
+
module PrettyFace
|
12
|
+
module Formatter
|
13
|
+
|
14
|
+
class Html
|
15
|
+
include Cucumber::Formatter::Io
|
16
|
+
include Cucumber::Formatter::Duration
|
17
|
+
include ViewHelper
|
18
|
+
|
19
|
+
def initialize(step_mother, path_or_io, options)
|
20
|
+
@path = path_or_io
|
21
|
+
@io = ensure_io(path_or_io, 'html')
|
22
|
+
@step_mother = step_mother
|
23
|
+
@options = options
|
24
|
+
@report = Report.new
|
25
|
+
@step_times = []
|
26
|
+
@scenario_times = []
|
27
|
+
@outline_steps = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def before_features(features)
|
31
|
+
@tests_started = Time.now
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_feature(feature)
|
35
|
+
@report.add_feature ReportFeature.new(feature)
|
36
|
+
end
|
37
|
+
|
38
|
+
def after_feature(feature)
|
39
|
+
@report.current_feature.title = feature.title
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_feature_element(feature_element)
|
43
|
+
@scenario_timer = Time.now
|
44
|
+
unless scenario_outline? feature_element
|
45
|
+
@report.add_scenario ReportScenario.new(feature_element)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def after_feature_element(feature_element)
|
50
|
+
unless scenario_outline?(feature_element)
|
51
|
+
process_scenario(feature_element)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def after_outline_table(outline_table)
|
56
|
+
process_scenario_outline(outline_table)
|
57
|
+
end
|
58
|
+
|
59
|
+
def after_table_row(example_row)
|
60
|
+
@scenario_times.push Time.now - @scenario_timer
|
61
|
+
end
|
62
|
+
|
63
|
+
def before_step(step)
|
64
|
+
@step_timer = Time.now
|
65
|
+
end
|
66
|
+
|
67
|
+
def after_step(step)
|
68
|
+
process_step(step)
|
69
|
+
end
|
70
|
+
|
71
|
+
def after_features(features)
|
72
|
+
@features = features
|
73
|
+
@duration = format_duration(Time.now - @tests_started)
|
74
|
+
generate_report
|
75
|
+
copy_images_directory
|
76
|
+
end
|
77
|
+
|
78
|
+
def features
|
79
|
+
@report.features
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def generate_report
|
85
|
+
filename = File.join(File.dirname(__FILE__), '..', 'templates', 'main.erb')
|
86
|
+
text = File.new(filename).read
|
87
|
+
@io.puts ERB.new(text, nil, "%").result(binding)
|
88
|
+
end
|
89
|
+
|
90
|
+
def copy_images_directory
|
91
|
+
path = "#{File.dirname(@path)}/images"
|
92
|
+
FileUtils.mkdir path unless File.directory? path
|
93
|
+
%w(face failed passed pending undefined skipped).each do |file|
|
94
|
+
FileUtils.cp File.join(File.dirname(__FILE__), '..', 'templates', "#{file}.jpg"), path
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_scenario(scenario)
|
99
|
+
@scenario_times.push Time.now - @scenario_timer
|
100
|
+
@report.current_scenario.populate(scenario)
|
101
|
+
end
|
102
|
+
|
103
|
+
def process_example_row(example_row)
|
104
|
+
@report.add_scenario build_scenario_outline_with example_row
|
105
|
+
end
|
106
|
+
|
107
|
+
def process_scenario_outline(scenario_outline)
|
108
|
+
scenario_outline.example_rows.each do |example_row|
|
109
|
+
process_example_row(example_row)
|
110
|
+
end
|
111
|
+
@outline_steps = []
|
112
|
+
end
|
113
|
+
|
114
|
+
def process_step(step)
|
115
|
+
@step_times.push Time.now - @step_timer
|
116
|
+
if step_belongs_to_outline? step
|
117
|
+
@outline_steps << ReportStep.new(step)
|
118
|
+
else
|
119
|
+
@report.add_step ReportStep.new(step)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def scenario_outline?(feature_element)
|
124
|
+
feature_element.is_a? Cucumber::Ast::ScenarioOutline
|
125
|
+
end
|
126
|
+
|
127
|
+
def step_belongs_to_outline?(step)
|
128
|
+
scenario = step.instance_variable_get "@feature_element"
|
129
|
+
not scenario.nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def build_scenario_outline_with(example_row)
|
133
|
+
scenario = ReportScenario.new(example_row)
|
134
|
+
scenario.steps = @outline_steps
|
135
|
+
scenario.populate example_row
|
136
|
+
scenario
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module PrettyFace
|
2
|
+
module Formatter
|
3
|
+
|
4
|
+
class Report
|
5
|
+
attr_reader :features
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@features = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def current_feature
|
12
|
+
@features.last
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_scenario
|
16
|
+
current_feature.scenarios.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_feature(feature)
|
20
|
+
@features << feature
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_scenario(scenario)
|
24
|
+
current_feature.scenarios << scenario
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_step(step)
|
28
|
+
current_scenario.steps << step
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class ReportFeature
|
33
|
+
attr_accessor :title, :scenarios
|
34
|
+
|
35
|
+
def initialize(feature)
|
36
|
+
self.scenarios = []
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ReportScenario
|
41
|
+
attr_accessor :name, :file_colon_line, :status, :steps
|
42
|
+
|
43
|
+
def initialize(scenario)
|
44
|
+
self.steps = []
|
45
|
+
end
|
46
|
+
|
47
|
+
def populate(scenario)
|
48
|
+
if scenario.instance_of? Cucumber::Ast::Scenario
|
49
|
+
self.name = scenario.name
|
50
|
+
self.file_colon_line = scenario.file_colon_line
|
51
|
+
elsif scenario.instance_of? Cucumber::Ast::OutlineTable::ExampleRow
|
52
|
+
self.name = scenario.scenario_outline.name
|
53
|
+
self.file_colon_line = scenario.backtrace_line
|
54
|
+
end
|
55
|
+
self.status = scenario.status
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ReportStep
|
60
|
+
attr_accessor :name, :file_colon_line, :status
|
61
|
+
def initialize(step)
|
62
|
+
self.name = step.name
|
63
|
+
self.file_colon_line = step.file_colon_line
|
64
|
+
self.status = step.status
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|