class Capybara::Selenium::Driver

Constants

DEFAULT_OPTIONS
SPECIAL_OPTIONS

Attributes

app[R]
options[R]

Public Class Methods

new(app, options={}) click to toggle source
# File lib/capybara/selenium/driver.rb, line 27
def initialize(app, options={})
  begin
    require 'selenium-webdriver'
  rescue LoadError => e
    if e.message =~ /selenium-webdriver/
      raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
    else
      raise e
    end
  end

  @app = app
  @browser = nil
  @exit_status = nil
  @frame_handles = {}
  @options = DEFAULT_OPTIONS.merge(options)
end

Public Instance Methods

accept_modal(type, options={}) { || ... } click to toggle source
# File lib/capybara/selenium/driver.rb, line 223
def accept_modal(type, options={}, &blk)
  yield if block_given?
  modal = find_modal(options)
  modal.send_keys options[:with] if options[:with]
  message = modal.text
  modal.accept
  message
end
browser() click to toggle source
# File lib/capybara/selenium/driver.rb, line 12
def browser
  unless @browser
    @browser = Selenium::WebDriver.for(options[:browser], options.reject { |key,val| SPECIAL_OPTIONS.include?(key) })

    main = Process.pid
    at_exit do
      # Store the exit status of the test run since it goes away after calling the at_exit proc...
      @exit_status = $!.status if $!.is_a?(SystemExit)
      quit if Process.pid == main
      exit @exit_status if @exit_status # Force exit with stored status
    end
  end
  @browser
end
browser_initialized?() click to toggle source

@deprecated This method is being removed

# File lib/capybara/selenium/driver.rb, line 260
def browser_initialized?
  super && !@browser.nil?
end
close_window(handle) click to toggle source
# File lib/capybara/selenium/driver.rb, line 182
def close_window(handle)
  within_given_window(handle) do
    browser.close
  end
end
current_url() click to toggle source
# File lib/capybara/selenium/driver.rb, line 65
def current_url
  browser.current_url
end
current_window_handle() click to toggle source
# File lib/capybara/selenium/driver.rb, line 158
def current_window_handle
  browser.window_handle
end
dismiss_modal(type, options={}) { || ... } click to toggle source
# File lib/capybara/selenium/driver.rb, line 232
def dismiss_modal(type, options={}, &blk)
  yield if block_given?
  modal = find_modal(options)
  message = modal.text
  modal.dismiss
  message
end
evaluate_script(script) click to toggle source
# File lib/capybara/selenium/driver.rb, line 84
def evaluate_script(script)
  browser.execute_script "return #{script}"
end
execute_script(script) click to toggle source
# File lib/capybara/selenium/driver.rb, line 80
def execute_script(script)
  browser.execute_script script
end
find_css(selector) click to toggle source
# File lib/capybara/selenium/driver.rb, line 73
def find_css(selector)
  browser.find_elements(:css, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
end
find_window(locator) click to toggle source

@api private

# File lib/capybara/selenium/driver.rb, line 201
def find_window(locator)
  handles = browser.window_handles
  return locator if handles.include? locator

  original_handle = browser.window_handle
  handles.each do |handle|
    switch_to_window(handle)
    if (locator == browser.execute_script("return window.name") ||
        browser.title.include?(locator) ||
        browser.current_url.include?(locator))
      switch_to_window(original_handle)
      return handle
    end
  end
  raise Capybara::ElementNotFound, "Could not find a window identified by #{locator}"
end
find_xpath(selector) click to toggle source
# File lib/capybara/selenium/driver.rb, line 69
def find_xpath(selector)
  browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
end
go_back() click to toggle source
# File lib/capybara/selenium/driver.rb, line 49
def go_back
  browser.navigate.back
end
go_forward() click to toggle source
# File lib/capybara/selenium/driver.rb, line 53
def go_forward
  browser.navigate.forward
end
html() click to toggle source
# File lib/capybara/selenium/driver.rb, line 57
def html
  browser.page_source
end
invalid_element_errors() click to toggle source
# File lib/capybara/selenium/driver.rb, line 248
def invalid_element_errors
  [Selenium::WebDriver::Error::StaleElementReferenceError,
   Selenium::WebDriver::Error::UnhandledError,
   Selenium::WebDriver::Error::ElementNotVisibleError,
   Selenium::WebDriver::Error::InvalidSelectorError]  # Work around a race condition that can occur with chromedriver and #go_back/#go_forward
end
maximize_window(handle) click to toggle source
# File lib/capybara/selenium/driver.rb, line 175
def maximize_window(handle)
  within_given_window(handle) do
    browser.manage.window.maximize
  end
  sleep 0.1 # work around for https://code.google.com/p/selenium/issues/detail?id=7405
end
needs_server?() click to toggle source
# File lib/capybara/selenium/driver.rb, line 78
def needs_server?; true; end
no_such_window_error() click to toggle source
# File lib/capybara/selenium/driver.rb, line 255
def no_such_window_error
  Selenium::WebDriver::Error::NoSuchWindowError
end
open_new_window() click to toggle source
# File lib/capybara/selenium/driver.rb, line 192
def open_new_window
  browser.execute_script('window.open();')
end
quit() click to toggle source
# File lib/capybara/selenium/driver.rb, line 240
def quit
  @browser.quit if @browser
rescue Errno::ECONNREFUSED
  # Browser must have already gone
ensure
  @browser = nil
end
reset!() click to toggle source
# File lib/capybara/selenium/driver.rb, line 92
def reset!
  # Use instance variable directly so we avoid starting the browser just to reset the session
  if @browser
    navigated = false
    start_time = Capybara::Helpers.monotonic_time
    begin
      if !navigated
        # Only trigger a navigation if we haven't done it already, otherwise it
        # can trigger an endless series of unload modals
        begin
          @browser.manage.delete_all_cookies
        rescue Selenium::WebDriver::Error::UnhandledError
          # delete_all_cookies fails when we've previously gone
          # to about:blank, so we rescue this error and do nothing
          # instead.
        end
        @browser.navigate.to("about:blank")
      end
      navigated = true

      #Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
      until find_xpath("/html/body/*").empty? do
        raise Capybara::ExpectationNotMet.new('Timed out waiting for Selenium session reset') if (Capybara::Helpers.monotonic_time - start_time) >= 10
        sleep 0.05
      end
    rescue Selenium::WebDriver::Error::UnhandledAlertError
      # This error is thrown if an unhandled alert is on the page
      # Firefox appears to automatically dismiss this alert, chrome does not
      # We'll try to accept it
      begin
        @browser.switch_to.alert.accept
        sleep 0.25 # allow time for the modal to be handled
      rescue Selenium::WebDriver::Error::NoAlertPresentError
        # The alert is now gone - nothing to do
      end
      # try cleaning up the browser again
      retry
    end
  end
end
resize_window_to(handle, width, height) click to toggle source
# File lib/capybara/selenium/driver.rb, line 169
def resize_window_to(handle, width, height)
  within_given_window(handle) do
    browser.manage.window.resize_to(width, height)
  end
end
save_screenshot(path, options={}) click to toggle source
# File lib/capybara/selenium/driver.rb, line 88
def save_screenshot(path, options={})
  browser.save_screenshot(path)
end
switch_to_window(handle) click to toggle source
# File lib/capybara/selenium/driver.rb, line 196
def switch_to_window(handle)
  browser.switch_to.window handle
end
title() click to toggle source
# File lib/capybara/selenium/driver.rb, line 61
def title
  browser.title
end
visit(path) click to toggle source
# File lib/capybara/selenium/driver.rb, line 45
def visit(path)
  browser.navigate.to(path)
end
wait?() click to toggle source
# File lib/capybara/selenium/driver.rb, line 77
def wait?; true; end
window_handles() click to toggle source
# File lib/capybara/selenium/driver.rb, line 188
def window_handles
  browser.window_handles
end
window_size(handle) click to toggle source
# File lib/capybara/selenium/driver.rb, line 162
def window_size(handle)
  within_given_window(handle) do
    size = browser.manage.window.size
    [size.width, size.height]
  end
end
within_frame(frame_handle) { || ... } click to toggle source

Webdriver supports frame name, id, index(zero-based) or {Capybara::Node::Element} to find iframe

@overload #within_frame(index)

@param [Integer] index                 index of a frame

@overload #within_frame(name_or_id)

@param [String] name_or_id             name or id of a frame

@overload #within_frame(element)

@param [Capybara::Node::Base] a_node   frame element
# File lib/capybara/selenium/driver.rb, line 144
def within_frame(frame_handle)
  frame_handle = frame_handle.native if frame_handle.is_a?(Capybara::Node::Base)
  @frame_handles[browser.window_handle] ||= []
  @frame_handles[browser.window_handle] << frame_handle
  browser.switch_to.frame(frame_handle)
  yield
ensure
  # would love to use browser.switch_to.parent_frame here
  # but it has an issue if the current frame is removed from within it
  @frame_handles[browser.window_handle].pop
  browser.switch_to.default_content
  @frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
end
within_window(locator) { || ... } click to toggle source
# File lib/capybara/selenium/driver.rb, line 218
def within_window(locator)
  handle = find_window(locator)
  browser.switch_to.window(handle) { yield }
end

Private Instance Methods

find_modal(options={}) click to toggle source
# File lib/capybara/selenium/driver.rb, line 278
def find_modal(options={})
  # Selenium has its own built in wait (2 seconds)for a modal to show up, so this wait is really the minimum time
  # Actual wait time may be longer than specified
  wait = Selenium::WebDriver::Wait.new(
    timeout: (options[:wait] || Capybara.default_max_wait_time),
    ignore: Selenium::WebDriver::Error::NoAlertPresentError)
  begin
    wait.until do
      alert = @browser.switch_to.alert
      regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
      alert.text.match(regexp) ? alert : nil
    end
  rescue Selenium::WebDriver::Error::TimeOutError
    raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
  end
end
within_given_window(handle) { || ... } click to toggle source
# File lib/capybara/selenium/driver.rb, line 266
def within_given_window(handle)
  original_handle = self.current_window_handle
  if handle == original_handle
    yield
  else
    switch_to_window(handle)
    result = yield
    switch_to_window(original_handle)
    result
  end
end