Class: Ace::TestRunner::Formatters::ProgressFormatter
- Inherits:
-
BaseFormatter
- Object
- BaseFormatter
- Ace::TestRunner::Formatters::ProgressFormatter
- Defined in:
- lib/ace/test_runner/formatters/progress_formatter.rb
Overview
Progress formatter that shows one dot per test (not per file)
Instance Attribute Summary
Attributes inherited from BaseFormatter
Instance Method Summary collapse
- #detect_target(file_path) ⇒ Object
- #format_report(report) ⇒ Object
- #format_stdout(result) ⇒ Object
-
#initialize(options = {}) ⇒ ProgressFormatter
constructor
A new instance of ProgressFormatter.
- #on_finish(result) ⇒ Object
- #on_start(total_files) ⇒ Object
- #on_start_with_totals(files_to_run, total_available) ⇒ Object
- #on_target_complete(target_name, success, duration, summary) ⇒ Object
- #on_target_start(target_name, file_count) ⇒ Object
- #on_test_complete(file, success, duration) ⇒ Object
- #on_test_stdout(stdout) ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ ProgressFormatter
Returns a new instance of ProgressFormatter.
10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 10 def initialize( = {}) super @test_count = 0 @line_width = [:line_width] || 80 @configuration = @max_failures_to_display = [:max_failures_to_display] || 7 @test_results = [] @current_group = nil @group_counts = Hash.new(0) @files_by_group = Hash.new { |h, k| h[k] = [] } @show_groups = [:show_groups] != false end |
Instance Method Details
#detect_target(file_path) ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 214 def detect_target(file_path) case file_path when /test\/(fast|unit)\/atoms\// :atoms when /test\/(fast|unit)\/molecules\// :molecules when /test\/(fast|unit)\/organisms\// :organisms when /test\/(fast|unit)\/models\// :models when /test\/feat\// :feat when /test\/edge\// :edge else :other end end |
#format_report(report) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 111 def format_report(report) # For CI, keep the report simple and parseable { status: report.success? ? "success" : "failure", stats: { total: report.result.total_tests, passed: report.result.passed, failed: report.result.failed, errors: report.result.errors, skipped: report.result.skipped, assertions: report.result.assertions, duration: report.result.duration }, failures: report.result.failures_detail.map { |f| failure_summary(f) } } end |
#format_stdout(result) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 23 def format_stdout(result) lines = [] # Progress dots are printed during execution, ensure newline lines << "" if @test_count > 0 # Report directory - use actual report path if available if @report_path lines << "Details: #{@report_path}/" elsif @configuration && @configuration[:save_reports] lines << "Details: #{@configuration[:report_dir] || ".ace-local/test/reports"}/latest/" end # Compact single-line summary with emoji status status = status_icon(result) summary = "#{status} #{result.total_tests} tests, #{result.assertions} assertions, " + "#{result.failed} failures, #{result.errors} errors" summary += ", #{result.skipped} skipped" if result.has_skips? summary += " (#{format_duration(result.duration)})" lines << summary # Add failure details if there are any if result.has_failures? lines << "" total_failures = result.failed + result.errors # Display up to max_failures_to_display failures failures_to_show = result.failures_detail.take(@max_failures_to_display) # Determine the label based on what types we have failure_count = result.failures_detail.count { |f| f.type == :failure } error_count = result.failures_detail.count { |f| f.type == :error } label = if failure_count > 0 && error_count > 0 "FAILURES & ERRORS" elsif error_count > 0 "ERRORS" else "FAILURES" end # Show failure count header with reference to full report if needed if total_failures > @max_failures_to_display report_path = @report_path || "#{@configuration[:report_dir] || ".ace-local/test/reports"}/latest" lines << "#{label} (#{failures_to_show.size}/#{total_failures}) → #{report_path}/failures.json:" else lines << "#{label} (#{total_failures}):" end failures_to_show.each_with_index do |failure, idx| # Extract file and line from location (e.g., "/path/file.rb:42:in `test_method'") if failure.location location_match = failure.location.match(/^([^:]+):(\d+)/) if location_match file = location_match[1].gsub(/^.*\/test\//, "test/") # Shorten path line = location_match[2] location = "#{file}:#{line}" else location = failure.location end else location = failure.test_name || "unknown" end # Format: location - short message with individual failure report path = (failure., 60) lines << " #{location} - #{}" # Show individual failure report path if we have the report path if @report_path failure_filename = format("%03d-%s.md", idx + 1, failure.full_test_name.gsub(/\W+/, "_").downcase[0...50]) lines << " → Details: #{@report_path}/failures/#{failure_filename}" end end # If there are more failures than displayed if result.failures_detail.size > @max_failures_to_display remaining = result.failures_detail.size - @max_failures_to_display report_path = @report_path || "#{@configuration[:report_dir] || ".ace-local/test/reports"}/latest" lines << " ... and #{remaining} more #{(remaining == 1) ? "failure" : "failures"}. See full report: #{report_path}/failures.json" end end lines.join("\n") end |
#on_finish(result) ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 254 def on_finish(result) # Ensure we're on a new line puts unless @test_count == 0 || @test_count % @line_width == 0 # Print target summary if we have target headers enabled if @show_groups && @group_counts.any? puts "" puts colorize("═══ Target Summary ═══", :cyan) @group_counts.each do |target, count| puts " #{target.to_s.capitalize}: #{count} #{(count == 1) ? "file" : "files"}" end end puts format_stdout(result) end |
#on_start(total_files) ⇒ Object
128 129 130 131 132 133 134 135 136 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 128 def on_start(total_files) # No verbose output in progress mode @test_count = 0 @test_results = [] @current_group = nil @group_counts = Hash.new(0) @total_files = total_files @total_available = nil end |
#on_start_with_totals(files_to_run, total_available) ⇒ Object
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 138 def on_start_with_totals(files_to_run, total_available) on_start(files_to_run) @total_available = total_available # Show file count if different from total available if total_available && total_available > files_to_run puts "Running #{files_to_run}/#{total_available} test files" puts "" end end |
#on_target_complete(target_name, success, duration, summary) ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 240 def on_target_complete(target_name, success, duration, summary) puts unless @test_count == 0 || @test_count % @line_width == 0 status_icon = success ? "✓" : "✗" test_count = summary[:runs] || 0 failure_count = summary[:failures] || 0 status_line = "#{status_icon} #{target_name} complete " + "(#{format_duration(duration)}, #{test_count} tests, #{failure_count} failures)" puts colorize(status_line, success ? :green : :red) puts "" end |
#on_target_start(target_name, file_count) ⇒ Object
233 234 235 236 237 238 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 233 def on_target_start(target_name, file_count) puts "" unless @test_count == 0 puts "" puts "Running #{target_name} (#{file_count} #{(file_count == 1) ? "file" : "files"})..." @test_count = 0 end |
#on_test_complete(file, success, duration) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 187 def on_test_complete(file, success, duration) # Detect target from file path target = detect_target(file) # Print target header if it's a new target and target headers are enabled if @show_groups && target != @current_group puts unless @test_count == 0 puts "" puts colorize("═══ #{target.to_s.capitalize} Tests ═══", :cyan) @current_group = target @test_count = 0 # Reset count for new line end # For per-test progress, we handle output in on_test_stdout if available # Otherwise fall back to per-file dots if @test_results.empty? # No per-test output received, show file-level dot char = success ? colorize(".", :green) : colorize("F", :red) print char @test_count += 1 puts if @test_count % @line_width == 0 end # Track target counts @group_counts[target] += 1 if @show_groups end |
#on_test_stdout(stdout) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/ace/test_runner/formatters/progress_formatter.rb', line 149 def on_test_stdout(stdout) # Parse individual test results from stdout return unless stdout # Look for test result lines in Minitest output # Handles both plain and ANSI-colored output from Minitest::Reporters stdout.each_line do |line| # Match test result lines like: # test_something [32m PASS[0m (0.00s) # test_other [31m FAIL[0m (0.01s) # test_error ERROR (0.00s) # test_skip SKIP (0.00s) # Improved regex to handle ANSI codes and underscores in test names # ANSI codes are: \e[32m (color start), \e[0m (reset) if line =~ /^\s*test_[\w_]+.*\s+(PASS|FAIL|ERROR|SKIP).*\([0-9.]+s\)/ result = case $1 when "PASS" "." when "FAIL" "F" when "ERROR" "E" when "SKIP" "S" else "." end print colorize(result, result_color(result)) @test_count += 1 @test_results << result # New line every N characters to prevent line overflow puts if @test_count % @line_width == 0 end end end |