Class: Capybara::Lightpanda::Driver
- Inherits:
-
Driver::Base
- Object
- Driver::Base
- Capybara::Lightpanda::Driver
- Extended by:
- Forwardable
- Defined in:
- lib/capybara/lightpanda/driver.rb
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
Returns the value of attribute app.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
-
#accept_modal(type, **options, &block) ⇒ Object
find_modal owns the wait default (browser.options.timeout) — pass wait only when the caller overrode it.
- #active_element ⇒ Object
- #add_headers(headers) ⇒ Object
- #browser ⇒ Object
- #browser_alive? ⇒ Boolean
- #clear_cookies ⇒ Object
- #dismiss_modal(type, **options, &block) ⇒ Object
- #evaluate_async_script(script, *args) ⇒ Object
- #evaluate_script(script, *args) ⇒ Object
- #execute_script(script, *args) ⇒ Object
- #find_css(selector) ⇒ Object
- #find_xpath(selector) ⇒ Object
- #go_back ⇒ Object
- #go_forward ⇒ Object
-
#headers ⇒ Object
– Headers (Cuprite-compatible driver surface) – Delegates to Network, which lazily enables the Network domain and remembers the headers across reset.
- #headers=(headers) ⇒ Object
- #html ⇒ Object (also: #body)
-
#initialize(app, options = {}) ⇒ Driver
constructor
A new instance of Driver.
-
#invalid_element_errors ⇒ Object
Expanded error list for Capybara retry logic (Cuprite pattern).
- #needs_server? ⇒ Boolean
-
#network ⇒ Object
Network tracker (lazily auto-enabled).
-
#pause ⇒ Object
Pause execution for interactive debugging.
- #quit ⇒ Object
- #refresh ⇒ Object
- #remove_cookie(name) ⇒ Object
-
#reset! ⇒ Object
Thin Cuprite-style wrapper.
-
#save_screenshot(path, **_options) ⇒ Object
(also: #render)
– Screenshots – Lightpanda has no rendering engine so screenshots are blank, but we handle the call gracefully so Rails’ before_teardown (screenshot on failure) doesn’t raise NotSupportedByDriverError.
-
#send_keys(*keys) ⇒ Object
Capybara’s Session#send_keys routes to Driver#send_keys; Cuprite’s pattern is to fan that out to whatever element currently has focus.
-
#set_cookie(name, value, **options) ⇒ Object
– Cookie Management –.
-
#switch_to_frame(frame) ⇒ Object
– Frame Support – Passes Node objects (with remote_object_id) to Browser’s frame stack.
- #visit(url) ⇒ Object
- #wait? ⇒ Boolean
-
#wait_for_network_idle(timeout: 5, connections: 0) ⇒ Object
Block until in-flight HTTP traffic settles.
-
#with_lightpanda_browser(&block) ⇒ Object
Escape hatch to the underlying Browser for callers that need raw CDP access — e.g.
Constructor Details
#initialize(app, options = {}) ⇒ Driver
Returns a new instance of Driver.
15 16 17 18 19 20 21 |
# File 'lib/capybara/lightpanda/driver.rb', line 15 def initialize(app, = {}) super() @app = app @options = @browser = nil @started = false end |
Instance Attribute Details
#app ⇒ Object (readonly)
Returns the value of attribute app.
11 12 13 |
# File 'lib/capybara/lightpanda/driver.rb', line 11 def app @app end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
11 12 13 |
# File 'lib/capybara/lightpanda/driver.rb', line 11 def @options end |
Instance Method Details
#accept_modal(type, **options, &block) ⇒ Object
find_modal owns the wait default (browser.options.timeout) — pass wait only when the caller overrode it.
165 166 167 168 169 |
# File 'lib/capybara/lightpanda/driver.rb', line 165 def accept_modal(type, **, &block) browser.accept_modal(type, text: [:with]) block&.call browser.find_modal(type, **{ text: [:text], wait: [:wait] }.compact) end |
#active_element ⇒ Object
70 71 72 73 |
# File 'lib/capybara/lightpanda/driver.rb', line 70 def active_element oid = browser.active_element oid && Node.new(self, oid) end |
#add_headers(headers) ⇒ Object
211 212 213 |
# File 'lib/capybara/lightpanda/driver.rb', line 211 def add_headers(headers) browser.network.add_headers(headers) end |
#browser ⇒ Object
23 24 25 26 |
# File 'lib/capybara/lightpanda/driver.rb', line 23 def browser @browser = nil if @browser && !browser_alive? @browser ||= Browser.new(@options) end |
#browser_alive? ⇒ Boolean
28 29 30 |
# File 'lib/capybara/lightpanda/driver.rb', line 28 def browser_alive? !@browser.nil? && @browser.alive? end |
#clear_cookies ⇒ Object
135 136 137 |
# File 'lib/capybara/lightpanda/driver.rb', line 135 def browser..clear end |
#dismiss_modal(type, **options, &block) ⇒ Object
171 172 173 174 175 |
# File 'lib/capybara/lightpanda/driver.rb', line 171 def dismiss_modal(type, **, &block) browser.dismiss_modal(type) block&.call browser.find_modal(type, **{ text: [:text], wait: [:wait] }.compact) end |
#evaluate_async_script(script, *args) ⇒ Object
100 101 102 |
# File 'lib/capybara/lightpanda/driver.rb', line 100 def evaluate_async_script(script, *args) unwrap_script_result(browser.evaluate_async(script.strip, *native_args(args))) end |
#evaluate_script(script, *args) ⇒ Object
91 92 93 |
# File 'lib/capybara/lightpanda/driver.rb', line 91 def evaluate_script(script, *args) unwrap_script_result(browser.evaluate(script.strip, *native_args(args))) end |
#execute_script(script, *args) ⇒ Object
95 96 97 98 |
# File 'lib/capybara/lightpanda/driver.rb', line 95 def execute_script(script, *args) browser.execute(script.strip, *native_args(args)) nil end |
#find_css(selector) ⇒ Object
86 87 88 89 |
# File 'lib/capybara/lightpanda/driver.rb', line 86 def find_css(selector) object_ids = browser.find("css", selector) object_ids.map { |oid| Node.new(self, oid) } end |
#find_xpath(selector) ⇒ Object
81 82 83 84 |
# File 'lib/capybara/lightpanda/driver.rb', line 81 def find_xpath(selector) object_ids = browser.find("xpath", selector) object_ids.map { |oid| Node.new(self, oid) } end |
#go_back ⇒ Object
53 54 55 |
# File 'lib/capybara/lightpanda/driver.rb', line 53 def go_back browser.back end |
#go_forward ⇒ Object
57 58 59 |
# File 'lib/capybara/lightpanda/driver.rb', line 57 def go_forward browser.forward end |
#headers ⇒ Object
– Headers (Cuprite-compatible driver surface) – Delegates to Network, which lazily enables the Network domain and remembers the headers across reset. Cuprite exposes these on the driver, and real suites call them there (page.driver.headers = …).
203 204 205 |
# File 'lib/capybara/lightpanda/driver.rb', line 203 def headers browser.network.extra_headers end |
#headers=(headers) ⇒ Object
207 208 209 |
# File 'lib/capybara/lightpanda/driver.rb', line 207 def headers=(headers) browser.network.headers = headers end |
#html ⇒ Object Also known as: body
65 66 67 |
# File 'lib/capybara/lightpanda/driver.rb', line 65 def html browser.body end |
#invalid_element_errors ⇒ Object
Expanded error list for Capybara retry logic (Cuprite pattern). MouseEventFailed is in Cuprite’s list, but Lightpanda has no rendering engine and the gem dispatches clicks through JS — the underlying CDP Input.dispatchMouseEvent path doesn’t run, so MouseEventFailed is never raised.
254 255 256 257 258 259 260 |
# File 'lib/capybara/lightpanda/driver.rb', line 254 def invalid_element_errors [ NodeNotFoundError, NoExecutionContextError, ObsoleteNode, ] end |
#needs_server? ⇒ Boolean
241 242 243 |
# File 'lib/capybara/lightpanda/driver.rb', line 241 def needs_server? true end |
#network ⇒ Object
Network tracker (lazily auto-enabled). Exposes ‘traffic`, `clear`, `wait_for_idle`, header overrides, etc. Cuprite parity.
108 109 110 |
# File 'lib/capybara/lightpanda/driver.rb', line 108 def network browser.network end |
#pause ⇒ Object
Pause execution for interactive debugging.
263 264 265 266 267 268 269 270 271 272 |
# File 'lib/capybara/lightpanda/driver.rb', line 263 def pause if $stdin.tty? warn "\nPaused. Press Enter to continue." $stdin.gets else warn "\nPaused. Send SIGCONT (kill -CONT #{::Process.pid}) to continue." trap("CONT") {} # rubocop:disable Lint/EmptyBlock ::Process.kill("STOP", ::Process.pid) end end |
#quit ⇒ Object
236 237 238 239 |
# File 'lib/capybara/lightpanda/driver.rb', line 236 def quit @browser&.quit @browser = nil end |
#refresh ⇒ Object
61 62 63 |
# File 'lib/capybara/lightpanda/driver.rb', line 61 def refresh browser.refresh end |
#remove_cookie(name) ⇒ Object
139 140 141 |
# File 'lib/capybara/lightpanda/driver.rb', line 139 def (name, **) browser..remove(name: name, **) end |
#reset! ⇒ Object
Thin Cuprite-style wrapper. The interesting work — disposing the BrowserContext (cookies, storage, all targets) and starting a fresh one — happens in Browser#reset.
Rescue is the gem hierarchy plus raw IO escapees only — NOT StandardError: reset! runs between every test, so a blanket rescue turns programmer errors (e.g. a NoMethodError in browser.rb) into a silent quit-and-respawn on every example with zero signal. The warn keeps repeated respawns visible.
226 227 228 229 230 231 232 233 234 |
# File 'lib/capybara/lightpanda/driver.rb', line 226 def reset! browser.reset rescue Error, SystemCallError, IOError => e warn "[capybara-lightpanda] reset! failed (#{e.class}: #{e.}); respawning browser" @browser&.quit @browser = nil ensure @started = false end |
#save_screenshot(path, **_options) ⇒ Object Also known as: render
– Screenshots – Lightpanda has no rendering engine so screenshots are blank, but we handle the call gracefully so Rails’ before_teardown (screenshot on failure) doesn’t raise NotSupportedByDriverError.
182 183 184 185 186 187 188 189 190 |
# File 'lib/capybara/lightpanda/driver.rb', line 182 def save_screenshot(path, **) browser.screenshot(path: path) rescue BinaryError, BinaryNotFoundError, BrowserError, TimeoutError # Browser can't start (version too old), is already dead (DeadBrowserError), # the CDP call timed out, or returned any other CDP-level error. Teardown # screenshots are best-effort — swallow so the real test failure surfaces # instead of a "browser already gone" stack trace. nil end |
#send_keys(*keys) ⇒ Object
Capybara’s Session#send_keys routes to Driver#send_keys; Cuprite’s pattern is to fan that out to whatever element currently has focus.
77 78 79 |
# File 'lib/capybara/lightpanda/driver.rb', line 77 def send_keys(*keys) active_element&.send_keys(*keys) end |
#set_cookie(name, value, **options) ⇒ Object
– Cookie Management –
122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/capybara/lightpanda/driver.rb', line 122 def (name, value, **) = { domain: [:domain] || default_domain } [:path] = [:path] if [:path] [:secure] = [:secure] if .key?(:secure) if .key?(:httpOnly) || .key?(:http_only) [:http_only] = [:httpOnly] || [:http_only] end [:expires] = [:expires] if [:expires] browser..set(name: name, value: value, **) end |
#switch_to_frame(frame) ⇒ Object
– Frame Support – Passes Node objects (with remote_object_id) to Browser’s frame stack. callFunctionOn on the iframe element scopes finding to its contentDocument.
147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/capybara/lightpanda/driver.rb', line 147 def switch_to_frame(frame) case frame when :top browser.clear_frames when :parent browser.pop_frame when Node browser.push_frame(frame) else # Capybara passes a Capybara::Node::Element; extract our driver Node browser.push_frame(frame.base) end end |
#visit(url) ⇒ Object
48 49 50 51 |
# File 'lib/capybara/lightpanda/driver.rb', line 48 def visit(url) @started = true browser.go_to(url) end |
#wait? ⇒ Boolean
245 246 247 |
# File 'lib/capybara/lightpanda/driver.rb', line 245 def wait? true end |
#wait_for_network_idle(timeout: 5, connections: 0) ⇒ Object
Block until in-flight HTTP traffic settles. Auto-enables the tracker on first call so callers don’t have to remember to flip it on. Returns true on success, false on timeout.
115 116 117 118 |
# File 'lib/capybara/lightpanda/driver.rb', line 115 def wait_for_network_idle(timeout: 5, connections: 0) network.enable network.wait_for_idle(timeout: timeout, connections: connections) end |
#with_lightpanda_browser(&block) ⇒ Object
Escape hatch to the underlying Browser for callers that need raw CDP access — e.g. Lightpanda’s ‘LP.*` extensions (`getMarkdown`, `getSemanticTree`, `detectForms`, …) that aren’t worth exposing through the Capybara DSL. Mirrors ‘capybara-playwright-driver`’s ‘with_playwright_page`. Yields the Browser; returns whatever the block returns.
driver.with_lightpanda_browser do |browser|
browser.page_command("LP.getMarkdown")
end
42 43 44 45 46 |
# File 'lib/capybara/lightpanda/driver.rb', line 42 def with_lightpanda_browser(&block) raise ArgumentError, "block must be given" unless block block.call(browser) end |