capydash 0.2.0 → 0.2.2
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/README.md +70 -171
- data/capydash.gemspec +7 -13
- data/lib/capydash/rspec.rb +567 -0
- data/lib/capydash/templates/report.html.erb +7 -24
- data/lib/capydash/version.rb +2 -2
- data/lib/capydash.rb +10 -59
- metadata +13 -84
- data/lib/capydash/auth.rb +0 -103
- data/lib/capydash/configuration.rb +0 -186
- data/lib/capydash/dashboard_server.rb +0 -167
- data/lib/capydash/engine.rb +0 -52
- data/lib/capydash/error_handler.rb +0 -101
- data/lib/capydash/event_emitter.rb +0 -29
- data/lib/capydash/forwarder.rb +0 -78
- data/lib/capydash/instrumentation.rb +0 -153
- data/lib/capydash/logger.rb +0 -99
- data/lib/capydash/persistence.rb +0 -134
- data/lib/capydash/report_generator.rb +0 -1007
- data/lib/capydash/rspec_integration.rb +0 -285
- data/lib/capydash/test_data_aggregator.rb +0 -221
- data/lib/capydash/test_data_collector.rb +0 -58
- data/lib/generators/capydash/install_generator.rb +0 -124
- data/lib/tasks/capydash.rake +0 -67
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
require 'time'
|
|
2
|
-
require 'securerandom'
|
|
3
|
-
require 'fileutils'
|
|
4
|
-
require 'erb'
|
|
5
|
-
|
|
6
|
-
module CapyDash
|
|
7
|
-
module RSpecIntegration
|
|
8
|
-
class << self
|
|
9
|
-
def setup!
|
|
10
|
-
return unless defined?(RSpec)
|
|
11
|
-
return if @configured
|
|
12
|
-
|
|
13
|
-
@results = []
|
|
14
|
-
@run_id = nil
|
|
15
|
-
@configured = true
|
|
16
|
-
|
|
17
|
-
RSpec.configure do |config|
|
|
18
|
-
config.before(:suite) do
|
|
19
|
-
CapyDash::RSpecIntegration.start_test_run
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
config.after(:each) do |example|
|
|
23
|
-
CapyDash::RSpecIntegration.record_example(example)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
config.after(:suite) do
|
|
27
|
-
CapyDash::RSpecIntegration.finish_test_run
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def start_test_run
|
|
33
|
-
@run_id = generate_run_id
|
|
34
|
-
@results = []
|
|
35
|
-
@started_at = Time.now
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def record_example(example)
|
|
39
|
-
return unless @run_id
|
|
40
|
-
|
|
41
|
-
execution_result = example.execution_result
|
|
42
|
-
|
|
43
|
-
# Map RSpec status to our status format
|
|
44
|
-
status = case execution_result.status.to_s
|
|
45
|
-
when 'passed'
|
|
46
|
-
'passed'
|
|
47
|
-
when 'failed'
|
|
48
|
-
'failed'
|
|
49
|
-
when 'pending'
|
|
50
|
-
'pending'
|
|
51
|
-
else
|
|
52
|
-
'unknown'
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Extract error message if test failed
|
|
56
|
-
error_message = nil
|
|
57
|
-
if execution_result.status == :failed && execution_result.exception
|
|
58
|
-
error_message = format_exception(execution_result.exception)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Extract class name from example location
|
|
62
|
-
# RSpec examples are typically in files like spec/features/user_spec.rb
|
|
63
|
-
# We'll use the file path to determine the "class" name
|
|
64
|
-
file_path = example.metadata[:file_path] || ''
|
|
65
|
-
class_name = extract_class_name_from_path(file_path)
|
|
66
|
-
|
|
67
|
-
# Create test data structure matching Minitest format
|
|
68
|
-
test_data = {
|
|
69
|
-
test_name: "#{class_name}##{example.full_description}",
|
|
70
|
-
steps: [
|
|
71
|
-
{
|
|
72
|
-
step_name: 'test_execution',
|
|
73
|
-
detail: example.full_description,
|
|
74
|
-
status: status,
|
|
75
|
-
error: error_message
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# Add location information
|
|
81
|
-
if example.metadata[:location]
|
|
82
|
-
test_data[:location] = example.metadata[:location]
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
@results << test_data
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def finish_test_run
|
|
89
|
-
return unless @run_id
|
|
90
|
-
return if @results.empty?
|
|
91
|
-
|
|
92
|
-
# Calculate summary statistics
|
|
93
|
-
total_tests = @results.length
|
|
94
|
-
passed_tests = @results.count { |r| r[:steps].any? { |s| s[:status] == 'passed' } }
|
|
95
|
-
failed_tests = @results.count { |r| r[:steps].any? { |s| s[:status] == 'failed' } }
|
|
96
|
-
pending_tests = @results.count { |r| r[:steps].any? { |s| s[:status] == 'pending' } }
|
|
97
|
-
|
|
98
|
-
# Create run data structure matching Minitest format
|
|
99
|
-
run_data = {
|
|
100
|
-
id: @run_id,
|
|
101
|
-
created_at: @started_at.iso8601,
|
|
102
|
-
total_tests: total_tests,
|
|
103
|
-
passed_tests: passed_tests,
|
|
104
|
-
failed_tests: failed_tests,
|
|
105
|
-
tests: @results.map { |r| { test_name: r[:test_name], steps: r[:steps] } }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
# Save using the existing persistence layer
|
|
109
|
-
CapyDash.save_test_run(run_data)
|
|
110
|
-
|
|
111
|
-
# Generate report
|
|
112
|
-
generate_report(run_data)
|
|
113
|
-
|
|
114
|
-
# Clear state
|
|
115
|
-
@run_id = nil
|
|
116
|
-
@results = []
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
private
|
|
120
|
-
|
|
121
|
-
def generate_run_id
|
|
122
|
-
"#{Time.now.to_i}_#{SecureRandom.hex(4)}"
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def extract_class_name_from_path(file_path)
|
|
126
|
-
return 'UnknownSpec' if file_path.nil? || file_path.empty?
|
|
127
|
-
|
|
128
|
-
# Extract filename without extension and path
|
|
129
|
-
filename = File.basename(file_path, '.rb')
|
|
130
|
-
|
|
131
|
-
# Convert snake_case to PascalCase
|
|
132
|
-
# e.g., "user_spec" -> "UserSpec", "features/user_flow_spec" -> "UserFlowSpec"
|
|
133
|
-
filename.split('_').map(&:capitalize).join('')
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def format_exception(exception)
|
|
137
|
-
return nil unless exception
|
|
138
|
-
|
|
139
|
-
message = exception.message || 'Unknown error'
|
|
140
|
-
backtrace = exception.backtrace || []
|
|
141
|
-
|
|
142
|
-
# Format similar to RSpec's output
|
|
143
|
-
formatted = "#{exception.class}: #{message}"
|
|
144
|
-
|
|
145
|
-
if backtrace.any?
|
|
146
|
-
# Include first few lines of backtrace
|
|
147
|
-
formatted += "\n" + backtrace.first(5).map { |line| " #{line}" }.join("\n")
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
formatted
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def generate_report(run_data)
|
|
154
|
-
# Use the existing ReportGenerator but with our RSpec data
|
|
155
|
-
# We need to adapt it to work with our in-memory data structure
|
|
156
|
-
report_dir = File.join(Dir.pwd, "capydash_report")
|
|
157
|
-
FileUtils.mkdir_p(report_dir)
|
|
158
|
-
|
|
159
|
-
assets_dir = File.join(report_dir, "assets")
|
|
160
|
-
FileUtils.mkdir_p(assets_dir)
|
|
161
|
-
|
|
162
|
-
screenshots_dir = File.join(report_dir, "screenshots")
|
|
163
|
-
FileUtils.mkdir_p(screenshots_dir)
|
|
164
|
-
|
|
165
|
-
# Generate HTML report using the same template
|
|
166
|
-
html_content = generate_html(run_data, run_data[:created_at])
|
|
167
|
-
html_path = File.join(report_dir, "index.html")
|
|
168
|
-
File.write(html_path, html_content)
|
|
169
|
-
|
|
170
|
-
# Generate CSS and JS - use ReportGenerator's private methods via send
|
|
171
|
-
# These methods are private but we need them for RSpec reports
|
|
172
|
-
css_content = CapyDash::ReportGenerator.send(:generate_css)
|
|
173
|
-
css_path = File.join(assets_dir, "dashboard.css")
|
|
174
|
-
File.write(css_path, css_content)
|
|
175
|
-
|
|
176
|
-
js_content = CapyDash::ReportGenerator.send(:generate_javascript)
|
|
177
|
-
js_path = File.join(assets_dir, "dashboard.js")
|
|
178
|
-
File.write(js_path, js_content)
|
|
179
|
-
|
|
180
|
-
html_path
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def generate_html(test_data, created_at)
|
|
184
|
-
# Process test data into a structured format (same as ReportGenerator)
|
|
185
|
-
processed_tests = process_test_data(test_data)
|
|
186
|
-
|
|
187
|
-
# Calculate summary statistics
|
|
188
|
-
total_tests = processed_tests.sum { |test| test[:methods].length }
|
|
189
|
-
passed_tests = processed_tests.sum { |test| test[:methods].count { |method| method[:status] == 'passed' } }
|
|
190
|
-
failed_tests = total_tests - passed_tests
|
|
191
|
-
|
|
192
|
-
# Parse created_at if it's a string, otherwise use Time object
|
|
193
|
-
created_at_time = if created_at.is_a?(String)
|
|
194
|
-
Time.parse(created_at)
|
|
195
|
-
else
|
|
196
|
-
created_at
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Generate HTML using ERB template
|
|
200
|
-
template = File.read(File.join(__dir__, 'templates', 'report.html.erb'))
|
|
201
|
-
erb = ERB.new(template)
|
|
202
|
-
|
|
203
|
-
erb.result(binding)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def process_test_data(test_data)
|
|
207
|
-
return [] unless test_data[:tests]
|
|
208
|
-
|
|
209
|
-
# Group tests by class
|
|
210
|
-
tests_by_class = {}
|
|
211
|
-
|
|
212
|
-
test_data[:tests].each do |test|
|
|
213
|
-
test_name = test[:test_name] || 'UnknownTest'
|
|
214
|
-
|
|
215
|
-
# Extract class and method names from test name like "UserSpec#should visit the home page"
|
|
216
|
-
if test_name.include?('#')
|
|
217
|
-
class_name, method_name = test_name.split('#', 2)
|
|
218
|
-
else
|
|
219
|
-
class_name = extract_class_name(test_name)
|
|
220
|
-
method_name = extract_method_name(test_name)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
tests_by_class[class_name] ||= {
|
|
224
|
-
class_name: class_name,
|
|
225
|
-
methods: []
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
# Process steps
|
|
229
|
-
steps = test[:steps] || []
|
|
230
|
-
processed_steps = steps.map do |step|
|
|
231
|
-
{
|
|
232
|
-
name: step[:step_name] || step[:name] || 'unknown_step',
|
|
233
|
-
detail: step[:detail] || step[:description] || '',
|
|
234
|
-
status: step[:status] || 'unknown',
|
|
235
|
-
screenshot: step[:screenshot] ? File.basename(step[:screenshot]) : nil,
|
|
236
|
-
error: step[:error] || step[:message]
|
|
237
|
-
}
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# Filter out "running" steps
|
|
241
|
-
processed_steps = processed_steps.reject { |step| step[:status] == 'running' }
|
|
242
|
-
|
|
243
|
-
# Determine method status
|
|
244
|
-
method_status = if processed_steps.any? { |s| s[:status] == 'failed' }
|
|
245
|
-
'failed'
|
|
246
|
-
elsif processed_steps.any? { |s| s[:status] == 'passed' }
|
|
247
|
-
'passed'
|
|
248
|
-
elsif processed_steps.any? { |s| s[:status] == 'pending' }
|
|
249
|
-
'pending'
|
|
250
|
-
else
|
|
251
|
-
'running'
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
tests_by_class[class_name][:methods] << {
|
|
255
|
-
name: method_name,
|
|
256
|
-
status: method_status,
|
|
257
|
-
steps: processed_steps
|
|
258
|
-
}
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
tests_by_class.values
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def extract_class_name(test_name)
|
|
265
|
-
return 'UnknownTest' if test_name.nil? || test_name.empty?
|
|
266
|
-
|
|
267
|
-
if test_name.include?('#')
|
|
268
|
-
test_name.split('#').first
|
|
269
|
-
else
|
|
270
|
-
test_name
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
def extract_method_name(test_name)
|
|
275
|
-
return 'unknown_method' if test_name.nil? || test_name.empty?
|
|
276
|
-
|
|
277
|
-
if test_name.include?('#')
|
|
278
|
-
test_name.split('#').last
|
|
279
|
-
else
|
|
280
|
-
test_name
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'time'
|
|
3
|
-
require 'securerandom'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
|
|
6
|
-
module CapyDash
|
|
7
|
-
class TestDataAggregator
|
|
8
|
-
class << self
|
|
9
|
-
def start_test_run
|
|
10
|
-
# Don't start a new run if one is already in progress
|
|
11
|
-
return if test_run_started?
|
|
12
|
-
|
|
13
|
-
run_id = generate_run_id
|
|
14
|
-
run_data = {
|
|
15
|
-
id: run_id,
|
|
16
|
-
created_at: Time.now.iso8601,
|
|
17
|
-
total_tests: 0,
|
|
18
|
-
passed_tests: 0,
|
|
19
|
-
failed_tests: 0,
|
|
20
|
-
tests: []
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
# Save initial run data to file
|
|
24
|
-
save_run_data(run_data)
|
|
25
|
-
|
|
26
|
-
# Set current test context
|
|
27
|
-
set_current_test_context(run_id, nil, [])
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_run_started?
|
|
31
|
-
get_current_run_id != nil
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def finish_test_run
|
|
35
|
-
run_id = get_current_run_id
|
|
36
|
-
return unless run_id
|
|
37
|
-
|
|
38
|
-
# Load current run data
|
|
39
|
-
run_data = load_run_data(run_id)
|
|
40
|
-
return unless run_data
|
|
41
|
-
|
|
42
|
-
# Save the final test run data
|
|
43
|
-
CapyDash.save_test_run(run_data)
|
|
44
|
-
|
|
45
|
-
# Clear current state
|
|
46
|
-
clear_current_test_context
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def handle_event(event)
|
|
50
|
-
run_id = get_current_run_id
|
|
51
|
-
return unless run_id
|
|
52
|
-
|
|
53
|
-
# Load current run data
|
|
54
|
-
run_data = load_run_data(run_id)
|
|
55
|
-
return unless run_data
|
|
56
|
-
|
|
57
|
-
case event[:step_name]
|
|
58
|
-
when 'test_start'
|
|
59
|
-
start_new_test(event, run_data)
|
|
60
|
-
when 'test_finish'
|
|
61
|
-
finish_current_test(event, run_data)
|
|
62
|
-
when 'test_result'
|
|
63
|
-
# This indicates the test is finished
|
|
64
|
-
finish_current_test(event, run_data)
|
|
65
|
-
else
|
|
66
|
-
# This is a test step (visit, click_button, fill_in, etc.)
|
|
67
|
-
# If we don't have a current test, start one
|
|
68
|
-
current_test = get_current_test
|
|
69
|
-
start_new_test(event, run_data) unless current_test
|
|
70
|
-
add_test_step(event, run_data)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
private
|
|
75
|
-
|
|
76
|
-
def start_new_test(event, run_data)
|
|
77
|
-
# Extract test name from the current test context
|
|
78
|
-
test_name = event[:test_name] || CapyDash.current_test || "unknown_test"
|
|
79
|
-
|
|
80
|
-
current_test = {
|
|
81
|
-
test_name: test_name,
|
|
82
|
-
steps: []
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
# Set current test context
|
|
86
|
-
set_current_test_context(run_data[:id], current_test, [])
|
|
87
|
-
|
|
88
|
-
# Add the test_start step
|
|
89
|
-
add_test_step(event, run_data)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def finish_current_test(event, run_data)
|
|
93
|
-
current_test = get_current_test
|
|
94
|
-
return unless current_test
|
|
95
|
-
|
|
96
|
-
# Add the test_finish step
|
|
97
|
-
add_test_step(event, run_data)
|
|
98
|
-
|
|
99
|
-
# Get updated test data
|
|
100
|
-
current_test = get_current_test
|
|
101
|
-
test_steps = get_current_test_steps
|
|
102
|
-
|
|
103
|
-
# Determine test status
|
|
104
|
-
test_status = determine_test_status(test_steps)
|
|
105
|
-
|
|
106
|
-
# Update counters
|
|
107
|
-
run_data[:total_tests] += 1
|
|
108
|
-
if test_status == 'passed'
|
|
109
|
-
run_data[:passed_tests] += 1
|
|
110
|
-
elsif test_status == 'failed'
|
|
111
|
-
run_data[:failed_tests] += 1
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Add test to current run
|
|
115
|
-
run_data[:tests] << current_test
|
|
116
|
-
|
|
117
|
-
# Save updated run data
|
|
118
|
-
save_run_data(run_data)
|
|
119
|
-
|
|
120
|
-
# Clear current test
|
|
121
|
-
set_current_test_context(run_data[:id], nil, [])
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def add_test_step(event, run_data)
|
|
125
|
-
current_test = get_current_test
|
|
126
|
-
return unless current_test
|
|
127
|
-
|
|
128
|
-
step = {
|
|
129
|
-
step_name: event[:step_name],
|
|
130
|
-
detail: event[:detail],
|
|
131
|
-
status: event[:status],
|
|
132
|
-
test_name: event[:test_name] || CapyDash.current_test || current_test[:test_name]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
# Add screenshot if present
|
|
136
|
-
if event[:screenshot]
|
|
137
|
-
step[:screenshot] = event[:screenshot]
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# Add error if present
|
|
141
|
-
if event[:error]
|
|
142
|
-
step[:error] = event[:error]
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Update current test with new step
|
|
146
|
-
current_test[:steps] << step
|
|
147
|
-
test_steps = get_current_test_steps + [step]
|
|
148
|
-
|
|
149
|
-
# Save updated test context
|
|
150
|
-
set_current_test_context(run_data[:id], current_test, test_steps)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def determine_test_status(steps)
|
|
154
|
-
return 'failed' if steps.any? { |step| step[:status] == 'failed' }
|
|
155
|
-
return 'passed' if steps.any? { |step| step[:status] == 'passed' }
|
|
156
|
-
'running'
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def generate_run_id
|
|
160
|
-
"#{Time.now.to_i}_#{SecureRandom.hex(4)}"
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
# File-based storage methods for parallel testing support
|
|
164
|
-
def run_data_file(run_id)
|
|
165
|
-
File.join(Dir.pwd, "tmp", "capydash_data", "run_#{run_id}.json")
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def context_file
|
|
169
|
-
File.join(Dir.pwd, "tmp", "capydash_data", "current_context.json")
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def save_run_data(run_data)
|
|
173
|
-
FileUtils.mkdir_p(File.dirname(run_data_file(run_data[:id])))
|
|
174
|
-
File.write(run_data_file(run_data[:id]), run_data.to_json)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def load_run_data(run_id)
|
|
178
|
-
file_path = run_data_file(run_id)
|
|
179
|
-
return nil unless File.exist?(file_path)
|
|
180
|
-
|
|
181
|
-
JSON.parse(File.read(file_path), symbolize_names: true)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def set_current_test_context(run_id, current_test, test_steps)
|
|
185
|
-
context = {
|
|
186
|
-
run_id: run_id,
|
|
187
|
-
current_test: current_test,
|
|
188
|
-
test_steps: test_steps
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
FileUtils.mkdir_p(File.dirname(context_file))
|
|
192
|
-
File.write(context_file, context.to_json)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def get_current_run_id
|
|
196
|
-
return nil unless File.exist?(context_file)
|
|
197
|
-
|
|
198
|
-
context = JSON.parse(File.read(context_file), symbolize_names: true)
|
|
199
|
-
context[:run_id]
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def get_current_test
|
|
203
|
-
return nil unless File.exist?(context_file)
|
|
204
|
-
|
|
205
|
-
context = JSON.parse(File.read(context_file), symbolize_names: true)
|
|
206
|
-
context[:current_test]
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def get_current_test_steps
|
|
210
|
-
return [] unless File.exist?(context_file)
|
|
211
|
-
|
|
212
|
-
context = JSON.parse(File.read(context_file), symbolize_names: true)
|
|
213
|
-
context[:test_steps] || []
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def clear_current_test_context
|
|
217
|
-
File.delete(context_file) if File.exist?(context_file)
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require 'capydash/event_emitter'
|
|
2
|
-
|
|
3
|
-
module CapyDash
|
|
4
|
-
class TestDataCollector
|
|
5
|
-
class << self
|
|
6
|
-
def start_test_run
|
|
7
|
-
@test_run_started = true
|
|
8
|
-
@test_count = 0
|
|
9
|
-
@passed_count = 0
|
|
10
|
-
@failed_count = 0
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def finish_test_run
|
|
14
|
-
return unless @test_run_started
|
|
15
|
-
|
|
16
|
-
@test_run_started = false
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def start_test(test_name, test_class, test_method)
|
|
20
|
-
return unless @test_run_started
|
|
21
|
-
|
|
22
|
-
@test_count += 1
|
|
23
|
-
|
|
24
|
-
# Emit test start event
|
|
25
|
-
CapyDash::EventEmitter.broadcast(
|
|
26
|
-
step_name: "test_start",
|
|
27
|
-
detail: "Starting test: #{test_name}",
|
|
28
|
-
test_name: test_name,
|
|
29
|
-
status: "running"
|
|
30
|
-
)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def finish_test(test_name, status, error_message = nil)
|
|
34
|
-
return unless @test_run_started
|
|
35
|
-
|
|
36
|
-
if status == "passed"
|
|
37
|
-
@passed_count += 1
|
|
38
|
-
elsif status == "failed"
|
|
39
|
-
@failed_count += 1
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Emit test finish event
|
|
43
|
-
event_data = {
|
|
44
|
-
step_name: "test_finish",
|
|
45
|
-
detail: "Test #{status}: #{test_name}",
|
|
46
|
-
test_name: test_name,
|
|
47
|
-
status: status
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if error_message
|
|
51
|
-
event_data[:error] = error_message
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
CapyDash::EventEmitter.broadcast(event_data)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
require 'rails/generators'
|
|
2
|
-
|
|
3
|
-
module Capydash
|
|
4
|
-
module Generators
|
|
5
|
-
class InstallGenerator < Rails::Generators::Base
|
|
6
|
-
source_root File.expand_path('templates', __dir__)
|
|
7
|
-
|
|
8
|
-
desc "Installs CapyDash with all necessary configuration files"
|
|
9
|
-
|
|
10
|
-
def create_initializer
|
|
11
|
-
create_file "config/initializers/capydash.rb", <<~RUBY
|
|
12
|
-
require 'capydash'
|
|
13
|
-
|
|
14
|
-
# Configure CapyDash
|
|
15
|
-
CapyDash.configure do |config|
|
|
16
|
-
config.port = 4000
|
|
17
|
-
config.screenshot_path = "tmp/capydash_screenshots"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Subscribe to events for test data collection
|
|
21
|
-
CapyDash::EventEmitter.subscribe do |event|
|
|
22
|
-
# Collect test data for report generation
|
|
23
|
-
CapyDash::TestDataAggregator.handle_event(event)
|
|
24
|
-
end
|
|
25
|
-
RUBY
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def create_rake_tasks
|
|
29
|
-
create_file "lib/tasks/capydash.rake", <<~RUBY
|
|
30
|
-
namespace :capydash do
|
|
31
|
-
desc "Generate static HTML test report"
|
|
32
|
-
task :report => :environment do
|
|
33
|
-
CapyDash::ReportGenerator.generate_report
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
desc "Start local server to view static HTML report"
|
|
37
|
-
task :server => :environment do
|
|
38
|
-
CapyDash::DashboardServer.start
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
RUBY
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def update_test_helper
|
|
45
|
-
test_helper_path = "test/test_helper.rb"
|
|
46
|
-
|
|
47
|
-
if File.exist?(test_helper_path)
|
|
48
|
-
# Read existing test helper
|
|
49
|
-
content = File.read(test_helper_path)
|
|
50
|
-
|
|
51
|
-
# Check if CapyDash is already configured
|
|
52
|
-
unless content.include?("require 'capydash'")
|
|
53
|
-
# Add CapyDash configuration
|
|
54
|
-
capydash_config = <<~RUBY
|
|
55
|
-
|
|
56
|
-
# CapyDash configuration
|
|
57
|
-
require 'capydash'
|
|
58
|
-
|
|
59
|
-
# Start test run data collection
|
|
60
|
-
CapyDash::TestDataCollector.start_test_run
|
|
61
|
-
|
|
62
|
-
# Hook into test execution to set current test name and manage test runs
|
|
63
|
-
module CapyDash
|
|
64
|
-
module TestHooks
|
|
65
|
-
def run(&block)
|
|
66
|
-
# Set the current test name for CapyDash
|
|
67
|
-
CapyDash.current_test = self.name
|
|
68
|
-
|
|
69
|
-
# Start test run data collection if not already started
|
|
70
|
-
CapyDash::TestDataAggregator.start_test_run unless CapyDash::TestDataAggregator.instance_variable_get(:@current_run)
|
|
71
|
-
|
|
72
|
-
super
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Apply the hook to the test case
|
|
78
|
-
class ActiveSupport::TestCase
|
|
79
|
-
prepend CapyDash::TestHooks
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Hook to finish test run when all tests are done
|
|
83
|
-
Minitest.after_run do
|
|
84
|
-
CapyDash::TestDataCollector.finish_test_run
|
|
85
|
-
CapyDash::TestDataAggregator.finish_test_run
|
|
86
|
-
end
|
|
87
|
-
RUBY
|
|
88
|
-
|
|
89
|
-
# Insert after the last require statement
|
|
90
|
-
if content.match(/require.*\n/)
|
|
91
|
-
content = content.gsub(/(require.*\n)/, "\\1#{capydash_config}")
|
|
92
|
-
else
|
|
93
|
-
content = capydash_config + content
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
File.write(test_helper_path, content)
|
|
97
|
-
say "Updated test/test_helper.rb with CapyDash configuration"
|
|
98
|
-
else
|
|
99
|
-
say "CapyDash already configured in test/test_helper.rb", :yellow
|
|
100
|
-
end
|
|
101
|
-
else
|
|
102
|
-
say "test/test_helper.rb not found. Please add CapyDash configuration manually.", :red
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def show_instructions
|
|
108
|
-
say "\n" + "="*60, :green
|
|
109
|
-
say "CapyDash has been successfully installed!", :green
|
|
110
|
-
say "="*60, :green
|
|
111
|
-
say "\nNext steps:", :yellow
|
|
112
|
-
say "1. Run your tests: bundle exec rails test"
|
|
113
|
-
say "2. Generate report: bundle exec rake capydash:report"
|
|
114
|
-
say "3. View report: open capydash_report/index.html"
|
|
115
|
-
say "\nImportant:", :yellow
|
|
116
|
-
say "- CapyDash only captures system tests that use Capybara methods (visit, click, fill_in, etc.)"
|
|
117
|
-
say "- Unit tests and integration tests without Capybara won't appear in the report"
|
|
118
|
-
say "- Works with parallel testing - no configuration needed"
|
|
119
|
-
say "\nFor more information, see the README.md file."
|
|
120
|
-
say "="*60, :green
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|