pretty_face 0.1
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.
- 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
|