panda-core 0.8.3 → 0.8.4

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: c2c7f949ef7ad87f9b6aa0ec54ccd8c1dc1574ee09f9ef3651af635930ae65e4
4
- data.tar.gz: 80e06efeb33c7092e93e1b2a06997e23c0951578f08524bdd6ef6483f7b07766
3
+ metadata.gz: 28b16d6a5d79cf880c87149553332200a4b0c685fd1c9e654ec969475c85b1a7
4
+ data.tar.gz: 67a0a3ae10b209c96219e3974f8917007443cfbd1734db1943c255c99554d674
5
5
  SHA512:
6
- metadata.gz: 482bf161016f2fc352083a22c9f85e5da7d01f72ca9be8c8755cfb0939f0bb7e48abd12b5e324e542047c164a193586ca9d083f80aaeec9d7e3179cccbae7397
7
- data.tar.gz: c74f6e9909a28464f636c0edd0fbb7a2086484bd2d1d3e58adffb9e85c93552d630109d8c944ac886f6d9c92825e5e447914506bf0ce2062a7e890f5afe58e91
6
+ metadata.gz: 501c2f8db9b9a09c55d1c2c990672683a11e1fe63ff99067b2844edab3c7c31a10ef50c7f76658e0ce9862acfd0cdc5d979227f6b56ab18c797634b2a0343776
7
+ data.tar.gz: ce9f83f3d6619f6bf6b58d29c4b589a6bb3727120e0695391edbe8c22007c50aeb96c1a508b1c9798386db6a9c567f31644943a48dc7978700fb0a7377e0d7fb
@@ -61,6 +61,8 @@ RSpec.configure do |config|
61
61
  if ENV["GITHUB_ACTIONS"] == "true"
62
62
  require "rspec/github"
63
63
  config.add_formatter RSpec::Github::Formatter
64
+ # Also add documentation formatter for colored real-time output in CI logs
65
+ config.add_formatter RSpec::Core::Formatters::DocumentationFormatter, $stdout
64
66
  end
65
67
 
66
68
  # Controller testing support (if rails-controller-testing is available)
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends Rails system tests with improved screenshot and driver handling
4
+ #
5
+ # This module provides enhancements to Rails system tests:
6
+ # - Multi-session screenshot support
7
+ # - CI-specific error handling and logging
8
+ # - Enhanced failure screenshots with HTML debugging
9
+ # - Network idle waiting before screenshots
10
+ #
11
+ # @example Using in RSpec
12
+ # RSpec.configure do |config|
13
+ # config.include Panda::Core::Testing::BetterSystemTests, type: :system
14
+ # end
15
+ module Panda
16
+ module Core
17
+ module Testing
18
+ module BetterSystemTests
19
+ # Make failure screenshots compatible with multi-session setup.
20
+ # That's where we use Capybara.last_used_session introduced before.
21
+ def take_screenshot
22
+ return super unless Capybara.last_used_session
23
+
24
+ Capybara.using_session(Capybara.last_used_session) { super }
25
+ end
26
+
27
+ module ClassMethods
28
+ # Configure better system tests for RSpec
29
+ # This sets up the necessary hooks and configuration
30
+ def configure_better_system_tests!
31
+ # Make urls in mailers contain the correct server host.
32
+ # This is required for testing links in emails (e.g., via capybara-email).
33
+ around(:each, type: :system) do |ex|
34
+ was_host = Rails.application.default_url_options[:host]
35
+ Rails.application.default_url_options[:host] = Capybara.server_host
36
+ ex.run
37
+ Rails.application.default_url_options[:host] = was_host
38
+ end
39
+
40
+ # Make sure this hook runs before others
41
+ # Means you don't have to set js: true in every system spec
42
+ prepend_before(:each, type: :system) do
43
+ driven_by :cuprite
44
+ end
45
+
46
+ # Enable automatic screenshots on failure
47
+ # Add CI-specific timeout and retry logic for form interactions
48
+ around(:each, type: :system) do |example|
49
+ if ENV["GITHUB_ACTIONS"] == "true"
50
+ # In CI, wrap the test execution with additional error handling
51
+ begin
52
+ example.run
53
+ rescue => e
54
+ # Log any error for debugging
55
+ puts "[CI] Test error detected: #{e.class} - #{e.message}"
56
+ puts "[CI] Current URL: #{begin
57
+ page.current_url
58
+ rescue
59
+ ""
60
+ end}"
61
+
62
+ # Re-raise the original error
63
+ raise e
64
+ end
65
+ else
66
+ example.run
67
+ end
68
+ end
69
+
70
+ after(:each, type: :system) do |example|
71
+ next unless example.exception
72
+
73
+ begin
74
+ # Wait for any pending JavaScript to complete
75
+ # Cuprite has direct network idle support
76
+ begin
77
+ page.driver.wait_for_network_idle
78
+ rescue
79
+ nil
80
+ end
81
+
82
+ # Wait for DOM to be ready
83
+ sleep 0.5
84
+
85
+ # Get comprehensive page info
86
+ page_html = begin
87
+ page.html
88
+ rescue
89
+ ""
90
+ end
91
+ current_url = begin
92
+ page.current_url
93
+ rescue
94
+ ""
95
+ end
96
+ current_path = begin
97
+ page.current_path
98
+ rescue
99
+ ""
100
+ end
101
+ page_title = begin
102
+ page.title
103
+ rescue
104
+ ""
105
+ end
106
+
107
+ # Check for redirect or blank page indicators
108
+ if page_html.length < 100
109
+ puts "Warning: Page content appears minimal (#{page_html.length} chars) when taking screenshot"
110
+ end
111
+
112
+ # Use Capybara's save_screenshot method
113
+ screenshot_path = Capybara.save_screenshot
114
+ if screenshot_path
115
+ puts "Screenshot saved to: #{screenshot_path}"
116
+ puts "Page title: #{page_title}" if page_title.present?
117
+ puts "Current URL: #{current_url}" if current_url.present?
118
+ puts "Current path: #{current_path}" if current_path.present?
119
+ puts "Page content length: #{page_html.length} characters"
120
+
121
+ # Save page HTML for debugging in CI
122
+ if ENV["GITHUB_ACTIONS"] && page_html.present?
123
+ html_debug_path = screenshot_path.gsub(".png", ".html")
124
+ File.write(html_debug_path, page_html)
125
+ puts "Page HTML saved to: #{html_debug_path}"
126
+ end
127
+ end
128
+ rescue => e
129
+ puts "Failed to capture screenshot: #{e.message}"
130
+ puts "Exception class: #{example.exception.class}"
131
+ puts "Exception message: #{example.exception.message}"
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ def self.included(base)
138
+ base.extend(ClassMethods)
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helper methods for Cuprite-based system tests
4
+ #
5
+ # This module provides utility methods for working with Cuprite in system tests:
6
+ # - Page state verification helpers
7
+ # - Network and DOM waiting utilities
8
+ # - Safe form interaction methods with automatic retry in CI
9
+ # - Debugging helpers for headful testing
10
+ #
11
+ # @example Using in a system test
12
+ # RSpec.configure do |config|
13
+ # config.include Panda::Core::Testing::CupriteHelpers, type: :system
14
+ # end
15
+ module Panda
16
+ module Core
17
+ module Testing
18
+ module CupriteHelpers
19
+ # Ensure page is loaded and stable before interacting
20
+ def ensure_page_loaded
21
+ # Check if we're on about:blank and need to reload
22
+ current_url = begin
23
+ page.current_url
24
+ rescue
25
+ "unknown"
26
+ end
27
+ if current_url.include?("about:blank")
28
+ puts "[CI] Page is on about:blank, skipping recovery to avoid loops" if ENV["GITHUB_ACTIONS"]
29
+ # Don't try to recover - let the test handle it
30
+ return false
31
+ end
32
+
33
+ # Wait for page to be ready
34
+ wait_for_ready_state
35
+ # Wait for JavaScript to load
36
+ wait_for_javascript
37
+ true
38
+ end
39
+
40
+ # Wait for document ready state
41
+ def wait_for_ready_state
42
+ Timeout.timeout(5) do
43
+ loop do
44
+ ready = page.evaluate_script("document.readyState")
45
+ break if ready == "complete"
46
+
47
+ sleep 0.1
48
+ end
49
+ end
50
+ rescue Timeout::Error
51
+ puts "[CI] Timeout waiting for document ready state" if ENV["GITHUB_ACTIONS"]
52
+ end
53
+
54
+ # Wait for JavaScript to load (application-specific flag)
55
+ # Override in your application if you have a custom loaded flag
56
+ def wait_for_javascript(timeout: 5)
57
+ Timeout.timeout(timeout) do
58
+ loop do
59
+ loaded = begin
60
+ # Check for common JavaScript loaded indicators
61
+ page.evaluate_script("document.readyState === 'complete'")
62
+ rescue
63
+ false
64
+ end
65
+ break if loaded
66
+
67
+ sleep 0.1
68
+ end
69
+ end
70
+ true
71
+ rescue Timeout::Error
72
+ puts "[CI] Timeout waiting for JavaScript to load" if ENV["GITHUB_ACTIONS"]
73
+ false
74
+ end
75
+
76
+ # Waits for a specific selector to be present and visible on the page
77
+ # @param selector [String] CSS selector to wait for
78
+ # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
79
+ # @return [Boolean] true if element is found, false if timeout occurs
80
+ def wait_for_selector(selector, timeout: 5)
81
+ start_time = Time.now
82
+ while Time.now - start_time < timeout
83
+ return true if page.has_css?(selector, visible: true)
84
+
85
+ sleep 0.1
86
+ end
87
+ false
88
+ end
89
+
90
+ # Waits for a specific text to be present on the page
91
+ # @param text [String] Text to wait for
92
+ # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
93
+ # @return [Boolean] true if text is found, false if timeout occurs
94
+ def wait_for_text(text, timeout: 5)
95
+ start_time = Time.now
96
+ while Time.now - start_time < timeout
97
+ return true if page.has_text?(text)
98
+
99
+ sleep 0.1
100
+ end
101
+ false
102
+ end
103
+
104
+ # Waits for network requests to complete
105
+ # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
106
+ # @return [Boolean] true if network is idle, false if timeout occurs
107
+ def wait_for_network_idle(timeout: 5)
108
+ # Cuprite has direct network idle support
109
+ page.driver.wait_for_network_idle(timeout: timeout)
110
+ true
111
+ rescue => e
112
+ puts "[CI] Network idle timeout: #{e.message}" if ENV["GITHUB_ACTIONS"]
113
+ false
114
+ end
115
+
116
+ # Waits for JavaScript to modify the DOM
117
+ # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
118
+ # @return [Boolean] true if mutation occurred, false if timeout occurs
119
+ def wait_for_dom_mutation(timeout: 5)
120
+ start_time = Time.now
121
+ initial_dom = page.html
122
+ while Time.now - start_time < timeout
123
+ return true if page.html != initial_dom
124
+
125
+ sleep 0.1
126
+ end
127
+ false
128
+ end
129
+
130
+ # Drop #pause anywhere in a test to stop the execution.
131
+ # Useful when you want to checkout the contents of a web page in the middle of a test
132
+ # running in a headful mode.
133
+ def pause
134
+ # Cuprite-specific pause method
135
+ page.driver.pause
136
+ end
137
+
138
+ # Drop #browser_debug anywhere in a test to open a Chrome inspector and pause the execution
139
+ # Usage: browser_debug(binding)
140
+ def browser_debug(*)
141
+ # Cuprite-specific debug method
142
+ page.driver.debug
143
+ end
144
+
145
+ # Allows sending a list of CSS selectors to be clicked on in the correct order (no delay)
146
+ # Useful where you need to trigger e.g. a blur event on an input field
147
+ def click_on_selectors(*css_selectors)
148
+ css_selectors.each do |selector|
149
+ find(selector).click
150
+ sleep 0.1 # Add a small delay to allow JavaScript to run
151
+ end
152
+ end
153
+
154
+ # Wait for a field to have a specific value
155
+ # @param field_name [String] The field name or label
156
+ # @param value [String] The expected value
157
+ # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
158
+ def wait_for_field_value(field_name, value, timeout: 5)
159
+ start_time = Time.now
160
+ while Time.now - start_time < timeout
161
+ return true if page.has_field?(field_name, with: value)
162
+
163
+ sleep 0.1
164
+ end
165
+ false
166
+ end
167
+
168
+ # Safe methods that handle Ferrum NodeNotFoundError in CI
169
+ def safe_fill_in(locator, with:)
170
+ retries = 0
171
+ start_time = Time.now
172
+ max_duration = 5 # Maximum 5 seconds total
173
+
174
+ begin
175
+ fill_in locator, with: with
176
+ rescue Ferrum::NodeNotFoundError, Capybara::ElementNotFound => e
177
+ retries += 1
178
+ elapsed = Time.now - start_time
179
+
180
+ if retries <= 2 && elapsed < max_duration && ENV["GITHUB_ACTIONS"]
181
+ puts "[CI] Element not found on fill_in '#{locator}', retry #{retries}/2 (#{elapsed.round(1)}s elapsed)"
182
+ sleep 0.5
183
+ retry
184
+ else
185
+ puts "[CI] Giving up on fill_in '#{locator}' after #{retries} retries and #{elapsed.round(1)}s" if ENV["GITHUB_ACTIONS"]
186
+ raise e
187
+ end
188
+ end
189
+ end
190
+
191
+ def safe_select(value, from:)
192
+ retries = 0
193
+ start_time = Time.now
194
+ max_duration = 5 # Maximum 5 seconds total
195
+
196
+ begin
197
+ select value, from: from
198
+ rescue Ferrum::NodeNotFoundError, Capybara::ElementNotFound => e
199
+ retries += 1
200
+ elapsed = Time.now - start_time
201
+
202
+ if retries <= 2 && elapsed < max_duration && ENV["GITHUB_ACTIONS"]
203
+ puts "[CI] Element not found on select '#{value}' from '#{from}', retry #{retries}/2 (#{elapsed.round(1)}s elapsed)"
204
+ sleep 0.5
205
+ retry
206
+ else
207
+ puts "[CI] Giving up on select '#{value}' from '#{from}' after #{retries} retries and #{elapsed.round(1)}s" if ENV["GITHUB_ACTIONS"]
208
+ raise e
209
+ end
210
+ end
211
+ end
212
+
213
+ def safe_click_button(locator)
214
+ retries = 0
215
+ start_time = Time.now
216
+ max_duration = 5 # Maximum 5 seconds total
217
+
218
+ begin
219
+ click_button locator
220
+ rescue Ferrum::NodeNotFoundError, Capybara::ElementNotFound => e
221
+ retries += 1
222
+ elapsed = Time.now - start_time
223
+
224
+ if retries <= 2 && elapsed < max_duration && ENV["GITHUB_ACTIONS"]
225
+ puts "[CI] Element not found on click_button '#{locator}', retry #{retries}/2 (#{elapsed.round(1)}s elapsed)"
226
+ sleep 0.5
227
+ retry
228
+ else
229
+ puts "[CI] Giving up on click_button '#{locator}' after #{retries} retries and #{elapsed.round(1)}s" if ENV["GITHUB_ACTIONS"]
230
+ raise e
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
@@ -24,10 +24,10 @@ module Panda
24
24
  inspector: ENV["INSPECTOR"].in?(%w[y 1 yes true]),
25
25
  headless: !ENV["HEADLESS"].in?(%w[n 0 no false]),
26
26
  slowmo: ENV["SLOWMO"]&.to_f || 0,
27
- timeout: 10,
27
+ timeout: ENV["CUPRITE_TIMEOUT"]&.to_i || 2,
28
28
  js_errors: true, # IMPORTANT: Report JavaScript errors as test failures
29
29
  ignore_default_browser_options: false,
30
- process_timeout: 2,
30
+ process_timeout: ENV["CUPRITE_PROCESS_TIMEOUT"]&.to_i || 2,
31
31
  wait_for_network_idle: false, # Don't wait for all network requests
32
32
  pending_connection_errors: false, # Don't fail on pending external connections
33
33
  browser_options: {
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "cuprite_helpers"
4
+ require_relative "better_system_tests"
5
+
3
6
  # Generic system test helpers for Cuprite-based testing
4
7
  # These methods work for any Rails application using Cuprite
5
8
 
@@ -7,134 +10,8 @@ module Panda
7
10
  module Core
8
11
  module Testing
9
12
  module SystemTestHelpers
10
- # Make failure screenshots compatible with multi-session setup
11
- def take_screenshot
12
- return super unless Capybara.last_used_session
13
-
14
- Capybara.using_session(Capybara.last_used_session) { super }
15
- end
16
-
17
- # Ensure page is loaded and stable before interacting
18
- def ensure_page_loaded
19
- # Check if we're on about:blank
20
- current_url = begin
21
- page.current_url
22
- rescue
23
- "unknown"
24
- end
25
-
26
- if current_url.include?("about:blank")
27
- puts "[CI] Page is on about:blank, skipping recovery to avoid loops" if ENV["GITHUB_ACTIONS"]
28
- return false
29
- end
30
-
31
- # Wait for page to be ready
32
- wait_for_ready_state
33
- true
34
- end
35
-
36
- # Wait for document ready state
37
- def wait_for_ready_state
38
- Timeout.timeout(5) do
39
- loop do
40
- ready = page.evaluate_script("document.readyState")
41
- break if ready == "complete"
42
-
43
- sleep 0.1
44
- end
45
- end
46
- rescue Timeout::Error
47
- puts "[CI] Timeout waiting for document ready state" if ENV["GITHUB_ACTIONS"]
48
- end
49
-
50
- # Waits for a specific selector to be present and visible
51
- # @param selector [String] CSS selector to wait for
52
- # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
53
- # @return [Boolean] true if element is found, false if timeout occurs
54
- def wait_for_selector(selector, timeout: 5)
55
- start_time = Time.now
56
- while Time.now - start_time < timeout
57
- return true if page.has_css?(selector, visible: true)
58
-
59
- sleep 0.1
60
- end
61
- false
62
- end
63
-
64
- # Waits for a specific text to be present on the page
65
- # @param text [String] Text to wait for
66
- # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
67
- # @return [Boolean] true if text is found, false if timeout occurs
68
- def wait_for_text(text, timeout: 5)
69
- start_time = Time.now
70
- while Time.now - start_time < timeout
71
- return true if page.has_text?(text)
72
-
73
- sleep 0.1
74
- end
75
- false
76
- end
77
-
78
- # Waits for network requests to complete
79
- # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
80
- # @return [Boolean] true if network is idle, false if timeout occurs
81
- def wait_for_network_idle(timeout: 5)
82
- page.driver.wait_for_network_idle(timeout: timeout)
83
- true
84
- rescue => e
85
- puts "[CI] Network idle timeout: #{e.message}" if ENV["GITHUB_ACTIONS"]
86
- false
87
- end
88
-
89
- # Waits for JavaScript to modify the DOM
90
- # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
91
- # @return [Boolean] true if mutation occurred, false if timeout occurs
92
- def wait_for_dom_mutation(timeout: 5)
93
- start_time = Time.now
94
- initial_dom = page.html
95
- while Time.now - start_time < timeout
96
- return true if page.html != initial_dom
97
-
98
- sleep 0.1
99
- end
100
- false
101
- end
102
-
103
- # Drop #pause anywhere in a test to stop the execution
104
- # Useful when you want to check out the contents of a web page in the middle of a test
105
- # running in a headful mode
106
- def pause
107
- page.driver.pause
108
- end
109
-
110
- # Drop #browser_debug anywhere in a test to open a Chrome inspector and pause the execution
111
- # Usage: browser_debug(binding)
112
- def browser_debug(*)
113
- page.driver.debug
114
- end
115
-
116
- # Allows sending a list of CSS selectors to be clicked on in the correct order (no delay)
117
- # Useful where you need to trigger e.g. a blur event on an input field
118
- def click_on_selectors(*css_selectors)
119
- css_selectors.each do |selector|
120
- find(selector).click
121
- sleep 0.1 # Add a small delay to allow JavaScript to run
122
- end
123
- end
124
-
125
- # Wait for a field to have a specific value
126
- # @param field_name [String] The field name or label
127
- # @param value [String] The expected value
128
- # @param timeout [Integer] Maximum time to wait in seconds (default: 5)
129
- def wait_for_field_value(field_name, value, timeout: 5)
130
- start_time = Time.now
131
- while Time.now - start_time < timeout
132
- return true if page.has_field?(field_name, with: value)
133
-
134
- sleep 0.1
135
- end
136
- false
137
- end
13
+ include CupriteHelpers
14
+ include BetterSystemTests
138
15
  end
139
16
  end
140
17
  end
@@ -144,8 +21,7 @@ end
144
21
  RSpec.configure do |config|
145
22
  config.include Panda::Core::Testing::SystemTestHelpers, type: :system
146
23
 
147
- # Make URLs in mailers contain the correct server host
148
- # This is required for testing links in emails (e.g., via capybara-email)
24
+ # Make urls in mailers contain the correct server host
149
25
  config.around(:each, type: :system) do |ex|
150
26
  was_host = Rails.application.default_url_options[:host]
151
27
  Rails.application.default_url_options[:host] = Capybara.server_host
@@ -154,7 +30,6 @@ RSpec.configure do |config|
154
30
  end
155
31
 
156
32
  # Make sure this hook runs before others
157
- # Means you don't have to set js: true in every system spec
158
33
  config.prepend_before(:each, type: :system) do
159
34
  driven_by :cuprite
160
35
  end
@@ -169,7 +44,7 @@ RSpec.configure do |config|
169
44
  puts "[CI] Current URL: #{begin
170
45
  page.current_url
171
46
  rescue
172
- "unknown"
47
+ ""
173
48
  end}"
174
49
  raise e
175
50
  end
@@ -190,22 +65,31 @@ RSpec.configure do |config|
190
65
  nil
191
66
  end
192
67
 
193
- sleep 0.5 # Wait for DOM to be ready
68
+ sleep 0.5
194
69
 
195
70
  # Get comprehensive page info
196
71
  page_html = begin
197
72
  page.html
198
73
  rescue
199
- "<html><body>Error loading page</body></html>"
74
+ ""
75
+ end
76
+ current_url = begin
77
+ page.current_url
78
+ rescue
79
+ ""
80
+ end
81
+ current_path = begin
82
+ page.current_path
83
+ rescue
84
+ ""
200
85
  end
201
-
202
86
  page_title = begin
203
87
  page.title
204
88
  rescue
205
- "N/A"
89
+ ""
206
90
  end
207
91
 
208
- # Warn about minimal page content
92
+ # Check for redirect or blank page indicators
209
93
  if page_html.length < 100
210
94
  puts "Warning: Page content appears minimal (#{page_html.length} chars) when taking screenshot"
211
95
  end
@@ -214,11 +98,13 @@ RSpec.configure do |config|
214
98
  screenshot_path = Capybara.save_screenshot
215
99
  if screenshot_path
216
100
  puts "Screenshot saved to: #{screenshot_path}"
217
- puts "Page title: #{page_title}"
101
+ puts "Page title: #{page_title}" if page_title.present?
102
+ puts "Current URL: #{current_url}" if current_url.present?
103
+ puts "Current path: #{current_path}" if current_path.present?
218
104
  puts "Page content length: #{page_html.length} characters"
219
105
 
220
106
  # Save page HTML for debugging in CI
221
- if ENV["GITHUB_ACTIONS"]
107
+ if ENV["GITHUB_ACTIONS"] && page_html.present?
222
108
  html_debug_path = screenshot_path.gsub(".png", ".html")
223
109
  File.write(html_debug_path, page_html)
224
110
  puts "Page HTML saved to: #{html_debug_path}"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Panda
4
4
  module Core
5
- VERSION = "0.8.3"
5
+ VERSION = "0.8.4"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Otaina Limited
@@ -505,7 +505,9 @@ files:
505
505
  - lib/panda/core/testing/support/omniauth_setup.rb
506
506
  - lib/panda/core/testing/support/service_stubs.rb
507
507
  - lib/panda/core/testing/support/setup.rb
508
+ - lib/panda/core/testing/support/system/better_system_tests.rb
508
509
  - lib/panda/core/testing/support/system/capybara_setup.rb
510
+ - lib/panda/core/testing/support/system/cuprite_helpers.rb
509
511
  - lib/panda/core/testing/support/system/cuprite_setup.rb
510
512
  - lib/panda/core/testing/support/system/database_connection_helpers.rb
511
513
  - lib/panda/core/testing/support/system/system_test_helpers.rb