Applitools Eyes Selenium SDK for Ruby

Gem Version

The Applitools Eyes Selenium SDK for Ruby provides comprehensive visual testing capabilities for web applications using Selenium WebDriver. Add AI-powered visual validations to your existing Selenium tests with minimal code changes.

Table of Contents

  1. Overview
  2. Installation
  3. Key Components
  4. Basic Usage
  5. Advanced Features
  6. Visual Grid / Ultrafast Grid
  7. Best Practices
  8. Troubleshooting
  9. FAQ
  10. Documentation
  11. API Reference

Overview

The Applitools Eyes Selenium SDK for Ruby seamlessly integrates visual testing into your Selenium WebDriver test automation. It captures screenshots of web pages and uses AI-powered visual comparison to detect visual changes and regressions.

Key Features

  • Full Page Screenshots: Automatic scrolling and stitching for complete page capture
  • Element & Region Testing: Target specific components for precise validation
  • Frame Support: Test content inside iframes with automatic context switching
  • Cross-Browser Testing: Run tests across multiple browsers with Visual Grid
  • Responsive Testing: Validate your app across different viewport sizes and devices
  • Smart Matching: Flexible algorithms to handle dynamic content
  • DOM Capture: Enhanced debugging with full DOM snapshots
  • Parallel Execution: Scale your tests with the Ultrafast Grid

Test Execution Modes

  1. Classic Runner: Sequential execution on your local browser
  2. Visual Grid Runner: Parallel execution across browsers in the cloud

Installation

Add the gem to your Gemfile:

gem 'eyes_selenium'

Or install it directly:

gem install eyes_selenium

Dependencies

The Eyes Selenium SDK has the following dependencies:

  • eyes_core - Core Applitools functionality
  • selenium-webdriver (>= 3) - WebDriver implementation
  • css_parser - CSS parsing for DOM analysis (!Deprecated)
  • crass - CSS parsing (!Deprecated)
  • state_machines - Internal state management (!Deprecated)

Key Components

Eyes Class

Applitools::Selenium::Eyes is the main class for interacting with the Applitools Eyes service. It provides the methods for initializing, configuring, and performing visual checks.

The Eyes class creates either a SeleniumEyes instance (for Classic Runner) or a VisualGridEyes instance (for Visual Grid), depending on the runner provided during initialization.

Target Class

Applitools::Selenium::Target defines what to capture during a check operation. It provides a fluent interface for specifying:

  • Full window or specific region to capture
  • Frames to switch to
  • Regions to ignore
  • Floating regions
  • Layout, content, and strict regions

Configuration Class

Applitools::Selenium::Configuration manages all the settings for Eyes tests, including:

  • Basic test information (app name, test name, etc.)
  • Screenshot capture options
  • Visual Grid browsers and devices
  • Match settings
  • Visual Grid options

Runners

The SDK offers two types of test runners:

  1. Classic Runner (Applitools::ClassicRunner):

    • Sequential execution
    • One browser at a time
    • Good for simple tests and debugging
  2. Visual Grid Runner (Applitools::Selenium::VisualGridRunner):

    • Parallel execution
    • Cross-browser and cross-device testing
    • Faster execution for multiple environments

Basic Usage

Initializing Eyes

require 'eyes_selenium'

# For Classic Runner (sequential execution)
runner = Applitools::ClassicRunner.new
eyes = Applitools::Selenium::Eyes.new(runner: runner)

# For Visual Grid (parallel execution)
runner = Applitools::Selenium::VisualGridRunner.new(10) # Concurrent sessions
eyes = Applitools::Selenium::Eyes.new(visual_grid_runner: runner)

# Set your API key
eyes.api_key = 'YOUR_API_KEY'

# Optional: Configure logging
eyes.log_handler = Logger.new(STDOUT)

Using WebDriver Elements Directly

The SDK allows direct usage of WebDriver elements:

# Initialize the WebDriver
driver = Selenium::WebDriver.for :chrome

# Initialize the Classic Runner
runner = Applitools::ClassicRunner.new

# Initialize Eyes with the runner
eyes = Applitools::Selenium::Eyes.new(runner: runner)

# Configure Eyes
eyes.api_key = ENV['APPLITOOLS_API_KEY']
eyes.configure do |conf|
  conf.app_name = 'My Application'
  conf.test_name = 'Simple Example'
  conf.viewport_size = { width: 1024, height: 768 }
end

# Open Eyes using the WebDriver directly
eyes.open(driver: driver)

# Navigate to the test page
driver.get 'https://applitools.com/helloworld'

# Check the full window
target = Applitools::Selenium::Target.window
eyes.check('Hello World', target)

# Check a specific element by using the element directly
element = driver.find_element(:id, 'button')
target_with_element = Applitools::Selenium::Target.region(element)
eyes.check('Just the button', target_with_element)

Note: While wrapper classes for WebDriver elements are still supported for backwards compatibility, it's recommended to use WebDriver elements directly as shown above.

Configuring the SDK

# Using configure block
eyes.configure do |conf|
  conf.app_name = 'My App'
  conf.test_name = 'My Test'
  conf.viewport_size = { width: 1200, height: 800 }

  # Screenshot settings
  conf.force_full_page_screenshot = true
  conf.stitch_mode = Applitools::STITCH_MODE[:css]
  conf.hide_scrollbars = true
  conf.wait_before_screenshots = 0.25 # seconds

  # Match settings
  conf.match_level = Applitools::MatchLevel::STRICT
  conf.send_dom = true
end

# Or using individual setters
eyes.match_level = Applitools::MatchLevel::LAYOUT
eyes.send_dom = true
eyes.force_full_page_screenshot = true

Opening a Test

# Initialize the WebDriver
web_driver = Selenium::WebDriver.for :chrome

# Start the test
driver = eyes.open(
  driver: web_driver,
  app_name: 'My App',
  test_name: 'My Test',
  viewport_size: { width: 1200, height: 800 }
)

# Navigate to the page
driver.get('https://example.com')

Capturing Screenshots

# Check the entire window
eyes.check('Home Page', Applitools::Selenium::Target.window)

# Check the entire window, capturing full page
eyes.check('Full Page', Applitools::Selenium::Target.window.fully)

# Alternative syntax for full window check
eyes.check_window('Home Page')

Closing a Test

# End the test
results = eyes.close(false) # Pass true to raise exception on differences

# Always clean up in an ensure block
ensure
  # If the test was not closed properly, abort it
  eyes.abort_if_not_closed

  # Close the WebDriver
  web_driver.quit

  # For Visual Grid, get all results and stop the runner
  if runner.is_a? Applitools::Selenium::VisualGridRunner
    all_results = runner.get_all_test_results
    runner.stop
  end

Advanced Features

Check Specific Regions

# Check a specific element by CSS selector
eyes.check('Header', Applitools::Selenium::Target.region(:css, 'header'))

# Check a specific element by ID
eyes.check('My Element', Applitools::Selenium::Target.region(:id, 'my-element'))

# Check a region by coordinates
region = Applitools::Region.new(10, 20, 200, 100) # left, top, width, height
eyes.check('Custom Region', Applitools::Selenium::Target.region(region))

Handling Frames

# Check content inside an iframe
eyes.check('Frame Content', Applitools::Selenium::Target.frame('frame-name'))

# Check a specific element inside a frame
eyes.check('Element in Frame', 
  Applitools::Selenium::Target.frame('frame-name').region(:css, '.my-class')
)

# Check nested frames
eyes.check('Nested Frame Content', 
  Applitools::Selenium::Target.frame('parent-frame').frame('child-frame')
)

Fluent Interface

The Target class provides a fluent interface for building complex check commands:

eyes.check('Complete Check',
  Applitools::Selenium::Target.window
    .fully                        # Capture full page
    .ignore(:css, '.timestamp')   # Ignore dynamic content
    .floating(:css, '.ad', 5, 5, 5, 5) # Floating region
    .layout(:css, '.dynamic-data') # Layout region
    .strict(:css, '.logo')         # Strict region
    .send_dom(true)                # Send DOM
)

Match Levels

Set different match levels to control how strict or lenient the comparison should be:

# Global match level
eyes.match_level = Applitools::MatchLevel::LAYOUT

# Match level for a specific check
eyes.check('Layout Check', 
  Applitools::Selenium::Target.window.match_level(Applitools::MatchLevel::LAYOUT)
)

# Available match levels:
# - Applitools::MatchLevel::EXACT   # Pixel-perfect matching
# - Applitools::MatchLevel::STRICT  # Default, allows small differences
# - Applitools::MatchLevel::CONTENT # Ignores colors, checks content
# - Applitools::MatchLevel::LAYOUT  # Checks only layout structure
# - Applitools::MatchLevel::NONE    # No comparison, just captures screenshot

Ignoring Regions

Specify regions to ignore during comparison:

# Ignore by selector
eyes.check('Ignore Timestamp',
  Applitools::Selenium::Target.window.ignore(:css, '.timestamp')
)

# Ignore multiple regions
eyes.check('Ignore Multiple',
  Applitools::Selenium::Target.window
    .ignore(:css, '.timestamp')
    .ignore(:id, 'ad-banner')
)

# Ignore by region
region = Applitools::Region.new(10, 20, 200, 100)
eyes.check('Ignore Region', Applitools::Selenium::Target.window.ignore(region))

Floating Regions

Floating regions allow elements to "float" or shift position within defined bounds:

# Floating region by selector with offsets (left, top, right, bottom)
eyes.check('Floating Region',
  Applitools::Selenium::Target.window.floating(:css, '.banner', 10, 10, 10, 10)
)

# Using FloatingBounds object
bounds = Applitools::FloatingBounds.new(10, 10, 10, 10)
eyes.check('Floating Region',
  Applitools::Selenium::Target.window.floating(:css, '.banner', bounds)
)

Layout, Content, and Strict Regions

Control the match level for specific regions:

# Layout region - only structure matters, not colors or content
eyes.check('With Layout Region',
  Applitools::Selenium::Target.window.layout(:css, '.dynamic-content')
)

# Content region - content matters, but not exact colors
eyes.check('With Content Region',
  Applitools::Selenium::Target.window.content(:css, '.important-text')
)

# Strict region - requires closer match than global setting
eyes.check('With Strict Region',
  Applitools::Selenium::Target.window.strict(:css, '.logo')
)

DOM Capture

DOM capture enhances visual testing by capturing the DOM structure of the page:

# Enable DOM capture globally
eyes.send_dom = true

# For a specific check
eyes.check('With DOM', Applitools::Selenium::Target.window.send_dom(true))

# Enable DOM-based matching
eyes.check('Use DOM', Applitools::Selenium::Target.window.use_dom(true))

Visual Grid / Ultrafast Grid

Applitools Visual Grid (also called Ultrafast Grid) allows running tests on multiple browsers and devices in parallel.

Configuring Visual Grid

# Create Visual Grid runner
runner = Applitools::Selenium::VisualGridRunner.new(10) # Concurrent sessions
eyes = Applitools::Selenium::Eyes.new(visual_grid_runner: runner)

# Configure browsers and devices
eyes.configure do |config|
  config.app_name = 'My App'
  config.test_name = 'Visual Grid Test'
  config.viewport_size = { width: 1200, height: 800 }

  # Add desktop browsers
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::CHROME)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::FIREFOX)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::EDGE_CHROMIUM)

  # Add mobile emulation
  config.add_device_emulation(Applitools::Selenium::Devices::iPhone_X, 
                             Applitools::Selenium::Orientations::PORTRAIT)
end

Cross-Browser Testing

# Configure multiple browsers
eyes.configure do |config|
  # Latest versions
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::CHROME)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::FIREFOX)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::SAFARI)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::EDGE_CHROMIUM)

  # Specific versions
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::CHROME_ONE_VERSION_BACK)
  config.add_browser(1200, 800, Applitools::Selenium::BrowserTypes::FIREFOX_TWO_VERSIONS_BACK)
end

Cross-Device Testing

# Configure multiple devices
eyes.configure do |config|
  # iOS devices
  config.add_device_emulation(Applitools::Selenium::Devices::iPhone_X, 
                             Applitools::Selenium::Orientations::PORTRAIT)
  config.add_device_emulation(Applitools::Selenium::Devices::iPad_Pro, 
                             Applitools::Selenium::Orientations::LANDSCAPE)

  # Android devices
  config.add_device_emulation(Applitools::Selenium::Devices::Pixel_3, 
                             Applitools::Selenium::Orientations::PORTRAIT)
  config.add_device_emulation(Applitools::Selenium::Devices::Galaxy_S9_Plus, 
                             Applitools::Selenium::Orientations::PORTRAIT)
end

Best Practices

  1. Efficient Test Organization

    • Use descriptive app and test names
    • Organize visual baselines by app/test name
    • Use batch info to group related tests
  2. Optimizing Checks

    • Check specific elements when possible instead of full page
    • Use appropriate match levels (layout for dynamic content)
    • Define ignore regions for highly dynamic elements
    • Use floating regions for elements that may shift position
  3. Working with Dynamic Content

    • Use layout match level for dynamic text
    • Ignore regions with timestamps, counters, or random data
    • Use the content match level for areas with text that changes but structure doesn't
  4. Visual Grid Optimization

    • Set an appropriate concurrency level based on your license
    • Group browser configurations logically
    • Prefer Visual Grid Runner for multiple browser/device tests
  5. Error Handling

    • Always call abort_if_not_closed in the ensure block
    • Handle test results properly
    • Close the WebDriver in the ensure block

Troubleshooting

Common Issues

  1. Authentication Errors

    • Ensure your API key is set correctly
    • Check if you need a proxy configuration
  2. Screenshot Mismatches

    • Use layout match level for dynamic content
    • Define ignore regions for highly dynamic elements
    • Check if you need to wait longer before taking screenshots
  3. Timing Issues

    • Increase the wait_before_screenshots value
    • Use explicit waits in your Selenium code before checks
  4. Browser Inconsistencies

    • Use specific browser versions in Visual Grid
    • Consider using force_full_page_screenshot
    • Check stitching mode (css vs scroll)
  5. Visual Grid Issues

    • Check that your license supports the number of concurrent sessions
    • Ensure you're calling runner.get_all_test_results and runner.stop

Debugging Tips

  1. Enable verbose logging:

    eyes.log_handler = Logger.new(STDOUT)
    eyes.log_handler.level = Logger::DEBUG
    
  2. Use debug screenshots:

    eyes.debug_screenshots = true
    
  3. Check test results in the Applitools dashboard for detailed information.

  4. For specific Visual Grid issues, check the specific browser renderings in the dashboard.

FAQ

Q: What's the difference between Classic Runner and Visual Grid Runner?
A: Classic Runner runs tests sequentially on your local browser, while Visual Grid Runner executes tests in parallel across multiple browsers and devices in the Applitools cloud.

Q: How do I handle dynamic content that changes between test runs?
A: You can:

  • Use layout match level for the entire page or specific regions
  • Define ignore regions for elements that frequently change
  • Use floating regions for elements that may move slightly

Q: Can I use Eyes with my existing Selenium tests?
A: Yes, the SDK integrates seamlessly with existing Selenium WebDriver tests. You just need to create an Eyes instance, wrap your driver, and add check commands.

Q: How do I test responsive designs?
A: Use the Visual Grid to test your application across multiple viewport sizes and devices in parallel.

Q: How can I exclude ads or dynamic content from comparison?
A: Use the ignore method on the Target to specify regions that should be ignored during comparison:

eyes.check('Ignore Ads', Applitools::Selenium::Target.window.ignore(:css, '.ad-container'))

Q: Does the SDK support testing with iframes?
A: Yes, use the frame method on the Target to test content inside iframes:

eyes.check('Frame Content', Applitools::Selenium::Target.frame('frame-name'))

Q: Can I use custom match settings for different elements on the page?
A: Yes, you can define specific regions with different match levels in a single check:

eyes.check('Mixed Match Levels',
  Applitools::Selenium::Target.window
    .layout(:css, '.dynamic-content')
    .strict(:css, '.logo')
    .content(:css, '.product-description')
)

Documentation

For comprehensive guides and tutorials, please refer to:

For API documentation and additional resources, visit:

API Reference

Applitools::Selenium::Eyes

Core methods:

  • initialize(options) - Creates a new Eyes instance
  • configure { |config| ... } - Configure the SDK with a block
  • open(options) - Starts a test
  • check(name, target) - Performs a checkpoint
  • check_window(tag, fully) - Performs a window checkpoint
  • check_region(how, what, options) - Performs a region checkpoint
  • close(raise_exception) - Closes a test
  • abort_if_not_closed - Aborts an open test

Configuration methods:

  • force_full_page_screenshot= - Sets full page screenshot mode
  • hide_scrollbars= - Controls hiding scrollbars
  • stitch_mode= - Sets the stitching mode (css or scroll)
  • match_level= - Sets the default match level
  • set_viewport_size - Sets the browser's viewport size

Applitools::Selenium::Target

Factory methods:

  • Target.window - Creates a target for the entire window
  • Target.region(...) - Creates a target for a specific region
  • Target.frame(...) - Creates a target for a frame

Instance methods:

  • fully(fully) - Sets whether to capture the full page
  • timeout(timeout_ms) - Sets the match timeout
  • ignore(...) - Defines regions to ignore
  • floating(...) - Defines floating regions
  • layout(...) - Defines layout regions
  • content(...) - Defines content regions
  • strict(...) - Defines strict regions
  • match_level(match_level) - Sets the match level for this target
  • send_dom(send_dom) - Sets whether to send DOM with this check
  • use_dom(use_dom) - Sets whether to use DOM for matching

Applitools::Selenium::Configuration

Main methods:

  • app_name= - Sets the application name
  • test_name= - Sets the test name
  • viewport_size= - Sets the viewport size
  • batch= - Sets the batch information
  • force_full_page_screenshot= - Controls full page screenshots
  • hide_scrollbars= - Controls hiding scrollbars
  • stitch_mode= - Sets the stitching mode
  • match_level= - Sets the default match level
  • add_browser(width, height, browser_type) - Adds a browser for Visual Grid
  • add_device_emulation(device, orientation) - Adds a device for Visual Grid

Applitools::ClassicRunner and Applitools::Selenium::VisualGridRunner

  • initialize(concurrency) - Creates a new runner
  • get_all_test_results - Gets results for all tests
  • stop - Stops the runner (Visual Grid only)

License

This SDK is distributed under the Applitools SDK License Agreement. See the LICENSE file for more details.

Important: This SDK may be used solely for your personal, non-commercial purposes. For commercial use, please contact your Applitools representative or visit applitools.com to obtain a commercial license.