class Applitools::Selenium::Driver

Constants

ANDROID

@!visibility private

FINDERS

Available finders

IOS

@!visibility private

LANDSCAPE

@!visibility private

RIGHT_ANGLE

Attributes

browser[R]
cached_default_content_viewport_size[R]
rotation[RW]

Public Class Methods

new(eyes, options) click to toggle source

Initializes a class instance.

If driver is not provided, Applitools::Selenium::Driver will raise an EyesError exception. @param eyes [Applitools::Selenium::Eyes] The eyes instance. @param options [Hash] The options. @option options [Selenium::WebDriver::Driver] :driver The Selenium webdriver instance. @option options [Boolean] :is_mobile_device Whether is a mobile device or not.

Calls superclass method
# File lib/applitools/selenium/driver.rb, line 46
def initialize(eyes, options)
  super(options[:driver])
  @is_mobile_device = options.fetch(:is_mobile_device, false)
  @eyes = eyes
  @frame_chain = Applitools::Selenium::FrameChain.new
  @browser = Applitools::Selenium::Browser.new(self, @eyes)
  Applitools::EyesLogger.warn '"screenshot_as" method not found!' unless driver.respond_to? :screenshot_as
end

Private Class Methods

normalize_image(driver, image, rotation) click to toggle source
# File lib/applitools/selenium/driver.rb, line 313
def normalize_image(driver, image, rotation)
  normalize_rotation(driver, image, rotation)
  normalize_width(driver, image)
end
normalize_rotation(driver, image, rotation) click to toggle source

Rotates the image as necessary. The rotation is either manually forced by passing a value in the rotation parameter, or automatically inferred if the rotation parameter is nil.

driver

Applitools::Selenium::Driver The driver which produced the screenshot.

image

ChunkyPNG::Canvas The image to normalize.

rotation

Integer|nil The degrees by which to rotate the image: positive values = clockwise rotation,

negative values = counter-clockwise, 0 = force no rotation, +nil+ = rotate automatically when needed.
# File lib/applitools/selenium/driver.rb, line 325
def normalize_rotation(driver, image, rotation)
  return if rotation && rotation.zero?

  num_quadrants = 0
  if !rotation.nil?
    if (rotation % RIGHT_ANGLE).nonzero?
      raise Applitools::EyesError.new('Currently only quadrant rotations are supported. Current rotation: '\
      "#{rotation}")
    end
    num_quadrants = (rotation / RIGHT_ANGLE).to_i
  elsif rotation.nil? && driver.mobile_device? && driver.landscape_orientation? && image.height > image.width
    # For Android, we need to rotate images to the right, and for iOS to the left.
    num_quadrants = driver.android? ? 1 : -1
  end

  Applitools::Utils::ImageUtils.quadrant_rotate!(image, num_quadrants)
end
normalize_width(driver, image) click to toggle source
# File lib/applitools/selenium/driver.rb, line 343
def normalize_width(driver, image)
  return if driver.mobile_device?

  normalization_factor = driver.browser.image_normalization_factor(image)
  Applitools::Utils::ImageUtils.scale!(image, normalization_factor) unless normalization_factor == 1
end

Public Instance Methods

default_content_viewport_size(force_query = false) click to toggle source

Gets default_content_viewport_size.

@param [Boolean] force_query if set to true, forces querying of viewport size from the browser,

otherwise returns cached value.

@return [Applitools::RectangleSize] The default content viewport size.

# File lib/applitools/selenium/driver.rb, line 207
def default_content_viewport_size(force_query = false)
  logger.info('default_content_viewport_size()')
  if cached_default_content_viewport_size && !force_query
    logger.info "Using cached viewport_size #{cached_default_content_viewport_size}"
    return cached_default_content_viewport_size
  end

  current_frames = frame_chain
  switch_to.default_content unless current_frames.empty?
  logger.info 'Extracting viewport size...'
  @cached_default_content_viewport_size = utils.extract_viewport_size(self)
  logger.info "Done! Viewport size is #{@cached_default_content_viewport_size}"

  switch_to.frames(frame_chain: current_frames) unless current_frames.empty?
  @cached_default_content_viewport_size
end
execute_script(*args) click to toggle source

Executes javascript in browser context.

@raise [Applitools::EyesDriverOperationException]

# File lib/applitools/selenium/driver.rb, line 58
def execute_script(*args)
  raises_error { __getobj__.execute_script(*args) }
end
find_element(*args) click to toggle source

Finds an element in a window. @param [Symbol] how Defines the way that what parameter will be interpreted (finder). Can be one

of: +:class+, +:class_name+, +:css+, +:id+, +:link+, +:link_text+, +:name+, +:partial_link_text+, +:tag_name+,
+:xpath+

@param [String] what The selector to find an element @example

driver.find_element :css, '.some_class'

@example

driver.find_element :css => '.some_class'

@example

driver.find_element :id, 'element_id'

@raise [ArgumentError] if invalid finder (how) is passed @return [Applitools::Selenium::Element] @!parse def find_element(how, what); end

# File lib/applitools/selenium/driver.rb, line 140
def find_element(*args)
  how, what = extract_args(args)
  return find_element_by_name_or_id(what) if how == :name_or_id
  # Make sure that "how" is a valid locator.
  raise ArgumentError, "cannot find element by: #{how.inspect}" unless FINDERS[how.to_sym]

  Applitools::Selenium::Element.new(self, driver.find_element(how, what))
end
find_element_by_name_or_id(name_or_id) click to toggle source
# File lib/applitools/selenium/driver.rb, line 149
def find_element_by_name_or_id(name_or_id)
  found_by_name = find_elements name: name_or_id
  return found_by_name.first unless found_by_name.empty?
  find_element id: name_or_id
end
find_elements(*args) click to toggle source

Finds elements in a window. @param [Symbol] how Defines the way that what parameter will be interpreted (finder). Can be one

of: +:class+, +:class_name+, +:css+, +:id+, +:link+, +:link_text+, +:name+, +:partial_link_text+, +:tag_name+,
+:xpath+

@param [String] what The selector to find an element @example

driver.find_elements :css, '.some_class'

@example

driver.find_elements :css => '.some_class'

@example

driver.find_elements :id, 'element_id'

@raise [ArgumentError] if invalid finder (how) is passed @return [ [Applitools::Selenium::Element] ] @!parse def find_elements(how, what); end

# File lib/applitools/selenium/driver.rb, line 170
def find_elements(*args)
  how, what = extract_args(args)

  raise ArgumentError, "cannot find element by: #{how.inspect}" unless FINDERS[how.to_sym]

  driver.find_elements(how, what).map { |el| Applitools::Selenium::Element.new(self, el) }
end
frame_chain() click to toggle source

Returns a copy of current frame chain. Frame chain stores information about all parent frames,

including scroll offset an frame coordinates.

@return [Applitools::Selenium::FrameChain] The frame chain.

# File lib/applitools/selenium/driver.rb, line 192
def frame_chain
  Applitools::Selenium::FrameChain.new other: @frame_chain
end
frame_chain!() click to toggle source

Returns current frame chain. Frame chain stores information about all parent frames,

including scroll offset an frame coordinates
# File lib/applitools/selenium/driver.rb, line 198
def frame_chain!
  @frame_chain
end
hide_scrollbars() click to toggle source

Hide the main document's scrollbars and returns the original overflow value.

# File lib/applitools/selenium/driver.rb, line 93
def hide_scrollbars
  @browser.hide_scrollbars
end
landscape_orientation?() click to toggle source

Returns true if the driver orientation is landscape.

# File lib/applitools/selenium/driver.rb, line 78
def landscape_orientation?
  driver.orientation.to_s.upcase == LANDSCAPE
rescue NameError, Selenium::WebDriver::Error::WebDriverError, Selenium::WebDriver::Error::UnknownError
  Applitools::EyesLogger.debug 'driver has no "orientation" attribute. Assuming: portrait.'
  false
end
mobile_device?() click to toggle source

Returns true if the platform running the test is a mobile platform. false otherwise.

# File lib/applitools/selenium/driver.rb, line 86
def mobile_device?
  # We CAN'T check if the device is an +Appium::Driver+ since it is not a RemoteWebDriver. Because of that we use a
  # flag we got as an option in the constructor.
  @is_mobile_device
end
overflow=(overflow) click to toggle source

Set the overflow value for document element and return the original overflow value.

# File lib/applitools/selenium/driver.rb, line 98
def overflow=(overflow)
  @browser.set_overflow(overflow)
end
Also aliased as: set_overflow
remote_web_driver() click to toggle source

Returns native driver

@return Selenium::WebDriver

# File lib/applitools/selenium/driver.rb, line 105
def remote_web_driver
  driver
end
screenshot_as(format) { |png_screenshot| ... } click to toggle source

Takes a screenshot.

@param [:Symbol] format A format to store screenshot (one of :base64 or :png) @return [String] A byte string, representing the screenshot

# File lib/applitools/selenium/driver.rb, line 115
def screenshot_as(format)
  raise "Invalid format (#{format}) passed! Available formats: :png, :base64" unless [:base64, :png].include? format
  png_screenshot = driver.screenshot_as(:png)
  yield png_screenshot if block_given?
  screenshot = Applitools::Screenshot.from_any_image(png_screenshot)
  self.class.normalize_rotation(self, screenshot, rotation)
  return Applitools::Utils::ImageUtils.base64_from_png_image(screenshot.restore) if format == :base64
  screenshot.to_blob
end
set_overflow(overflow)
Alias for: overflow=
switch_to() click to toggle source
# File lib/applitools/selenium/driver.rb, line 224
def switch_to
  @switch_to ||= Applitools::Selenium::EyesTargetLocator.new(
    self, driver.switch_to, FrameChangeEventListener.new(self)
  )
end

Private Instance Methods

bridge() click to toggle source
# File lib/applitools/selenium/driver.rb, line 240
def bridge
  __getobj__.send(:bridge)
end
driver() click to toggle source
# File lib/applitools/selenium/driver.rb, line 244
def driver
  @driver ||= __getobj__
end
extract_args(args) click to toggle source
# File lib/applitools/selenium/driver.rb, line 248
def extract_args(args)
  case args.size
  when 2
    args
  when 1
    arg = args.first

    raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift" unless arg.respond_to?(:shift)

    # This will be a single-entry hash, so use #shift over #first or #[].
    arg.dup.shift.tap do |arr|
      raise ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
    end
  else
    raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
  end
end
raises_error() { || ... } click to toggle source
# File lib/applitools/selenium/driver.rb, line 234
def raises_error
  yield if block_given?
rescue => e
  raise Applitools::EyesDriverOperationException.new e.message
end