Class: Capybara::Lightpanda::Driver

Inherits:
Driver::Base
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/capybara/lightpanda/driver.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ Driver

Returns a new instance of Driver.



14
15
16
17
18
19
# File 'lib/capybara/lightpanda/driver.rb', line 14

def initialize(app, options = {})
  super()
  @app = app
  @options = options
  @browser = nil
end

Instance Attribute Details

#appObject (readonly)

Returns the value of attribute app.



10
11
12
# File 'lib/capybara/lightpanda/driver.rb', line 10

def app
  @app
end

#optionsObject (readonly)

Returns the value of attribute options.



10
11
12
# File 'lib/capybara/lightpanda/driver.rb', line 10

def options
  @options
end

Instance Method Details

#accept_modal(type, **options, &block) ⇒ Object

– Modal/Dialog Support –



151
152
153
154
155
156
157
# File 'lib/capybara/lightpanda/driver.rb', line 151

def accept_modal(type, **options, &block)
  browser.accept_modal(type, text: options[:with])
  block&.call
  browser.find_modal(type,
                     text: options[:text],
                     wait: options.fetch(:wait, browser.options.timeout))
end

#active_elementObject



53
54
55
56
# File 'lib/capybara/lightpanda/driver.rb', line 53

def active_element
  oid = browser.active_element
  oid && Node.new(self, oid)
end

#browserObject



21
22
23
24
# File 'lib/capybara/lightpanda/driver.rb', line 21

def browser
  @browser = nil if @browser && !browser_alive?
  @browser ||= Browser.new(@options)
end

#browser_alive?Boolean

Returns:

  • (Boolean)


26
27
28
29
30
# File 'lib/capybara/lightpanda/driver.rb', line 26

def browser_alive?
  @browser.client && !@browser.client.closed?
rescue StandardError
  false
end

#clear_cookiesObject



103
104
105
# File 'lib/capybara/lightpanda/driver.rb', line 103

def clear_cookies
  browser.cookies.clear
end

#dismiss_modal(type, **options, &block) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/capybara/lightpanda/driver.rb', line 159

def dismiss_modal(type, **options, &block)
  browser.dismiss_modal(type)
  block&.call
  browser.find_modal(type,
                     text: options[:text],
                     wait: options.fetch(:wait, browser.options.timeout))
end

#evaluate_async_script(script, *args) ⇒ Object



83
84
85
# File 'lib/capybara/lightpanda/driver.rb', line 83

def evaluate_async_script(script, *args)
  unwrap_script_result(browser.evaluate_async(script.strip, *native_args(args)))
end

#evaluate_script(script, *args) ⇒ Object



74
75
76
# File 'lib/capybara/lightpanda/driver.rb', line 74

def evaluate_script(script, *args)
  unwrap_script_result(browser.evaluate(script.strip, *native_args(args)))
end

#execute_script(script, *args) ⇒ Object



78
79
80
81
# File 'lib/capybara/lightpanda/driver.rb', line 78

def execute_script(script, *args)
  browser.execute(script.strip, *native_args(args))
  nil
end

#find_css(selector) ⇒ Object



69
70
71
72
# File 'lib/capybara/lightpanda/driver.rb', line 69

def find_css(selector)
  object_ids = browser.find("css", selector)
  object_ids.map { |oid| Node.new(self, oid) }
end

#find_xpath(selector) ⇒ Object



64
65
66
67
# File 'lib/capybara/lightpanda/driver.rb', line 64

def find_xpath(selector)
  object_ids = browser.find("xpath", selector)
  object_ids.map { |oid| Node.new(self, oid) }
end

#frame_titleObject



141
142
143
144
145
146
147
# File 'lib/capybara/lightpanda/driver.rb', line 141

def frame_title
  frame = browser.frame_stack.last
  return browser.title unless frame

  browser.call_function_on(frame.remote_object_id,
                           "function() { return this.contentDocument.title }")
end

#frame_urlObject

Capybara::Driver::Base falls back to running these via the top execution context, which always reports the parent document. Resolve them through the iframe element’s contentWindow / contentDocument so they reflect the active frame.



133
134
135
136
137
138
139
# File 'lib/capybara/lightpanda/driver.rb', line 133

def frame_url
  frame = browser.frame_stack.last
  return browser.current_url unless frame

  browser.call_function_on(frame.remote_object_id,
                           "function() { return this.contentWindow.location.href }")
end

#go_backObject



36
37
38
# File 'lib/capybara/lightpanda/driver.rb', line 36

def go_back
  browser.back
end

#go_forwardObject



40
41
42
# File 'lib/capybara/lightpanda/driver.rb', line 40

def go_forward
  browser.forward
end

#htmlObject Also known as: body



48
49
50
# File 'lib/capybara/lightpanda/driver.rb', line 48

def html
  browser.body
end

#invalid_element_errorsObject

Expanded error list for Capybara retry logic (Cuprite pattern).



205
206
207
208
209
210
211
212
# File 'lib/capybara/lightpanda/driver.rb', line 205

def invalid_element_errors
  [
    NodeNotFoundError,
    NoExecutionContextError,
    ObsoleteNode,
    MouseEventFailed,
  ]
end

#needs_server?Boolean

Returns:

  • (Boolean)


196
197
198
# File 'lib/capybara/lightpanda/driver.rb', line 196

def needs_server?
  true
end

#pauseObject

Pause execution for interactive debugging.



215
216
217
218
219
220
221
222
223
224
# File 'lib/capybara/lightpanda/driver.rb', line 215

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

#quitObject



191
192
193
194
# File 'lib/capybara/lightpanda/driver.rb', line 191

def quit
  @browser&.quit
  @browser = nil
end

#refreshObject



44
45
46
# File 'lib/capybara/lightpanda/driver.rb', line 44

def refresh
  browser.refresh
end


107
108
109
# File 'lib/capybara/lightpanda/driver.rb', line 107

def remove_cookie(name, **)
  browser.cookies.remove(name: name, **)
end

#reset!Object

– Lifecycle –



181
182
183
184
185
186
187
188
189
# File 'lib/capybara/lightpanda/driver.rb', line 181

def reset!
  browser.clear_frames
  browser.reset_modals
  browser.cookies.clear
  browser.go_to("about:blank")
rescue StandardError
  @browser&.quit
  @browser = nil
end

#save_screenshot(path, **_options) ⇒ Object

– 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.



172
173
174
175
176
177
# File 'lib/capybara/lightpanda/driver.rb', line 172

def save_screenshot(path, **_options)
  browser.screenshot(path: path)
rescue BinaryError, BinaryNotFoundError
  # Browser can't start (e.g., version too old) — don't crash teardown
  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.



60
61
62
# File 'lib/capybara/lightpanda/driver.rb', line 60

def send_keys(*keys)
  active_element&.send_keys(*keys)
end

– Cookie Management –



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/capybara/lightpanda/driver.rb', line 89

def set_cookie(name, value, **options)
  cookie_options = {}
  cookie_options[:domain] = options[:domain] if options[:domain]
  cookie_options[:path] = options[:path] if options[:path]
  cookie_options[:secure] = options[:secure] if options.key?(:secure)
  if options.key?(:httpOnly) || options.key?(:http_only)
    cookie_options[:http_only] =
      options[:httpOnly] || options[:http_only]
  end
  cookie_options[:expires] = options[:expires] if options[:expires]

  browser.cookies.set(name: name, value: value, **cookie_options)
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.



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/capybara/lightpanda/driver.rb', line 115

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



32
33
34
# File 'lib/capybara/lightpanda/driver.rb', line 32

def visit(url)
  browser.go_to(url)
end

#wait?Boolean

Returns:

  • (Boolean)


200
201
202
# File 'lib/capybara/lightpanda/driver.rb', line 200

def wait?
  true
end