Selenium C# SDK

The Evinced Selenium C# 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.WebDriver version 4.10.0 or higher
  • .Net Core version 7 or higher
  • ChromeDriver

Get Started

Installation

Install Selenium C# SDK from a locally provided file

  1. Download the Selenium.CS.SDK.version.nupkg file.
  2. Add it to the project
1# To install the SDK.
2dotnet add package Selenium.CS.SDK -v <version> -s <path-to-folder-with-nupkg-file>
3
4# To restore all needed .NET dependencies.dotnet add reference <path-to-dll>Selenium.CS.SDK.dll
5dotnet restore

Your First Test

SDK Initialization

To work with Selenium C# SDK you need to have authentication token. Please refer to licensing section for details. The only command you need to add is to wrap the existing WebDriver object

1using Evinced.SDK;
2
3IEvincedDriver driver = EvincedDriverFactory.Create(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.

1[Test]
2public void EvAnalyzeTest() {
3 EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
4
5 // Initialize EvincedWebDriver which wraps a ChromeDriver instance
6 IEvincedDriver driver = EvincedDriverFactory.Create(new ChromeDriver());
7
8 try {
9 // Navigate to the site under test
10 driver.Navigate().GoToUrl("https://www.google.com");
11
12 // Run analysis and get the accessibility report
13 IReport result = driver.EvAnalyze();
14
15 // Assert that there are no accessibility issues
16 Assert.That(result.GetIssues(), Has.Count.EqualTo(0));
17 } finally {
18 driver.Quit();
19 }
20}

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 navigations 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.

1[Test]
2public void StartStopSimpleTest() {
3 EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
4
5 // Initialize EvincedWebDriver which wraps a ChromeDriver instance
6 IEvincedDriver driver = EvincedDriverFactory.Create(new ChromeDriver());
7
8 try {
9 // Navigate to the site under test
10 driver.Navigate().GoToUrl("https://www.google.com");
11 // Start the Evinced engine scanning for accessibility issues
12 driver.EvStart();
13
14 // More test code to interact with the page
15
16 // Stop the Evinced engine
17 IReport report = driver.EvStop();
18 // Output the Evinced report in either JSON or HTML format
19 EvincedSDK.EvSaveFile("test-results", report, FileFormat.JSON);
20 EvincedSDK.EvSaveFile("test-results", report, FileFormat.HTML, driver);
21
22 // Reports will be stored in the current directory
23 Console.WriteLine(Directory.GetCurrentDirectory());
24
25 } finally {
26 driver.Quit();
27 }
28}

API

global initialization

Initializes the Evinced object within the project.

Example

The EvincedDriverFactory.Create method expects an instance of ChromeDriver. It is possible to pass an instance of a class that implements a IWebDriver interface.

1ChromeDriver chromeDriver = new ChromeDriver();
2IEvincedDriver evincedWebDriver = EvincedDriverFactory.Create(chromeDriver);

Please refer to configuration to see examples of using init with options.

EvAnalyze(options)

Scans the current page and returns a list of accessibility issues.

Note: This method is not supported if EvStart is already running.

Please refer to configuration to see examples of using init with options.

Example

1IReport result = evincedWebDriver.EvAnalyze();

Return value

1IReport result = evincedWebDriver.EvAnalyze();

A Report object is returned containing accessibility issues. This is the recommended method for static page analysis. 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 and records all accessibility issues until the EvStop method is called. This method is recommended for dynamic page flows.

Example

1evincedWebDriver.EvStart();

Return value

1void

EvStop

Stops the process of issue gathering started by EvStart command.

Example

1evincedWebDriver.EvStart();
2IReport report = evincedWebDriver.EvStop();

Return value

1IReport

Returns an object containing recorded accessibility issues from the point in time at which the EvStart method was instantiated. For more information regarding reports as well as the returned object itself, please refer to detailed Web Reports page.

EvSaveFile(destination, format, issues)

Saves list of the issues in a file, with the specified format and location. For example, format could be ‘json', 'html, 'sarif' or 'csv'. Please find detailed information on Web Reports page.

Example

1IReport report = evincedWebDriver.EvStop();
2 -- or --
3IReport report = evincedWebDriver.EvAnalyze();
4
5// create a JSON file named jsonReport.json
6EvincedSDK.EvSaveFile.EvSaveFile("jsonReport", report, EvincedReporter.FileFormat.JSON);
7
8// create an HTML file named htmlReport.html
9EvincedSDK.EvSaveFile("htmlReport", report, EvincedReporter.FileFormat.HTML);
10
11// create an SARIF file named sarifReport.sarif.json
12EvincedSDK.EvSaveFile("sarifReport", report, EvincedReporter.FileFormat.SARIF);
13
14// create an CSV file named csvReport.csv
15EvincedSDK.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();
2EvincedSDK.EvSaveFile("sarifReport", report, EvincedReporter.FileFormat.SARIF, driver);
3driver.Quit();

FileFormat

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

Return value

1string

The string object representing the location where the result file was stored.

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.

Example

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Licensing

To work with Selenium C# SDK you need to have Authentication token. There are two methods to provide the token: offline mode and online mode. The difference is if you use online mode the request to obtain the token will be sent to Evinced Licencing Server. You need to provide Service ID and Secret API key in such a case. They are available via the Evinced Product Hub.

Offline mode assumes that you already have token and can provide it directly. If an offline token is required please reach out to your account team or support@evinced.com.

We encourage to use environment variables to store credentials and read them in code

1# Offline mode
2export AUTH_SERVICE_ID=<serviceId>
3export AUTH_TOKEN=<token>
4
5# Online mode
6export AUTH_SERVICE_ID=<serviceId>
7export AUTH_SECRET=<secret>

Example

1using Evinced.SDK;
2
3// Offline mode
4EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
5
6// Online mode (not yet implemented)
7EvincedSDK.SetCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_SECRET"));

Configuration

The same configuration object can be used in global initialization, EvStart and EvAnalyze methods but with a bit different consequences. By providing some options in global initialization method you define a global configuration for all calls of EvStart or EvAnalyze methods. Please note that global configuration is not intended to be altered from tests due to it will affect all the rest tests as well as tests running in parallel threads. To alter configuration in specific tests you can provide config on the method's level, for instance with EvStart it defines local configuration for this particular session until EvStop is called. If provided in both levels, the command's level config will override the global one.

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 our toggles section.

Configuration object type

Global.Config is a global configuration of type EvincedConfig that will be used with all commands by default.

1Global.Config.RootSelector = "#some-selector";

The configurations can be passed to a specific command, such as EvAnalyze or EvStart, it will override the global configuration for a single run.

1EvincedConfig config = new EvConfig();
2config.RootSelector = "#some-selector";
3driver.EvStart(config);

Root Selector

Instructs engine to return issues which belong to or which are nested to element with the specified selector. By default the issues for all elements from document root will be returned.

null by default.

Example

1EvincedConfig config = new();
2config.RootSelector = ".some-selector";

AXE Configuration

Evinced leverages Axe open-source accessibility toolkit as part of its own accessibility detection engine. The Evinced engine is able to pinpoint far more issues than Axe alone.

For the full Axe config options, see Axe Core API.

Example

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Errors Strict Mode

When set to true it switches SDK in mode when Evinced SDK errors are thrown as runtime errors and stops current test execution. Otherwise errors are printed into console except critical ones.

false by default.

Example

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Engine Logging

Switches logging on for engine. Log messages from the engine will be printed to console.

Levels are: debug, info, warn, error

null by default.

error is a default level on engine side.

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Reports Screenshots

The Screenshots feature allows to include screenshots to the Evinced reports. When the feature is enabled, Evinced will take screenshots of the page, highlight an element with a specific accessibility issue, and include them to the report.

screenshots_feature

false by default.

Note: The Screenshots feature may affect the test run performance.

Enabling the Screenshots feature

1// On global level
2Global.Config.EnableScreenshots = true;
3
4// OR
5
6// On command level
7EvincedConfig config = new() {
8 EnableScreenshots = false
9};
10evincedWebDriver.EvAnalyze(config);

Toggles

Toggles are feature flags which controls SDK and Engine behavior. With toggles we introduce experimental features or manage the way how accessibility issues are gathered. The list of toggles is not specified so we suggest not to rely on specific toggle name or value and use them in investigation purposes only.

Example enabling aXe Best Practices and Needs Review Issues

1// Globally
2Global.Config.AddToggle(USE_AXE_NEEDS_REVIEW, true)
3 .AddToggle(USE_AXE_BEST_PRACTICES, true);

Skip Validations

Skips specific validations for the given URL pattern and the selector.

SkipValidation[] by default.

Example

1string selector1 = "test.1--selector";
2string type1 = "NO_DESCRIPTIVE_TEXT";
3string type2 = "NOT_FOCUSABLE";
4Global.Config.AddSkipValidation(selector1, "http://url.to.skip/path1", new List<string> { type1, type2 });

How to identify ID for the specific issue type is described in web reports section.

Knowledge Base Link overrides

This custom parameter helps to customize knowledge base links in the reports. Those links are displayed in the reports as follows:

kb_links

The knowledge base link can be overridden for every issue type ID.

Example

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Shadow DOM support

Example

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

IFrames support

When set to true, the accessibility tests run analysis on iframes that exist inside the page. Default is false.

The feature **is not yet implemented** in this SDK. If you'd like to increase the priority of it, please contact support@evinced.com.

Global Switch

Global Switch allows to disable or enable Evinced functionality. It could be needed, for example, while working on functional tests in your local environment or for running some CI jobs that are not intended to gather information regarding accessibility issues.

When switched off

  • EvStart and EvSaveFile will be bypassed.
  • EvStop and EvAnalyze will return an empty report.
  • evValid() will never fail.

true by default.

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

Switch on/off Evinced functionality in config

1EvincedSDK.SwitchOn(false);

Switching off Evinced functionality with environment variable

1export EV_SWITCH_ON=false

Tutorials

You can find fully functional example projects on our GitHub

Step-by-step adding Evinced to existing test suite.

Preface: Existing test suite

1using Evinced.SDK;
2using NUnit.Framework;
3using OpenQA.Selenium;
4using OpenQA.Selenium.Chrome;
5using OpenQA.Selenium.Support.UI;
6using SeleniumExtras.WaitHelpers;
7
8
9namespace Tests {
10 public static class Locators {
11 public const string HOUSE_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > div.dropdown.line";
12 public const string TENT_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > ul > li:nth-child(4)";
13 public const string LOCATION_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > div.dropdown.line";
14 public const string CANADA_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > ul > li:nth-child(1)";
15 public const string SEARCH_BUTTON = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > a";
16 public const string SEARCH_RESULTS = "#gatsby-focus-wrapper > main > h1";
17 }
18
19 public class AccessibilityTests {
20 private IEvincedDriver driver;
21
22 [OneTimeSetUp]
23 public void OneTimeSetUp() {
24 EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
25 this.driver = new ChromeDriver();
26 }
27
28 [OneTimeTearDown]
29 public void OneTimeTearDown() {
30 driver.Quit();
31 }
32
33 [Test]
34 public void TutorialTest1() {
35 driver.Navigate().GoToUrl("https://demo.evinced.com");
36 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Displayed, Is.True);
37 }
38
39 [Test]
40 public void TutorialTest2() {
41 driver.Navigate().GoToUrl("https://demo.evinced.com");
42 driver.FindElement(By.CssSelector(Locators.HOUSE_DROPDOWN)).Click();
43 driver.FindElement(By.CssSelector(Locators.TENT_OPTION)).Click();
44 driver.FindElement(By.CssSelector(Locators.LOCATION_DROPDOWN)).Click();
45 driver.FindElement(By.CssSelector(Locators.CANADA_OPTION)).Click();
46 driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Click();
47 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
48 wait.Until(ExpectedConditions.ElementExists(By.TagName("body")));
49 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_RESULTS)).Displayed, Is.True);
50 }
51 }
52}

Step 1: Add Evinced, use snapshot scan and partial report

1using Evinced.SDK;
2using NUnit.Framework;
3using OpenQA.Selenium;
4using OpenQA.Selenium.Chrome;
5using OpenQA.Selenium.Support.UI;
6using SeleniumExtras.WaitHelpers;
7
8
9namespace Tests {
10 public static class Locators {
11 public const string HOUSE_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > div.dropdown.line";
12 public const string TENT_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > ul > li:nth-child(4)";
13 public const string LOCATION_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > div.dropdown.line";
14 public const string CANADA_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > ul > li:nth-child(1)";
15 public const string SEARCH_BUTTON = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > a";
16 public const string SEARCH_RESULTS = "#gatsby-focus-wrapper > main > h1";
17 }
18
19 public class AccessibilityTests {
20 private IEvincedDriver driver;
21
22 [OneTimeSetUp]
23 public void OneTimeSetUp() {
24 EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
25 this.driver = EvincedDriverFactory.Create(new ChromeDriver());
26 }
27
28 [OneTimeTearDown]
29 public void OneTimeTearDown() {
30 driver.Quit();
31 }
32
33 [Test]
34 public void TutorialTest1() {
35 driver.Navigate().GoToUrl("https://demo.evinced.com");
36 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Displayed, Is.True);
37 IReport report = driver.EvAnalyze();
38 EvincedSDK.EvSaveFile(TestContext.CurrentContext.Test.Name, report, FileFormat.JSON);
39 }
40
41 [Test]
42 public void TutorialTest2() {
43 driver.Navigate().GoToUrl("https://demo.evinced.com");
44 driver.FindElement(By.CssSelector(Locators.HOUSE_DROPDOWN)).Click();
45 driver.FindElement(By.CssSelector(Locators.TENT_OPTION)).Click();
46 driver.FindElement(By.CssSelector(Locators.LOCATION_DROPDOWN)).Click();
47 driver.FindElement(By.CssSelector(Locators.CANADA_OPTION)).Click();
48 driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Click();
49 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
50 wait.Until(ExpectedConditions.ElementExists(By.TagName("body")));
51 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_RESULTS)).Displayed, Is.True);
52 // Get issues snapshot on the result page
53 IReport report = driver.EvAnalyze();
54 // Assert page does not contain accessibility issues
55 Assert.That(result.GetIssues(), Has.Count.EqualTo(0));
56 }
57 }
58}

Step 2: Use continuous mode

Let's do a step back to the original test and start modifying it again. Some steps will be similar.

1using Evinced.SDK;
2using NUnit.Framework;
3using OpenQA.Selenium;
4using OpenQA.Selenium.Chrome;
5using OpenQA.Selenium.Support.UI;
6using SeleniumExtras.WaitHelpers;
7
8
9namespace Tests {
10 public static class Locators {
11 public const string HOUSE_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > div.dropdown.line";
12 public const string TENT_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(1) > div > ul > li:nth-child(4)";
13 public const string LOCATION_DROPDOWN = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > div.dropdown.line";
14 public const string CANADA_OPTION = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > div:nth-child(2) > div > ul > li:nth-child(1)";
15 public const string SEARCH_BUTTON = "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container > a";
16 public const string SEARCH_RESULTS = "#gatsby-focus-wrapper > main > h1";
17 }
18
19 public class AccessibilityTests {
20 private IEvincedDriver driver;
21
22 [OneTimeSetUp]
23 public void OneTimeSetUp() {
24 EvincedSDK.SetOfflineCredentials(Environment.GetEnvironmentVariable("AUTH_SERVICE_ID"), Environment.GetEnvironmentVariable("AUTH_TOKEN"));
25 this.driver = EvincedDriverFactory.Create(new ChromeDriver());
26 }
27
28 [OneTimeTearDown]
29 public void OneTimeTearDown() {
30 driver.Quit();
31 }
32
33 [SetUp]
34 public void SetUp() {
35 // Start the Evinced Engine
36 driver.EvStart();
37 }
38
39 [TearDown]
40 public void TearDown() {
41 // Stop the Evinced Engine
42 IReport report = driver.EvStop();
43 EvincedSDK.EvSaveFile(TestContext.CurrentContext.Test.Name, report, FileFormat.HTML, driver);
44 }
45
46 [Test]
47 public void TutorialTest1() {
48 driver.Navigate().GoToUrl("https://demo.evinced.com");
49 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Displayed, Is.True);
50 }
51
52 [Test]
53 public void TutorialTest2() {
54 driver.Navigate().GoToUrl("https://demo.evinced.com");
55 driver.FindElement(By.CssSelector(Locators.HOUSE_DROPDOWN)).Click();
56 driver.FindElement(By.CssSelector(Locators.TENT_OPTION)).Click();
57 driver.FindElement(By.CssSelector(Locators.LOCATION_DROPDOWN)).Click();
58 driver.FindElement(By.CssSelector(Locators.CANADA_OPTION)).Click();
59 driver.FindElement(By.CssSelector(Locators.SEARCH_BUTTON)).Click();
60 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
61 wait.Until(ExpectedConditions.ElementExists(By.TagName("body")));
62 Assert.That(driver.FindElement(By.CssSelector(Locators.SEARCH_RESULTS)).Displayed, Is.True);
63 }
64 }
65}

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.