capydash 0.2.1 → 0.2.3
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 +4 -4
- data/lib/capydash/rspec.rb +160 -24
- data/lib/capydash/templates/report.html.erb +6 -1
- data/lib/capydash/version.rb +1 -1
- data/lib/capydash.rb +10 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8120c468fac1e4d0e67b3190f2fd3905bf047a1628f66232cedbc3085e0af2f5
|
|
4
|
+
data.tar.gz: ea62c0dd462b95ad7a2405f0f139b9c9f3d5f3bfa0c9315b93e70ee39df094e0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b2cbd4509f3dc292b2dc3873ae74e03fa3315cf850cd9bc10dbddfe63926c4cd03f1003fa728b527a3f48906149375709d432b347b774366607114209ec58a8
|
|
7
|
+
data.tar.gz: ec5f1fb549172b312df50562c60c3e40a641518acd2f2e86e8288882a6c17820d4550cfe5824188ed50ea59567758a7af085010156ebec8b5806fb117e46ac74
|
data/lib/capydash/rspec.rb
CHANGED
|
@@ -5,39 +5,18 @@ require 'erb'
|
|
|
5
5
|
module CapyDash
|
|
6
6
|
module RSpec
|
|
7
7
|
class << self
|
|
8
|
-
|
|
9
|
-
return unless defined?(::RSpec)
|
|
10
|
-
return if @configured
|
|
11
|
-
|
|
12
|
-
@configured = true
|
|
13
|
-
@results = []
|
|
14
|
-
@started_at = nil
|
|
15
|
-
|
|
16
|
-
::RSpec.configure do |config|
|
|
17
|
-
config.before(:suite) do
|
|
18
|
-
CapyDash::RSpec.start_run
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
config.after(:each) do |example|
|
|
22
|
-
CapyDash::RSpec.record_example(example)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
config.after(:suite) do
|
|
26
|
-
CapyDash::RSpec.generate_report
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
8
|
+
# Public method: Called from RSpec before(:suite) hook
|
|
31
9
|
def start_run
|
|
32
10
|
@results = []
|
|
33
11
|
@started_at = Time.now
|
|
34
12
|
end
|
|
35
13
|
|
|
14
|
+
# Public method: Called from RSpec after(:each) hook
|
|
36
15
|
def record_example(example)
|
|
37
16
|
return unless @started_at
|
|
38
17
|
|
|
39
18
|
execution_result = example.execution_result
|
|
40
|
-
status = execution_result.status
|
|
19
|
+
status = normalize_status(execution_result.status)
|
|
41
20
|
|
|
42
21
|
error_message = nil
|
|
43
22
|
if execution_result.status == :failed && execution_result.exception
|
|
@@ -56,6 +35,7 @@ module CapyDash
|
|
|
56
35
|
}
|
|
57
36
|
end
|
|
58
37
|
|
|
38
|
+
# Public method: Called from RSpec after(:suite) hook
|
|
59
39
|
def generate_report
|
|
60
40
|
return unless @started_at
|
|
61
41
|
return if @results.empty?
|
|
@@ -108,8 +88,59 @@ module CapyDash
|
|
|
108
88
|
report_dir
|
|
109
89
|
end
|
|
110
90
|
|
|
91
|
+
# Public method: Sets up RSpec hooks
|
|
92
|
+
def setup!
|
|
93
|
+
return unless rspec_available?
|
|
94
|
+
return if @configured
|
|
95
|
+
|
|
96
|
+
begin
|
|
97
|
+
@configured = true
|
|
98
|
+
@results = []
|
|
99
|
+
@started_at = nil
|
|
100
|
+
|
|
101
|
+
::RSpec.configure do |config|
|
|
102
|
+
config.before(:suite) do
|
|
103
|
+
CapyDash::RSpec.start_run
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
config.after(:each) do |example|
|
|
107
|
+
CapyDash::RSpec.record_example(example)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
config.after(:suite) do
|
|
111
|
+
CapyDash::RSpec.generate_report
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
rescue => e
|
|
115
|
+
# If RSpec isn't ready, silently fail - it will be set up later
|
|
116
|
+
@configured = false
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
111
120
|
private
|
|
112
121
|
|
|
122
|
+
def rspec_available?
|
|
123
|
+
return false unless defined?(::RSpec)
|
|
124
|
+
return false unless ::RSpec.respond_to?(:configure)
|
|
125
|
+
true
|
|
126
|
+
rescue
|
|
127
|
+
false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def normalize_status(status)
|
|
131
|
+
# Normalize RSpec status symbols to strings
|
|
132
|
+
case status
|
|
133
|
+
when :passed, 'passed'
|
|
134
|
+
'passed'
|
|
135
|
+
when :failed, 'failed'
|
|
136
|
+
'failed'
|
|
137
|
+
when :pending, 'pending'
|
|
138
|
+
'pending'
|
|
139
|
+
else
|
|
140
|
+
status.to_s
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
113
144
|
def extract_class_name(file_path)
|
|
114
145
|
return 'UnknownSpec' if file_path.nil? || file_path.empty?
|
|
115
146
|
|
|
@@ -184,6 +215,26 @@ module CapyDash
|
|
|
184
215
|
.header .subtitle {
|
|
185
216
|
color: #666;
|
|
186
217
|
font-size: 0.9rem;
|
|
218
|
+
margin-bottom: 1rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.search-container {
|
|
222
|
+
margin-top: 1rem;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.search-input {
|
|
226
|
+
width: 100%;
|
|
227
|
+
padding: 0.75rem 1rem;
|
|
228
|
+
border: 2px solid #ddd;
|
|
229
|
+
border-radius: 6px;
|
|
230
|
+
font-size: 1rem;
|
|
231
|
+
transition: border-color 0.2s;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.search-input:focus {
|
|
235
|
+
outline: none;
|
|
236
|
+
border-color: #3498db;
|
|
237
|
+
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
|
|
187
238
|
}
|
|
188
239
|
|
|
189
240
|
.summary {
|
|
@@ -241,6 +292,10 @@ module CapyDash
|
|
|
241
292
|
border-bottom: none;
|
|
242
293
|
}
|
|
243
294
|
|
|
295
|
+
.test-class.hidden {
|
|
296
|
+
display: none;
|
|
297
|
+
}
|
|
298
|
+
|
|
244
299
|
.test-class h2 {
|
|
245
300
|
background: #f8f9fa;
|
|
246
301
|
padding: 1rem 1.5rem;
|
|
@@ -259,6 +314,10 @@ module CapyDash
|
|
|
259
314
|
border-bottom: none;
|
|
260
315
|
}
|
|
261
316
|
|
|
317
|
+
.test-method.hidden {
|
|
318
|
+
display: none;
|
|
319
|
+
}
|
|
320
|
+
|
|
262
321
|
.test-method-header {
|
|
263
322
|
display: flex;
|
|
264
323
|
align-items: center;
|
|
@@ -274,6 +333,30 @@ module CapyDash
|
|
|
274
333
|
flex: 1;
|
|
275
334
|
}
|
|
276
335
|
|
|
336
|
+
.method-status {
|
|
337
|
+
padding: 0.25rem 0.75rem;
|
|
338
|
+
border-radius: 4px;
|
|
339
|
+
font-size: 0.75rem;
|
|
340
|
+
font-weight: 600;
|
|
341
|
+
text-transform: uppercase;
|
|
342
|
+
letter-spacing: 0.5px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.method-status-passed {
|
|
346
|
+
background: #27ae60;
|
|
347
|
+
color: white;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.method-status-failed {
|
|
351
|
+
background: #e74c3c;
|
|
352
|
+
color: white;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.method-status-pending {
|
|
356
|
+
background: #f39c12;
|
|
357
|
+
color: white;
|
|
358
|
+
}
|
|
359
|
+
|
|
277
360
|
.expand-toggle {
|
|
278
361
|
background: none;
|
|
279
362
|
border: none;
|
|
@@ -408,6 +491,59 @@ module CapyDash
|
|
|
408
491
|
}
|
|
409
492
|
}
|
|
410
493
|
}
|
|
494
|
+
|
|
495
|
+
// Search functionality
|
|
496
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
497
|
+
const searchInput = document.getElementById('searchInput');
|
|
498
|
+
if (!searchInput) return;
|
|
499
|
+
|
|
500
|
+
searchInput.addEventListener('input', function(e) {
|
|
501
|
+
const query = e.target.value.toLowerCase().trim();
|
|
502
|
+
const testMethods = document.querySelectorAll('.test-method');
|
|
503
|
+
const testClasses = document.querySelectorAll('.test-class');
|
|
504
|
+
|
|
505
|
+
// Determine if query is a status filter
|
|
506
|
+
const isStatusFilter = query === 'pass' || query === 'fail' ||
|
|
507
|
+
query === 'passed' || query === 'failed' ||
|
|
508
|
+
query === 'pending';
|
|
509
|
+
|
|
510
|
+
testMethods.forEach(function(method) {
|
|
511
|
+
const name = method.getAttribute('data-name') || '';
|
|
512
|
+
const status = method.getAttribute('data-status') || '';
|
|
513
|
+
|
|
514
|
+
let shouldShow = false;
|
|
515
|
+
|
|
516
|
+
if (!query) {
|
|
517
|
+
// No query - show all
|
|
518
|
+
shouldShow = true;
|
|
519
|
+
} else if (isStatusFilter) {
|
|
520
|
+
// Status filter - check status
|
|
521
|
+
shouldShow = (query === 'pass' && status === 'passed') ||
|
|
522
|
+
(query === 'fail' && status === 'failed') ||
|
|
523
|
+
query === status;
|
|
524
|
+
} else {
|
|
525
|
+
// Name filter - check if name contains query
|
|
526
|
+
shouldShow = name.includes(query);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (shouldShow) {
|
|
530
|
+
method.classList.remove('hidden');
|
|
531
|
+
} else {
|
|
532
|
+
method.classList.add('hidden');
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// Hide test classes if all methods are hidden
|
|
537
|
+
testClasses.forEach(function(testClass) {
|
|
538
|
+
const visibleMethods = testClass.querySelectorAll('.test-method:not(.hidden)');
|
|
539
|
+
if (visibleMethods.length === 0) {
|
|
540
|
+
testClass.classList.add('hidden');
|
|
541
|
+
} else {
|
|
542
|
+
testClass.classList.remove('hidden');
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
|
411
547
|
JS
|
|
412
548
|
end
|
|
413
549
|
end
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
<div class="header">
|
|
12
12
|
<h1>CapyDash Test Report</h1>
|
|
13
13
|
<div class="subtitle">Generated on <%= created_at.strftime('%B %d, %Y at %I:%M %p') %></div>
|
|
14
|
+
|
|
15
|
+
<div class="search-container">
|
|
16
|
+
<input type="text" id="searchInput" placeholder="Search tests or type 'pass' or 'fail' to filter..." class="search-input" autocomplete="off">
|
|
17
|
+
</div>
|
|
14
18
|
</div>
|
|
15
19
|
|
|
16
20
|
<div class="summary">
|
|
@@ -34,12 +38,13 @@
|
|
|
34
38
|
<h2><%= test_class[:class_name] %></h2>
|
|
35
39
|
|
|
36
40
|
<% test_class[:methods].each do |method| %>
|
|
37
|
-
<div class="test-method">
|
|
41
|
+
<div class="test-method" data-status="<%= method[:status] %>" data-name="<%= method[:name].downcase %>">
|
|
38
42
|
<div class="test-method-header">
|
|
39
43
|
<button class="expand-toggle" onclick="toggleTestMethod('<%= method[:safe_id] %>')">
|
|
40
44
|
<span class="expand-icon">▶</span>
|
|
41
45
|
</button>
|
|
42
46
|
<h3><%= method[:name] %></h3>
|
|
47
|
+
<span class="method-status method-status-<%= method[:status] %>"><%= method[:status] %></span>
|
|
43
48
|
</div>
|
|
44
49
|
<div class="steps collapsed" id="steps-<%= method[:safe_id] %>">
|
|
45
50
|
<% method[:steps].each do |step| %>
|
data/lib/capydash/version.rb
CHANGED
data/lib/capydash.rb
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
require "capydash/version"
|
|
2
2
|
|
|
3
|
-
# Auto-setup RSpec integration if RSpec is present
|
|
4
|
-
if defined?(RSpec)
|
|
3
|
+
# Auto-setup RSpec integration if RSpec is present and ready
|
|
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!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
7
15
|
end
|