class Capybara::Playwright::Browser

Responsibility of this class is:

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

Public Class Methods

new(driver:, playwright_browser:, page_options:, record_video: false) click to toggle source
# File lib/capybara/playwright/browser.rb, line 17
def initialize(driver:, playwright_browser:, page_options:, record_video: false)
  @driver = driver
  @playwright_browser = playwright_browser
  @page_options = page_options
  if record_video
    @page_options[:record_video_dir] ||= tmpdir
  end
  @playwright_page = create_page(create_browser_context)
end

Public Instance Methods

accept_modal(dialog_type, **options, &block) click to toggle source
# File lib/capybara/playwright/browser.rb, line 296
def accept_modal(dialog_type, **options, &block)
  assert_page_alive

  @playwright_page.capybara_accept_modal(dialog_type, **options, &block)
end
clear_browser_contexts() click to toggle source
# File lib/capybara/playwright/browser.rb, line 47
def clear_browser_contexts
  @playwright_browser.contexts.each(&:close)
end
close_window(handle) click to toggle source
# File lib/capybara/playwright/browser.rb, line 255
def close_window(handle)
  on_window(handle) do |page|
    page.close

    if @playwright_page&.guid == handle
      @playwright_page = nil
    end
  end
end
current_url() click to toggle source
# File lib/capybara/playwright/browser.rb, line 51
def current_url
  assert_page_alive

  @playwright_page.url
end
current_window_handle() click to toggle source
# File lib/capybara/playwright/browser.rb, line 223
def current_window_handle
  @playwright_page&.guid
end
dismiss_modal(dialog_type, **options, &block) click to toggle source
# File lib/capybara/playwright/browser.rb, line 302
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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 152
      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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 145
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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 138
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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 86
def find_css(query, **options)
  assert_page_alive

  @playwright_page.capybara_current_frame.query_selector_all(query).map do |el|
    Node.new(@driver, @playwright_page, el)
  end
end
find_xpath(query, **options) click to toggle source
# File lib/capybara/playwright/browser.rb, line 78
def find_xpath(query, **options)
  assert_page_alive

  @playwright_page.capybara_current_frame.query_selector_all("xpath=#{query}").map do |el|
    Node.new(@driver, @playwright_page, el)
  end
end
fullscreen_window(handle) click to toggle source
# File lib/capybara/playwright/browser.rb, line 287
def fullscreen_window(handle)
  puts "[WARNING] 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_back() click to toggle source
# File lib/capybara/playwright/browser.rb, line 126
def go_back
  assert_page_alive

  @playwright_page.go_back
end
go_forward() click to toggle source
# File lib/capybara/playwright/browser.rb, line 132
def go_forward
  assert_page_alive

  @playwright_page.go_forward
end
html() click to toggle source
# File lib/capybara/playwright/browser.rb, line 106
      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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 277
def maximize_window(handle)
  puts "[WARNING] 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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 227
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) click to toggle source

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

# File lib/capybara/playwright/browser.rb, line 178
def raw_screenshot(**options)
  return nil if !@playwright_page || @playwright_page.closed?

  @playwright_page.screenshot(**options)
end
refresh() click to toggle source
# File lib/capybara/playwright/browser.rb, line 72
def refresh
  assert_page_alive

  @playwright_page.capybara_current_frame.evaluate('() => { location.reload(true) }')
end
resize_window_to(handle, width, height) click to toggle source
# File lib/capybara/playwright/browser.rb, line 271
def resize_window_to(handle, width, height)
  on_window(handle) do |page|
    page.viewport_size = { width: width, height: height }
  end
end
response_headers() click to toggle source
# File lib/capybara/playwright/browser.rb, line 94
def response_headers
  assert_page_alive

  @playwright_page.capybara_response_headers
end
save_screenshot(path, **options) click to toggle source
# File lib/capybara/playwright/browser.rb, line 184
def save_screenshot(path, **options)
  assert_page_alive

  @playwright_page.screenshot(path: path)
end
send_keys(*args) click to toggle source
# File lib/capybara/playwright/browser.rb, line 190
def send_keys(*args)
  Node::SendKeys.new(@playwright_page.keyboard, args).execute
end
status_code() click to toggle source
# File lib/capybara/playwright/browser.rb, line 100
def status_code
  assert_page_alive

  @playwright_page.capybara_status_code
end
switch_to_frame(frame) click to toggle source
# File lib/capybara/playwright/browser.rb, line 194
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) click to toggle source
# File lib/capybara/playwright/browser.rb, line 247
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
title() click to toggle source
# File lib/capybara/playwright/browser.rb, line 120
def title
  assert_page_alive

  @playwright_page.title
end
video_path() click to toggle source

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

# File lib/capybara/playwright/browser.rb, line 170
def video_path
  return nil if !@playwright_page || @playwright_page.closed?

  @playwright_page.video&.path
end
visit(path) click to toggle source
# File lib/capybara/playwright/browser.rb, line 57
def visit(path)
  assert_page_alive

  url =
    if Capybara.app_host
      URI(Capybara.app_host).merge(path)
    elsif Capybara.default_host
      URI(Capybara.default_host).merge(path)
    else
      path
    end

  @playwright_page.capybara_current_frame.goto(url)
end
window_handles() click to toggle source
# File lib/capybara/playwright/browser.rb, line 219
def window_handles
  pages.map(&:guid)
end
window_size(handle) click to toggle source
# File lib/capybara/playwright/browser.rb, line 265
def window_size(handle)
  on_window(handle) do |page|
    page.evaluate('() => [window.innerWidth, window.innerHeight]')
  end
end
with_playwright_page(&block) click to toggle source
# File lib/capybara/playwright/browser.rb, line 354
def with_playwright_page(&block)
  assert_page_alive

  block.call(@playwright_page)
end

Private Instance Methods

assert_page_alive() click to toggle source
# File lib/capybara/playwright/browser.rb, line 209
        def assert_page_alive
  if !@playwright_page || @playwright_page.closed?
    raise NoSuchWindowError
  end
end
create_browser_context() click to toggle source
# File lib/capybara/playwright/browser.rb, line 27
        def create_browser_context
  @playwright_browser.new_context(**@page_options).tap do |browser_context|
    browser_context.on('page', ->(page) {
      unless @playwright_page
        @playwright_page = page
      end
    })
  end
end
create_page(browser_context) click to toggle source
# File lib/capybara/playwright/browser.rb, line 37
        def create_page(browser_context)
  browser_context.new_page.tap do |page|
    page.on('close', -> {
      if @playwright_page
        @playwright_page = nil
      end
    })
  end
end
on_window(handle, &block) click to toggle source
# File lib/capybara/playwright/browser.rb, line 238
        def on_window(handle, &block)
  page = pages.find { |page| page.guid == handle }
  if page
    block.call(page)
  else
    raise NoSuchWindowError
  end
end
pages() click to toggle source
# File lib/capybara/playwright/browser.rb, line 215
        def pages
  @playwright_browser.contexts.flat_map(&:pages)
end
unwrap_node(args) click to toggle source
# File lib/capybara/playwright/browser.rb, line 308
        def unwrap_node(args)
  args.map do |arg|
    if arg.is_a?(Node)
      arg.send(:element)
    else
      arg
    end
  end
end
wrap_node(arg) click to toggle source
# File lib/capybara/playwright/browser.rb, line 318
        def wrap_node(arg)
  case arg
  when Array
    arg.map do |item|
      wrap_node(item)
    end
  when Hash
    arg.map do |key, value|
      [key, wrap_node(value)]
    end.to_h
  when ::Playwright::ElementHandle
    Node.new(@driver, @playwright_page, arg)
  when ::Playwright::JSHandle
    obj_type, is_array = arg.evaluate('obj => [typeof obj, Array.isArray(obj)]')
    if obj_type == 'object'
      if is_array
        # Firefox often include 'toJSON' into properties.
        # https://github.com/microsoft/playwright/issues/7015
        #
        # Get rid of non-numeric entries.
        arg.properties.select { |key, _| key.to_i.to_s == key.to_s }.map  do |_, value|
          wrap_node(value)
        end
      else
        arg.properties.map do |key, value|
          [key, wrap_node(value)]
        end.to_h
      end
    else
      arg.json_value
    end
  else
    arg
  end
end