Selenium Java SDK

The Evinced Selenium Java SDK integrates with new or existing Selenium WebDriver tests to automatically detect accessibility issues. By adding a few lines of code to your Selenium WebDriver project, you can begin analyzing all the web pages and DOM changes to provide a dynamic view of how your site can become more accessible. As a result of the test, a rich and comprehensive report is generated to easily track issues to resolution.

Interested in seeing this in action? Contact us to get started!

Prerequisites

  • Selenium version 3.141.59 or higher
  • Java Version 11 or higher
  • ChromeDriver or FirefoxDriver

Get started

Installation

To install Selenium Java SDK you will need either a file provided by Evinced Support or access to a remote repository that provides it. If you have neither, contact us to get started.

Installation with a locally provided file

You can install Selenium Java SDK using a standalone .jar distribution. In this case, you need to do the following:

  1. Download the .jar file.
  2. Unpack the provided selenium-sdk.zip to any desirable location.
  3. Add the following dependencies entries pointing to selenium-sdk.jar
    1. Gradle:
      1 implementation files('/Users/<path-to-your-unpacked-folder>/selenium-sdk.jar')
    2. Maven:
      1. First, install the “all” jar into your local Maven repository by the following command:
        1mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -Dfile=selenium-sdk-<version>.jar -DpomFile=selenium-sdk-<version>.pom
        Example:
        1mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -Dfile=selenium-sdk-1.30.1.jar -DpomFile=selenium-sdk-1.30.1.pom
      2. Add the corresponding dependency into your pom.xml:
        1 <dependency>
        2 <groupId>com.evinced</groupId>
        3 <artifactId>selenium-sdk</artifactId>
        4 <version>1.30.1</version>
        5 </dependency>

Installation from a remote repository

Evinced Customers have the option of accessing Selenium Java SDK from a remote repository - the Evinced JFrog Artifactory - to keep their SDK version up-to-date and to share the SDK internally at their organization.

When access is enabled, Selenium Java SDK is available at
https://evinced.jfrog.io/artifactory/restricted-maven/com/evinced/selenium-sdk.

Authentication

To launch Selenium Java SDK, you need to have a Service ID and an API Key.

Where to find your Evinced SDK credentials

These credentials are available via the Evinced Product Hub in the “Automation for Web” or “Automation for Mobile” product areas. Click the “Get SDK” button to see the Service Account ID and API Key at the bottom of the page.

Authenticate for Offline Testing

There are two methods to provide the token: online mode and offline mode. Online mode contacts the Evinced Licensing Server. Offline mode assumes that an Evinced employee has supplied a JSON Web Token (JWT). If an offline token is required, please reach out to your account team or support@evinced.com.

Please set credentials in environment variables and reference the environment variables in code.

1# Online mode
2export EVINCED_SERVICE_ID=<serviceId>
3export EVINCED_API_KEY=<apiKey>
4
5# Offline mode, when a JWT has been provided by Evinced
6export EVINCED_SERVICE_ID=<serviceId>
7export EVINCED_AUTH_TOKEN=<token>

Setting credentials, an example:

Add this code either in some static initializer section or into BeforeAll clause, so it should be called once before the first test.

1// Online mode
2EvincedSDK.setCredentials(System.getenv("EVINCED_SERVICE_ID"), System.getenv("EVINCED_API_KEY"));
3
4// OR
5
6// If provided a JWT by Evinced
7// Offline mode
8EvincedSDK.setOfflineCredentials(System.getenv("EVINCED_SERVICE_ID"), System.getenv("EVINCED_AUTH_TOKEN"));
9

Your First Test

SDK Initialization

To use Selenium Java SDK, you first need to authenticate. Please refer to Authentication for details.

Add the import statement to the beginning of your test file.

1import com.evinced.EvincedWebDriver;

Under the hood, the Evinced SDK utilizes several Selenium commands in order to get accessibility data. For this reason, we need to initialize EvincedWebDriver with the ChromeDriver instance in the following way:

1EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver());
Using Evinced with RemoteWebDriver? Learn more

If your test framework is built on top of a RemoteWebDriver implementation (e.g., Selenium Grid, cloud-based services like BrowserStack, Sauce Labs, or other custom WebDriver servers), it is recommended to initialize the driver using the following code snippet:

1EvincedRemoteWebDriver driver = new EvincedRemoteWebDriver(new ChromeDriver());

Add Evinced Accessibility Checks (Single Run Mode)

This is a simple example of how to add an Evinced accessibility scan to a test. Please note the inline comments that give detail on each test step.

This is a simple JUnit example of how to add a single Evinced accessibility scan to a test. Please note the inline comments that give detail on each test step.

1@Test
2public void evAnalyzeSimpleTest() {
3 // Initialize EvincedWebDriver which wraps a ChromeDriver instance
4 EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver());
5
6 // Navigate to the site under test
7 driver.get("https://www.google.com");
8
9 // Run analysis and get the accessibility report
10 Report report = driver.evAnalyze();
11
12 // Assert that there are no accessibility issues
13 assertTrue(report.getIssues().size() == 0);
14}

Add Evinced Accessibility Checks (Continuous Mode)

This is an example of how to add a continuous Evinced accessibility scan to a test. Using the evStart() and evStop() methods, the Evinced engine will continually scan in the background capturing all DOM changes and page navigation as the test is executed. This will capture all accessibility issues as clicking on drop-downs or similar interactions reveals more of the page. The advantage of continuous mode is that no interaction with the actual test code is needed.

This is a simple JUnit example of how to add a continuous Evinced accessibility scan to a test. Using the evStart and evStop methods, the Evinced engine will continually scan in the background capturing all DOM changes as the test is executed. This will capture all accessibility issues as clicking on dropdowns or similar interactions reveals more of the page. The advantage of continuous mode is that no interaction with the actual test code is needed.

1import com.evinced.EvincedWebDriver;
2import com.evinced.EvincedSDK;
3import com.evinced.EvincedReporter;
4
5@BeforeClass
6public static void setUp() throws MalformedURLException, IOException {
7 EvincedSDK.setCredentials(System.getenv("EVINCED_SERVICE_ID"), System.getenv("EVINCED_API_KEY"));
8 driver = new EvincedWebDriver(new ChromeDriver());
9 // Start the Evinced engine scanning for accessibility issues
10 driver.evStart();
11 //... the rest of our setup code
12}
13
14@AfterClass
15public static void tearDown() throws MalformedURLException, IOException {
16 // Stop the Evinced engine
17 Report report = driver.evStop();
18 //Output the Evinced report in either JSON or HTML format
19 EvincedReporter.evSaveFile("test-results", report, EvincedReporter.FileFormat.HTML);
20 EvincedReporter.evSaveFile("test-results", report, EvincedReporter.FileFormat.JSON);
21 driver.quit();
22}
23
24@Test
25public void evAnalyzeSimpleTest() {
26 // Navigate to the site under test
27 driver.get("https://www.google.com");
28 // More test code...
29}
Using Evinced with Selenium BiDi. Learn more

For faster execution and analysis, you can configure the Evinced SDK to use Selenium BiDi (Bidirectional Protocol). BiDi enables more efficient communication between the test automation and the browser, resulting in improved performance during accessibility scanning.

To configure ChromeDriver with BiDi enabled, use the following code snippet:

1ChromeOptions options = new ChromeOptions();
2options.setCapability("webSocketUrl", true);
3ChromeDriver chromeDriver = new ChromeDriver(options);
4EvincedWebDriver driver = new EvincedWebDriver(chromeDriver);

Advantage of using Selenium BiDi:

  • Faster execution and analysis: Reduced communication overhead between the driver and browser enables more efficient accessibility data collection

API


EvincedWebDriver(chromeDriver, configuration)

Prepares the Evinced object for use in the project.

The EvincedWebDriver constructor expects an instance of ChromeWebDriver. It is possible to pass an instance of a class that inherits or extends WebDriver.

1ChromeDriver chromeDriver = new ChromeDriver();
2EvincedWebDriver driver = new EvincedWebDriver(chromeDriver);

Refer to Configuration to see examples of initializing with options.


evAnalyze(options)

Scans the current page and returns a list of accessibility issues. This is the recommended method for static page analysis.

Note: This method is not supported if evStart() is already running.

1Report report = evincedWebDriver.evAnalyze();

Returns Report.

The returned report object contains a list of accessibility issues.

For more information regarding reports as well as the report object itself, please refer to our detailed Web Reports page.


evStart(options)

Continually watches for DOM mutations and page navigation, recording accessibility issues until the evStop() method is called. This method is recommended for dynamic page flows.

1evincedWebDriver.evStart();

Returns void.


evStop(options)

Stops the issue-gathering process started by evStart().

1evincedWebDriver.evStart();
2Report report = evincedWebDriver.evStop();

Returns Report.

The returned report object includes all accessibility issues detected between the evStart() and evStop() method calls. A single evStop() call still returns one deduplicated report even if evSwitchDriver rebound the session to a different WebDriver mid-session.

For more information regarding reports as well as the report object itself, please refer to our detailed Web Reports page.


evSwitchDriver(newDriver)

Rebinds an active continuous-analysis session to a new WebDriver instance, mid-session, without ending it — every accessibility issue captured before and after the swap is aggregated into the same session. Useful when the driver actually driving the test is created after evStart() (for example, a fresh driver per test step), or when a page reload recreates the driver.

1evincedWebDriver.evStart();
2
3evincedWebDriver = (EvincedWebDriver) evincedWebDriver.evSwitchDriver(new ChromeDriver());
4evincedWebDriver.get("https://www.example.com");
5
6Report report = evincedWebDriver.evStop(); // one aggregated report spanning every driver used

Important. Always reassign your driving variable to the value evSwitchDriver returns (a cast back to EvincedWebDriver is needed to keep calling evStart/evStop/evAnalyze on it) — interactions performed on the old driver instance after the swap are no longer captured.

Using evSwitchDriver with RemoteWebDriver or a Grid session. Learn more

A common pattern: use a Grid/RemoteWebDriver-backed session to own the continuous-analysis session, while each test step drives its own locally-created driver. Here session itself is never reassigned — evSwitchDriver returns the inner EvincedWebDriver (a different object from the outer session), so it's the driving variable that gets reassigned each step, while session stays bound to the Grid connection so a single evStop() still finalizes the whole session.

1EvincedRemoteWebDriver session = new EvincedRemoteWebDriver(gridRemoteWebDriver);
2session.evStart();
3
4WebDriver driver = session.evSwitchDriver(new ChromeDriver()); // first step's driver
5driver.get("https://www.example.com");
6
7driver = session.evSwitchDriver(new ChromeDriver()); // next step's driver
8driver.get("https://www.example.com/next-page");
9
10Report report = session.evStop(); // one aggregated report across every driver used

Returns the WebDriver handle to keep driving the page through — reassign your driver variable to it and continue the test from there.


evSaveFile(destination, issues, format)

Saves issues in a file with the specified format and location. Supported formats are json, html, sarif, and csv. Find detailed information in the Web Reports page.

1Report report = evincedWebDriver.evStop();
2 -- or --
3Report report = evincedWebDriver.evAnalyze();
4
5// create a JSON file named jsonReport.json
6EvincedReporter.evSaveFile("jsonReport", report, EvincedReporter.FileFormat.JSON);
7
8// create an HTML file named htmlReport.html
9EvincedReporter.evSaveFile("htmlReport", report, EvincedReporter.FileFormat.HTML);
10
11// create an SARIF file named sarifReport.sarif.json
12EvincedReporter.evSaveFile("sarifReport", report, EvincedReporter.FileFormat.SARIF);
13
14// create an CSV file named csvReport.csv
15EvincedReporter.evSaveFile("csvReport", report, EvincedReporter.FileFormat.CSV);

Note: To generate a report in the specific format (but JSON) we are running some code on the browser side. If you are using custom WebDriver or there are some environmental issues with starting browser or driver during report generation, please use the command where you can provide the WebDriver object.

1WebDriver driver = yourCustomMethodToInstaantiateDriver();
2// Generates aggregated report using custom WebDriver object
3EvincedReporter.evSaveFile("htmlReport", EvincedReporter.FileFormat.HTML, driver);
4driver.quit();

FileFormat

Defines the file type of the report. Options are JSON, HTML, SARIF and CSV.

Returns Path.

Aggregated Report

The aggregated report feature allows you to have a general aggregated report for the whole run (not only for one test or suite). This report will contain all the issues found by the tests where evStart() and evStop() commands were called. It is still possible to use the evSaveFile() command in any place of your code along with this Aggregated Report feature.

1Path htmlAggregatedReport = EvincedReporter.evSaveFile("evinced-html-report", EvincedReporter.FileFormat.HTML);

Configuration

The same configuration options can be used when initializing the Evinced object using EvincedConfiguration() and when calling the evStart() and evAnalyze() methods but with a bit different consequences. Providing options when initializing defines a global configuration for all calls of evAnalyze() and evStart(), while providing options to either of those methods affect only the test in which they are called. Some SDKs also let you define configuration outside your code, in a config file that is picked up automatically at startup.

Options provided in either evAnalyze() or evStart() override those set in Evinced engine initialization.

Engines Configuration

Evinced uses two separate engines when scanning for accessibility issues, one is the aXe engine and the other is the Evinced engine. By default, Evinced disables the aXe Needs Review and Best Practices issues based on customer request and due to the fact they are mostly false positives. Please note this setting when comparing issue counts directly. See an example of how to enable Needs Review and Best practices issues in the Toggles section.

Configuration File

Place a configuration file at the root of your working directory to set options without touching code. The SDK looks for one of the following, in this order, and uses the first one it finds — file formats are never merged together:

  1. evConfig.yaml
  2. evConfig.yml
  3. evConfig.json
1scan:
2 iframes: true
3logging:
4 enabled: true
5 preset: standard
6platform:
7 upload:
8 enabled: true

How settings are combined

Configuration can come from several places, and each one can override the ones before it:

  1. Built-in defaults — what the SDK ships with.
  2. Environment variables — a small set of process-wide switches, listed below.
  3. The evConfig file — settings for the whole project, discovered automatically as described above.
  4. Your code, when you create the SDK instance — using EvincedOptions, or the deprecated configuration object.
  5. Your code, on an individual call — options passed directly to a single evStart() or evAnalyze() call, which apply only to that call.

Later steps win over earlier ones for the same setting. A setting your code never touches keeps falling through to whatever the evConfig file, an environment variable, or the built-in default provided.

Settings that are objects merge key by key rather than replacing each other wholesale. Most lists, by contrast, are replaced wholesale by whichever layer set them last — setting the same list-typed setting in the evConfig file and again in code means the code's value wins outright, not a combination of both. The list of domains allowed for hidden iframes (scan.iframeDomains) is the one named exception: it's always combined across layers instead, with duplicate entries removed, so a list in the evConfig file and one added in code both end up applied. A handful of other settings that accumulate entries one call at a time (rather than taking a whole list at once) behave the same way — check that setting's own reference entry below for its specific merge behavior.

Environment variables

A handful of environment variables participate in this same layering, primarily useful in CI environments where you don't want to check in a config file:

VariableSame asNotes
EV_SWITCH_ONswitchOnOnly the literal value true turns Evinced on; anything else is treated as off.
EV_PLATFORM_UPLOADplatform.upload.enabledSet to enable to turn on report uploads to the Evinced Platform.
EV_PLATFORM_URLplatform upload endpointOverrides the Evinced Platform address reports are uploaded to.
EVINCED_DISABLE_ANALYTICStelemetry.channels.sdk (inverted)Set to any value to disable SDK telemetry.

An environment variable that is left unset never overrides a lower-priority default — it only takes effect when you explicitly set it.

Configuration Object

Global configuration for Selenium Java SDK can be defined in three ways, all sharing the same nested structure: an evConfig file at the root of your project (see Configuration File), the modern EvincedOptions builder passed to EvincedWebDriver(chromeDriver, configuration), or the deprecated configuration object, which keeps working unchanged. Options passed directly to a single evStart() or evAnalyze() call override all three for that call only.

The full shape of the configuration, shown here as a type definition for reference:

1type EvConfig = {
2 switchOn?: boolean;
3 mock?: boolean;
4 scan?: {
5 rootSelector?: string;
6 iframes?: boolean;
7 iframeDomains?: string[];
8 withPasses?: boolean;
9 screenshots?: {
10 enabled?: boolean;
11 mode?: 'browser' | 'sdk';
12 scale?: number;
13 quality?: number;
14 timeout?: number;
15 };
16 dedupe?: {
17 local?: boolean;
18 };
19 settle?: {
20 enabled?: boolean;
21 throttle?: { enabled?: boolean; delay?: number };
22 };
23 alerts?: { expected?: boolean; timeout?: number };
24 navigation?: {
25 spaTracking?: boolean;
26 lossRecovery?: boolean;
27 processingTimeout?: number;
28 iframeInjectionWaitTime?: number;
29 finishInterval?: number;
30 };
31 };
32 analysis?: {
33 [key: string]: unknown;
34 };
35 logging?: {
36 enabled?: boolean;
37 preset?: 'errors' | 'standard' | 'diagnostic';
38 level?: 'error' | 'warn' | 'info' | 'debug' | 'trace';
39 outputDir?: string;
40 maxEntryLength?: number;
41 consoleLogger?: boolean;
42 systemInfo?: boolean;
43 configurationFile?: string;
44 channels?: {
45 sdk?: boolean;
46 engine?: boolean;
47 browserConsole?: boolean;
48 httpClient?: boolean;
49 performance?: boolean;
50 scanInsights?: boolean;
51 };
52 };
53 network?: {
54 enabled?: boolean;
55 maxRetries?: number;
56 retryDelay?: number;
57 idle?: { enabled?: boolean; timeout?: number; maxWait?: number };
58 };
59 platform?: {
60 upload?: { enabled?: boolean; autoUpload?: boolean };
61 };
62 telemetry?: {
63 enabled?: boolean;
64 channels?: { sdk?: boolean; engine?: boolean };
65 };
66 performance?: {
67 scriptBatching?: boolean;
68 bundleCache?: boolean;
69 };
70};
1switchOn: true
2scan:
3 rootSelector: '#main'
4 iframes: true
5 screenshots:
6 enabled: true
7logging:
8 enabled: true
9 level: debug

A bare null literal — evStart()``(null) / evAnalyze()``(null) — no longer compiles, since it's ambiguous between the EvincedConfiguration and EvincedOptions overloads; cast it to whichever type you mean. The two casts are not equivalent: (EvincedConfiguration) null is a no-op, preserving whatever configuration was already in effect for that call, while (EvincedOptions) null throws IllegalArgumentException.

Root Selector

Sets a CSS selector to limit the Evinced Engine to scan only the selected element and its children. Must be a valid CSS selector. If not set, the Evinced Engine will scan the entire document.

Default: no value

1scan:
2 rootSelector: '.some-selector'

Axe Configuration

Configures Axe open-source accessibility toolkit, which the Evinced engine includes with its own, more extensive accessibility detection. For full Axe config options, see Axe Core API.

1analysis:
2 AXE_CONFIG:
3 rules:
4 html-has-lang:
5 enabled: false

Engine Logging

Set level of messages the Evinced engine will print to the console. Valid levels are "debug", "info", "warn" and "error".

Default: "error"

Beyond the engine's own log level, the logging.* section controls the SDK's logging as a whole: whether logging is on at all, which channels are captured (the SDK's own messages, the engine's, the browser console, the HTTP client, performance timings, and scan insights), where logs are written, and how verbose they are. A preset is a shortcut that sets several of these at once — errors, standard, or diagnostic (which additionally turns on the engine channel).

1logging:
2 enabled: true
3 preset: diagnostic
4 level: debug
5 channels:
6 engine: true

Valid values for level/loggingLevel are "error", "warn", "info", "debug", and "trace" (case-insensitive).

Reports Screenshots

When true, the Evinced SDK will include screenshots in its reports that highlight elements with accessibility issues.

Default: false.

Note: Enabling screenshots may affect test run performance.

screenshot of a demo.evinced.com page with an issue highlighted

Screenshots have two independent settings: whether they're captured at all (scan.screenshots.enabled), and — once enabled — who captures them (scan.screenshots.mode).

mode wire valueJava constantWho captures
sdkScreenshotMode.SDKThe SDK, via Chrome DevTools — full-page, pixel-true, faster on heavy pages. Chromium only; falls back to PAGE on other drivers. Default when screenshots are enabled.
browserScreenshotMode.PAGEThe accessibility engine, in-page (html2canvas).
1scan:
2 screenshots:
3 enabled: true
4 mode: sdk

Toggles

Enables experimental features. Feature names and values may vary from release to release.

Example:

1analysis:
2 TOGGLES:
3 USE_AXE_NEEDS_REVIEW: true
4 USE_AXE_BEST_PRACTICES: true

Skip Validations

Sets validation types to be skipped for specified URL pattern and CSS selector. Issue type IDs can be found by inspecting a JSON report as described in Web Reports.

Default: no validations skipped.

1analysis:
2 SKIP_VALIDATIONS:
3 - selector: 'test.1--selector'
4 urlRegex: 'http://url.to.skip/path1'
5 validationTypes: ['NO_DESCRIPTIVE_TEXT', 'NOT_FOCUSABLE']
6 - selector: 'test.2--selector'
7 urlRegex: 'http://url.to.skip/path2'
8 validationTypes: ['NOT_FOCUSABLE', 'ONE_MORE_TYPE_TO_EXCLUDE', 'NO_DESCRIPTIVE_TEXT']

Skipping every validation type

To suppress all validation types for a selector, pass the wildcard * in place of a list of type names.

The wildcard must be the only value. Listed alongside concrete type names it is not treated as a wildcard — the wildcard entry is ignored and only the concrete types given with it are skipped.

1analysis:
2 SKIP_VALIDATIONS:
3 - selector: '#parent, #parent *'
4 urlRegex: 'http://url.to.skip/path1'
5 validationTypes: '*'

A selector matches elements, not subtrees

Skip rules are evaluated against each reported element on its own, so a selector suppresses issues only on the elements it matches — not on anything nested inside them. To cover a container and its contents, list both the container and its descendants:

1#parent, #parent *

#parent alone suppresses only issues reported on #parent itself.

Recording Service

This setting controls how frequently event-triggered functions are executed, helping to optimize performance and responsiveness. The option does not enable or disable the event-handling service itself but determines how frequently events are processed based on the selected mode.

Available modes:

  • debounce - Delays execution until a set time has passed since the last event. Useful for actions triggered by continuous input, such as typing in a search box, to avoid excessive function calls.
  • throttle - Ensures execution at fixed intervals, regardless of event frequency. Ideal for scenarios like handling window resize events or scroll tracking, where limiting execution prevents performance degradation.

Default: Functions execute as triggering events occur.

An example of how to modify settings:

1analysis:
2 RECORDING_SERVICE:
3 ENABLE_DEBOUNCE_NEW_SELECTORS: true
4 DEBOUNCE_NEW_SELECTORS_MS: 1000
5 DELAY_MODE: throttle

Performance

Settings under performance that reduce the SDK's per-interaction and per-test overhead.

Script Batching

Groups the small scripts the SDK injects into the page into fewer round-trips to the browser, reducing per-interaction overhead.

Default: true.

1performance:
2 scriptBatching: false

Script batching is enabled by default. Disable it only if you're diagnosing an issue and want to isolate individual script executions.

Bundle Cache

Caches the Evinced engine bundle across test runs instead of fetching and re-initializing it every time, reducing per-test startup overhead.

Default: false.

1performance:
2 bundleCache: true

Turn this on for test suites that create many short-lived driver instances against the same application, so repeat test runs skip re-fetching and re-initializing the engine bundle.

Settled Analysis

This setting controls accessibility analysis after user interactions like clicks and actions. It ensures that accessibility issues in dynamic content that appears after user actions are properly captured and reported.

Why you need this configuration:

Settled analysis automatically captures accessibility issues that appear after user interactions such as clicks, form submissions, or other dynamic changes. When users interact with your application, new content may be revealed (dropdowns, modals, dynamically loaded sections) that contains accessibility violations. Without settled analysis, these issues would only be detected during the final evStop() call, potentially missing critical accessibility problems that occur during the user journey.

Key benefits:

  • Complete coverage: Captures accessibility issues in dynamically revealed content
  • Real-time detection: Issues are found immediately after user interactions
  • Better debugging: Issues are associated with specific user actions that triggered them
  • Comprehensive reporting: Provides a complete picture of accessibility state throughout the test

When to disable: You may want to disable settled analysis in performance-critical test scenarios where the additional analysis calls impact test execution time, or when testing static pages with no dynamic content.

Throttling mechanism:

The throttling feature prevents excessive analysis calls when users perform rapid interactions (like multiple quick clicks or form field changes). Without throttling, each user action could trigger a separate analysis, leading to:

  • Performance degradation: Multiple concurrent analysis calls can slow down test execution
  • Resource consumption: Excessive CPU and memory usage from frequent DOM analysis

Why you need throttling configuration:

  • Optimize performance: Reduce the frequency of analysis calls during rapid user interactions
  • Prevent resource exhaustion: Control CPU and memory usage in complex test scenarios
  • Maintain test stability: Avoid conflicts between multiple simultaneous analysis operations
  • Customize timing: Adjust delay based on your application's response characteristics

Default:

  • Settled analysis: Enabled.
  • Throttling: Disabled (immediate execution).
  • Throttle delay: 200ms when enabled.

An example of how to modify settings:

1scan:
2 settle:
3 enabled: true
4 throttle:
5 enabled: true
6 delay: 500

Knowledge-Base Link Overrides

Sets customized knowledge-base links in the reports. The links are displayed in the reports “Issue Type” column, as shown in the following screenshot:

An issue report table where the “Issue Type” column contains links to a knowledge base

The knowledge base link can be overridden for every issue type ID. Issue type IDs can be found by inspecting a JSON report as described in Web Reports. For example, the issue with name Interactable Role has ID WRONG_SEMANTIC_ROLE.

Knowledge-base links can be overridden per Evinced issue type ID or per axe-core rule ID. Both are now also configurable via evConfig.yaml/.json and EvincedOptions, in addition to the existing EvincedConfiguration setters.

1analysis:
2 ISSUE_CONTENT_PER_TYPE:
3 WRONG_SEMANTIC_ROLE:
4 knowledgeBaseLink: 'https://kb.example.com/wrong-semantic-role'
5 AXE_ISSUE_CONTENT_PER_TYPE:
6 color-contrast:
7 knowledgeBaseLink: 'https://kb.example.com/color-contrast'

knowledgeBaseLink(issueType, url) overrides the link for an Evinced-engine issue type ID, the same IDs described in Knowledge-Base Link Overrides above. axeKnowledgeBaseLink(ruleId, url) overrides the link for an axe-core rule ID directly (for example color-contrast).

Shadow DOM Support

Shadow DOM is now supported by default. No additional configuration is needed.

If using an earlier release, configure shadow DOM support as follows: There is no dedicated scan.shadowDom setting — shadow DOM support is always on. To turn it off (matching the pre-default-support behavior), use the same engine toggle mechanism as Toggles:

1analysis:
2 TOGGLES:
3 SUPPORT_SHADOW_DOM: false

IFrames Support

When true, accessibility analysis includes iframe that exist inside the page.

Default: true.

1scan:
2 iframes: false

Include Hidden IFrames Domain

Configures which hidden iframe domains are included in accessibility analysis. By default, hidden iframes are excluded for performance and security reasons.

This setting allows you to specify a list of domains to analyze even when the iframe is hidden.

1scan:
2 iframes: true
3 iframeDomains:
4 - example.com
5 - test.com

Passed Validations

By default, the Evinced SDK only reports accessibility issues that have failed validation. However, you can also configure the SDK to include passed validations in your reports. Passed validations represent accessibility checks that were successfully completed without any issues found.

Why include passed validations?

Including passed validations in your reports provides several benefits:

  • Comprehensive Coverage: Get a complete picture of all accessibility checks performed, not just the failures
  • Compliance Documentation: Demonstrate which accessibility standards your application successfully meets
  • Trend Analysis: Track improvements over time by monitoring both failed and passed validation counts
  • Quality Assurance: Verify that accessibility checks are running as expected across your entire application
  • Regulatory Reporting: Provide evidence of accessibility testing coverage for compliance audits

Report Structure

When passed validations are enabled, your reports will include both:

  • failedValidations: Array of accessibility issues that need to be fixed
  • passedValidations: Array of accessibility checks that passed successfully

Default: false (passed validations are not included)

Enabling passed validations has a performance impact, since the report now records every check that passed in addition to the ones that failed.

1scan:
2 withPasses: true

Passed validations are included only in JSON format reports saved via evSaveFile(destination, issues, format).

Proxy

Configures proxy server access settings. Needed to enable outbound communication to the Evinced Platform through a proxy server.

1...
2String proxyString = "ip:port";
3//Or if you have credentials
4String proxyString = "user:password@ip:port";
5Proxy proxy = new Proxy();
6proxy.setHttpProxy(proxyString)
7 .setSslProxy(proxyString);
8ChromeOptions chromeOptions = new ChromeOptions();
9chromeOptions.setProxy(proxy);
10EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver(chromeOptions));
11...

SPA Navigation Tracking

Automatically detects client-side navigation in Single Page Applications (SPAs) and restarts accessibility analysis to capture issues in dynamically loaded content.

Why you need this feature:

Modern web applications built with frameworks like React, Angular, or Vue.js use client-side routing where content changes without full page reloads. Without SPA navigation tracking, accessibility issues in these dynamically loaded views would be missed.

What it monitors:

  • URL changes via browser history API (pushState, replaceState)
  • Browser back/forward navigation (popstate)
  • Hash-based routing changes (#/page)

Default: false (disabled)

Note: This feature works with Selenium BiDi for enhanced performance. Enable BiDi to activate this functionality.

1scan:
2 navigation:
3 spaTracking: true

This feature works with Selenium BiDi for enhanced performance — enable BiDi on your driver (as shown above) to activate it, and combine it with Continuous Mode (evStart()/evStop()) to capture every navigation event.

Network Idle Detection

The networkIdle configuration enables the SDK to wait for all network requests to complete before running accessibility analysis. This is particularly useful for modern web applications that load content dynamically after the initial page load.

Why use Network Idle Detection?

When testing modern web applications, accessibility analysis may run before all content has loaded, resulting in:

  • Incomplete results: Dynamic content not yet rendered won't be analyzed
  • False negatives: Accessibility issues in delayed content won't be detected
  • Inconsistent results: Analysis timing may vary between test runs

Network idle detection solves this by ensuring all network activity has settled before analysis begins.

Configuration Options:

OptionTypeDefaultDescription
enabledbooleanfalseEnables or disables network idle detection
idleTimeoutnumber300Time in milliseconds to wait after the last network request completes before considering the network idle
maxWaitTimenumber7500Maximum time in milliseconds to wait for network idle. If exceeded, analysis proceeds with a warning

Network idle detection can be configured globally during SDK initialization or per-command for granular control.

1network:
2 idle:
3 enabled: true
4 timeout: 300
5 maxWait: 7500

Implementation note: network-idle detection relies on the WebDriver BiDi Network API to count in-flight requests. Enable BiDi on your driver (for example ChromeOptions.setCapability("webSocketUrl", true)) — without it, the idle wait is skipped and analysis proceeds immediately regardless of this configuration.

How It Works:

The SDK monitors all network requests and waits for the network to become idle before proceeding with analysis:

  1. Network is considered "idle" when no requests are active for at least idleTimeout milliseconds
  2. Analysis waits for idle state or maxWaitTime, whichever comes first
  3. Configuration from evStart() automatically applies to subsequent page navigations and evStop()

Best Practices:

  • Start with defaults: Enable with default settings and adjust only if needed
  • Increase timeout for slow APIs: If your backend is slow, increase maxWaitTime
  • Use per-command for specific pages: Enable only for pages with dynamic content

Important Notes:

  • Disabled by default: The feature is opt-in to maintain backward compatibility
  • No overhead when disabled: When not enabled, there is zero performance impact
  • Automatic timeout extension: Command timeouts are automatically adjusted based on maxWaitTime
  • Warning on timeout: If maxWaitTime is exceeded, the SDK logs a warning and proceeds with analysis

Custom SSL Trust Store

Some enterprise environments route outbound HTTPS traffic through a corporate proxy that performs TLS inspection. The proxy re-signs every connection with an internal Certificate Authority (CA) that the JVM does not recognise out of the box, and SDK network calls fail with PKIX path building failed: unable to find valid certification path to requested target.

The SDK funnels every outbound HTTPS call through a single network layer, so this affects all SDK traffic — license validation, anonymized telemetry, component-recognition backends, and uploading reports to the Evinced Platform. Depending on which destinations your proxy intercepts you may see some or all of these failures in the SDK log.

The fix is a configuration option on the SDK: you build an SSLContext that trusts your internal root CA, attach it to the SDK's configuration object, and pass that configuration to the SDK entry point. The SDK takes care of the rest. The JVM-wide truststore is not modified, and the rest of your application's HTTPS traffic is untouched. You never need to call internal SDK APIs directly.

Default: no value — the SDK falls back to the JVM default truststore and honours -Djavax.net.ssl.trustStore=... when set.

Trust an internal Certificate Authority from a PEM/DER file

Most environments only need to trust one extra root CA — the one used by the corporate proxy. The bundled SslContextFactory builds an SSLContext that combines the JVM defaults with your additional certificate(s).

An SSLContext instance can't be expressed in an evConfig file or an environment variable, so this setting is programmatic-only, either through EvincedOptions or the deprecated configuration object:

1import com.evinced.EvincedWebDriver;
2import com.evinced.common.network.SslContextFactory;
3import com.evinced.dto.configuration.EvincedOptions;
4
5import javax.net.ssl.SSLContext;
6import java.io.InputStream;
7
8EvincedOptions options;
9try (InputStream rootCa = MyTest.class.getResourceAsStream("/corp-root.pem")) {
10 SSLContext sslContext = SslContextFactory.composedWithDefaults(rootCa);
11 options = EvincedOptions.create().network(n -> n.sslContext(sslContext));
12}
13
14// The SDK uses the supplied SSLContext for every outbound HTTPS call —
15// license validation, telemetry, component-recognition backends, and
16// uploads to the Evinced Platform.
17EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver(), options);

Both PEM (-----BEGIN CERTIFICATE----- / -----END CERTIFICATE-----) and DER (binary) inputs are accepted. You can pass several streams in one call if your proxy chains multiple internal CAs.

Re-use an SSLContext you already have

If your application already builds an SSLContext (for example via Spring's SslBundles or your own keystore loader), pass it in directly — there is no requirement to use SslContextFactory:

1SSLContext myContext = ...; // already configured elsewhere
2
3EvincedOptions options = EvincedOptions.create().network(n -> n.sslContext(myContext));
4
5EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver(), options);

Verify it worked

If the trust chain is still broken, the SDK short-circuits each affected network call instead of retrying three times. Look for this WARN line in the SDK log — it can appear against any *.evinced.com host the SDK contacts:

1[NetworkManager] TLS trust failure for https://host.evinced.com/... —
2PKIX path building failed: ...

If you see it, the certificate you supplied does not match the chain the proxy presents — re-export the proxy's root CA from the browser and try again. If SDK network calls succeed, no TLS-related warnings appear at all.

Global Switch

When false, disables Evinced functionality. Enabled by default, use this setting to disable Evinced accessibility analysis when not needed during test development or when running CI jobs where accessibility testing is not intended.

Default: true.

When switched off:

  • evStart() and evSaveFile() will be bypassed.
  • evStop() and evAnalyze() will return an empty report.

Switching Evinced Functionality Off in Configuration

1switchOn: false

Important! Global Switch environment variable overrides the global configuration option.

Switching Evinced Functionality Off in Environment

1export EV_SWITCH_ON=false

Alerts

When true, Evinced expects alerts to be displayed at any time, after any action, and will wait for them to be closed. When false, Evinced will not wait for alerts to be closed and will continue the analysis.

Default: false.

1scan:
2 alerts:
3 expected: true
4 timeout: 5000

Uploading Reports to Evinced Platform

Introduction

Evinced Platform allows you to seamlessly collect, organize, visualize and monitor Evinced accessibility reports in one place. In this section, we will guide you through the key functionalities of the upload methods of the accessibility reports from the Evinced SDK to the Evinced Platform, which was introduced in version 3.4.2. This upload method is fully compatible with the previous versions of the Evinced SDK API, and is disabled by default.

Enable Upload Report to Platform

To enable the uploading functionality of accessibility reports to the Evinced Platform you will need to set the enableUploadToPlatform method to "true":

1EvincedSDK.enableUploadToPlatform(true);

Note: Using PlatformUpload.ENABLED in method parameters (e.g., driver.evAnalyze(PlatformUpload.ENABLED)) is not sufficient on its own. You must first enable the feature by calling EvincedSDK.enableUploadToPlatform(true). The method parameter only controls whether a specific report uploads when the feature is already enabled.

Automatic Report Upload

Once the enableUploadToPlatform method is set to true and setUploadToPlatformDefault is true (which is the default), all generated reports will be automatically uploaded to the Platform immediately upon calling the evStop() or evAnalyze() command.

How it works:

  • When enableUploadToPlatform: true and setUploadToPlatformDefault: true (default), upload happens automatically
  • No additional code is needed - just call evAnalyze() or evStop() and the report uploads
  • Upload occurs synchronously as part of the command execution

If you want to change this behavior and control uploads manually, set the setUploadToPlatformDefault feature flag to false.

1EvincedSDK.setUploadToPlatformDefault(false);

If the setUploadToPlatformDefault is disabled, you can still upload selected reports to the platform. For that, use the following parameter in the evStop() command:

1...
2driver.evStop(PlatformUpload.ENABLED);

Or, in the evAnalyze() command:

1driver.evAnalyze(PlatformUpload.ENABLED);

Test Names

To facilitate report management and be able to distinguish between different reports on the Platform, use the setTestInfo method to inform the test name and test class. It’s recommended to do that in the “beforeEach” hook.

JUnit:

1...
2@Rule
3public TestName testName = new TestName();
4
5@Before
6public void platformUploadingTestSetup(){
7 driver.setTestInfo(testName.getMethodName(), this.getClass().getCanonicalName());
8}
9...

TestNG:

1@BeforeMethod
2protected void evStartBeforeMethod(ITestContext context, ITestResult result) {
3 driver.setTestInfo(result.getMethod().getMethodName(), result.getTestClass().getName());
4}

Labels and Custom Fields

You can attach labels and custom fields to your report to enhance readability and organization in the platform. Labels help you filter, search, and organize reports on the Evinced Platform.

There are two types of labels:

Built-in Labels: Pre-defined labels that can be set using the addLabel method. Available built-in labels include:

  • testName - The name of the test
  • testFile - The file path of the test
  • environment - The environment where the test runs (e.g., "Development", "Staging", "Production")
  • flow - The test flow identifier
  • gitBranch - The Git branch name
  • gitUserName - The Git user name
  • gitVersion - The Git commit version

Custom Labels: Flexible key-value pairs that can be set using the customLabel method. You can use any custom key-value pairs, including:

  • Single values: { productVersion: '1.0.0' }
  • Multiple values (arrays): { browsers: ['Chrome', 'Firefox'] }
  • Special label unitId: Use this to tag tests for relevant units within your organization

See the following code examples of how to set up labels:

1EvincedSDK.getTestRunInfo()
2 .addLabel(Parameter.GIT_USER_NAME, "git")
3 .addLabel(Parameter.GIT_BRANCH, "main")
4 .addLabel(Parameter.USER_AGENT, "agent007")
5 .addLabel(Parameter.ENVIRONMENT, "production")
6 .addLabel(Parameter.FLOW, "standard")
7 .customLabel("Product version", "1.2.3")
8 .customLabel("OS Type", "Linux")
9 .customLabel("OS Name", "openSuse");

Use of beforeEach and afterEach Hooks

We recommend using the beforeEach and afterEach hooks to control analysis sessions and upload reports to the platform. This way, each test will be uploaded separately with its own report.

In beforeEach hook use evStart() to start Evinced analysis and set any labels you want for the report to contain when uploading to the platform. In the afterEach hook call evStop() to stop analysis and upload reports to the platform. See this code example:

TestNG:

1@BeforeMethod
2protected void evStartBeforeMethod(ITestContext context, ITestResult result) {
3 driver.setTestInfo(result.getMethod().getMethodName(), result.getTestClass().getName());
4 driver.evStart();
5}
6
7@AfterMethod
8protected void evStopAfterMethod(ITestContext context, ITestResult result) {
9 driver.evStop();
10}

Putting All of This Together

Here is a complete code snippet of how to perform uploads to the platform on a per-test basis.

TestNG:

1package com.evinced.example;
2
3import com.evinced.EvincedSDK;
4import com.evinced.EvincedWebDriver;
5import com.evinced.dto.platform.TestRunInfo.Parameter;
6import org.openqa.selenium.chrome.ChromeDriver;
7import org.openqa.selenium.chrome.ChromeOptions;
8import org.testng.ITestContext;
9import org.testng.ITestResult;
10import org.testng.annotations.*;
11
12
13public class TestExample {
14
15 public static EvincedWebDriver driver;
16
17 @BeforeSuite
18 protected void beforeSuite() {
19 EvincedSDK.setOfflineCredentials(System.getenv("EVINCED_SERVICE_ID"), System.getenv("EVINCED_AUTH_TOKEN"));
20 EvincedSDK.enableUploadToPlatform(true);
21
22 EvincedSDK.getTestRunInfo()
23 .addLabel(Parameter.GIT_USER_NAME, "git")
24 .addLabel(Parameter.GIT_BRANCH, "master")
25 .customLabel("Testing purpose", "Test platform uploading feature");
26 }
27
28 @BeforeTest
29 protected void beforeTest() {
30 initDriver();
31 }
32
33 @AfterTest
34 protected void afterTest() {
35 driver.quit();
36 }
37
38 @BeforeMethod
39 protected void evStartBeforeMethod(ITestContext context, ITestResult result) {
40 driver.setTestInfo(result.getMethod().getMethodName(), result.getTestClass().getName());
41 driver.evStart();
42 }
43
44 @AfterMethod
45 protected void evStopAfterMethod(ITestContext context, ITestResult result) {
46 driver.evStop();
47 }
48
49 protected void initDriver() {
50 ChromeOptions options = new ChromeOptions();
51 String browserMode = System.getenv("BROWSER_MODE");
52 if (browserMode != null) {
53 options.addArguments(browserMode);
54 }
55 driver = new EvincedWebDriver(new ChromeDriver(options));
56 }
57
58 @Test(testName = "Test url")
59 public void testUrl() {
60 driver.get("https://demo.evinced.com");
61 }
62}

Tutorials

You can find fully functional example projects on our GitHub.

Generating a comprehensive accessibility report for your application

In this tutorial, we will enhance our existing Selenium UI test with the Evinced Selenium SDK in order to check our application for accessibility issues. In order to get started you will need the following:

  1. All of the prerequisites for the Evinced Selenium SDK should be met
  2. Evinced Selenium SDK should be added to your project

Preface - existing UI test overview

Let’s consider the following basic UI test as our starting point.

1import com.evinced.EvincedReporter;
2import com.evinced.EvincedWebDriver;
3import com.evinced.dto.results.Issue;
4import com.evinced.dto.results.Report;
5import org.junit.Assert;
6import org.junit.Test;
7import org.openqa.selenium.By;
8import org.openqa.selenium.WebElement;
9import org.openqa.selenium.chrome.ChromeDriver;
10import java.util.List;
11
12public class AccessibilityTests {
13 @Test
14 public void evAnalyzeWithAnOpenDropdownTest() {
15 ChromeDriver driver = new ChromeDriver();
16 driver.get("https://demo.evinced.com/");
17 WebElement firstDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(1) > div > div.dropdown.line"));
18 firstDropdown.click();
19 WebElement secondDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(2) > div > div.dropdown.line"));
20 secondDropdown.click();
21 driver.findElement(By.cssSelector(".react-date-picker")).click();
22 }
23}

We wrote this test for a demo travel site called TRVL that has a few known accessibility issues.

The purpose of this test is to check the functionality of the main application screen and ensure a user can successfully select their desired trip. For now, this test is only concerned with the functional testing of the app. However, with the help of the Evinced Selenium SDK, we can also check it for accessibility issues along the way. Let’s go through this process with the following step-by-step instructions.

Step #1 - Initialize the Evinced Selenium SDK

Before making any assertions against our app, we need to initialize EvincedWebDriver object. This object is used primarily as an entry point to all of the accessibility scanning features. Since we are going to use it scan throughout our test, the best place for its initialization will be our setUp method which gets executed first.

1import com.evinced.EvincedReporter;
2import com.evinced.EvincedWebDriver;
3import com.evinced.dto.results.Issue;
4import com.evinced.dto.results.Report;
5import org.junit.Assert;
6import org.junit.Test;
7import org.openqa.selenium.By;
8import org.openqa.selenium.WebElement;
9import org.openqa.selenium.chrome.ChromeDriver;
10import com.evinced.EvincedWebDriver;
11import java.util.List;
12
13public class AccessibilityTests {
14 private EvincedWebDriver driver;
15
16 @Before
17 public void setUp() {
18 driver = new EvincedWebDriver(new ChromeDriver());
19 }
20
21 @Test
22 public void evAnalyzeWithAnOpenDropdownTest() {
23 driver.get("https://demo.evinced.com/");
24 WebElement firstDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(1) > div > div.dropdown.line"));
25 firstDropdown.click();
26 WebElement secondDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(2) > div > div.dropdown.line"));
27 secondDropdown.click();
28 driver.findElement(By.cssSelector(".react-date-picker")).click();
29 }
30}

The EvincedWebDriver requires only an instance of ChromeDriver.

Step #2 - Start the Evinced engine

Now that we have initiated the Selenium driver and added the capabilities needed to scan for accessibility issues, let’s start the Evinced engine. Since we are going to use it scan throughout our test, the best place for its initialization will be our setUp method after our Selenium driver is configured.

1import com.evinced.EvincedReporter;
2import com.evinced.EvincedWebDriver;
3import com.evinced.dto.results.Issue;
4import com.evinced.dto.results.Report;
5import org.junit.Assert;
6import org.junit.Test;
7import org.openqa.selenium.By;
8import org.openqa.selenium.WebElement;
9import org.openqa.selenium.chrome.ChromeDriver;
10import com.evinced.EvincedWebDriver;
11import java.util.List;
12
13public class AccessibilityTests {
14 private EvincedWebDriver driver;
15
16 @Before
17 public void setUp() {
18 driver = new EvincedWebDriver(new ChromeDriver());
19 // Start the Evinced Engine
20 driver.evStart();
21 }
22
23 @Test
24 public void evAnalyzeWithAnOpenDropdownTest() {
25 driver.get("https://demo.evinced.com/");
26 WebElement firstDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(1) > div > div.dropdown.line"));
27 firstDropdown.click();
28 WebElement secondDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(2) > div > div.dropdown.line"));
29 secondDropdown.click();
30 driver.findElement(By.cssSelector(".react-date-picker")).click();
31 }
32}

There are additional configuration options that can be included as well. More information can be found in the API section of this documentation.

Step #3 - Stop the Evinced engine and create reports

As our test was executed we collected a lot of accessibility information. We can now perform accessibility assertions at the end of our test suite. Referring back again to our UI test the best place for this assertion will be the method that gets invoked last - tearDown. To stop the Evinced engine and generate the actual object representation of your accessibility report simply call the evStop() method. We can then output the report files in either HTML or JSON format (or both!).

1import com.evinced.EvincedReporter;
2import com.evinced.EvincedWebDriver;
3import com.evinced.dto.results.Issue;
4import com.evinced.dto.results.Report;
5import org.junit.Assert;
6import org.junit.Test;
7import org.openqa.selenium.By;
8import org.openqa.selenium.WebElement;
9import org.openqa.selenium.chrome.ChromeDriver;
10import com.evinced.EvincedWebDriver;
11import java.util.List;
12
13public class AccessibilityTests {
14 private EvincedWebDriver driver;
15
16 @Before
17 public void setUp() {
18 driver = new EvincedWebDriver(new ChromeDriver());
19 // Start the Evinced Engine
20 driver.evStart();
21 }
22
23 @After
24 public void tearDown() {
25 // Stop the Evinced Engine
26 Report report = driver.evStop();
27 // Output the Accessibility results in JSON or HTML
28 EvincedReporter.evSaveFile(testName.getMethodName(), report, EvincedReporter.FileFormat.HTML);
29 EvincedReporter.evSaveFile(testName.getMethodName(), report, EvincedReporter.FileFormat.JSON);
30 driver.quit();
31 }
32
33 @Test
34 public void evAnalyzeWithAnOpenDropdownTest() {
35 driver.get("https://demo.evinced.com/");
36 WebElement firstDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(1) > div > div.dropdown.line"));
37 firstDropdown.click();
38 WebElement secondDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(2) > div > div.dropdown.line"));
39 secondDropdown.click();
40 driver.findElement(By.cssSelector(".react-date-picker")).click();
41 }
42}

For the sake of simplicity of this tutorial let’s simply assume that our application is accessible as long as it has no accessibility issues found. Thus, if we have at least one accessibility issue detected - we want our tests to be failed. Let’s add the corresponding assertion to our tearDown method

1@After
2public void tearDown() {
3 // Stop the Evinced Engine
4 Report report = driver.evStop();
5 // Output the Accessibility results in JSON or HTML
6 EvincedReporter.evSaveFile(testName.getMethodName(), report, EvincedReporter.FileFormat.HTML);
7 EvincedReporter.evSaveFile(testName.getMethodName(), report, EvincedReporter.FileFormat.JSON);
8
9 // Optional assertion for gating purposes
10 List<Issue> issues = report.getIssues();
11 Assert.assertEquals(0, issues.size());
12
13 driver.quit();
14}

You are now set to run the test and ensure the accessibility of your application! So, go ahead and run it via your IDE or any other tooling you use for Java development.

Additional Configuration Examples

Testing accessibility in a specific state of the application

In this example, we are going to test the accessibility of a page in a specific state. This test navigates to a page, opens a dropdown, and only then runs the accessibility engines to identify issues.

1import com.evinced.EvincedReporter;
2import com.evinced.EvincedWebDriver;
3import com.evinced.dto.results.Issue;
4import com.evinced.dto.results.Report;
5import org.junit.Assert;
6import org.junit.Test;
7import org.openqa.selenium.By;
8import org.openqa.selenium.WebElement;
9import org.openqa.selenium.chrome.ChromeDriver;
10
11import java.util.List;
12
13public class AccessibilityTests {
14
15 @Test
16 public void evAnalyzeWithAnOpenDropdownTest() {
17 EvincedWebDriver driver = new EvincedWebDriver(new ChromeDriver());
18 driver.get("https://demo.evinced.com/");
19
20 // interacting with the page - opening all dropdown
21 WebElement firstDropdown = driver.findElement(By.cssSelector("div.filter-container > div:nth-child(1) > div > div.dropdown.line"));
22 firstDropdown.click();
23
24 Report report = driver.evAnalyze();
25 List<Issue> issues = report.getIssues();
26 Assert.assertEquals(8, issues.size());
27
28 // write the report to HTML format to a file named: "test-results.html"
29 EvincedReporter.evSaveFile("test-results", report, EvincedReporter.FileFormat.HTML);
30 }
31}
Running evAnalyze on multiple tabs

The evAnalyze command will works as expected on the primary tab. When testing on an additional browser tab, simply switch the driver from the primary Selenium window handle to the window handle of the new tab and then run evAnalyze. This code is shown on lines 14-15 of the example below.

Example In the example below, page1.html has a link that opens in a new tab.

1// navigate to page1
2driver.get("page1.html");
3
4// get report for page1
5Report report = driver.evAnalyze();
6List<Issue> issues = report.getIssues();
7// run some assertions
8assertEquals(1, issues.size());
9
10// perform an action that opens a new tab
11driver.findElement(new By.ById("open-tab-link")).click();
12
13// switch to new tab
14String tabWindowHandle = driver.getWindowHandles().toArray()[1].toString();
15driver.switchTo().window(tabWindowHandle);
16
17// get report for the new tab,
18// the issues for page1 won't appear here, only ones found on the new tab
19report = driver.evAnalyze();
20issues = report.getIssues();
21assertEquals(3, issues.size());

Running evStart and evStop on multiple tabs

The evStart and evStop method scopes are limited to a single tab or Selenium window handle. This means that if you have more than one tab, you will need to call evStop and then switch to the window handle of the new tab. Once the window handle switch has occurred, run a new instance of evStart followed evStop at the appropriate time.evStop must be called on the tab that evStart command was called on, before starting evStart on a new tab.

In the example below, page1.html has a link that opens in a new tab.

1 // navigate to page1
2 driver.get("page1.html");
3
4 driver.evStart();
5
6 // perform actions on page1, clicks, etc...
7
8 // the evStart and evStop scopes are limited to a single window handle.
9 // this means that if you have more than one tab, you need to switch it's window and only then run `evStart` and `evStop`
10 // The `evStop` must be called on the tab that `evStart` command was called on, before starting `evStart` on a new tab
11 Report report = driver.evStop();
12 List<Issue> issues = report.getIssues();
13 assertEquals(1, issues.size());
14
15 // perform an action that opens a new tab
16 driver.findElement(new By.ById("open-tab-link")).click();
17
18 // move to tab
19 String tabWindowHandle = driver.getWindowHandles().toArray()[1].toString();
20 driver.switchTo().window(tabWindowHandle);
21
22 // get report for the new tab,
23 // the issues for page1 won't appear here, only ones found on the new tab
24 driver.evStart();
25 report = driver.evStop();
26 issues = report.getIssues();
27 assertEquals(3, issues.size());

Running evStart and evStop on a different TargetLocator (frame / iframe)

In case the evStart command is called on a different context, for example - after switching WebDriver’s context into an iframe, the Evinced engines will be injected into that iframe only. In order to get the results back you will need to switch to the same context evStart was called on, before calling evStop. In case you are using a website that relies deeply on iframes, we suggest using the IncludeIframes API configuration.

In the example below, page1.html has an iframe in it, with id iframe1.

1 // navigate to page1
2 driver.get("page1.html");
3
4 // switch to the iframe
5 driver.switchTo().frame(driver.findElement(By.id("iframe1")));
6
7 // start recording
8 driver.evStart();
9
10 // perform actions on iframe1 inside page1, clicks, etc...
11
12 // if you go back to the defaultContent (the iframe parent)
13 // the `evStop` method will fail
14 driver.switchTo().defaultContent();
15
16 // don't do that, it will fail
17 driver.evStop();
18
19 // but you can get the results when inside the iframe
20 // switch to the iframe
21 driver.switchTo().frame(driver.findElement(By.id("iframe1")));
22
23 // now evStop returns all the issues recorded inside the iframe
24 Report report = driver.evStop();
25 List<Issue> issues = report.getIssues();
26 assertEquals(1, issues.size());

Add accessibility testing to existing tests

It is possible to configure EvincedWebDriver to be called also used in @Before and @After methods. In the example below, evStart starts recording before the test starts, and evStop is called after each test.

1import com.evinced.dto.results.Report;
2import io.github.bonigarcia.wdm.WebDriverManager;
3import org.junit.*;
4import org.junit.rules.TestName;
5import org.openqa.selenium.chrome.ChromeDriver;
6
7public class BeforeAfterTest {
8
9 @Rule
10 public TestName testName = new TestName();
11
12 private EvincedWebDriver driver;
13
14 /**
15 * Instantiate the WebDriver
16 */
17 @BeforeClass
18 public void setupClass() {
19 WebDriverManager.chromedriver().setup();
20 driver = new EvincedWebDriver(new ChromeDriver());
21 driver.manage().window().maximize();
22 }
23
24 /**
25 * Start recording before each test
26 */
27 @Before
28 public void setUp() {
29 driver.evStart();
30 }
31
32 /**
33 * Ensure we close the WebDriver after finishing
34 */
35 @After
36 public void after() {
37 // write an HTML report to file
38 Report report = driver.evStop();
39 EvincedReporter.evSaveFile(testName.getMethodName(), report, EvincedReporter.FileFormat.HTML);
40 }
41
42 @Test
43 public void visitDemoPage() {
44 driver.get("https://demo.evinced.com");
45 }
46
47 @Test
48 public void visitGoogle() {
49 driver.get("https://www.google.com");
50 }
51}

Fail the test if critical issues are found

Here you can see a way of failing your test if critical accessibility issues are found using the Selenium Java SDK.

Using evAnalyze:

1Report report = driver.evAnalyze();
2
3List<Issue> criticalIssues = report.getIssues().stream()
4 .filter(issue -> "Critical".equals(issue.getSeverity().getName()))
5 .collect(Collectors.toList());
6
7assertTrue(criticalIssues.isEmpty(), "Critical issues are found");

Using evStart/evStop:

1driver.evStart();
2Report report = driver.evStop();
3
4List<Issue> criticalIssues = DATA.getReport().getIssues().stream()
5.filter(issue -> "Critical".equals(issue.getSeverity().getName()))
6.collect(Collectors.toList());
7
8assertTrue(criticalIssues.isEmpty(), "Critical issues are found");

The criticalIssues array will contain all the critical issues found during the scan. If the array is not empty, the test will fail on the assertion.

Support

Please feel free to reach out to support@evinced.com with any questions.

FAQ

  1. Can I configure which validations to run?

Yes, see the Configuration section for details on how to configure Axe validations to your needs.

  1. Can I run tests with Evinced using cloud-based services like Sauce Labs, Perfecto, or BrowserStack?

Yes, we have tested the Evinced SDK on many of these types of cloud-based services and expect no issues.