minitest-reporters 1.0.18 → 1.0.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a09422c8dc047a458f9470eb685541711e3114d
4
- data.tar.gz: fe50bb460ede6b6ac28b1974bea0fc6845424a96
3
+ metadata.gz: c79f88a67d61dda24ebe17a89046fe86046e101a
4
+ data.tar.gz: 26cec6b5fab44023ba5e4ceb71e9554ebc9a53ff
5
5
  SHA512:
6
- metadata.gz: 4bafc6d01fb44ad81bb2c65acbef27ffd9b01d8544501a1921f839c9cef5dcda8617d76c9768a4090fc48687994a0b3b5256b1df4338e70c230d3508cc3d6604
7
- data.tar.gz: 291cf234cd9b19c8dc817ba1ff7ee611bd2769fd7bd3544d41269ef11c1120beed66a73b2701947556ab3d1c2ec10799873a72165efb655414b4239cc8c98f18
6
+ metadata.gz: 4d089e802175a8ba1d677f7e3710ca6f08771a94a4bbeb5d2bb83b6349b782ebde0c8ffe3546826f313a677e86aa87177e0e119ad7caeb5101c543a81c345296
7
+ data.tar.gz: ccf2cd2b9dc9e473c60d4b4be0ddb2b78b9118354eac249ba855e4045f222853a1ec6082952055926932b8cdf2afaee30effb468a9c9edee2ceaf7b170e69e0c
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [gem]: https://rubygems.org/gems/minitest-reporters
2
- [travis]: https://travis-ci.org/rom-rb/rom-mongo
2
+ [travis]: https://travis-ci.org/kern/minitest-reporters
3
3
 
4
4
  # minitest-reporters - create customizable Minitest output formats
5
5
  [![Gem Version](https://badge.fury.io/rb/minitest-reporters.svg)][gem]
data/Rakefile CHANGED
@@ -34,7 +34,8 @@ task :gallery do
34
34
  "ProgressReporter",
35
35
  "RubyMateReporter",
36
36
  "SpecReporter",
37
- "RubyMineReporter"
37
+ "RubyMineReporter",
38
+ "HtmlReporter"
38
39
  ].each do |reporter|
39
40
  puts
40
41
  puts "-" * 72
@@ -15,6 +15,7 @@ module Minitest
15
15
  autoload :RubyMateReporter, "minitest/reporters/ruby_mate_reporter"
16
16
  autoload :RubyMineReporter, "minitest/reporters/rubymine_reporter"
17
17
  autoload :JUnitReporter, "minitest/reporters/junit_reporter"
18
+ autoload :HtmlReporter, "minitest/reporters/html_reporter"
18
19
 
19
20
  class << self
20
21
  attr_accessor :reporters
@@ -0,0 +1,212 @@
1
+ require 'builder'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module Minitest
6
+ module Reporters
7
+ # A reporter for generating HTML test reports
8
+ # This is recommended to be used with a CI server, where the report is kept as an artifact and is accessible via a shared link
9
+ #
10
+ # The reporter sorts the results alphabetically and then by results so that failing and skipped tests are at the top.
11
+ #
12
+ # When using Minitest Specs, the number prefix is dropped from the name of the test so that it reads well
13
+ #
14
+ # On each test run all files in the reports directory are deleted, this prevents a build up of old reports
15
+ #
16
+ # The report is generated using ERB. A custom ERB template can be provided but it is not required
17
+ # The default ERB template uses JQuery and Bootstrap, both of these are included by referencing the CDN sites
18
+ class HtmlReporter < BaseReporter
19
+
20
+ # The title of the report
21
+ attr_reader :title
22
+
23
+ # The number of tests that passed
24
+ def passes
25
+ count - failures - errors - skips
26
+ end
27
+
28
+ # The percentage of tests that passed, calculated in a way that avoids rounding errors
29
+ def percent_passes
30
+ 100 - percent_skipps - percent_errors_failures
31
+ end
32
+
33
+ # The percentage of tests that were skipped
34
+ def percent_skipps
35
+ (skips/count.to_f * 100).to_i
36
+ end
37
+
38
+ # The percentage of tests that failed
39
+ def percent_errors_failures
40
+ ((errors+failures)/count.to_f * 100).to_i
41
+ end
42
+
43
+ # Trims off the number prefix on test names when using Minitest Specs
44
+ def friendly_name(test)
45
+ groups = test.name.scan(/(test_\d+_)(.*)/i)
46
+ return test.name if groups.empty?
47
+ "it #{groups[0][1]}"
48
+ end
49
+
50
+ # The constructor takes a hash, and uses the following keys:
51
+ # :title - the title that will be used in the report, defaults to 'Test Results'
52
+ # :reports_dir - the directory the reports should be written to, defaults to 'test/html_reports'
53
+ # :erb_template - the path to a custom ERB template, defaults to the supplied ERB template
54
+ # :mode - Useful for debugging, :terse suppresses errors and is the default, :verbose lets errors bubble up
55
+ def initialize(args = {})
56
+ super({})
57
+
58
+ defaults = {
59
+ :title => 'Test Results',
60
+ :erb_template => "#{File.dirname(__FILE__)}/../templates/index.html.erb",
61
+ :reports_dir => 'test/html_reports',
62
+ :mode => :safe
63
+ }
64
+
65
+ settings = defaults.merge(args)
66
+
67
+ @mode = settings[:mode]
68
+ @title = settings[:title]
69
+ @erb_template = settings[:erb_template]
70
+ reports_dir = settings[:reports_dir]
71
+
72
+ @reports_path = File.absolute_path(reports_dir)
73
+
74
+ puts "Emptying #{@reports_path}"
75
+ FileUtils.remove_dir(@reports_path) if File.exists?(@reports_path)
76
+ FileUtils.mkdir_p(@reports_path)
77
+ end
78
+
79
+ # Called by the framework to generate the report
80
+ def report
81
+ super
82
+
83
+ begin
84
+ puts "Writing HTML reports to #{@reports_path}"
85
+ html_file = @reports_path + "/index.html"
86
+ erb_str = File.read(@erb_template)
87
+ renderer = ERB.new(erb_str)
88
+
89
+ tests_by_suites = tests.group_by(&:class) # taken from the JUnit reporter
90
+
91
+ suites = tests_by_suites.map do |suite, tests|
92
+ suite_summary = summarize_suite(suite, tests)
93
+ suite_summary[:tests] = tests.sort { |a, b| compare_tests(a, b) }
94
+ suite_summary
95
+ end
96
+
97
+ suites.sort! { |a, b| compare_suites(a, b) }
98
+
99
+ result = renderer.result(binding)
100
+ File.open(html_file, 'w') do |f|
101
+ f.write(result)
102
+ end
103
+
104
+ rescue Exception => e
105
+ puts 'There was an error writing the HTML report'
106
+ puts 'This may have been caused by cancelling the test run'
107
+ puts 'Use mode => :verbose in the HTML reporters constructor to see more detail' if @mode == :terse
108
+ puts 'Use mode => :terse in the HTML reporters constructor to see less detail' if @mode != :terse
109
+ raise e if @mode != :terse
110
+ end
111
+
112
+ end
113
+
114
+ private
115
+
116
+ def compare_suites_by_name(suite_a, suite_b)
117
+ suite_a[:name] <=> suite_b[:name]
118
+ end
119
+
120
+ def compare_tests_by_name(test_a, test_b)
121
+ friendly_name(test_a) <=> friendly_name(test_b)
122
+ end
123
+
124
+ # Test suites are first ordered by evaluating the results of the tests, then by test suite name
125
+ # Test suites which have failing tests are given highest order
126
+ # Tests suites which have skipped tests are given second highest priority
127
+ def compare_suites(suite_a, suite_b)
128
+ return compare_suites_by_name(suite_a, suite_b) if suite_a[:has_errors_or_failures] && suite_b[:has_errors_or_failures]
129
+ return -1 if suite_a[:has_errors_or_failures] && !suite_b[:has_errors_or_failures]
130
+ return 1 if !suite_a[:has_errors_or_failures] && suite_b[:has_errors_or_failures]
131
+
132
+ return compare_suites_by_name(suite_a, suite_b) if suite_a[:has_skipps] && suite_b[:has_skipps]
133
+ return -1 if suite_a[:has_skipps] && !suite_b[:has_skipps]
134
+ return 1 if !suite_a[:has_skipps] && suite_b[:has_skipps]
135
+
136
+ compare_suites_by_name(suite_a, suite_b)
137
+ end
138
+
139
+ # Tests are first ordered by evaluating the results of the tests, then by tests names
140
+ # Tess which fail are given highest order
141
+ # Tests which are skipped are given second highest priority
142
+ def compare_tests(test_a, test_b)
143
+ return compare_tests_by_name(test_a, test_b) if test_fail_or_error?(test_a) && test_fail_or_error?(test_b)
144
+
145
+ return -1 if test_fail_or_error?(test_a) && !test_fail_or_error?(test_b)
146
+ return 1 if !test_fail_or_error?(test_a) && test_fail_or_error?(test_b)
147
+
148
+ return compare_tests_by_name(test_a, test_b) if test_a.skipped? && test_b.skipped?
149
+ return -1 if test_a.skipped? && !test_b.skipped?
150
+ return 1 if !test_a.skipped? && test_b.skipped?
151
+
152
+ compare_tests_by_name(test_a, test_b)
153
+ end
154
+
155
+ def test_fail_or_error?(test)
156
+ test.error? || test.failure
157
+ end
158
+
159
+ # based on analyze_suite from the JUnit reporter
160
+ def summarize_suite(suite, tests)
161
+ summary = Hash.new(0)
162
+ summary[:name] = suite.to_s
163
+ tests.each do |test|
164
+ summary[:"#{result(test)}_count"] += 1
165
+ summary[:assertion_count] += test.assertions
166
+ summary[:test_count] += 1
167
+ summary[:time] += test.time
168
+ end
169
+ summary[:has_errors_or_failures] = (summary[:fail_count] + summary[:error_count]) > 0
170
+ summary[:has_skipps] = summary[:skip_count] > 0
171
+ summary
172
+ end
173
+
174
+ # based on message_for(test) from the JUnit reporter
175
+ def message_for(test)
176
+ suite = test.class
177
+ name = test.name
178
+ e = test.failure
179
+
180
+ if test.passed?
181
+ nil
182
+ elsif test.skipped?
183
+ "Skipped:\n#{name}(#{suite}) [#{location(e)}]:\n#{e.message}\n"
184
+ elsif test.failure
185
+ "Failure:\n#{name}(#{suite}) [#{location(e)}]:\n#{e.message}\n"
186
+ elsif test.error?
187
+ "Error:\n#{name}(#{suite}):\n#{e.message}"
188
+ end
189
+ end
190
+
191
+ # taken from the JUnit reporter
192
+ def location(exception)
193
+ last_before_assertion = ''
194
+ exception.backtrace.reverse_each do |s|
195
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
196
+ last_before_assertion = s
197
+ end
198
+ last_before_assertion.sub(/:in .*$/, '')
199
+ end
200
+
201
+ def total_time_to_hms
202
+ return ('%.2fs' % total_time) if total_time < 1
203
+
204
+ hours = total_time / (60 * 60)
205
+ minutes = ((total_time / 60) % 60).to_s.rjust(2,'0')
206
+ seconds = (total_time % 60).to_s.rjust(2,'0')
207
+
208
+ "#{ hours }h#{ minutes }m#{ seconds }s"
209
+ end
210
+ end
211
+ end
212
+ end
@@ -1,5 +1,5 @@
1
1
  module Minitest
2
2
  module Reporters
3
- VERSION = '1.0.18'
3
+ VERSION = '1.0.19'
4
4
  end
5
5
  end
@@ -0,0 +1,83 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title><%= title %></title>
5
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
6
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
7
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
8
+ <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
9
+ </head>
10
+
11
+ <body>
12
+ <div class="container">
13
+ <div class="jumbotron">
14
+ <h1><%= title %></h1>
15
+ <p>
16
+ Finished in <%= total_time_to_hms %>, <%= '%.2f tests/s' % (count / total_time) %>, <%= '%.2f assertions/s' % (assertions / total_time) %>
17
+ </p>
18
+ <p>
19
+ <strong>
20
+ <span class="<%= 'text-info' if (failures == 0 && errors == 0) %>"><%= '%d' % count %> tests</span>,
21
+ <span class="<%= 'text-info' if (failures == 0 && errors == 0) %>"> <%= '%d' % assertions %> assertions</span>,
22
+ <span class="<%= 'text-danger' if failures > 0 %>"> <%= '%d' % failures %> failures</span>,
23
+ <span class="<%= 'text-danger' if errors > 0 %>"> <%= '%d' % errors %> errors</span>,
24
+ <span class="<%= 'text-warning' if skips > 0 %>"> <%= '%d' % skips %> skips</span>
25
+ </strong>
26
+ </p>
27
+
28
+ <div class="progress">
29
+ <div class="progress-bar progress-bar-info" style="width: <%= percent_passes %>%">
30
+ <%= '%d' % percent_passes %>% passed
31
+ </div>
32
+ <div class="progress-bar progress-bar-danger" style="width: <%= percent_errors_failures %>%">
33
+ <%= '%d' % percent_errors_failures %>% failed
34
+ </div>
35
+ <div class="progress-bar progress-bar-warning" style="width: <%= percent_skipps %>%">
36
+ <%= '%d' % percent_skipps %>% skipped
37
+ </div>
38
+ </div>
39
+
40
+
41
+ </div>
42
+
43
+ <% suites.each do |suite| %>
44
+ <div class="panel panel-default">
45
+ <div class="panel-heading"><strong><%= suite[:name] %></strong>
46
+ <span class="pull-right">
47
+ <span class="<%= 'text-info' if (suite[:fail_count] == 0 && suite[:error_count] == 0) %>"><%= '%d' % suite[:test_count] %> tests</span>,
48
+ <span class="<%= 'text-info' if (failures == 0 && errors == 0) %>"> <%= '%d' % suite[:assertion_count] %> assertions</span>,
49
+ <span class="<%= 'text-danger' if suite[:fail_count] > 0 %>"> <%= '%d' % suite[:fail_count] %> failures</span>,
50
+ <span class="<%= 'text-danger' if suite[:error_count] > 0 %>"> <%= '%d' % suite[:error_count] %> errors</span>,
51
+ <span class="<%= 'text-warning' if suite[:skip_count] > 0 %>"> <%= '%d' % suite[:skip_count] %> skips</span>,
52
+ <span> finished in <%= '%.4fs' % suite[:time] %></span>
53
+ </span>
54
+ </div>
55
+ <div class="panel-body">
56
+ <div class="list-group">
57
+ <% suite[:tests].each do |test| %>
58
+ <div class="list-group-item">
59
+ <h5 class="list-group-item-heading">
60
+ <% if result(test) == :pass %>
61
+ <span class="glyphicon glyphicon-ok text-info" aria-hidden="true"></span>
62
+ <% elsif result(test) == :skip %>
63
+ <span class="glyphicon glyphicon-ban-circle text-warning" aria-hidden="true"></span>
64
+ <% else %>
65
+ <span class="glyphicon glyphicon-remove text-danger" aria-hidden="true"></span>
66
+ <% end %>
67
+ <%= friendly_name(test) %>
68
+ <span class="pull-right">
69
+ Assertions <%= test.assertions %>, time <%= ('%.6fs' % test.time) %>
70
+ </span>
71
+ </h5>
72
+ <% if !test.passed? %>
73
+ <pre class="list-group-item-text"><%= "#{location(test.failure)}\n\n#{test.failure.message}" %></pre>
74
+ <% end %>
75
+ </div>
76
+ <% end %>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <% end %>
81
+ </div>
82
+ </body>
83
+ </html>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-reporters
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.18
4
+ version: 1.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Kern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-07 00:00:00.000000000 Z
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -120,12 +120,14 @@ files:
120
120
  - lib/minitest/reporters/ansi.rb
121
121
  - lib/minitest/reporters/base_reporter.rb
122
122
  - lib/minitest/reporters/default_reporter.rb
123
+ - lib/minitest/reporters/html_reporter.rb
123
124
  - lib/minitest/reporters/junit_reporter.rb
124
125
  - lib/minitest/reporters/progress_reporter.rb
125
126
  - lib/minitest/reporters/ruby_mate_reporter.rb
126
127
  - lib/minitest/reporters/rubymine_reporter.rb
127
128
  - lib/minitest/reporters/spec_reporter.rb
128
129
  - lib/minitest/reporters/version.rb
130
+ - lib/minitest/templates/index.html.erb
129
131
  - minitest-reporters.gemspec
130
132
  - test/fixtures/junit_filename_bug_example_test.rb
131
133
  - test/fixtures/progress_detailed_skip_test.rb