class Applitools::Selenium::Browser

@!visibility private

Constants

EPSILON_WIDTH
JS_GET_CURRENT_SCROLL_POSITION
JS_GET_CURRENT_TRANSFORM
JS_GET_DEVICE_PIXEL_RATIO
JS_GET_PAGE_METRICS
JS_GET_USER_AGENT
JS_SCROLL_TO
JS_SET_OVERFLOW
JS_SET_TRANSFORM
MAX_SCROLLBAR_SIZE
MIN_SCREENSHOT_PART_HEIGHT
OVERFLOW_HIDDEN

Public Class Methods

new(driver, eyes) click to toggle source

Initialize class instance.

@param [Applitools::Selenium::Driver] driver The wrapped Selenium driver. @param [Applitools::Selenium::Eyes] eyes The eyes instance.

# File lib/applitools/selenium/browser.rb, line 68
def initialize(driver, eyes)
  @driver = driver
  @eyes = eyes
end

Public Instance Methods

chrome?() click to toggle source
# File lib/applitools/selenium/browser.rb, line 73
def chrome?
  running_browser_name == :chrome
end
current_scroll_position() click to toggle source

Returns the current scroll position.

@return [Applitools::Base::Point] The coordinates of the scroll position.

# File lib/applitools/selenium/browser.rb, line 129
def current_scroll_position
  position = Applitools::Utils.underscore_hash_keys(execute_script(JS_GET_CURRENT_SCROLL_POSITION))
  Applitools::Base::Point.new(position[:left], position[:top])
end
current_transform() click to toggle source
# File lib/applitools/selenium/browser.rb, line 138
def current_transform
  execute_script(JS_GET_CURRENT_TRANSFORM)
end
entire_page_size() click to toggle source

The dimensions of the entire page.

@return [Applitools::Base::Dimension] The dimensions of the entire page.

# File lib/applitools/selenium/browser.rb, line 116
def entire_page_size
  max_document_element_height = [page_metrics[:client_height], page_metrics[:scroll_height]].max
  max_body_height = [page_metrics[:body_client_height], page_metrics[:body_scroll_height]].max

  total_width = [page_metrics[:scroll_width], page_metrics[:body_scroll_width]].max
  total_height = [max_document_element_height, max_body_height].max

  Applitools::Base::Dimension.new(total_width, total_height)
end
firefox?() click to toggle source
# File lib/applitools/selenium/browser.rb, line 77
def firefox?
  running_browser_name == :firefox
end
hide_scrollbars() click to toggle source

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

# File lib/applitools/selenium/browser.rb, line 154
def hide_scrollbars
  set_overflow(OVERFLOW_HIDDEN)
end
image_normalization_factor(image) click to toggle source

Gets the normalization factor.

@param [ChunkyPNG::Canvas] image The image to normalize. @return [Integer] The image normalization factor.

# File lib/applitools/selenium/browser.rb, line 101
def image_normalization_factor(image)
  # If the user manually set the scale ratio, we use that.
  return @eyes.scale_ratio unless @eyes.scale_ratio.nil?

  if image.width == @eyes.viewport_size.extract_viewport_from_browser.width ||
      (image.width - entire_page_size.width).abs <= EPSILON_WIDTH
    return 1
  end

  1.to_f / device_pixel_ratio
end
running_browser_name() click to toggle source
# File lib/applitools/selenium/browser.rb, line 81
def running_browser_name
  @driver.__getobj__.browser
end
scroll_to(point) click to toggle source
# File lib/applitools/selenium/browser.rb, line 134
def scroll_to(point)
  execute_script(JS_SCROLL_TO % { left: point.left, top: point.top }, 0.25)
end
set_overflow(overflow) click to toggle source

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

# File lib/applitools/selenium/browser.rb, line 148
def set_overflow(overflow)
  execute_script(JS_SET_OVERFLOW % { overflow: overflow }, 0.1)
end
set_transform(transform) click to toggle source

rubocop:disable Style/AccessorMethodName

# File lib/applitools/selenium/browser.rb, line 143
def set_transform(transform)
  execute_script(JS_SET_TRANSFORM % { transform: transform }, 0.25)
end
translate_to(point) click to toggle source
# File lib/applitools/selenium/browser.rb, line 158
def translate_to(point)
  set_transform("translate(-#{point.left}px, -#{point.top}px)")
end
user_agent() click to toggle source
# File lib/applitools/selenium/browser.rb, line 85
def user_agent
  return @user_agent if defined?(@user_agent)

  @user_agent = begin
    execute_script(JS_GET_USER_AGENT).freeze
  rescue => e
    Applitools::EyesLogger.error "Failed to obtain user-agent: (#{e.message})"

    nil
  end
end

Private Instance Methods

device_pixel_ratio() click to toggle source
# File lib/applitools/selenium/browser.rb, line 225
def device_pixel_ratio
  @device_pixel_ratio ||= execute_script(JS_GET_DEVICE_PIXEL_RATIO).freeze
end
execute_script(script, stabilization_time = nil) click to toggle source

# Takes a full page screenshot. # # @return [ChunkyPNG::Canvas] image The result of the screenshot. def fullpage_screenshot

# Scroll to the top/left corner of the screen.
original_scroll_position = current_scroll_position
scroll_to(Applitools::Base::Point::TOP_LEFT)
if current_scroll_position != Applitools::Base::Point::TOP_LEFT
  raise 'Could not scroll to the top/left corner of the screen!'
end

# Translate to top/left of the page (notice this is different from JavaScript scrolling).
if @eyes.use_css_transition
  original_transform = current_transform
  translate_to(Applitools::Base::Point::TOP_LEFT)
end

# Take screenshot of the (0,0) tile.
screenshot = @driver.visible_screenshot

# Normalize screenshot width/height.
size_factor = 1
page_size = entire_page_size
factor = image_normalization_factor(screenshot)
if factor == 0.5
  size_factor = 2
  page_size.width *= size_factor
  page_size.height *= size_factor
  page_size.width = [page_size.width, screenshot.width].max
end

# NOTE: this is required! Since when calculating the screenshot parts for full size, we use a screenshot size
# which is a bit smaller (see comment below).
if screenshot.width < page_size.width || screenshot.height < page_size.height
  # We use a smaller size than the actual screenshot size in order to eliminate duplication of bottom scroll bars,
  # as well as footer-like elements with fixed position.
  max_scrollbar_size = @eyes.use_css_transition ? 0 : MAX_SCROLLBAR_SIZE
  height = [screenshot.height - (max_scrollbar_size * size_factor), MIN_SCREENSHOT_PART_HEIGHT * size_factor].max
  screenshot_part_size = Applitools::Base::Dimension.new(screenshot.width, height)

  sub_regions = Applitools::Base::Region.new(0, 0, page_size.width,
    page_size.height).subregions(screenshot_part_size)
  parts = sub_regions.map do |screenshot_part|
    # Skip (0,0), as we already got the screenshot.
    if screenshot_part.left.zero? && screenshot_part.top.zero?
      next Applitools::Base::ImagePosition.new(screenshot, Applitools::Base::Point::TOP_LEFT)
    end

    process_screenshot_part(screenshot_part, size_factor)
  end
  screenshot = Applitools::Utils::ImageUtils.stitch_images(page_size, parts)
end
set_transform(original_transform) if @eyes.use_css_transition
scroll_to(original_scroll_position)
screenshot

end

# File lib/applitools/selenium/browser.rb, line 221
def execute_script(script, stabilization_time = nil)
  @driver.execute_script(script).tap { sleep(stabilization_time) if stabilization_time }
end
page_metrics() click to toggle source
# File lib/applitools/selenium/browser.rb, line 229
def page_metrics
  Applitools::Utils.underscore_hash_keys(execute_script(JS_GET_PAGE_METRICS))
end
process_screenshot_part(part, size_factor) click to toggle source
# File lib/applitools/selenium/browser.rb, line 233
def process_screenshot_part(part, size_factor)
  part_coords = Applitools::Base::Point.new(part.left, part.top)
  part_coords_normalized = Applitools::Base::Point.new(part.left.to_f / size_factor, part.top.to_f / size_factor)

  if @eyes.use_css_transition
    translate_to(part_coords_normalized)
    current_position = part_coords
  else
    scroll_to(part_coords_normalized)
    position = current_scroll_position
    current_position = Applitools::Base::Point.new(position.left * size_factor, position.top * size_factor)
  end

  Applitools::Base::ImagePosition.new(@driver.visible_screenshot, current_position)
end