E2E test frameworks
Selenium Java
Background Runner

Background Runner

UserWay Background Runner is a tool that reduces amount of effort you need to add UserWay analysis to your existing E2E-tests.

Background Runner is designed in a way that allows you to enable it once, and then it will automatically implicitly analyze your pages while your tests run.

Background Runner will watch your Selenium WebDriver instances and analyze page and saves a report for CA11Y whenever you call any driver method that can possibly affect page's content or appearance, for example - clicking a button on a page.

Why using Background Runner?

If you have a really huge amount of E2E tests then extending your tests with UserWay analysis becomes quite a difficult task because you need to go through all your E2E tests and call analysis after each action that changes a page, e.g. after each time you click a button, send a form or use navigation bar to change to another page etc.

To prevent this hard and time-consuming work we introduced the UserWay Background Runner.

Usage

To configure Background Runner you should fulfill the following steps:

  1. You should configure global analysis configuration for all UserWay analysis executions that will be made in background and enable background monitoring before ALL your E2E-tests.
  2. Every time you create Selenium WebDriver instance you should exchange it with our proxy WebDriver by calling UserWayBackgroundRunner.getInstance().watch(driver) method.
  3. You should disable Background Runner after ALL your E2E-tests.

Example

Since we should configure and enable Background Runner before all our tests and then disable it after all tests, and we definitely have more than one test class and maybe more than one package of tests, we should use a tool that can help us with such configuration.

We recommend using JUnit Suite API that is available as a Maven artifact (opens in a new tab). This library allows us to create test suites that can combine any number of test classes and packages in it.

To configure a test suite we should just create main class and annotate it with @Suite and @SelectPackages/@SelectClasses.

// src/test/java/org/userway/selenium/runner/BackgroundRunnerTestSuiteRunner.java
 
@Suite
@SelectPackages({
        "org.userway.selenium.runner",
        "org.userway.selenium.example1",
        "org.userway.selenium.example2",
})
@SelectClasses({
    MyE2ETestClass1.class,
    MyE2ETestClass2.class,
    MyE2ETestClass3.class
})
public class BackgroundRunnerTestSuiteRunner {
 
    /**
     * This method will be called before ALL tests
     * that were added in this suite
     */
    @BeforeSuite
    static void setup() {
        var backgroundRunner = UserWayBackgroundRunner.getInstance();
 
        var analysisConfig = AnalysisConfig.builder()
                .level(Level.AAA)
                .ignoreSelectors(Set.of("#password", "form", "p"))
                .includeBestPractices(true)
                .includeExperimental(false)
                .excludeRules(
                        Set.of(
                                Rule.COLOR_CONTRAST,
                                Rule.COLOR_CONTRAST_ENHANCED
                        )
                )
                .build();
 
        var auditConfig = AuditConfig.builder()
                .strict(false)
                .auditTimeout(Duration.ofMinutes(5))
                .analysisConfiguration(analysisConfig)
                .elementScreenshots(false)
                .reportPath("./uw-a11y-reports")
                .build();
 
        // Set single global configuration for all background analysis calls
        backgroundRunner.setGlobalAuditConfig(auditConfig);
 
        // Enable UserWay Background Runner
        backgroundRunner.enableBackgroundRunner();
    }
 
    /**
     * This method will be called after ALL tests
     * that were added in this suite
     */
    @AfterSuite
    static void teardown() {
        // Disable UserWay Background Runner
        UserWayBackgroundRunner.getInstance().disableBackgroundRunner();
    }
 
}

Now as we are able to enable Runner before all tests and disable it after all tests finished, we can modify our test classes.

As you can see in the previous code snippet, we added MyE2ETestClass1.class in our test suite. Now let's see what should be inside of this test class. Here is how this class looked before:

public class MyE2ETestClass1 {
 
    private static WebDriver driver;
 
    @BeforeAll
    static void setup() {
        var options = new ChromeOptions();
        options.addArguments("--headless");
        driver = new ChromeDriver();
    }
 
    @AfterAll
    static void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
 
    @Test
    void test_1() {
        driver.get("https://example.com");
 
        var button = driver.findElement(By.cssSelector("button"));
 
        button.click();
    }
 
    @Test
    void test_2() {
        driver.get("https://example.com/example-form");
 
        var username = driver.findElement(By.id("username"));
        username.sendKeys("email@example.com");
 
        var password = driver.findElement(By.id("password"));
        password.sendKeys("Pa$$w0rd");
 
        var form = driver.findElement(By.id("my-form"));
        form.submit();
    }
 
}

Now we modify this test class by replacing default WebDriver we used with UserWay's proxy. Here is updated test class:

public class MyE2ETestClass1 {
 
    private static WebDriver driver;
 
    @BeforeAll
    static void setup() {
        var options = new ChromeOptions();
        options.addArguments("--headless");
        driver = new ChromeDriver();
 
        // Replacing driver with proxy
        var runner = UserWayBackgroundRunner.getInstance();
        driver = runner.watchDriver(driver, "MyE2ETestClass1-shared-driver"); // Second argument is optional and used for logs only
    }
 
    @AfterAll
    static void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
 
    @Test
    void test_1() {
        driver.get("https://example.com"); // After this call Runner will implicitly execute analysis
 
        var button = driver.findElement(By.cssSelector("button"));
 
        button.click(); // After this call Runner will implicitly execute analysis
    }
 
    @Test
    void test_2() {
        driver.get("https://example.com/example-form"); // After this call Runner will implicitly execute analysis
 
        var username = driver.findElement(By.id("username"));
        username.sendKeys("email@example.com"); // After this call Runner will implicitly execute analysis
 
        var password = driver.findElement(By.id("password"));
        password.sendKeys("Pa$$w0rd"); // After this call Runner will implicitly execute analysis
 
        var form = driver.findElement(By.id("my-form"));
        form.submit(); // After this call Runner will implicitly execute analysis
    }
 
}

So in conclusion if you have a lot of E2E tests and do not want to spend a lot of time adding hundreds or thousands UserWay analysis calls, the UserWay Background Runner is for you.

Covered methods

This section defines list of methods of Selenium WebDriver that trigger UserWay analysis after their execution.

Note: driver has type WebDriver, element has type WebElement

  • driver.get(...)
  • driver.executeScript(...)
  • driver.executeAsyncScript(...)
  • driver.navigate().back()
  • driver.navigate().forward()
  • driver.navigate().to()
  • driver.navigate().refresh()
  • driver.manage().window().maximize()
  • driver.manage().window().minimize()
  • driver.manage().window().fullscreen()
  • driver.manage().window().setSize(...)
  • element.click()
  • element.sendKeys()
  • element.clear()
  • element.submit()