minitest-reporters 1.0.18 → 1.0.19

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