capydash 0.1.1 → 0.1.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/README.md +35 -15
- data/lib/capydash/dashboard_server.rb +0 -8
- data/lib/capydash/engine.rb +0 -2
- data/lib/capydash/forwarder.rb +0 -6
- data/lib/capydash/instrumentation.rb +64 -29
- data/lib/capydash/persistence.rb +0 -5
- data/lib/capydash/report_generator.rb +1007 -0
- data/lib/capydash/templates/report.html.erb +92 -0
- data/lib/capydash/test_data_aggregator.rb +128 -0
- data/lib/capydash/test_data_collector.rb +0 -18
- data/lib/capydash/version.rb +1 -1
- data/lib/capydash.rb +2 -0
- data/lib/tasks/capydash.rake +62 -6
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa238074c05a59e8c88ec84c887944dc2c376ae379ffde69c3422b939d052d77
|
4
|
+
data.tar.gz: fdfc24fbe669f5a8d0ff44792383b5eae3abcf69d21ed52810228972d0773959
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b49bd9f834a849025f79fc72fc3c317e971fba0ea74504e09d35026a4bdb18b224f48a86ab6041fb43a78de5dd6897ecba9ca43e9f57bfc356385a318313f0e4
|
7
|
+
data.tar.gz: 9c3f988ea6164e454f73d1600ec61ceddfc63f9f6dbb4220c535df60ecf4662f08653fdbcfc9bf6936616382455d8bef473a5f03336d6af8aba72da328c67428
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# CapyDash
|
2
2
|
|
3
|
-
A
|
3
|
+
A static HTML dashboard for Capybara tests that provides comprehensive test reporting with screenshots, step-by-step tracking, error reporting, and search capabilities. Perfect for debugging test failures and understanding test behavior.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,24 +18,44 @@ bundle add capydash
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
22
|
-
```bash
|
23
|
-
bundle exec rake capydash:server
|
24
|
-
```
|
21
|
+
### Generate Test Report
|
25
22
|
|
26
|
-
|
27
|
-
```bash
|
28
|
-
npx vite
|
29
|
-
```
|
23
|
+
After running your Capybara tests, generate a static HTML report:
|
30
24
|
|
31
|
-
|
25
|
+
```bash
|
26
|
+
bundle exec rake capydash:report
|
27
|
+
```
|
28
|
+
|
29
|
+
This will create a `capydash_report/index.html` file with:
|
30
|
+
- Test steps in chronological order
|
31
|
+
- Embedded screenshots for each step
|
32
|
+
- Click-to-open/close functionality for screenshots
|
33
|
+
- Typeahead search across test names, step text, and pass/fail status
|
34
|
+
- Summary statistics
|
35
|
+
|
36
|
+
### View Report in Browser
|
37
|
+
|
38
|
+
**Option 1: Open directly in browser**
|
39
|
+
```bash
|
40
|
+
open capydash_report/index.html
|
41
|
+
```
|
42
|
+
|
43
|
+
**Option 2: Use the built-in server**
|
44
|
+
```bash
|
45
|
+
bundle exec rake capydash:server
|
46
|
+
```
|
47
|
+
|
48
|
+
Then open `http://localhost:5173` in your browser.
|
49
|
+
|
50
|
+
### Run Tests with CapyDash
|
32
51
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
52
|
+
Run your tests normally - CapyDash will automatically instrument them:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
bundle exec rails test
|
56
|
+
```
|
37
57
|
|
38
|
-
The
|
58
|
+
The report will be generated in `capydash_report/index.html` after test completion.
|
39
59
|
|
40
60
|
## Development
|
41
61
|
|
@@ -87,7 +87,6 @@ module CapyDash
|
|
87
87
|
command: args.join(' '),
|
88
88
|
client_id: ws.object_id
|
89
89
|
})
|
90
|
-
puts "[CapyDash] Running command: #{args.join(' ')}"
|
91
90
|
|
92
91
|
Thread.new do
|
93
92
|
begin
|
@@ -100,21 +99,16 @@ module CapyDash
|
|
100
99
|
directory: dummy_app_path,
|
101
100
|
exists: Dir.exist?(dummy_app_path)
|
102
101
|
})
|
103
|
-
puts "[CapyDash] Running tests in: #{dummy_app_path}"
|
104
|
-
puts "[CapyDash] Directory exists: #{Dir.exist?(dummy_app_path)}"
|
105
102
|
|
106
103
|
Dir.chdir(dummy_app_path) do
|
107
104
|
# Set Rails environment and ensure CapyDash is loaded
|
108
105
|
ENV["RAILS_ENV"] = "test"
|
109
106
|
ENV["CAPYDASH_EXTERNAL_WS"] = "1" # Use external WebSocket mode
|
110
107
|
|
111
|
-
puts "[CapyDash] Current directory: #{Dir.pwd}"
|
112
|
-
puts "[CapyDash] Running: #{args.join(' ')}"
|
113
108
|
|
114
109
|
# Run the command and capture both stdout and stderr
|
115
110
|
IO.popen(args, err: [:child, :out]) do |io|
|
116
111
|
io.each_line do |line|
|
117
|
-
puts "[CapyDash] Test output: #{line.strip}"
|
118
112
|
event = { type: "runner", line: line.strip, status: "running", ts: Time.now.to_i }
|
119
113
|
broadcast(event.to_json)
|
120
114
|
end
|
@@ -132,8 +126,6 @@ module CapyDash
|
|
132
126
|
end
|
133
127
|
rescue => e
|
134
128
|
CapyDash::ErrorHandler.handle_websocket_error(e, ws)
|
135
|
-
warn "[CapyDash] ws.onmessage error: #{e.message}"
|
136
|
-
puts "[CapyDash] Backtrace: #{e.backtrace.first(5).join("\n")}"
|
137
129
|
end
|
138
130
|
end
|
139
131
|
|
data/lib/capydash/engine.rb
CHANGED
@@ -34,13 +34,11 @@ module CapyDash
|
|
34
34
|
port: port,
|
35
35
|
environment: Rails.env
|
36
36
|
})
|
37
|
-
puts "[CapyDash] WebSocket server started on ws://localhost:#{port}"
|
38
37
|
else
|
39
38
|
CapyDash::Logger.info("Skipping in-process WebSocket server", {
|
40
39
|
reason: ENV["CAPYDASH_EXTERNAL_WS"] == "1" ? "external_mode" : "production_environment",
|
41
40
|
environment: Rails.env
|
42
41
|
})
|
43
|
-
puts "[CapyDash] Skipping in-process WebSocket server (external mode)" if ENV["CAPYDASH_EXTERNAL_WS"] == "1"
|
44
42
|
end
|
45
43
|
rescue => e
|
46
44
|
CapyDash::ErrorHandler.handle_error(e, {
|
data/lib/capydash/forwarder.rb
CHANGED
@@ -34,37 +34,31 @@ module CapyDash
|
|
34
34
|
|
35
35
|
def connect
|
36
36
|
url = "ws://127.0.0.1:#{@port}"
|
37
|
-
puts "[CapyDash Forwarder] Attempting to connect to #{url}"
|
38
37
|
@ws = Faye::WebSocket::Client.new(url)
|
39
38
|
|
40
39
|
@ws.on(:open) do |_event|
|
41
40
|
@connected = true
|
42
|
-
puts "[CapyDash Forwarder] Connected to WebSocket server"
|
43
41
|
flush_queue
|
44
42
|
end
|
45
43
|
|
46
44
|
@ws.on(:close) do |_event|
|
47
45
|
@connected = false
|
48
|
-
puts "[CapyDash Forwarder] Disconnected from WebSocket server"
|
49
46
|
# attempt reconnect after short delay
|
50
47
|
EM.add_timer(0.5) { connect }
|
51
48
|
end
|
52
49
|
|
53
50
|
@ws.on(:error) do |event|
|
54
|
-
puts "[CapyDash Forwarder] WebSocket error: #{event.inspect}"
|
55
51
|
# keep trying; errors are expected if server not yet up
|
56
52
|
end
|
57
53
|
end
|
58
54
|
|
59
55
|
def send_message(raw_message)
|
60
56
|
message = raw_message.is_a?(String) ? raw_message : JSON.dump(raw_message)
|
61
|
-
puts "[CapyDash Forwarder] Sending message: #{message[0..100]}..."
|
62
57
|
@mutex.synchronize do
|
63
58
|
if @connected && @ws
|
64
59
|
@ws.send(message)
|
65
60
|
else
|
66
61
|
@queue << message
|
67
|
-
puts "[CapyDash Forwarder] Queued message (not connected)"
|
68
62
|
end
|
69
63
|
end
|
70
64
|
end
|
@@ -3,8 +3,6 @@ require 'capydash/dashboard_server'
|
|
3
3
|
require 'base64'
|
4
4
|
require 'fileutils'
|
5
5
|
|
6
|
-
puts "[CapyDash] Instrumentation file loaded"
|
7
|
-
|
8
6
|
module CapyDash
|
9
7
|
module Instrumentation
|
10
8
|
def visit(path)
|
@@ -22,7 +20,18 @@ module CapyDash
|
|
22
20
|
private
|
23
21
|
|
24
22
|
def emit_step(step_name, detail)
|
25
|
-
#
|
23
|
+
# emit "running" event first (without screenshot)
|
24
|
+
CapyDash::EventEmitter.broadcast(
|
25
|
+
step_name: step_name,
|
26
|
+
detail: detail,
|
27
|
+
test_name: (defined?(CapyDash) ? CapyDash.current_test : nil),
|
28
|
+
status: "running"
|
29
|
+
)
|
30
|
+
|
31
|
+
# run the original step
|
32
|
+
yield
|
33
|
+
|
34
|
+
# take screenshot AFTER the action is completed
|
26
35
|
base_dir = if CapyDash.respond_to?(:configuration)
|
27
36
|
CapyDash.configuration&.screenshot_path || "tmp/capydash_screenshots"
|
28
37
|
else
|
@@ -40,16 +49,12 @@ module CapyDash
|
|
40
49
|
if defined?(Capybara)
|
41
50
|
begin
|
42
51
|
current_driver = Capybara.current_driver
|
43
|
-
|
44
|
-
if current_driver == :rack_test
|
45
|
-
puts "[CapyDash] Skipping screenshot (rack_test driver)"
|
46
|
-
else
|
52
|
+
if current_driver != :rack_test
|
47
53
|
if respond_to?(:page)
|
48
54
|
page.save_screenshot(screenshot_path)
|
49
55
|
else
|
50
56
|
Capybara.current_session.save_screenshot(screenshot_path)
|
51
57
|
end
|
52
|
-
puts "[CapyDash] Saved screenshot: #{screenshot_path}"
|
53
58
|
|
54
59
|
# Try to find the actual screenshot file location
|
55
60
|
actual_screenshot_path = nil
|
@@ -66,43 +71,74 @@ module CapyDash
|
|
66
71
|
if actual_screenshot_path && File.exist?(actual_screenshot_path)
|
67
72
|
encoded = Base64.strict_encode64(File.binread(actual_screenshot_path))
|
68
73
|
data_url = "data:image/png;base64,#{encoded}"
|
69
|
-
puts "[CapyDash] Generated data URL for screenshot from: #{actual_screenshot_path}"
|
70
|
-
else
|
71
|
-
puts "[CapyDash] Screenshot file not found. Tried: #{absolute_screenshot_path} and #{capybara_path rescue 'N/A'}"
|
72
74
|
end
|
73
75
|
end
|
74
76
|
rescue => e
|
75
|
-
|
77
|
+
# Silently handle screenshot capture failures
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
#
|
80
|
-
CapyDash::EventEmitter.broadcast(
|
81
|
-
step_name: step_name,
|
82
|
-
detail: detail,
|
83
|
-
screenshot: screenshot_path,
|
84
|
-
data_url: data_url,
|
85
|
-
test_name: (defined?(CapyDash) ? CapyDash.current_test : nil),
|
86
|
-
status: "running"
|
87
|
-
)
|
88
|
-
|
89
|
-
# run the original step
|
90
|
-
yield
|
91
|
-
|
92
|
-
# mark success
|
81
|
+
# mark success with screenshot
|
93
82
|
CapyDash::EventEmitter.broadcast(
|
94
83
|
step_name: step_name,
|
95
84
|
detail: detail,
|
96
|
-
screenshot: screenshot_path,
|
85
|
+
screenshot: actual_screenshot_path || screenshot_path,
|
97
86
|
data_url: data_url,
|
98
87
|
test_name: (defined?(CapyDash) ? CapyDash.current_test : nil),
|
99
88
|
status: "passed"
|
100
89
|
)
|
101
90
|
rescue => e
|
91
|
+
# take screenshot even on failure (after the action was attempted)
|
92
|
+
base_dir = if CapyDash.respond_to?(:configuration)
|
93
|
+
CapyDash.configuration&.screenshot_path || "tmp/capydash_screenshots"
|
94
|
+
else
|
95
|
+
"tmp/capydash_screenshots"
|
96
|
+
end
|
97
|
+
FileUtils.mkdir_p(base_dir) unless Dir.exist?(base_dir)
|
98
|
+
timestamp = Time.now.strftime('%Y%m%d-%H%M%S-%L')
|
99
|
+
safe_step = step_name.gsub(/\s+/, '_')
|
100
|
+
screenshot_path = File.join(base_dir, "#{safe_step}-#{timestamp}.png")
|
101
|
+
|
102
|
+
# Ensure we have an absolute path for Base64 encoding
|
103
|
+
absolute_screenshot_path = File.absolute_path(screenshot_path)
|
104
|
+
|
105
|
+
data_url = nil
|
106
|
+
if defined?(Capybara)
|
107
|
+
begin
|
108
|
+
current_driver = Capybara.current_driver
|
109
|
+
if current_driver != :rack_test
|
110
|
+
if respond_to?(:page)
|
111
|
+
page.save_screenshot(screenshot_path)
|
112
|
+
else
|
113
|
+
Capybara.current_session.save_screenshot(screenshot_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Try to find the actual screenshot file location
|
117
|
+
actual_screenshot_path = nil
|
118
|
+
if File.exist?(absolute_screenshot_path)
|
119
|
+
actual_screenshot_path = absolute_screenshot_path
|
120
|
+
else
|
121
|
+
# Check if it was saved in the capybara tmp directory
|
122
|
+
capybara_path = File.join(Dir.pwd, "tmp", "capybara", screenshot_path)
|
123
|
+
if File.exist?(capybara_path)
|
124
|
+
actual_screenshot_path = capybara_path
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if actual_screenshot_path && File.exist?(actual_screenshot_path)
|
129
|
+
encoded = Base64.strict_encode64(File.binread(actual_screenshot_path))
|
130
|
+
data_url = "data:image/png;base64,#{encoded}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
rescue => e
|
134
|
+
# Silently handle screenshot capture failures
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
102
138
|
CapyDash::EventEmitter.broadcast(
|
103
139
|
step_name: step_name,
|
104
140
|
detail: detail,
|
105
|
-
screenshot: screenshot_path,
|
141
|
+
screenshot: actual_screenshot_path || screenshot_path,
|
106
142
|
data_url: data_url,
|
107
143
|
test_name: (defined?(CapyDash) ? CapyDash.current_test : nil),
|
108
144
|
status: "failed",
|
@@ -115,4 +151,3 @@ end
|
|
115
151
|
|
116
152
|
# Prepend into Capybara DSL so it wraps all calls
|
117
153
|
Capybara::Session.prepend(CapyDash::Instrumentation)
|
118
|
-
puts "[CapyDash] Instrumentation prepended into Capybara::Session"
|
data/lib/capydash/persistence.rb
CHANGED
@@ -10,11 +10,6 @@ module CapyDash
|
|
10
10
|
|
11
11
|
begin
|
12
12
|
File.write(file_path, JSON.pretty_generate(test_run_data))
|
13
|
-
Logger.info("Test run saved", {
|
14
|
-
run_id: test_run_data[:id],
|
15
|
-
file_path: file_path,
|
16
|
-
test_count: test_run_data[:tests]&.length || 0
|
17
|
-
})
|
18
13
|
file_path
|
19
14
|
rescue => e
|
20
15
|
ErrorHandler.handle_error(e, {
|