minitest-heat 0.0.12 → 0.0.13

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
  SHA256:
3
- metadata.gz: d95ecb7dad79fef49909bf766fb8c428489a71a0a2a50f815e4f0e7b0dbe480b
4
- data.tar.gz: f9e03a7fcb915c0f5f0e74eb20fb7cec2d65de7e4d73f6130b61d50d48d8fafc
3
+ metadata.gz: c523abe811fe169d2a919fe4495cad61c8f282f0d76809d302504f94b6030eb4
4
+ data.tar.gz: fffa2dcf19662bd6aa2b4ab46243cb797f9de5fa32723428008496d6942ad11e
5
5
  SHA512:
6
- metadata.gz: d9903cc0ea5edb14005ddcef3027ea09414100013f3e829989670a238bce2c2bd02b0227835632658022b82fff658d86dcab07aa58c7ddecdfb2452408258f97
7
- data.tar.gz: 2ea218a55b33d8ba6fdb41f8aa3ef7d07443537e482a2a995a7aad2c01fc952c22135263739aa0963d9e0e88a153ffd146ac32e4a9979c5a32ccf218391f66cf
6
+ metadata.gz: 7efa01e486a94c5506b6e68b0eb7c200243575909546f871dc2a905e7477d124f85c79d4f0160b9f101fc2d42f01828500565c6fb3434f207d5699b7adabd715
7
+ data.tar.gz: 114ee328cacda9818932c188368f7d808587374012af973998dcd1ee777f30c6fd878f97b3093e2fadb87010e6db5d7f3a0b739a2c805dd162ff41b51a05f99c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- minitest-heat (0.0.12)
4
+ minitest-heat (0.0.13)
5
5
  minitest
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,12 +1,41 @@
1
1
  # Minitest::Heat
2
- **Important:** As of September 13, 2021, Minitest::Heat is an early work-in-progress. It's usable, but it can still ocasionally be buggy as it takes shape.
2
+ Minitest::Heat helps you identify problems faster so you can more efficiently resolve test failures. It does this through a few different methods.
3
3
 
4
- Minitest::Heat aims to surface context around test failures to help you more efficiently identify and prioritize fixing failed tests to help save time.
4
+ It collects failures and inspects backtraces to identify patterns and provide a heat map summary of the files and line numbers that most frequently appear to be the causes of issues.
5
5
 
6
- For some early insight about priorities and how it works, this [Twitter thread](https://twitter.com/garrettdimon/status/1432703746526560266) is currently the best place to start.
6
+ ![Example Heat Map Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/map.png)
7
7
 
8
- ## Installation
8
+ It suppresses less critical issues like skips or slows when there are legitimate failures. It won't display information about slow tests unless all tests are passing (meaning no errors, failures, or skips)
9
+
10
+ It presents failures differently depending on the context of failure. For instance, it treats exceptions differently based on whether they arose directly from a test or from source code. It also treats extremely slow tests differently from moderately slow tests.
11
+
12
+ Markers get some nuance so that slow tests receive different markers than standard passing tests, and exception-triggered failures get different markers for source-code triggered exceptions (E) and test-triggered exceptions ('B' for 'Broken Test').
13
+
14
+ ![Example Markers Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/markers.png)
15
+
16
+ It also formats the failure details and backtraces to make them more scannable by emphasizing the project-relates lines from the backtrace.
17
+
18
+ It intelligently recognizes when an exception was raised from a test defintion vs. when an exception is genuinely triggered from the source code in order to help focus on fixing deeper exceptions first.
19
+
20
+ ![Example Exceptions Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/exceptions.png)
21
+
22
+ Failures are displayed ina fairly predictable manner but formatted to show the source code from the test so you can see the assertion that failed in addition to the summary of values that didn't satisfy the assertion.
23
+
24
+ ![Example Failures Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/failures.png)
25
+
26
+ Skipped tests are displayed in a simple manner as well so that it's easy to see the source of the skipped test as well as the reason it was skipped.
27
+
28
+ ![Example Skips Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/skips.png)
29
+
30
+ Slow tests get slightly more informative labels to indicate that they did pass, but they could use performance improvements. Tests that are particularly slow are called out with a little more emphasis so it's easier to focus on really slow tests first as they frequently represent the most potential for performance gains.
9
31
 
32
+ ![Example Slows Displayed by Minitest Heat](https://raw.githubusercontent.com/garrettdimon/minitest-heat/main/examples/slows.png)
33
+
34
+ It also always displays the most significant issues at the bottom of the list in order to reduce the need to scroll up through the test failures. As you fix issues, the list becomes shorter, and the less significant issues will make there way to the bottom and be visible without scrolling.
35
+
36
+ For some additional insight about priorities and how it works, this [Twitter thread](https://twitter.com/garrettdimon/status/1432703746526560266) is currently the best place to start.
37
+
38
+ ## Installation
10
39
  Add this line to your application's Gemfile:
11
40
 
12
41
  ```ruby
@@ -27,27 +56,33 @@ And depending on your usage, you may need to require Minitest Heat in your test
27
56
  require 'minitest/heat'
28
57
  ```
29
58
 
30
- ## Usage
31
-
32
- **Important:** In its current state, `Minitest::Heat` replaces any other reporter plugins you may have. Long-term, it should play nicer with other reporters, but during the initial heavy development cycle, it's been easier to have a high confidence that other reporters aren't the source of unexpected behavior.
33
-
34
- Otherwise, once it's bundled and added to your `test_helper`, it shold "just work" whenever you run your test suite.
59
+ ## Configuration
60
+ Minitest Heat doesn't currently offer a significant set of configuration options, but it will eventually support customizing the thresholds for "Slow" and "Painfully Slow". By default, it considers anything over 1.0s to be 'slow' and anything over 3.0s to be 'painfully slow'.
35
61
 
36
62
  ## Development
37
-
38
63
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
39
64
 
40
65
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
41
66
 
42
- ## Contributing
67
+ ### Forcing Test Failures
68
+ In order to easily see how Minitest Heat handles different combinations of different types of failures, the following environment variables can be used to force failures.
69
+
70
+ ```bash
71
+ IMPLODE=true # Every possible type of failure, skip, and slow is generated
72
+ FORCE_EXCEPTIONS=true # Only exception-triggered failures
73
+ FORCE_FAILURES=true # Only standard assertion failures
74
+ FORCE_SKIPS=true # No errors, just the skipped tests
75
+ FORCE_SLOWS=true # No errors or skipped tests, just slow tests
76
+ ```
43
77
 
44
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/minitest-heat. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/minitest-heat/blob/master/CODE_OF_CONDUCT.md).
78
+ So to see the full context of a test suite, `IMPLODE=true bundle exec rake` will work its magic.
45
79
 
80
+ ## Contributing
81
+ Bug reports and pull requests are welcome on GitHub at https://github.com/garrettdimon/minitest-heat. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/minitest-heat/blob/master/CODE_OF_CONDUCT.md).
46
82
 
47
83
  ## License
48
84
 
49
85
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
50
86
 
51
87
  ## Code of Conduct
52
-
53
88
  Everyone interacting in the Minitest::Heat project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/minitest-heat/blob/master/CODE_OF_CONDUCT.md).
Binary file
Binary file
data/examples/map.png ADDED
Binary file
Binary file
Binary file
Binary file
@@ -26,7 +26,7 @@ module Minitest
26
26
 
27
27
  # All lines of the backtrace converted to Backtrace::LineParser's
28
28
  #
29
- # @return [Line] the full set of backtrace lines parsed as Backtrace::LineParser instances
29
+ # @return [Array<Location>] the full set of backtrace lines parsed as Location instances
30
30
  def locations
31
31
  return [] if raw_backtrace.nil?
32
32
 
@@ -36,28 +36,28 @@ module Minitest
36
36
  # All entries from the backtrace within the project and sorted with the most recently modified
37
37
  # files at the beginning
38
38
  #
39
- # @return [Line] the sorted backtrace lines from the project parsed as Backtrace::LineParser's
39
+ # @return [Array<Location>] the sorted backtrace lines from the project
40
40
  def recently_modified_locations
41
41
  @recently_modified_locations ||= project_locations.sort_by(&:mtime).reverse
42
42
  end
43
43
 
44
44
  # All entries from the backtrace that are files within the project
45
45
  #
46
- # @return [Line] the backtrace lines from within the project parsed as Backtrace::LineParser's
46
+ # @return [Array<Location>] the backtrace lines from within the project
47
47
  def project_locations
48
48
  @project_locations ||= locations.select(&:project_file?)
49
49
  end
50
50
 
51
51
  # All entries from the backtrace within the project tests
52
52
  #
53
- # @return [Line] the backtrace lines from within the project tests parsed as Backtrace::LineParser's
53
+ # @return [Array<Location>] the backtrace lines from within the tests
54
54
  def test_locations
55
55
  @test_locations ||= project_locations.select(&:test_file?)
56
56
  end
57
57
 
58
58
  # All source code entries from the backtrace (i.e. excluding tests)
59
59
  #
60
- # @return [Line] the backtrace lines from within the source code parsed as Backtrace::LineParser's
60
+ # @return [Array<Location>] the backtrace lines from within the source code
61
61
  def source_code_locations
62
62
  @source_code_locations ||= project_locations.select(&:source_code_file?)
63
63
  end
@@ -116,20 +116,38 @@ module Minitest
116
116
  !passed? || slow? || painful?
117
117
  end
118
118
 
119
+ # The number, in seconds, for a test to be considered "slow"
120
+ #
121
+ # @return [Float] number of seconds after which a test is considered slow
122
+ def slow_threshold
123
+ # Using a method here so that this can eventually be configurable such that the constant is
124
+ # only a fallback value if it's not specified anywhere else
125
+ SLOW_THRESHOLDS[:slow]
126
+ end
127
+
128
+ # The number, in seconds, for a test to be considered "painfully slow"
129
+ #
130
+ # @return [Float] number of seconds after which a test is considered painfully slow
131
+ def painfully_slow_threshold
132
+ # Using a method here so that this can eventually be configurable such that the constant is
133
+ # only a fallback value if it's not specified anywhere else
134
+ SLOW_THRESHOLDS[:painful]
135
+ end
136
+
119
137
  # Determines if a test should be considered slow by comparing it to the low end definition of
120
138
  # what is considered slow.
121
139
  #
122
- # @return [Boolean] true if the test took longer to run than `SLOW_THRESHOLDS[:slow]`
140
+ # @return [Boolean] true if the test took longer to run than `slow_threshold`
123
141
  def slow?
124
- execution_time >= SLOW_THRESHOLDS[:slow] && execution_time < SLOW_THRESHOLDS[:painful]
142
+ execution_time >= slow_threshold && execution_time < painful_threshold
125
143
  end
126
144
 
127
145
  # Determines if a test should be considered painfully slow by comparing it to the high end
128
146
  # definition of what is considered slow.
129
147
  #
130
- # @return [Boolean] true if the test took longer to run than `SLOW_THRESHOLDS[:painful]`
148
+ # @return [Boolean] true if the test took longer to run than `painful_threshold`
131
149
  def painful?
132
- execution_time >= SLOW_THRESHOLDS[:painful]
150
+ execution_time >= painful_threshold
133
151
  end
134
152
 
135
153
  # Determines if the issue is an exception that was raised from directly within a test
@@ -3,7 +3,7 @@
3
3
  module Minitest
4
4
  module Heat
5
5
  class Output
6
- # Builds the collection of tokens for a backtrace when an exception occurs
6
+ # Builds the collection of tokens for displaying a backtrace when an exception occurs
7
7
  class Backtrace
8
8
  DEFAULT_LINE_COUNT = 10
9
9
  DEFAULT_INDENTATION_SPACES = 2
@@ -17,31 +17,47 @@ module Minitest
17
17
  end
18
18
 
19
19
  def tokens
20
- # There could be option to expand and display more than one line of source code for the
21
- # final backtrace line if it might be relevant/helpful?
22
-
23
20
  # Iterate over the selected lines from the backtrace
24
- backtrace_locations.each do |location|
25
- @tokens << backtrace_location_tokens(location)
26
- end
27
-
28
- @tokens
21
+ @tokens = backtrace_locations.map { |location| backtrace_location_tokens(location) }
29
22
  end
30
23
 
24
+ # Determines the number of lines to display from the backtrace.
25
+ #
26
+ # @return [Integer] the number of lines to limit the backtrace to
31
27
  def line_count
28
+ # Defined as a method instead of using the constant directlyr in order to easily support
29
+ # adding options for controlling how many lines are displayed from a backtrace.
30
+ #
31
+ # For example, instead of a fixed number, the backtrace could dynamically calculate how
32
+ # many lines it should displaye in order to get to the origination point. Or it could have
33
+ # a default, but inteligently go back further if the backtrace meets some criteria for
34
+ # displaying more lines.
32
35
  DEFAULT_LINE_COUNT
33
36
  end
34
37
 
35
- # This should probably be smart about what lines are displayed in a backtrace.
36
- # Maybe...
37
- # ...it could intelligently display the full back trace?
38
- # ...only the backtrace from the first/last line of project source?
39
- # ...it behaves a little different when it's a broken test vs. a true exception?
40
- # ...it could be smart about subtly flagging the lines that show up in the heat map frequently?
41
- # ...it could be influenced by a "compact" or "robust" reporter super-style?
42
- # ...it's smart about exceptions that were raised outside of the project?
43
- # ...it's smart about highlighting lines of code differently based on whether it's source code, test code, or external code?
38
+ # A subset of parsed lines from the backtrace.
39
+ #
40
+ # @return [Array<Location>] the backtrace locations determined to be most relevant to the
41
+ # context of the underlying issue
44
42
  def backtrace_locations
43
+ # This could eventually have additional intelligence to determine what lines are most
44
+ # relevant for a given type of issue. For now, it simply takes the line numbers, but the
45
+ # idea is that long-term, it could adjust that on the fly to keep the line count as low
46
+ # as possible but expand it if necessary to ensure enough context is displayed.
47
+ #
48
+ # - If there's no clear cut details about the source of the error from within the project,
49
+ # it could display the entire backtrace without filtering anything.
50
+ # - It could scan the backtrace to the first appearance of project files and then display
51
+ # all of the lines that occurred after that instance
52
+ # - It coudl filter the lines differently whether the issue originated from a test or from
53
+ # the source code.
54
+ # - It could allow supporting a "compact" or "robust" reporter style so that someone on
55
+ # a smaller screen could easily reduce the information shown so that the results could
56
+ # be higher density even if it means truncating some occasionally useful details
57
+ # - It could be smarter about displaying context/guidance when the full backtrace is from
58
+ # outside the project's code
59
+ #
60
+ # But for now. It just grabs some lines.
45
61
  backtrace.locations.take(line_count)
46
62
  end
47
63
 
@@ -65,8 +81,17 @@ module Minitest
65
81
  backtrace_locations.all?(&:project_file?)
66
82
  end
67
83
 
84
+ # Determines if the file referenced by a backtrace line is the most recently modified file
85
+ # of all the files referenced in the visible backtrace locations.
86
+ #
87
+ # @param [Location] location the location to examine
88
+ #
89
+ # @return [<type>] <description>
90
+ #
68
91
  def most_recently_modified?(location)
69
- # If there's more than one line being displayed, and the current line is the freshest
92
+ # If there's more than one line being displayed (otherwise, with one line, of course it's
93
+ # the most recently modified because there_aren't any others) and the current line is the
94
+ # same as the freshest location in the backtrace
70
95
  backtrace_locations.size > 1 && location == locations.freshest
71
96
  end
72
97
 
@@ -14,28 +14,16 @@ module Minitest
14
14
 
15
15
  def tokens
16
16
  case issue.type
17
- when :error then error_tokens
18
- when :broken then broken_tokens
19
- when :failure then failure_tokens
20
- when :skipped then skipped_tokens
21
- when :painful then painful_tokens
22
- when :slow then slow_tokens
17
+ when :error, :broken then exception_tokens
18
+ when :failure then failure_tokens
19
+ when :skipped then skipped_tokens
20
+ when :painful, :slow then slow_tokens
23
21
  end
24
22
  end
25
23
 
26
24
  private
27
25
 
28
- def error_tokens
29
- [
30
- headline_tokens,
31
- test_location_tokens,
32
- summary_tokens,
33
- *backtrace_tokens,
34
- newline_tokens
35
- ]
36
- end
37
-
38
- def broken_tokens
26
+ def exception_tokens
39
27
  [
40
28
  headline_tokens,
41
29
  test_location_tokens,
@@ -62,14 +50,6 @@ module Minitest
62
50
  ]
63
51
  end
64
52
 
65
- def painful_tokens
66
- [
67
- headline_tokens,
68
- slowness_summary_tokens,
69
- newline_tokens
70
- ]
71
- end
72
-
73
53
  def slow_tokens
74
54
  [
75
55
  headline_tokens,
@@ -82,6 +62,11 @@ module Minitest
82
62
  [label_token(issue), spacer_token, [:default, test_name(issue)]]
83
63
  end
84
64
 
65
+ # Creates a display-friendly version of the test name with underscores removed and the
66
+ # first letter capitalized regardless of the formatt used for the test definition
67
+ # @param issue [Issue] the issue to use to generate the test name
68
+ #
69
+ # @return [String] the cleaned up version of the test name
85
70
  def test_name(issue)
86
71
  test_prefix = 'test_'
87
72
  identifier = issue.test_identifier
@@ -97,27 +82,10 @@ module Minitest
97
82
  [issue.type, issue_label(issue.type)]
98
83
  end
99
84
 
100
- def issue_label(issue_type)
101
- case issue_type
102
- when :error then 'Error'
103
- when :broken then 'Broken Test'
104
- when :failure then 'Failure'
105
- when :skipped then 'Skipped'
106
- when :slow then 'Passed but Slow'
107
- when :painful then 'Passed but Very Slow'
108
- when :passed then 'Success'
109
- else 'Unknown'
110
- end
111
- end
112
-
113
85
  def test_name_and_class_tokens
114
86
  [[:default, issue.test_class], *test_location_tokens]
115
87
  end
116
88
 
117
- def backtrace_tokens
118
- @backtrace_tokens ||= ::Minitest::Heat::Output::Backtrace.new(locations).tokens
119
- end
120
-
121
89
  def test_location_tokens
122
90
  [
123
91
  [:default, locations.test_definition.relative_filename],
@@ -176,6 +144,27 @@ module Minitest
176
144
  def arrow_token
177
145
  Output::TOKENS[:muted_arrow]
178
146
  end
147
+
148
+ def backtrace_tokens
149
+ @backtrace_tokens ||= ::Minitest::Heat::Output::Backtrace.new(locations).tokens
150
+ end
151
+
152
+ # The string to use to describe the failure type when displaying results/
153
+ # @param issue_type [Symbol] the symbol representing the issue's failure type
154
+ #
155
+ # @return [String] the display-friendly string describing the failure reason
156
+ def issue_label(issue_type)
157
+ case issue_type
158
+ when :error then 'Error'
159
+ when :broken then 'Broken Test'
160
+ when :failure then 'Failure'
161
+ when :skipped then 'Skipped'
162
+ when :slow then 'Passed but Slow'
163
+ when :painful then 'Passed but Very Slow'
164
+ when :passed then 'Success'
165
+ else 'Unknown'
166
+ end
167
+ end
179
168
  end
180
169
  end
181
170
  end
@@ -14,24 +14,34 @@ module Minitest
14
14
 
15
15
  def tokens
16
16
  results.heat_map.file_hits.each do |hit|
17
- # If there's legitimate failures or errors, skips and slows aren't relevant
17
+ # Focus on the relevant issues based on most significant problems. i.e. If there are
18
+ # legitimate failures or errors, skips and slows aren't relevant
18
19
  next unless relevant_issue_types?(hit)
19
20
 
21
+ # Add a new line
20
22
  @tokens << [[:muted, ""]]
23
+
24
+ # Build the summary line for the file
21
25
  @tokens << file_summary_tokens(hit)
22
26
 
23
- repeats = repeated_line_numbers(hit)
24
- next unless repeats.any?
27
+ # Get the set of line numbers that appear more than once
28
+ repeated_line_numbers = find_repeated_line_numbers_in(hit)
25
29
 
26
- repeats.each do |line_number|
27
- @tokens << [[:muted, " Issues on Line #{line_number} initially triggered from these locations:"]]
30
+ # Only display more details if the same line number shows up more than once
31
+ next unless repeated_line_numbers.any?
28
32
 
33
+ repeated_line_numbers.each do |line_number|
34
+ # Get the backtraces for the given line numbers
29
35
  traces = hit.lines[line_number.to_s]
30
- sorted_traces = traces.sort_by { |trace| trace.locations.last.line_number }
31
36
 
32
- sorted_traces.each do |trace|
33
- @tokens << origination_location_token(trace)
34
- end
37
+ # If there aren't any traces there's no way to provide additional details
38
+ break unless traces.any?
39
+
40
+ # A short summary explaining the details that will follow
41
+ @tokens << [[:muted, " Issues on Line #{line_number} initially triggered from these locations:"]]
42
+
43
+ # The last relevant location for each error's backtrace
44
+ @tokens += origination_sources(traces)
35
45
  end
36
46
  end
37
47
 
@@ -40,6 +50,14 @@ module Minitest
40
50
 
41
51
  private
42
52
 
53
+ def origination_sources(traces)
54
+ # 1. Sort the traces by the most recent line number so they're displayed in numeric order
55
+ # 2. Get the final relevant location from the trace
56
+ traces.
57
+ sort_by { |trace| trace.locations.last.line_number }.
58
+ map { |trace| origination_location_token(trace) }
59
+ end
60
+
43
61
  def file_summary_tokens(hit)
44
62
  pathname_tokens = pathname(hit)
45
63
  line_number_list_tokens = sorted_line_number_list(hit)
@@ -75,16 +93,18 @@ module Minitest
75
93
  end
76
94
 
77
95
  def relevant_issue_types?(hit)
96
+ # The intersection of which issue types are relevant based on the context and which issues
97
+ # matc those issue types
78
98
  intersection_issue_types = relevant_issue_types & hit.issues.keys
79
99
 
80
100
  intersection_issue_types.any?
81
101
  end
82
102
 
83
- def repeated_line_numbers(hit)
103
+ def find_repeated_line_numbers_in(hit)
84
104
  repeated_line_numbers = []
85
105
 
86
106
  hit.lines.each_pair do |line_number, traces|
87
- # If there aren't multiple traces for a line number, it's not a repeat, right?
107
+ # If there aren't multiple traces for a line number, it's not a repeat
88
108
  next unless traces.size > 1
89
109
 
90
110
  repeated_line_numbers << Integer(line_number)
@@ -93,10 +113,6 @@ module Minitest
93
113
  repeated_line_numbers.sort
94
114
  end
95
115
 
96
- def repeated_line_numbers?(hit)
97
- repeated_line_numbers(hit).any?
98
- end
99
-
100
116
  def pathname(hit)
101
117
  directory = hit.pathname.dirname.to_s.delete_prefix("#{Dir.pwd}/")
102
118
  filename = hit.pathname.basename.to_s
@@ -108,6 +124,11 @@ module Minitest
108
124
  ]
109
125
  end
110
126
 
127
+ # Gets the list of line numbers for a given hit location (i.e. file) so they can be
128
+ # displayed after the file name to show which lines were problematic
129
+ # @param hit [Hit] the instance to extract line numbers from
130
+ #
131
+ # @return [Array<Symbol,String>] [description]
111
132
  def line_number_tokens_for_hit(hit)
112
133
  line_number_tokens = []
113
134
 
@@ -124,16 +145,23 @@ module Minitest
124
145
  line_number_tokens.compact
125
146
  end
126
147
 
148
+ # Builds a token representing a styled line number
149
+ #
150
+ # @param style [Symbol] the relevant display style for the issue
151
+ # @param line_number [Integer] the affected line number
152
+ #
153
+ # @return [Array<Symbol,Integer>] array token representing the line number and issue type
127
154
  def line_number_token(style, line_number)
128
155
  [style, "#{line_number} "]
129
156
  end
130
157
 
131
- # Generates the line number tokens styled based on their error type
158
+ # Sorts line number tokens so that line numbers are displayed in order regardless of their
159
+ # underlying issue type
132
160
  #
133
- # @param [Hit] hit the instance of the hit file details to build the heat map entry
161
+ # @param hit [Hit] the instance of the hit file details to build the heat map entry
134
162
  #
135
163
  # @return [Array] the arrays representing the line number tokens to display next to a file
136
- # name in the heat map
164
+ # name in the heat map. ex [[:error, 12], [:falure, 13]]
137
165
  def sorted_line_number_list(hit)
138
166
  # Sort the collected group of line number hits so they're in order
139
167
  line_number_tokens_for_hit(hit).sort do |a, b|
@@ -48,10 +48,13 @@ module Minitest
48
48
  newline
49
49
 
50
50
  # Issues start with the least critical and go up to the most critical so that the most
51
- # pressing issues are displayed at the bottom of the report in order to reduce scrolling.
52
- # This way, as you fix issues, the list gets shorter, and eventually the least critical
53
- # issues will be displayed without scrolling once more problematic issues are resolved.
51
+ # pressing issues are displayed at the bottom of the report in order to reduce scrolling.
52
+ #
53
+ # This way, as you fix issues, the list gets shorter, and eventually the least critical
54
+ # issues will be displayed without scrolling once more problematic issues are resolved.
54
55
  %i[slows painfuls skips failures brokens errors].each do |issue_category|
56
+ # Only show categories for the most pressing issues after the suite runs, otherwise,
57
+ # suppress them until the more critical issues are resolved.
55
58
  next unless show?(issue_category, results)
56
59
 
57
60
  results.send(issue_category).each { |issue| issue_details(issue) }
@@ -64,7 +67,7 @@ module Minitest
64
67
  def issue_details(issue)
65
68
  print_tokens Minitest::Heat::Output::Issue.new(issue).tokens
66
69
  rescue StandardError => e
67
- message = "Sorry, but Minitest Heat couldn't display output for a failure."
70
+ message = "Sorry, but Minitest Heat couldn't display output for a specific failure."
68
71
  exception_guidance(message, e)
69
72
  end
70
73
 
@@ -89,6 +92,15 @@ module Minitest
89
92
  exception_guidance(message, e)
90
93
  end
91
94
 
95
+ private
96
+
97
+ # Displays some guidance related to exceptions generated by Minitest Heat in order to help
98
+ # people get back on track (and ideally submit issues)
99
+ # @param message [String] a slightly more specific explanation of which part of minitest-heat
100
+ # caused the failure
101
+ # @param exception [Exception] the exception that caused the problem
102
+ #
103
+ # @return [void] displays the guidance to the console
92
104
  def exception_guidance(message, exception)
93
105
  newline
94
106
  puts "#{message} Disabling Minitest Heat can get you back on track until the problem can be fixed."
@@ -100,8 +112,6 @@ module Minitest
100
112
  newline
101
113
  end
102
114
 
103
- private
104
-
105
115
  def no_problems?(results)
106
116
  !results.problems?
107
117
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Minitest
4
4
  module Heat
5
- VERSION = '0.0.12'
5
+ VERSION = '0.0.13'
6
6
  end
7
7
  end
@@ -96,7 +96,7 @@ module Minitest
96
96
  # The list of individual issues and their associated details
97
97
  output.issues_list(results)
98
98
 
99
- # Display a short summary of the total issue counts fore ach category as well as performance
99
+ # Display a short summary of the total issue counts for each category as well as performance
100
100
  # details for the test suite as a whole
101
101
  output.compact_summary(results, timer)
102
102
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-heat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garrett Dimon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-15 00:00:00.000000000 Z
11
+ date: 2021-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -141,6 +141,12 @@ files:
141
141
  - Rakefile
142
142
  - bin/console
143
143
  - bin/setup
144
+ - examples/exceptions.png
145
+ - examples/failures.png
146
+ - examples/map.png
147
+ - examples/markers.png
148
+ - examples/skips.png
149
+ - examples/slows.png
144
150
  - lib/minitest/heat.rb
145
151
  - lib/minitest/heat/backtrace.rb
146
152
  - lib/minitest/heat/backtrace/line_parser.rb