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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72ac597d4f4b57d15d412dcdfa56e2cba5600a045e62278d44a082c9ca2e6eff
4
- data.tar.gz: c0fb3be58f53129bc4f048f6ea591f1250ef0cc03ca6d004322d86848002b953
3
+ metadata.gz: aa238074c05a59e8c88ec84c887944dc2c376ae379ffde69c3422b939d052d77
4
+ data.tar.gz: fdfc24fbe669f5a8d0ff44792383b5eae3abcf69d21ed52810228972d0773959
5
5
  SHA512:
6
- metadata.gz: 634aabfc97331a3d68d452ac8806bb4a6b979549791c18344725bfdf5ed0bfbee41e27b39afb050d56b87dc6bff06e7b8790afcb231a877acd46fa9e487a2ae3
7
- data.tar.gz: 9eddf128a30f7317483eeddc385c1170ec7a14701e0f077100d06e72dcdf63aea188b440483fac9c75502408aad64e2b284f103353693c8f7e09972f1bb5b4e0
6
+ metadata.gz: b49bd9f834a849025f79fc72fc3c317e971fba0ea74504e09d35026a4bdb18b224f48a86ab6041fb43a78de5dd6897ecba9ca43e9f57bfc356385a318313f0e4
7
+ data.tar.gz: 9c3f988ea6164e454f73d1600ec61ceddfc63f9f6dbb4220c535df60ecf4662f08653fdbcfc9bf6936616382455d8bef473a5f03336d6af8aba72da328c67428
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CapyDash
2
2
 
3
- A live dashboard for Capybara tests that provides real-time visualization of test execution with screenshots, step-by-step tracking, comprehensive error reporting, and search capabilities. Perfect for debugging test failures and understanding test behavior.
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
- 1. **Start the dashboard server** in one terminal:
22
- ```bash
23
- bundle exec rake capydash:server
24
- ```
21
+ ### Generate Test Report
25
22
 
26
- 2. **Start the frontend** in another terminal:
27
- ```bash
28
- npx vite
29
- ```
23
+ After running your Capybara tests, generate a static HTML report:
30
24
 
31
- 3. **Open your browser** to `http://localhost:5173` to view the dashboard
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
- 4. **Run your tests** with external WebSocket:
34
- ```bash
35
- CAPYDASH_EXTERNAL_WS=1 bundle exec rails test
36
- ```
52
+ Run your tests normally - CapyDash will automatically instrument them:
53
+
54
+ ```bash
55
+ bundle exec rails test
56
+ ```
37
57
 
38
- The dashboard will show your tests running in real-time with screenshots, detailed step information, and search functionality to filter tests by name, status, or content.
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
 
@@ -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, {
@@ -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
- # take screenshot
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
- puts "[CapyDash] Current Capybara driver: #{current_driver}"
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
- warn "[CapyDash] Screenshot capture failed: #{e.message}"
77
+ # Silently handle screenshot capture failures
76
78
  end
77
79
  end
78
80
 
79
- # emit event
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"
@@ -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, {