capydash 0.2.5 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc3c0c3e8b55e78af53e8f1a8a34f44165da41b6149dec134cd2a573ba959a98
4
- data.tar.gz: 4e3dbca12dc81a9914e418092def3c7a58a0bb1dfcad61d9b8d8056c99b2c063
3
+ metadata.gz: 59bf6aaa616cf19064f4fc9d98b53f81fc79f54ef604c2034636f6ea8dbf936d
4
+ data.tar.gz: 605412b29c494e55a96eb8a79293e2bd4b68cf06f3c6fbb0f0be7efbf1e362d9
5
5
  SHA512:
6
- metadata.gz: 578279a43a188c65e710d163fb30936f96ceee8d4a4803408a25683d6547695c48250f960d87f63179206b3e1345fe52290f40b184805a9b8c3e004205c05f09
7
- data.tar.gz: 72218c84707dfd0e7b7275b87287862e45cf2bfa629169cea372be719a6314b63350a427831ad5016478fe443d3c680385b5cc5f879948e11048cdf494ba1f3f
6
+ metadata.gz: 496f1563f50549166ae3ff4a0e31fce18941522401bc9aa0a83076907a9996238d9102896857aabf8ecf813a92a89b9daeb9d25753ff097ea966cd5b4b2509a4
7
+ data.tar.gz: c070c748dbbe64238712368702279a49bb2a5c0c6af4635916b5e39308b8d81ddf92dda24b9369517c52fa48a48937b810b0901044b6c98820eac062d002fcb5
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CapyDash
2
2
 
3
- Minimal, zero-config HTML report for your RSpec tests. Add the gem, run your tests, get a report.
3
+ Minimal, zero-config HTML report for your RSpec and Minitest tests. Add the gem, run your tests, get a report.
4
4
 
5
5
  ![CapyDash Report](docs/capydash-demo.gif)
6
6
 
@@ -21,7 +21,12 @@ Run `bundle install`. That's it — no configuration needed.
21
21
  Run your tests as usual:
22
22
 
23
23
  ```bash
24
+ # RSpec
24
25
  bundle exec rspec
26
+
27
+ # Minitest
28
+ bundle exec rails test
29
+ bundle exec rails test:system
25
30
  ```
26
31
 
27
32
  After the suite finishes, open the generated report:
@@ -30,16 +35,30 @@ After the suite finishes, open the generated report:
30
35
  capydash_report/index.html
31
36
  ```
32
37
 
33
- The report includes pass/fail counts, tests grouped by spec file, and expandable error details with backtraces.
38
+ The report includes pass/fail counts, tests grouped by class, expandable error details with backtraces, and failure screenshots with a clickable lightbox.
39
+
40
+ ## Failure Screenshots
41
+
42
+ When a test fails and Capybara with a browser driver is available, CapyDash automatically captures a screenshot and embeds it in the report. Click the thumbnail to view the full-size image.
43
+
44
+ - **RSpec** — screenshot captured during `after(:each)`, before session teardown
45
+ - **Minitest** — uses Rails' built-in failure screenshot from `tmp/capybara/`
46
+
47
+ No configuration needed. If Capybara isn't available, screenshots are silently skipped.
34
48
 
35
49
  ## Requirements
36
50
 
37
- - RSpec >= 3.0
51
+ - RSpec >= 3.0 **or** Minitest >= 5.0
38
52
  - Ruby 2.7+
39
53
 
40
54
  ## How It Works
41
55
 
42
- CapyDash hooks into RSpec automatically via `before(:suite)`, `after(:each)`, and `after(:suite)` callbacks. It collects results in memory during the run and writes a static HTML report to `capydash_report/` when the suite completes. No server, no database, no config files.
56
+ CapyDash auto-detects your test framework and hooks in automatically:
57
+
58
+ - **RSpec** — registers `before(:suite)`, `after(:each)`, and `after(:suite)` callbacks via `RSpec.configure`
59
+ - **Minitest** — registers a reporter via the [Minitest plugin system](https://docs.seattlerb.org/minitest/Minitest.html) (`start`, `record`, `report`)
60
+
61
+ Results are collected in memory during the run and written as a static HTML report to `capydash_report/` when the suite completes. Each run produces a fresh report — no server, no database, no config files.
43
62
 
44
63
  ## License
45
64
 
data/capydash.gemspec CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
7
7
  spec.authors = ["Damon Clark"]
8
8
  spec.email = ["dclark312@gmail.com"]
9
9
 
10
- spec.summary = "Minimal static HTML report generator for RSpec system tests"
11
- spec.description = "CapyDash automatically generates clean, readable HTML test reports after your RSpec suite finishes. Zero configuration required."
10
+ spec.summary = "Minimal static HTML report generator for RSpec and Minitest system tests"
11
+ spec.description = "CapyDash automatically generates clean, readable HTML test reports after your RSpec or Minitest suite finishes. Zero configuration required."
12
12
  spec.homepage = "https://github.com/damonclark/capydash"
13
13
  spec.license = "MIT"
14
14
 
@@ -16,10 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.files = Dir["lib/**/*", "README.md", "LICENSE*", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- # Dependencies
20
- spec.add_runtime_dependency "rspec", ">= 3.0"
21
-
22
- # Development dependencies
19
+ # Development dependencies (no runtime deps — works with RSpec or Minitest)
23
20
  spec.add_development_dependency "rspec-rails", "~> 6.0"
24
21
  spec.add_development_dependency "rails", ">= 6.0"
25
22
 
@@ -291,3 +291,50 @@ body {
291
291
  white-space: pre-wrap;
292
292
  word-wrap: break-word;
293
293
  }
294
+
295
+ .screenshot-container {
296
+ margin-top: 1rem;
297
+ padding: 1rem;
298
+ background: #fff5f5;
299
+ border: 1px solid #fed7d7;
300
+ border-radius: 6px;
301
+ cursor: pointer;
302
+ }
303
+
304
+ .screenshot-container h4 {
305
+ color: #e53e3e;
306
+ margin: 0 0 0.5rem 0;
307
+ font-size: 0.9rem;
308
+ }
309
+
310
+ .screenshot-container img {
311
+ max-width: 100%;
312
+ max-height: 300px;
313
+ border-radius: 4px;
314
+ border: 1px solid #ddd;
315
+ }
316
+
317
+ .lightbox {
318
+ display: none;
319
+ position: fixed;
320
+ top: 0;
321
+ left: 0;
322
+ width: 100%;
323
+ height: 100%;
324
+ background: rgba(0, 0, 0, 0.85);
325
+ z-index: 9999;
326
+ justify-content: center;
327
+ align-items: center;
328
+ cursor: pointer;
329
+ }
330
+
331
+ .lightbox.active {
332
+ display: flex;
333
+ }
334
+
335
+ .lightbox img {
336
+ max-width: 90%;
337
+ max-height: 90%;
338
+ border-radius: 6px;
339
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
340
+ }
@@ -1,3 +1,25 @@
1
+ function openLightbox(src) {
2
+ var lightbox = document.getElementById('screenshotLightbox');
3
+ var img = document.getElementById('lightboxImage');
4
+ if (lightbox && img) {
5
+ img.src = src;
6
+ lightbox.classList.add('active');
7
+ }
8
+ }
9
+
10
+ function closeLightbox() {
11
+ var lightbox = document.getElementById('screenshotLightbox');
12
+ if (lightbox) {
13
+ lightbox.classList.remove('active');
14
+ }
15
+ }
16
+
17
+ document.addEventListener('keydown', function(e) {
18
+ if (e.key === 'Escape') {
19
+ closeLightbox();
20
+ }
21
+ });
22
+
1
23
  function toggleTestMethod(safeId) {
2
24
  const stepsContainer = document.getElementById('steps-' + safeId);
3
25
  const button = document.querySelector('[onclick*="' + safeId + '"]');
@@ -0,0 +1,79 @@
1
+ require 'capydash/reporter'
2
+
3
+ module CapyDash
4
+ module Minitest
5
+ class Reporter < ::Minitest::AbstractReporter
6
+ include CapyDash::Reporter
7
+
8
+ def start
9
+ start_run
10
+ end
11
+
12
+ def record(result)
13
+ return unless @started_at
14
+ return unless system_test?(result)
15
+
16
+ status = if result.skipped?
17
+ 'pending'
18
+ elsif result.passed?
19
+ 'passed'
20
+ else
21
+ 'failed'
22
+ end
23
+
24
+ error_message = nil
25
+ if result.failure
26
+ error_message = format_exception(result.failure)
27
+ end
28
+
29
+ screenshot_path = nil
30
+ if status == 'failed'
31
+ # Rails system tests save screenshots before teardown to tmp/capybara/.
32
+ # By the time the reporter's record() runs, the session is torn down,
33
+ # so we look for the Rails-generated screenshot first.
34
+ screenshot_path = find_rails_screenshot(result.name) || capture_screenshot
35
+ end
36
+
37
+ class_name = result.klass || 'UnknownTest'
38
+ method_name = result.name.to_s.sub(/\Atest_/, '').tr('_', ' ')
39
+
40
+ location = nil
41
+ if result.respond_to?(:source_location) && result.source_location
42
+ location = result.source_location.join(':')
43
+ end
44
+
45
+ record_result({
46
+ class_name: class_name,
47
+ method_name: method_name,
48
+ status: status,
49
+ error: error_message,
50
+ location: location,
51
+ screenshot_path: screenshot_path
52
+ })
53
+ end
54
+
55
+ def report
56
+ generate_report
57
+ end
58
+
59
+ def passed?
60
+ true
61
+ end
62
+
63
+ private
64
+
65
+ def system_test?(result)
66
+ return false unless defined?(::ActionDispatch::SystemTestCase)
67
+ klass = Object.const_get(result.klass) rescue nil
68
+ klass && klass <= ::ActionDispatch::SystemTestCase
69
+ end
70
+
71
+ def find_rails_screenshot(test_name)
72
+ path = File.join(Dir.pwd, "tmp", "capybara", "failures_#{test_name}.png")
73
+ File.exist?(path) ? path : nil
74
+ rescue
75
+ nil
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,180 @@
1
+ require 'time'
2
+ require 'fileutils'
3
+ require 'erb'
4
+ require 'cgi'
5
+ require 'tmpdir'
6
+
7
+ module CapyDash
8
+ class ReportData
9
+ attr_reader :processed_tests, :created_at, :total_tests, :passed_tests, :failed_tests
10
+
11
+ def initialize(processed_tests:, created_at:, total_tests:, passed_tests:, failed_tests:)
12
+ @processed_tests = processed_tests
13
+ @created_at = created_at
14
+ @total_tests = total_tests
15
+ @passed_tests = passed_tests
16
+ @failed_tests = failed_tests
17
+ end
18
+
19
+ def h(text)
20
+ CGI.escapeHTML(text.to_s)
21
+ end
22
+
23
+ def get_binding
24
+ binding
25
+ end
26
+ end
27
+
28
+ module Reporter
29
+ def start_run
30
+ @results = []
31
+ @started_at = Time.now
32
+ end
33
+
34
+ def record_result(result_hash)
35
+ return unless @started_at
36
+ @results << result_hash
37
+ end
38
+
39
+ def generate_report
40
+ return unless @started_at
41
+ return if @results.empty?
42
+
43
+ report_dir = File.join(Dir.pwd, "capydash_report")
44
+ FileUtils.mkdir_p(report_dir)
45
+
46
+ assets_dir = File.join(report_dir, "assets")
47
+ FileUtils.mkdir_p(assets_dir)
48
+
49
+ screenshots_dir = File.join(assets_dir, "screenshots")
50
+ FileUtils.rm_rf(screenshots_dir)
51
+ FileUtils.mkdir_p(screenshots_dir)
52
+
53
+ # Group results by class
54
+ tests_by_class = @results.group_by { |r| r[:class_name] }
55
+
56
+ # Calculate statistics
57
+ total_tests = @results.length
58
+ passed_tests = @results.count { |r| r[:status] == 'passed' }
59
+ failed_tests = @results.count { |r| r[:status] == 'failed' }
60
+
61
+ # Copy screenshots into report and build relative paths
62
+ screenshot_index = 0
63
+ @results.each do |result|
64
+ if result[:screenshot_path] && File.exist?(result[:screenshot_path])
65
+ screenshot_index += 1
66
+ dest_name = format("%03d.png", screenshot_index)
67
+ dest_path = File.join(screenshots_dir, dest_name)
68
+ FileUtils.cp(result[:screenshot_path], dest_path)
69
+ result[:screenshot_relative] = "assets/screenshots/#{dest_name}"
70
+ end
71
+ end
72
+
73
+ # Process for template
74
+ processed_tests = tests_by_class.map do |class_name, examples|
75
+ {
76
+ class_name: class_name,
77
+ methods: examples.map do |ex|
78
+ {
79
+ name: ex[:method_name],
80
+ status: ex[:status],
81
+ steps: [{
82
+ name: 'test_execution',
83
+ detail: ex[:method_name],
84
+ status: ex[:status],
85
+ error: ex[:error],
86
+ screenshot: ex[:screenshot_relative]
87
+ }]
88
+ }
89
+ end
90
+ }
91
+ end
92
+
93
+ # Generate HTML
94
+ html_content = generate_html(processed_tests, @started_at, total_tests, passed_tests, failed_tests)
95
+ File.write(File.join(report_dir, "index.html"), html_content)
96
+
97
+ # Generate CSS
98
+ css_content = generate_css
99
+ File.write(File.join(assets_dir, "dashboard.css"), css_content)
100
+
101
+ # Generate JS
102
+ js_content = generate_javascript
103
+ File.write(File.join(assets_dir, "dashboard.js"), js_content)
104
+
105
+ report_dir
106
+ end
107
+
108
+ def normalize_status(status)
109
+ case status
110
+ when :passed, 'passed'
111
+ 'passed'
112
+ when :failed, 'failed'
113
+ 'failed'
114
+ when :pending, 'pending', :skipped, 'skipped'
115
+ 'pending'
116
+ else
117
+ status.to_s
118
+ end
119
+ end
120
+
121
+ def format_exception(exception)
122
+ return nil unless exception
123
+
124
+ message = exception.message || 'Unknown error'
125
+ backtrace = exception.backtrace || []
126
+
127
+ formatted = "#{exception.class}: #{message}"
128
+ if backtrace.any?
129
+ formatted += "\n" + backtrace.first(5).map { |line| " #{line}" }.join("\n")
130
+ end
131
+
132
+ formatted
133
+ end
134
+
135
+ def capture_screenshot
136
+ return nil unless defined?(::Capybara) && defined?(::Capybara.current_session)
137
+
138
+ session = ::Capybara.current_session
139
+ return nil unless session.respond_to?(:save_screenshot)
140
+
141
+ tmpfile = File.join(Dir.tmpdir, "capydash_#{Time.now.to_i}_#{rand(10000)}.png")
142
+ session.save_screenshot(tmpfile)
143
+ tmpfile
144
+ rescue => _e
145
+ nil
146
+ end
147
+
148
+ private
149
+
150
+ def generate_html(processed_tests, created_at, total_tests, passed_tests, failed_tests)
151
+ processed_tests.each do |test_class|
152
+ test_class[:methods].each do |method|
153
+ method[:safe_id] = method[:name].gsub(/['"]/, '').gsub(/[^a-zA-Z0-9]/, '_')
154
+ end
155
+ end
156
+
157
+ template_path = File.join(File.dirname(__FILE__), 'templates', 'report.html.erb')
158
+ template = File.read(template_path)
159
+ erb = ERB.new(template)
160
+
161
+ report_data = CapyDash::ReportData.new(
162
+ processed_tests: processed_tests,
163
+ created_at: created_at,
164
+ total_tests: total_tests,
165
+ passed_tests: passed_tests,
166
+ failed_tests: failed_tests
167
+ )
168
+
169
+ erb.result(report_data.get_binding)
170
+ end
171
+
172
+ def generate_css
173
+ File.read(File.join(File.dirname(__FILE__), 'assets', 'dashboard.css'))
174
+ end
175
+
176
+ def generate_javascript
177
+ File.read(File.join(File.dirname(__FILE__), 'assets', 'dashboard.js'))
178
+ end
179
+ end
180
+ end
@@ -1,114 +1,10 @@
1
- require 'time'
2
- require 'fileutils'
3
- require 'erb'
4
- require 'cgi'
1
+ require 'capydash/reporter'
5
2
 
6
3
  module CapyDash
7
- class ReportData
8
- attr_reader :processed_tests, :created_at, :total_tests, :passed_tests, :failed_tests
9
-
10
- def initialize(processed_tests:, created_at:, total_tests:, passed_tests:, failed_tests:)
11
- @processed_tests = processed_tests
12
- @created_at = created_at
13
- @total_tests = total_tests
14
- @passed_tests = passed_tests
15
- @failed_tests = failed_tests
16
- end
17
-
18
- def h(text)
19
- CGI.escapeHTML(text.to_s)
20
- end
21
-
22
- def get_binding
23
- binding
24
- end
25
- end
26
-
27
4
  module RSpec
28
- class << self
29
- # Public method: Called from RSpec before(:suite) hook
30
- def start_run
31
- @results = []
32
- @started_at = Time.now
33
- end
34
-
35
- # Public method: Called from RSpec after(:each) hook
36
- def record_example(example)
37
- return unless @started_at
38
-
39
- execution_result = example.execution_result
40
- status = normalize_status(execution_result.status)
41
-
42
- error_message = nil
43
- if execution_result.status == :failed && execution_result.exception
44
- error_message = format_exception(execution_result.exception)
45
- end
46
-
47
- class_name = extract_class_name(example)
5
+ extend CapyDash::Reporter
48
6
 
49
- @results << {
50
- class_name: class_name,
51
- method_name: example.full_description,
52
- status: status,
53
- error: error_message,
54
- location: example.metadata[:location]
55
- }
56
- end
57
-
58
- # Public method: Called from RSpec after(:suite) hook
59
- def generate_report
60
- return unless @started_at
61
- return if @results.empty?
62
-
63
- report_dir = File.join(Dir.pwd, "capydash_report")
64
- FileUtils.mkdir_p(report_dir)
65
-
66
- assets_dir = File.join(report_dir, "assets")
67
- FileUtils.mkdir_p(assets_dir)
68
-
69
- # Group results by class
70
- tests_by_class = @results.group_by { |r| r[:class_name] }
71
-
72
- # Calculate statistics
73
- total_tests = @results.length
74
- passed_tests = @results.count { |r| r[:status] == 'passed' }
75
- failed_tests = @results.count { |r| r[:status] == 'failed' }
76
-
77
- # Process for template
78
- processed_tests = tests_by_class.map do |class_name, examples|
79
- {
80
- class_name: class_name,
81
- methods: examples.map do |ex|
82
- {
83
- name: ex[:method_name],
84
- status: ex[:status],
85
- steps: [{
86
- name: 'test_execution',
87
- detail: ex[:method_name],
88
- status: ex[:status],
89
- error: ex[:error]
90
- }]
91
- }
92
- end
93
- }
94
- end
95
-
96
- # Generate HTML
97
- html_content = generate_html(processed_tests, @started_at, total_tests, passed_tests, failed_tests)
98
- File.write(File.join(report_dir, "index.html"), html_content)
99
-
100
- # Generate CSS
101
- css_content = generate_css
102
- File.write(File.join(assets_dir, "dashboard.css"), css_content)
103
-
104
- # Generate JS
105
- js_content = generate_javascript
106
- File.write(File.join(assets_dir, "dashboard.js"), js_content)
107
-
108
- report_dir
109
- end
110
-
111
- # Public method: Sets up RSpec hooks
7
+ class << self
112
8
  def setup!
113
9
  return unless rspec_available?
114
10
  return if @configured
@@ -132,11 +28,48 @@ module CapyDash
132
28
  end
133
29
  end
134
30
  rescue => e
135
- # If RSpec isn't ready, silently fail - it will be set up later
136
31
  @configured = false
137
32
  end
138
33
  end
139
34
 
35
+ def record_example(example)
36
+ return unless @started_at
37
+ return unless example.metadata[:type] == :system
38
+
39
+ execution_result = example.execution_result
40
+
41
+ # Derive status from exception since execution_result.status
42
+ # is not yet set during after(:each) hooks
43
+ status = if example.pending? || example.skipped?
44
+ 'pending'
45
+ elsif execution_result.exception
46
+ 'failed'
47
+ else
48
+ 'passed'
49
+ end
50
+
51
+ error_message = nil
52
+ if execution_result.exception
53
+ error_message = format_exception(execution_result.exception)
54
+ end
55
+
56
+ screenshot_path = nil
57
+ if status == 'failed'
58
+ screenshot_path = capture_screenshot
59
+ end
60
+
61
+ class_name = extract_class_name(example)
62
+
63
+ record_result({
64
+ class_name: class_name,
65
+ method_name: example.full_description,
66
+ status: status,
67
+ error: error_message,
68
+ location: example.metadata[:location],
69
+ screenshot_path: screenshot_path
70
+ })
71
+ end
72
+
140
73
  private
141
74
 
142
75
  def rspec_available?
@@ -147,19 +80,6 @@ module CapyDash
147
80
  false
148
81
  end
149
82
 
150
- def normalize_status(status)
151
- case status
152
- when :passed, 'passed'
153
- 'passed'
154
- when :failed, 'failed'
155
- 'failed'
156
- when :pending, 'pending'
157
- 'pending'
158
- else
159
- status.to_s
160
- end
161
- end
162
-
163
83
  def extract_class_name(example)
164
84
  group = example.metadata[:example_group]
165
85
  while group && group[:parent_example_group]
@@ -175,51 +95,6 @@ module CapyDash
175
95
  filename.split('_').map(&:capitalize).join('')
176
96
  end
177
97
  end
178
-
179
- def format_exception(exception)
180
- return nil unless exception
181
-
182
- message = exception.message || 'Unknown error'
183
- backtrace = exception.backtrace || []
184
-
185
- formatted = "#{exception.class}: #{message}"
186
- if backtrace.any?
187
- formatted += "\n" + backtrace.first(5).map { |line| " #{line}" }.join("\n")
188
- end
189
-
190
- formatted
191
- end
192
-
193
- def generate_html(processed_tests, created_at, total_tests, passed_tests, failed_tests)
194
- # Create safe IDs for method names (escape special chars for HTML/JS)
195
- processed_tests.each do |test_class|
196
- test_class[:methods].each do |method|
197
- method[:safe_id] = method[:name].gsub(/['"]/, '').gsub(/[^a-zA-Z0-9]/, '_')
198
- end
199
- end
200
-
201
- template_path = File.join(__dir__, 'templates', 'report.html.erb')
202
- template = File.read(template_path)
203
- erb = ERB.new(template)
204
-
205
- report_data = CapyDash::ReportData.new(
206
- processed_tests: processed_tests,
207
- created_at: created_at,
208
- total_tests: total_tests,
209
- passed_tests: passed_tests,
210
- failed_tests: failed_tests
211
- )
212
-
213
- erb.result(report_data.get_binding)
214
- end
215
-
216
- def generate_css
217
- File.read(File.join(__dir__, 'assets', 'dashboard.css'))
218
- end
219
-
220
- def generate_javascript
221
- File.read(File.join(__dir__, 'assets', 'dashboard.js'))
222
- end
223
98
  end
224
99
  end
225
100
  end
@@ -63,6 +63,13 @@
63
63
  <pre><%= h(step[:error]) %></pre>
64
64
  </div>
65
65
  <% end %>
66
+
67
+ <% if step[:screenshot] %>
68
+ <div class="screenshot-container" onclick="openLightbox('<%= h(step[:screenshot]) %>')">
69
+ <h4>Failure Screenshot</h4>
70
+ <img src="<%= h(step[:screenshot]) %>" alt="Failure screenshot">
71
+ </div>
72
+ <% end %>
66
73
  </div>
67
74
  <% end %>
68
75
  </div>
@@ -72,6 +79,9 @@
72
79
  <% end %>
73
80
  </div>
74
81
  </div>
82
+ <div class="lightbox" id="screenshotLightbox" onclick="closeLightbox()">
83
+ <img id="lightboxImage" src="" alt="Screenshot full view">
84
+ </div>
75
85
  <script src="assets/dashboard.js"></script>
76
86
  </body>
77
87
  </html>
@@ -1,3 +1,3 @@
1
1
  module CapyDash
2
- VERSION = "0.2.5"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/capydash.rb CHANGED
@@ -4,12 +4,18 @@ require "capydash/version"
4
4
  if defined?(RSpec) && RSpec.respond_to?(:configure)
5
5
  require "capydash/rspec"
6
6
  CapyDash::RSpec.setup!
7
- elsif defined?(Rails)
8
- # In Rails, RSpec might load after the gem, so set up a hook
9
- Rails.application.config.after_initialize do
10
- if defined?(RSpec) && RSpec.respond_to?(:configure)
11
- require "capydash/rspec" unless defined?(CapyDash::RSpec)
12
- CapyDash::RSpec.setup!
7
+ elsif defined?(Rails) && defined?(Rails::Railtie)
8
+ # In Rails, RSpec might load after the gem, so defer setup
9
+ class CapyDash::Railtie < Rails::Railtie
10
+ config.after_initialize do
11
+ if defined?(RSpec) && RSpec.respond_to?(:configure)
12
+ require "capydash/rspec" unless defined?(CapyDash::RSpec)
13
+ CapyDash::RSpec.setup!
14
+ end
13
15
  end
14
16
  end
15
17
  end
18
+
19
+ # Minitest integration is handled automatically via the minitest plugin system.
20
+ # Minitest discovers lib/minitest/capydash_plugin.rb and calls
21
+ # plugin_capydash_init during Minitest.run, which adds our reporter.
@@ -0,0 +1,6 @@
1
+ module Minitest
2
+ def self.plugin_capydash_init(options)
3
+ require 'capydash/minitest'
4
+ self.reporter << CapyDash::Minitest::Reporter.new
5
+ end
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capydash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damon Clark
@@ -9,20 +9,6 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: rspec
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '3.0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '3.0'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: rspec-rails
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -52,7 +38,7 @@ dependencies:
52
38
  - !ruby/object:Gem::Version
53
39
  version: '6.0'
54
40
  description: CapyDash automatically generates clean, readable HTML test reports after
55
- your RSpec suite finishes. Zero configuration required.
41
+ your RSpec or Minitest suite finishes. Zero configuration required.
56
42
  email:
57
43
  - dclark312@gmail.com
58
44
  executables: []
@@ -64,9 +50,12 @@ files:
64
50
  - lib/capydash.rb
65
51
  - lib/capydash/assets/dashboard.css
66
52
  - lib/capydash/assets/dashboard.js
53
+ - lib/capydash/minitest.rb
54
+ - lib/capydash/reporter.rb
67
55
  - lib/capydash/rspec.rb
68
56
  - lib/capydash/templates/report.html.erb
69
57
  - lib/capydash/version.rb
58
+ - lib/minitest/capydash_plugin.rb
70
59
  homepage: https://github.com/damonclark/capydash
71
60
  licenses:
72
61
  - MIT
@@ -88,5 +77,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
77
  requirements: []
89
78
  rubygems_version: 3.6.7
90
79
  specification_version: 4
91
- summary: Minimal static HTML report generator for RSpec system tests
80
+ summary: Minimal static HTML report generator for RSpec and Minitest system tests
92
81
  test_files: []