Class: Applitools::Selenium::Eyes

Inherits:
EyesBase
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/applitools/selenium/eyes.rb

Overview

The main API gateway for the SDK

Constant Summary collapse

DEFAULT_DEVICE_PIXEL_RATIO =

The pixel ratio will be used if detection of device pixel ratio is failed

1
DEFAULT_WAIT_BEFORE_SCREENSHOTS =

Seconds

0.1
USE_DEFAULT_MATCH_TIMEOUT =
-1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server_url = nil) ⇒ Eyes

Creates a new (possibly disabled) Eyes instance that interacts with the Eyes Server at the specified url.

Parameters:

  • server_url (defaults to: nil)

    The Eyes Server URL.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/applitools/selenium/eyes.rb', line 93

def initialize(server_url = nil)
  super
  self.base_agent_id = "eyes.selenium.ruby/#{Applitools::VERSION}".freeze
  self.check_frame_or_element = false
  self.region_to_check = nil
  self.force_full_page_screenshot = false
  self.dont_get_title = false
  self.hide_scrollbars = false
  self.device_pixel_ratio = UNKNOWN_DEVICE_PIXEL_RATIO
  self.stitch_mode = STICH_MODE[:scroll]
  self.wait_before_screenshots = DEFAULT_WAIT_BEFORE_SCREENSHOTS
  self.region_visibility_strategy = MoveToRegionVisibilityStrategy.new
  self.debug_screenshot = false
  self.disable_horizontal_scrolling = false
  self.disable_vertical_scrolling = false
  self.explicit_entire_size = nil
end

Instance Attribute Details

#base_agent_idObject

Returns the value of attribute base_agent_id.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def base_agent_id
  @base_agent_id
end

#debug_screenshotObject

Returns the value of attribute debug_screenshot.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def debug_screenshot
  @debug_screenshot
end

#disable_horizontal_scrollingObject

Returns the value of attribute disable_horizontal_scrolling.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def disable_horizontal_scrolling
  @disable_horizontal_scrolling
end

#disable_vertical_scrollingObject

Returns the value of attribute disable_vertical_scrolling.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def disable_vertical_scrolling
  @disable_vertical_scrolling
end

#driverObject (readonly)

Returns the value of attribute driver.



85
86
87
# File 'lib/applitools/selenium/eyes.rb', line 85

def driver
  @driver
end

#explicit_entire_sizeObject

Returns the value of attribute explicit_entire_size.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def explicit_entire_size
  @explicit_entire_size
end

#force_full_page_screenshotboolean

Forces a full page screenshot (by scrolling and stitching) if the browser only supports viewport screenshots.

Returns:

  • (boolean)

    force full page screenshot flag



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

attr_accessor :base_agent_id, :screenshot, :force_full_page_screenshot, :hide_scrollbars,
:wait_before_screenshots, :debug_screenshot, :stitch_mode, :disable_horizontal_scrolling,
:disable_vertical_scrolling, :explicit_entire_size

#hide_scrollbarsboolean

Turns on/off hiding scrollbars before taking a screenshot

Returns:

  • (boolean)

    hide_scrollbars flag



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

attr_accessor :base_agent_id, :screenshot, :force_full_page_screenshot, :hide_scrollbars,
:wait_before_screenshots, :debug_screenshot, :stitch_mode, :disable_horizontal_scrolling,
:disable_vertical_scrolling, :explicit_entire_size

#screenshotObject

Returns the value of attribute screenshot.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

def screenshot
  @screenshot
end

#stitch_modeboolean

May be set to :CSS or :SCROLL (:SCROLL is default). When :CSS - SDK will use CSS transitions to perform scrolling, otherwise it will use Javascript window.scroll_to() function for scrolling purposes

Returns:

  • (boolean)

    stitch_mode (:CSS or :SCROLL)



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

attr_accessor :base_agent_id, :screenshot, :force_full_page_screenshot, :hide_scrollbars,
:wait_before_screenshots, :debug_screenshot, :stitch_mode, :disable_horizontal_scrolling,
:disable_vertical_scrolling, :explicit_entire_size

#wait_before_screenshotsFloat

Sets the time to wait just before taking a screenshot (e.g., to allow positioning to stabilize when performing a full page stitching).

Returns:

  • (Float)

    The time to wait (Seconds). Values smaller or equal to 0, will cause the default value to be used.



82
83
84
# File 'lib/applitools/selenium/eyes.rb', line 82

attr_accessor :base_agent_id, :screenshot, :force_full_page_screenshot, :hide_scrollbars,
:wait_before_screenshots, :debug_screenshot, :stitch_mode, :disable_horizontal_scrolling,
:disable_vertical_scrolling, :explicit_entire_size

Class Method Details

.eyes_driver(driver, eyes = nil) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/applitools/selenium/eyes.rb', line 24

def eyes_driver(driver, eyes = nil)
  if driver.respond_to? :driver_for_eyes
    driver.driver_for_eyes eyes
  elsif driver.is_a? Capybara::Poltergeist::Driver
    Applitools::Poltergeist::Driver.new(eyes, driver: driver)
  else
    unless driver.is_a?(Applitools::Selenium::Driver)
      Applitools::EyesLogger.warn("Unrecognized driver type: (#{driver.class.name})!")
      is_mobile_device = driver.respond_to?(:capabilities) && driver.capabilities['platformName']
      Applitools::Selenium::Driver.new(eyes, driver: driver, is_mobile_device: is_mobile_device)
    end
    raise Applitools::EyesError.new "Unknown driver #{driver}!"
  end
end

.position_provider(stitch_mode, driver, disable_horizontal = false, disable_vertical = false, explicit_entire_size = nil) ⇒ Object



1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
# File 'lib/applitools/selenium/eyes.rb', line 1165

def position_provider(stitch_mode, driver, disable_horizontal = false, disable_vertical = false,
  explicit_entire_size = nil)

  max_width = nil
  max_height = nil
  unless explicit_entire_size.nil?
    max_width = explicit_entire_size.width
    max_height = explicit_entire_size.height
  end
  case stitch_mode
  when :SCROLL
    Applitools::Selenium::ScrollPositionProvider.new(driver, disable_horizontal, disable_vertical,
      max_width, max_height)
  when :CSS
    Applitools::Selenium::CssTranslatePositionProvider.new(driver, disable_horizontal, disable_vertical,
      max_width, max_height)
  end
end

.set_viewport_size(driver, viewport_size) ⇒ Object

Set the viewport size.

Parameters:



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/applitools/selenium/eyes.rb', line 43

def set_viewport_size(driver, viewport_size)
  Applitools::ArgumentGuard.not_nil(driver, 'Driver')
  Applitools::ArgumentGuard.not_nil(viewport_size, 'viewport_size')
  Applitools::ArgumentGuard.is_a?(viewport_size, 'viewport_size', Applitools::RectangleSize)
  begin
    Applitools::Utils::EyesSeleniumUtils.set_viewport_size eyes_driver(driver), viewport_size
  rescue => e
    Applitools::EyesLogger.error e.class
    Applitools::EyesLogger.error e.message
    raise Applitools::EyesError.new 'Failed to set viewport size!'
  end
end

Instance Method Details

#check(name, target) ⇒ Applitools::MatchResult

Takes a snapshot and matches it with the expected output.

Parameters:

Returns:

  • (Applitools::MatchResult)

    The match results.



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/applitools/selenium/eyes.rb', line 248

def check(name, target)
  Applitools::ArgumentGuard.is_a? target, 'target', Applitools::Selenium::Target
  original_overflow = nil
  original_position_provider = position_provider

  eyes_element = nil

  self.eyes_screenshot_factory = lambda do |image|
    Applitools::Selenium::EyesWebDriverScreenshot.new(
      image, driver: driver, force_offset: position_provider.force_offset
    )
  end

  check_in_frame target_frames: target.frames do
    begin
      match_data = Applitools::MatchWindowData.new
      match_data.tag = name
      match_data.match_level = default_match_settings[:match_level]
      match_data.read_target(target, driver)
      eyes_element = target.region_to_check.call(driver)
      region_visibility_strategy.move_to_region original_position_provider,
        Applitools::Location.new(eyes_element.location.x.to_i, eyes_element.location.y.to_i)

      check_window = false
      if !target.frames.empty? && eyes_element.is_a?(Applitools::Region)
        # check_current_frame
        region_provider = region_provider_for_frame

      elsif eyes_element.is_a? Applitools::Selenium::Element
        # check_element
        region_provider = Applitools::Selenium::RegionProvider.new(
          region_for_element(eyes_element),
          target.coordinate_type
        )
      else
        # check_window
        region_provider = Applitools::Selenium::RegionProvider.new(
          region_for_element(eyes_element),
          target.coordinate_type
        )
        check_window = true
      end

      if target.options[:stitch_content]
        check_window ? self.force_full_page_screenshot = true : self.check_frame_or_element = true
        if eyes_element.is_a? Applitools::Selenium::Element
          self.position_provider = Applitools::Selenium::ElementPositionProvider.new driver, eyes_element

          original_overflow = eyes_element.overflow
          eyes_element.overflow = 'hidden'
        end

        self.region_to_check = region_provider

        region_provider = Applitools::Selenium::RegionProvider.new(
          Applitools::Region::EMPTY,
          nil
        )
      end

      check_window_base(
        region_provider, target.options[:timeout] || USE_DEFAULT_MATCH_TIMEOUT, match_data
      )
    ensure
      eyes_element.overflow = original_overflow unless original_overflow.nil?
      self.check_frame_or_element = false
      self.force_full_page_screenshot = false
      self.position_provider = original_position_provider
      self.region_to_check = nil
      region_visibility_strategy.return_to_original_position position_provider
    end
  end
end

#check_frame(options = {}) ⇒ Applitools::MatchResult

Validates the contents of an iframe and matches it with the expected output.

Parameters:

  • options (Hash) (defaults to: {})

    The specific parameters of the desired screenshot.

Options Hash (options):

  • :timeout (Fixnum)

    The amount of time to retry matching. (Seconds)

  • :tag (String)

    An optional tag to be associated with the snapshot.

  • :frame_key (String)

    The key of the relevant frame.

  • :name_or_id (String)

    The name or id of the screenshot.

Returns:

  • (Applitools::MatchResult)

    The match results.



442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/applitools/selenium/eyes.rb', line 442

def check_frame(options = {})
  options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil }.merge!(options)

  process_in_frame options do |opts, frame_key|
    if disabled?
      logger.info "check_frame(#{frame_key}: #{opts[frame_key]}, timeout: #{opts[:timeout]}, " \
        "tag: #{opts[:tag]}): Ignored"
      return
    end

    logger.info "check_frame(#{frame_key}: #{opts[frame_key]}, timeout: #{opts[:timeout]}, " \
      "tag: #{opts[:tag]})"
    check_current_frame opts[:timeout], opts[:tag]
  end
end

#check_frame__(options = {}) ⇒ Object

Validates the contents of an iframe and matches it with the expected output.

Parameters:

  • options (Hash) (defaults to: {})

    The options.

  • [Fixnum] (Hash)

    a customizable set of options

  • [String] (Hash)

    a customizable set of options

  • [Applitools::Selenium::Element] (Hash)

    a customizable set of options

  • [Array] (Hash)

    a customizable set of options

  • [Applitools::Selenium::FrameChain] (Hash)

    a customizable set of options



531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/applitools/selenium/eyes.rb', line 531

def check_frame__(options = {})
  options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil }.merge!(options)

  unless options[:index] ||
      options[:name_or_id] ||
      options[:frame_element] ||
      options[:frame_chain] ||
      options[:frames_path]
    raise Applitools::EyesIllegalArgument.new 'You must pass :index or :name_or_id or :frame_element option' \
      '  or :frame_chain option or :frames_path option'
  end

  if (needed_keys = (options.keys & [:index, :name_or_id, :frame_element, :frame_chain, :frames_path])).length == 1
    frame_key = needed_keys.first
  else
    raise Applitools::EyesIllegalArgument.new 'You\'ve passed some extra keys!' \
      'Only one of :index, :name_or_id or :frame_elenent or :frame_chain or :frames_path is allowed.'
  end

  if disabled?
    logger.info "check_frame(#{frame_key}: #{options[frame_key]}, timeout: #{options[:timeout]}," \
      " tag: #{options[:tag]}): Ignored"
    return
  end

  frame_or_frames = options[frame_key]
  if frame_or_frames.respond_to? :pop
    frame_to_check = frame_or_frames.pop
    original_frame_chain = driver.frame_chain
    logger.info 'Switching to parent frame according to frames path...'
    driver.switch_to.frames(frame_key => frame_or_frames)
    logger.info 'Done!'
    case frame_to_check
    when String
      frame_options = { name_or_id: frame_to_check }
    when Applitools::Selenium::Element
      frame_options = { frame_element: frame_to_check }
    else
      raise Applitools::EyesError.new "Unknown frame class: #{frame_to_check.class}"
    end
  else
    frame_options = { frame_key => options[frame_key] }
  end

  logger.info "check_frame(#{frame_key}: #{options[frame_key]}, timeout: #{options[:timeout]}," /
    " tag: #{options[:tag]})"
  logger.info 'Switching to requested frame...'

  driver.switch_to.frame frame_options
  logger.info 'Done!'

  check_current_frame options[:timeout], options[:tag]

  logger.info 'Switching back to parent_frame...'
  driver.switch_to.parent_frame
  logger.info 'Done!'
  return unless original_frame_chain

  logger.info 'Switching back into original frame...'
  driver.switch_to.frames frame_chain: original_frame_chain
end

#check_region(element, how = nil, what = nil, options = {}) ⇒ Object

Takes a snapshot of the application under test and matches a region of a specific element with the expected region output.

Examples:

Check region by element

check_region(element, tag: 'Check a region by element', match_timeout: 3, stitch_content: false)

Check region by css selector

check_region(:css, '.form-row .input#e_mail', tag: 'Check a region by element', match_timeout: 3,
stitch_content: false)

Parameters:

  • element (Applitools::Selenium::Element)

    Represents a region to check.

  • how (Symbol) (defaults to: nil)

    a finder, such :css or :id. Selects a finder will be used to find an element See Selenium::Webdriver::Element#find_element documentation for full list of possible finders.

  • what (String) (defaults to: nil)

    The value will be passed to a specified finder. If finder is :css it must be a css selector.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :tag (String)

    An optional tag to be associated with the snapshot.

  • :match_timeout (Fixnum)

    The amount of time to retry matching. (Seconds)

  • :stitch_content (Boolean)

    If set to true, will try to get full content of the element (including hidden content due overflow settings) by scrolling the element, taking and stitching partial screenshots.



424
425
426
427
428
429
430
431
432
# File 'lib/applitools/selenium/eyes.rb', line 424

def check_region(*args)
  options = Applitools::Utils.extract_options! args
  self.screenshot_name_enumerator = nil
  if options.delete(:stitch_content)
    check_element args, options
  else
    check_region_ args, options
  end
end

#check_region_in_frame(options = {}) ⇒ Applitools::MatchResult

Validates the contents of a region in an iframe and matches it with the expected output.

Parameters:

  • options (Hash) (defaults to: {})

    The specific parameters of the desired screenshot.

Options Hash (options):

  • :name_or_id (String)

    The name or id of the frame.

  • :tag (String)

    An optional tag to be associated with the snapshot.

  • :by (Symbol)

    By which identifier to find the region (e.g :css, :id).

  • :timeout (Fixnum)

    The amount of time to retry matching. (Seconds)

  • :stitch_content (Boolean)

    Whether to stitch the content or not.

Returns:

  • (Applitools::MatchResult)

    The match results.



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/applitools/selenium/eyes.rb', line 467

def check_region_in_frame(options = {})
  options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil, stitch_content: false }.merge!(options)
  Applitools::ArgumentGuard.not_nil options[:by], 'options[:by]'
  Applitools::ArgumentGuard.is_a? options[:by], 'options[:by]', Array

  how_what = options.delete(:by)

  process_in_frame options do |opts, frame_key|
    if disabled?
      logger.info "check_region_in_frame(#{frame_key}: #{options[frame_key]}, by: #{options[:by]}, " \
                      "timeout: #{options[:timeout]}, tag: #{options[:tag]}): Ignored)"
      return
    end

    check_region(*how_what, tag: opts[:tag], timeout: opts[:timeout], stitch_content: opts[:stitch_content])
  end
end

#check_window(tag = nil, match_timeout = USE_DEFAULT_MATCH_TIMEOUT) ⇒ Object

Takes a snapshot of the application under test and matches it with the expected output.

Parameters:

  • tag (String) (defaults to: nil)

    An optional tag to be assosiated with the snapshot.

  • match_timeout (Fixnum) (defaults to: USE_DEFAULT_MATCH_TIMEOUT)

    The amount of time to retry matching (seconds)



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/applitools/selenium/eyes.rb', line 192

def check_window(tag = nil, match_timeout = USE_DEFAULT_MATCH_TIMEOUT)
  self.tag_for_debug = tag
  self.screenshot_name_enumerator = nil
  if disabled?
    logger.info "check_window(#{tag}, #{match_timeout}): Ignored"
    return
  end

  logger.info "check_window(match_timeout: #{match_timeout}, tag: #{tag}): Ignored" if disabled?
  logger.info "check_window(match_timeout: #{match_timeout}, tag: #{tag})"

  region_provider = Object.new
  region_provider.instance_eval do
    define_singleton_method :region do
      Applitools::Region::EMPTY
    end
    define_singleton_method :coordinate_type do
      nil
    end
  end

  self.eyes_screenshot_factory = lambda do |image|
    Applitools::Selenium::EyesWebDriverScreenshot.new(
      image, driver: driver, force_offset: position_provider.force_offset
    )
  end

  match_data = Applitools::MatchWindowData.new.tap do |d|
    d.tag = tag
    d.ignore_mismatch = false
    d.match_level = default_match_settings[:match_level]
  end

  check_window_base region_provider, match_timeout, match_data
end

#open(options = {}) ⇒ Applitools::Selenium::Driver

Starts a test

Parameters:

  • options (Hash) (defaults to: {})

    options

Options Hash (options):

  • :driver (Object)

    The driver that controls the browser hosting the application under the test. (Required option)

  • :app_name (String)

    The name of the application under the test. (Required option)

  • :test_name (String)

    The test name (Required option)

  • :viewport_size (String | Hash)

    The required browser’s viewport size (i.e., the visible part of the document’s body) or nil to use the current window’s viewport.

  • :session_type (Object)

    The type of the test (e.g., standard test / visual performance test). Default value is ‘SEQUENTAL’

Returns:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/applitools/selenium/eyes.rb', line 124

def open(options = {})
  driver = options.delete(:driver)
  options[:viewport_size] = Applitools::RectangleSize.from_any_argument options[:viewport_size] if
      options[:viewport_size]
  Applitools::ArgumentGuard.not_nil driver, 'options[:driver]'
  Applitools::ArgumentGuard.hash options, 'open(options)', [:app_name, :test_name]

  if disabled?
    logger.info('Ignored')
    return driver
  end

  @driver = self.class.eyes_driver(driver, self)

  # if driver.respond_to? :driver_for_eyes
  #   @driver = driver.driver_for_eyes self
  # elsif driver.is_a? Capybara::Poltergeist::Driver
  #   @driver = Applitools::Poltergeist::Driver.new(self, driver: driver)
  # else
  #   unless driver.is_a?(Applitools::Selenium::Driver)
  #     logger.warn("Unrecognized driver type: (#{driver.class.name})!")
  #     is_mobile_device = driver.respond_to?(:capabilities) && driver.capabilities['platformName']
  #     @driver = Applitools::Selenium::Driver.new(self, driver: driver, is_mobile_device: is_mobile_device)
  #   end
  # end

  self.device_pixel_ratio = UNKNOWN_DEVICE_PIXEL_RATIO

  self.position_provider = self.class.position_provider(
    stitch_mode, driver, disable_horizontal_scrolling, disable_vertical_scrolling, explicit_entire_size
  )

  self.eyes_screenshot_factory = lambda do |image|
    Applitools::Selenium::EyesWebDriverScreenshot.new(
      image, driver: @driver, force_offset: position_provider.force_offset
    )
  end

  open_base options
  @driver
end

#region_provider_for_frameApplitools::Region

Returns the region of a given iframe.

Returns:

  • (Applitools::Region)

    The region of the iframe.



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/applitools/selenium/eyes.rb', line 374

def region_provider_for_frame
  Object.new.tap do |provider|
    current_frame_size = lambda do
      frame_region = Applitools::Region.from_location_size(
        Applitools::Location.new(0, 0), driver.frame_chain!.current_frame.size
      )
      begin
        frame_region.intersect Applitools::Region.from_location_size(
          Applitools::Location.new(0, 0),
          Applitools::Utils::EyesSeleniumUtils.entire_page_size(driver)
        )
        frame_region
      ensure
        frame_region
      end
    end

    provider.instance_eval do
      define_singleton_method :region do
        current_frame_size.call
      end
      define_singleton_method :coordinate_type do
        Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative]
      end
    end
  end
end

#test(options = {}) {|driver| ... } ⇒ Object

Use this method to perform seamless testing with selenium through eyes driver. It yields a block and passes to it an Applitools::Selenium::Driver instance, which wraps standard driver. Using Selenium methods inside the ‘test’ block will send the messages to Selenium after creating the Eyes triggers for them. Options are similar to #open

Examples:

eyes.test(app_name: 'my app', test_name: 'my test') do |driver|
   driver.get "http://www.google.com"
   driver.check_window("initial")
end

Yield Parameters:



498
499
500
501
502
503
504
# File 'lib/applitools/selenium/eyes.rb', line 498

def test(options = {}, &_block)
  open(options)
  yield(driver)
  close
ensure
  abort_if_not_closed
end