Applitools Selenium Integration: Add Visual Testing to Your Selenium Tests

Applitools Selenium Integration: Add Visual Testing to Your Selenium Tests

Adding Applitools Eyes to existing Selenium tests is straightforward. The SDK wraps your WebDriver instance and adds visual checkpoint methods. Your existing test structure stays intact.

This guide covers Java, Python, and JavaScript integrations with practical examples.

Java Integration

Maven Dependency

<dependency>
  <groupId>com.applitools</groupId>
  <artifactId>eyes-selenium-java5</artifactId>
  <version>5.66.0</version>
</dependency>

Gradle

implementation 'com.applitools:eyes-selenium-java5:5.66.0'

Basic Test Structure

import com.applitools.eyes.selenium.Eyes;
import com.applitools.eyes.selenium.Configuration;
import com.applitools.eyes.RectangleSize;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.*;

public class VisualLoginTest {
  private WebDriver driver;
  private Eyes eyes;

  @BeforeClass
  public void setUp() {
    driver = new ChromeDriver();
    eyes = new Eyes();
    eyes.setApiKey(System.getenv("APPLITOOLS_API_KEY"));
  }

  @Test
  public void testLoginPage() {
    eyes.open(driver, "My App", "Login Test",
      new RectangleSize(1280, 720));

    driver.get("https://myapp.example.com/login");
    eyes.checkWindow("Login page");

    driver.findElement(By.id("email")).sendKeys("test@example.com");
    driver.findElement(By.id("password")).sendKeys("password");
    eyes.checkWindow("Login form filled");

    driver.findElement(By.id("submit")).click();
    eyes.checkWindow("After login");

    eyes.close();
  }

  @AfterClass
  public void tearDown() {
    driver.quit();
    eyes.abortIfNotClosed();
  }
}

Checking Specific Elements

import com.applitools.eyes.selenium.fluent.Target;
import org.openqa.selenium.By;

// Check a specific element by WebElement
WebElement header = driver.findElement(By.cssSelector(".page-header"));
eyes.check("Header", Target.region(header));

// Check by CSS selector directly
eyes.check("Navigation", Target.region(By.cssSelector("nav.main-nav")));

// Check with ignore regions
eyes.check("Dashboard",
  Target.window()
    .ignore(By.cssSelector(".live-feed"))
    .ignore(By.cssSelector(".timestamp")));

Python Integration

Installation

pip install eyes-selenium

Test with pytest

import os
import pytest
from selenium import webdriver
from applitools.selenium import Eyes, Target

@pytest.fixture
def eyes_driver():
    driver = webdriver.Chrome()
    eyes = Eyes()
    eyes.api_key = os.environ['APPLITOOLS_API_KEY']
    
    yield driver, eyes
    
    driver.quit()
    eyes.abort_if_not_closed()

def test_homepage_visual(eyes_driver):
    driver, eyes = eyes_driver
    
    eyes.open(driver, "My App", "Homepage", {"width": 1280, "height": 720})
    
    driver.get("https://myapp.example.com")
    eyes.check_window("Homepage")
    
    # Navigate and check another page
    driver.find_element("id", "nav-products").click()
    eyes.check_window("Products page")
    
    eyes.close()

def test_form_validation_visual(eyes_driver):
    driver, eyes = eyes_driver
    
    eyes.open(driver, "My App", "Form Validation", {"width": 1280, "height": 720})
    
    driver.get("https://myapp.example.com/signup")
    
    # Submit empty form to trigger validation
    driver.find_element("id", "submit").click()
    eyes.check_window("Validation errors shown")
    
    eyes.close()

Python Element Targeting

from applitools.selenium import Target
from selenium.webdriver.common.by import By

# Check full page
eyes.check("Full page", Target.window().fully())

# Check a region
nav = driver.find_element(By.css_selector, "nav")
eyes.check("Navigation", Target.region(nav))

# Ignore dynamic content
eyes.check("Dashboard",
  Target.window()
    .ignore(driver.find_element(By.css_selector, ".notifications"))
    .layout(driver.find_element(By.css_selector, ".chart-area")))

JavaScript Integration

Installation

npm install @applitools/eyes-selenium

Test with WebdriverIO

const { Eyes, Target, Configuration, BatchInfo } = require('@applitools/eyes-selenium');
const { Builder } = require('selenium-webdriver');

describe('Visual tests', () => {
  let driver, eyes;

  beforeAll(async () => {
    driver = await new Builder().forBrowser('chrome').build();
    
    eyes = new Eyes();
    const config = new Configuration();
    config.setApiKey(process.env.APPLITOOLS_API_KEY);
    config.setBatch(new BatchInfo('My App Suite'));
    eyes.setConfiguration(config);
  });

  it('Homepage visual check', async () => {
    await eyes.open(driver, 'My App', 'Homepage', { width: 1280, height: 720 });
    
    await driver.get('https://myapp.example.com');
    await eyes.check('Homepage', Target.window().fully());
    
    await eyes.close();
  });

  afterAll(async () => {
    await driver.quit();
    await eyes.abortIfNotClosed();
  });
});

Integrating Into Existing Tests

The most common pattern: add visual checkpoints at key moments in existing functional tests without changing test structure.

// Existing test: login flow
@Test
public void testUserCanLogin() {
  driver.get(baseUrl + "/login");
  
  // === ADD VISUAL CHECKPOINT ===
  eyes.checkWindow("Login page before interaction");
  // =============================
  
  driver.findElement(By.id("email")).sendKeys(testUser.email);
  driver.findElement(By.id("password")).sendKeys(testUser.password);
  driver.findElement(By.id("submit")).click();
  
  // Functional assertion (existing)
  assertTrue(driver.getCurrentUrl().contains("/dashboard"));
  
  // === ADD VISUAL CHECKPOINT ===
  eyes.checkWindow("Dashboard after login");
  // =============================
}

This way, each functional test also generates visual baselines. Visual regressions surface alongside functional failures.

Configuration Patterns

Batch Configuration (for CI)

Group all tests in a run into one batch:

BatchInfo batch = new BatchInfo("CI Run - " + System.getenv("BUILD_NUMBER"));
batch.setId(System.getenv("BUILD_NUMBER"));  // Stable ID for CI runs
eyes.setBatch(batch);

Match Level

// Default: exact pixel comparison
eyes.setMatchLevel(MatchLevel.STRICT);

// Layout only — ignores colors, font details
eyes.setMatchLevel(MatchLevel.LAYOUT);

// Content — ignores all styling
eyes.setMatchLevel(MatchLevel.CONTENT);

Viewport Size

Set consistent viewport to avoid baseline mismatches:

eyes.open(driver, "App", "Test", new RectangleSize(1280, 720));

Or configure globally:

Configuration config = eyes.getConfiguration();
config.setViewportSize(new RectangleSize(1280, 720));
eyes.setConfiguration(config);

CI Configuration

Set APPLITOOLS_API_KEY as a CI secret. Optionally set APPLITOOLS_BATCH_ID to group parallel runs:

- name: Run visual tests
  env:
    APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
    APPLITOOLS_BATCH_ID: ${{ github.run_id }}
  run: mvn test -Dtest=VisualTests

Related:

Read more

Start now free