capydash 0.1.7 → 0.2.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 +4 -4
- data/README.md +70 -171
- data/capydash.gemspec +7 -13
- data/lib/capydash/rspec.rb +415 -0
- data/lib/capydash/templates/report.html.erb +4 -26
- data/lib/capydash/version.rb +2 -2
- data/lib/capydash.rb +4 -55
- metadata +13 -83
- 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/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,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
|
data/lib/tasks/capydash.rake
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
namespace :capydash do
|
|
2
|
-
desc "Start local server to view static HTML report"
|
|
3
|
-
task server: :environment do
|
|
4
|
-
require 'webrick'
|
|
5
|
-
require 'capydash/report_generator'
|
|
6
|
-
|
|
7
|
-
report_dir = File.join(Dir.pwd, "capydash_report")
|
|
8
|
-
|
|
9
|
-
unless Dir.exist?(report_dir)
|
|
10
|
-
puts "No report directory found. Run 'bundle exec rake capydash:report' first."
|
|
11
|
-
exit 1
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Try different ports if 5173 is busy
|
|
15
|
-
port = 5173
|
|
16
|
-
begin
|
|
17
|
-
server = WEBrick::HTTPServer.new(
|
|
18
|
-
Port: port,
|
|
19
|
-
DocumentRoot: report_dir,
|
|
20
|
-
Logger: WEBrick::Log.new(nil, WEBrick::Log::ERROR),
|
|
21
|
-
AccessLog: [],
|
|
22
|
-
BindAddress: '127.0.0.1'
|
|
23
|
-
)
|
|
24
|
-
rescue Errno::EADDRINUSE
|
|
25
|
-
port = 8080
|
|
26
|
-
puts "Port 5173 is busy, trying port #{port}..."
|
|
27
|
-
server = WEBrick::HTTPServer.new(
|
|
28
|
-
Port: port,
|
|
29
|
-
DocumentRoot: report_dir,
|
|
30
|
-
Logger: WEBrick::Log.new(nil, WEBrick::Log::ERROR),
|
|
31
|
-
AccessLog: [],
|
|
32
|
-
BindAddress: '127.0.0.1'
|
|
33
|
-
)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
puts "Starting static file server on http://localhost:#{port}"
|
|
37
|
-
puts "Report available at: http://localhost:#{port}/index.html"
|
|
38
|
-
puts "Press Ctrl+C to stop the server"
|
|
39
|
-
|
|
40
|
-
trap("INT") {
|
|
41
|
-
puts "\nShutting down server..."
|
|
42
|
-
server.shutdown
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
begin
|
|
46
|
-
server.start
|
|
47
|
-
rescue => e
|
|
48
|
-
puts "Error starting server: #{e.message}"
|
|
49
|
-
exit 1
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
desc "Generate static HTML test report"
|
|
54
|
-
task report: :environment do
|
|
55
|
-
require 'capydash/report_generator'
|
|
56
|
-
|
|
57
|
-
report_path = CapyDash::ReportGenerator.generate_report
|
|
58
|
-
|
|
59
|
-
if report_path
|
|
60
|
-
puts "Report generated: file://#{File.absolute_path(report_path)}"
|
|
61
|
-
else
|
|
62
|
-
puts "No test data found. Run some tests first to generate a report."
|
|
63
|
-
exit 1
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
end
|