Class: Capybara::Playwright::Browser

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
TmpdirOwner
Defined in:
lib/capybara/playwright/browser.rb

Overview

Responsibility of this class is:

  • Handling Capybara::Driver commands.
  • Managing Playwright browser contexts and pages.

Note that this class doesn't manage Playwright::Browser. We should not use Playwright::Browser#close in this class.

Defined Under Namespace

Classes: NoSuchWindowError

Instance Method Summary collapse

Methods included from TmpdirOwner

#remove_tmpdir, #tmpdir

Constructor Details

#initialize(driver:, internal_logger:, playwright_browser:, page_options:, record_video: false, callback_on_save_trace: nil, default_timeout: nil, default_navigation_timeout: nil) ⇒ Browser

Returns a new instance of Browser.



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/capybara/playwright/browser.rb', line 18

def initialize(driver:, internal_logger:, playwright_browser:, page_options:, record_video: false, callback_on_save_trace: nil, default_timeout: nil, default_navigation_timeout: nil)
  @driver = driver
  @internal_logger = internal_logger
  @playwright_browser = playwright_browser
  @page_options = page_options
  if record_video
    @page_options[:record_video_dir] ||= tmpdir
  end
  @callback_on_save_trace = callback_on_save_trace
  @default_timeout = default_timeout
  @default_navigation_timeout = default_navigation_timeout
  @playwright_page = create_page(create_browser_context)
end

Instance Method Details

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



380
381
382
383
384
# File 'lib/capybara/playwright/browser.rb', line 380

def accept_modal(dialog_type, **options, &block)
  assert_page_alive {
    @playwright_page.capybara_accept_modal(dialog_type, **options, &block)
  }
end

#active_elementObject



200
201
202
203
204
205
206
207
# File 'lib/capybara/playwright/browser.rb', line 200

def active_element
  el = @playwright_page.capybara_current_frame.evaluate_handle('() => document.activeElement')
  if el
    Node.new(@driver, @internal_logger, @playwright_page, el)
  else
    nil
  end
end

#clear_browser_contextsObject



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/capybara/playwright/browser.rb', line 58

def clear_browser_contexts
  if @callback_on_save_trace
    @playwright_browser.contexts.each do |browser_context|
      filename = SecureRandom.hex(8)
      zip_path = File.join(tmpdir, "#{filename}.zip")
      browser_context.tracing.stop(path: zip_path)
      @callback_on_save_trace.call(zip_path)
    end
  end
  @playwright_browser.contexts.each(&:close)
end

#close_window(handle) ⇒ Object



320
321
322
323
324
325
326
327
328
# File 'lib/capybara/playwright/browser.rb', line 320

def close_window(handle)
  on_window(handle) do |page|
    page.close

    if @playwright_page&.guid == handle
      @playwright_page = nil
    end
  end
end

#current_urlObject



70
71
72
73
74
# File 'lib/capybara/playwright/browser.rb', line 70

def current_url
  assert_page_alive {
    @playwright_page.url
  }
end

#current_window_handleObject



288
289
290
# File 'lib/capybara/playwright/browser.rb', line 288

def current_window_handle
  @playwright_page&.guid
end

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



386
387
388
389
390
# File 'lib/capybara/playwright/browser.rb', line 386

def dismiss_modal(dialog_type, **options, &block)
  assert_page_alive {
    @playwright_page.capybara_dismiss_modal(dialog_type, **options, &block)
  }
end

#evaluate_async_script(script, *args) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/capybara/playwright/browser.rb', line 184

def evaluate_async_script(script, *args)
  assert_page_alive {
    js = <<~JAVASCRIPT
    function(_arguments){
      let args = Array.prototype.slice.call(_arguments);
      return new Promise((resolve, reject) => {
        args.push(resolve);
        (function(){ #{script} }).apply(this, args);
      });
    }
    JAVASCRIPT
    result = @playwright_page.capybara_current_frame.evaluate_handle(js, arg: unwrap_node(args))
    wrap_node(result)
  }
end

#evaluate_script(script, *args) ⇒ Object



177
178
179
180
181
182
# File 'lib/capybara/playwright/browser.rb', line 177

def evaluate_script(script, *args)
  assert_page_alive {
    result = @playwright_page.capybara_current_frame.evaluate_handle("function (arguments) { return #{script} }", arg: unwrap_node(args))
    wrap_node(result)
  }
end

#execute_script(script, *args) ⇒ Object



170
171
172
173
174
175
# File 'lib/capybara/playwright/browser.rb', line 170

def execute_script(script, *args)
  assert_page_alive {
    @playwright_page.capybara_current_frame.evaluate("function (arguments) { #{script} }", arg: unwrap_node(args))
  }
  nil
end

#find_css(query, **options) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/capybara/playwright/browser.rb', line 116

def find_css(query, **options)
  assert_page_alive {
    @playwright_page.capybara_current_frame.query_selector_all(query).map do |el|
      Node.new(@driver, @internal_logger, @playwright_page, el)
    end
  }
end

#find_xpath(query, **options) ⇒ Object



108
109
110
111
112
113
114
# File 'lib/capybara/playwright/browser.rb', line 108

def find_xpath(query, **options)
  assert_page_alive {
    @playwright_page.capybara_current_frame.query_selector_all("xpath=#{query}").map do |el|
      Node.new(@driver, @internal_logger, @playwright_page, el)
    end
  }
end

#fullscreen_window(handle) ⇒ Object



371
372
373
374
375
376
377
378
# File 'lib/capybara/playwright/browser.rb', line 371

def fullscreen_window(handle)
  @internal_logger.warn("fullscreen_window is not supported in Playwright driver")
  # incomplete in Playwright
  # ref: https://github.com/twalpole/apparition/blob/11aca464b38b77585191b7e302be2e062bdd369d/lib/capybara/apparition/page.rb#L341
  on_window(handle) do |page|
    page.evaluate('() => document.body.requestFullscreen()')
  end
end

#go_backObject



156
157
158
159
160
161
# File 'lib/capybara/playwright/browser.rb', line 156

def go_back
  assert_page_alive {
    response = @playwright_page.go_back
    @playwright_page.capybara_set_last_response(response)
  }
end

#go_forwardObject



163
164
165
166
167
168
# File 'lib/capybara/playwright/browser.rb', line 163

def go_forward
  assert_page_alive {
    response = @playwright_page.go_forward
    @playwright_page.capybara_set_last_response(response)
  }
end

#htmlObject



136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/capybara/playwright/browser.rb', line 136

def html
  assert_page_alive {
    js = <<~JAVASCRIPT
    () => {
      let html = '';
      if (document.doctype) html += new XMLSerializer().serializeToString(document.doctype);
      if (document.documentElement) html += document.documentElement.outerHTML;
      return html;
    }
    JAVASCRIPT
    @playwright_page.capybara_current_frame.evaluate(js)
  }
end

#maximize_window(handle) ⇒ Object



361
362
363
364
365
366
367
368
369
# File 'lib/capybara/playwright/browser.rb', line 361

def maximize_window(handle)
  @internal_logger.warn("maximize_window is not supported in Playwright driver")
  # incomplete in Playwright
  # ref: https://github.com/twalpole/apparition/blob/11aca464b38b77585191b7e302be2e062bdd369d/lib/capybara/apparition/page.rb#L346
  on_window(handle) do |page|
    screen_size = page.evaluate('() => ({ width: window.screen.width, height: window.screen.height})')
    page.viewport_size = screen_size
  end
end

#open_new_window(kind = :tab) ⇒ Object



292
293
294
295
296
297
298
299
300
301
# File 'lib/capybara/playwright/browser.rb', line 292

def open_new_window(kind = :tab)
  browser_context =
    if kind == :tab
      @playwright_page&.context || create_browser_context
    else
      create_browser_context
    end

  create_page(browser_context)
end

#raw_screenshot(**options) ⇒ Object

Not used by Capybara::Session. Intended to be directly called by user.



219
220
221
222
223
# File 'lib/capybara/playwright/browser.rb', line 219

def raw_screenshot(**options)
  return nil if !@playwright_page || @playwright_page.closed?

  @playwright_page.screenshot(**options)
end

#refreshObject



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/capybara/playwright/browser.rb', line 96

def refresh
  if firefox?
    # ref: https://github.com/microsoft/playwright/issues/39738
    @playwright_page.capybara_current_frame.evaluate('() => { location.reload(true) }')
  else
    assert_page_alive {
      response = @playwright_page.reload
      @playwright_page.capybara_set_last_response(response)
    }
  end
end

#resize_window_to(handle, width, height) ⇒ Object



336
337
338
339
340
# File 'lib/capybara/playwright/browser.rb', line 336

def resize_window_to(handle, width, height)
  on_window(handle) do |page|
    page.viewport_size = viewport_size_for(page, width, height)
  end
end

#response_headersObject



124
125
126
127
128
# File 'lib/capybara/playwright/browser.rb', line 124

def response_headers
  assert_page_alive {
    @playwright_page.capybara_response_headers
  }
end

#save_screenshot(path, **options) ⇒ Object



225
226
227
228
229
# File 'lib/capybara/playwright/browser.rb', line 225

def save_screenshot(path, **options)
  assert_page_alive {
    @playwright_page.screenshot(path: path)
  }
end

#send_keys(*args) ⇒ Object



231
232
233
# File 'lib/capybara/playwright/browser.rb', line 231

def send_keys(*args)
  Node::SendKeys.new(@playwright_page.keyboard, args).execute
end

#status_codeObject



130
131
132
133
134
# File 'lib/capybara/playwright/browser.rb', line 130

def status_code
  assert_page_alive {
    @playwright_page.capybara_status_code
  }
end

#switch_to_frame(frame) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/capybara/playwright/browser.rb', line 235

def switch_to_frame(frame)
  assert_page_alive {
    case frame
    when :top
      @playwright_page.capybara_reset_frames
    when :parent
      @playwright_page.capybara_pop_frame
    else
      playwright_frame = frame.native.content_frame
      raise ArgumentError.new("Not a frame element: #{frame}") unless playwright_frame
      @playwright_page.capybara_push_frame(playwright_frame)
    end
  }
end

#switch_to_window(handle) ⇒ Object



312
313
314
315
316
317
318
# File 'lib/capybara/playwright/browser.rb', line 312

def switch_to_window(handle)
  if @playwright_page&.guid != handle
    on_window(handle) do |page|
      @playwright_page = page.tap(&:bring_to_front)
    end
  end
end

#titleObject



150
151
152
153
154
# File 'lib/capybara/playwright/browser.rb', line 150

def title
  assert_page_alive {
    @playwright_page.title
  }
end

#video_pathObject

Not used by Capybara::Session. Intended to be directly called by user.



211
212
213
214
215
# File 'lib/capybara/playwright/browser.rb', line 211

def video_path
  return nil if !@playwright_page || @playwright_page.closed?

  @playwright_page.video&.path
end

#visit(path) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/capybara/playwright/browser.rb', line 76

def visit(path)
  assert_page_alive {
    url =
    if Capybara.app_host
      Addressable::URI.parse(Capybara.app_host) + path
    elsif Capybara.default_host
      Addressable::URI.parse(Capybara.default_host) + path
    else
      path
    end

    response = @playwright_page.capybara_current_frame.goto(url)
    @playwright_page.capybara_set_last_response(response)
  }
end

#window_handlesObject



284
285
286
# File 'lib/capybara/playwright/browser.rb', line 284

def window_handles
  pages.map(&:guid)
end

#window_size(handle) ⇒ Object



330
331
332
333
334
# File 'lib/capybara/playwright/browser.rb', line 330

def window_size(handle)
  on_window(handle) do |page|
    outer_window_size(page)
  end
end

#with_playwright_page(&block) ⇒ Object



438
439
440
441
442
# File 'lib/capybara/playwright/browser.rb', line 438

def with_playwright_page(&block)
  assert_page_alive {
    block.call(@playwright_page)
  }
end