Cypress SDK

The Evinced Cypress SDK integrates with new or existing Cypress tests to automatically detect accessibility issues. With the addition of as few as 3 lines of code to your Cypress project, you can begin to analyze all the pages and DOM changes to offer a dynamic view of how your site can become more accessible. At the conclusion 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

  • Cypress version 6.8.0 or higher

Get Started

Add Evinced as a dependency

In your project directory install the Evinced SDK using npm . The Cypress SDK package is not publicly available. Contact us to get started!

1npm install @evinced/cypress-sdk

Your first test

Initialize the SDK object

In the cypress/support/index.js file add the following lines to add the Evinced engine to your project.

1import Evinced from "@evinced/cypress-sdk";
2Evinced.init();

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.

1it("Evinced basic example", () => {
2 // Navigate to site
3 cy.visit("https://demo.evinced.com/");
4 //Scan for a11y issues, generate the report, and assert on the number of issues found
5 cy.evReport().should((issues) => {
6 expect(issues).to.be.empty();
7 });
8});

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.

1context('Evinced Demo Site tests', () => {
2
3 it('Search Test', () => {
4 cy.visit('https://demo.evinced.com/');
5
6 // Start the Evinced engine
7 cy.evStart();
8
9 const BASE_FORM_SELECTOR = '#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container';
10 const SELECT_HOME_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > div.dropdown.line`;
11 const SELECT_WHERE_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > div.dropdown.line`;
12 const TINY_HOME_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)`;
13 const EAST_COST_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)`;
14 cy.get(SELECT_HOME_DROPDOWN).click();
15 cy.get(TINY_HOME_OPTION).click();
16 cy.get(SELECT_WHERE_DROPDOWN).click();
17 cy.get(EAST_COST_OPTION).click();
18
19 // Conclude the scan, create the JSON report, and assert on the number of critical issues found
20 cy.evStop({ logIssues: true }).should((issues) => {
21 console.log(JSON.stringify(issues, null, 2));
22 });
23});

API

Evinced.init(options)

Initializes the Evinced object within the project.

Example

1import Evinced from "@evinced/cypress-sdk";
2Evinced.init();

Default options

1{
2 debug: false, // Outputs all Evinced verbose logs to Cypress
3 axeConfig: null, // Set Axe configuration
4 strict: false // Will throw exceptions on warnings
5}

Return value

1void;

Side effects

  • Listens to Cypress events
    • window:before:load - Injects Evinced to the page, continues recording if needed
    • window:before:unload - Stores the state of the current page
    • test:before:run - Initializes test scope state
  • Registers ev commands
    • evReport
    • evStart
    • evStop
  • Registers Chai assertions
    • evValid

evReport(options)

Scans the current page and returns a list of accessibility issues. 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 see our detailed Web Reports page. Note: This method is not supported if evStart is already running.

Example

1cy.evReport({ rootSelector: "#some .selector" }).should((issues) => {
2 expect(issues).to.have.length(6);
3});

Default options

1{
2 logIssues: false, // Will log every accessibility issue to Cypress console
3 rootSelector: null, // Set to scan only a subset of the DOM
4 axeConfig: null // Set Axe configuration
5}

Return value

1Promise<Issue[]>;

evStart(options)

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

Example

1cy.visit("https://example.com/page-a");
2cy.evStart({ rootSelector: "#some .selector" });
3cy.visit("https://example.com/page-b");
4cy.evStop().should((issues) => {
5 expect(issues).to.have.length(6);
6});

Default options

1{
2 rootSelector: null, // Set to scan only a subset of the DOM
3 axeConfig: null // Set Axe configuration
4}

Return value

1Promise<void>;

evStop(options)

Returns a Report 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 Report object itself, please see our detailed Web Reports page.

1cy.visit('https://example.com/page-a');
2cy.evStart();
3cy.get('#some .selector').click();
4cy.visit('https://example.com/page-b');
5cy.get('#another .selector').click();
6cy.evStop().should((issues) => {
7 expect(issues).to.have.length(10);
8});
9Default options
10{
11 logIssues: false // Will log every accessibility issue to Cypress console
12}

Return value

1Promise<Issue[]>;

Axe Config

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.

You can set custom Axe options globally in Evinced.init, or per individual command in evReport or evStart. If provided in both, the command config will be used. For the full Axe config options, see [Axe Core API].

Example

1const axeConfig = {
2 rules: {
3 "link-name": { enabled: false },
4 },
5};
6
7// Global config
8Evinced.init({ axeConfig });
9
10// Command config
11cy.evReport({ axeConfig });
12cy.evStart({ axeConfig });

Experimental

Assertions

issues.evValid(options)

Default options
1{
2 ignoreSeverities: [],
3 ignoreTypes: []
4}
Side effects

Throws a chai exception if any issues exist that don't match the provided filters:

1expected #{this} to have no accessibility issues
Example
1cy.evReport().should("be.evValid", {
2 ignoreSeverities: ["CRITICAL"],
3 ignoreTypes: ["NOT_FOCUSABLE"],
4});

Chrome Dev Tools Console Report Example

Reports are provided JSON responses and can most easily be viewed in the Chrome dev tools in the Cypress execution window but can be easily exported wherever needed. Reports include Element ID, Issues type, description, issue severity, suggested fixes, and a link to the Evinced knowledge base. The report is generated by calling evReport or evStop. For more information regarding reports as well as the Report object itself, please see our detailed Web Reports page.

Chrome Dev Tools Console Report Example. Chrome devtools displaying a "Keyboard accessible" issue output

Tutorials

Generating a comprehensive accessibility report for your application

In this tutorial, we will enhance our existing Cypress UI test with the Evinced Cypress 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 Cypress SDK should be met
  2. Evinced Cypress SDK should be added to your project

Preface - existing UI test overview

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

1context("Evinced Demo Site tests", () => {
2 it("Search Test", () => {
3 cy.visit("https://demo.evinced.com/");
4 const BASE_FORM_SELECTOR =
5 "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container";
6 const SELECT_HOME_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > div.dropdown.line`;
7 const SELECT_WHERE_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > div.dropdown.line`;
8 const TINY_HOME_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)`;
9 const EAST_COST_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)`;
10 cy.get(SELECT_HOME_DROPDOWN).click();
11 cy.get(TINY_HOME_OPTION).click();
12 cy.get(SELECT_WHERE_DROPDOWN).click();
13 cy.get(EAST_COST_OPTION).click();
14 });
15});

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 Cypress 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 Cypress SDK

In your cypress/support/index.js file add the following lines to add the Evinced engine to your project.

1import Evinced from "@evinced/cypress-sdk";
2Evinced.init();

Step #2 - Start the Evinced engine

Now that we have everything we need 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 before method.

1context("Evinced Demo Site tests", () => {
2 before(() => {
3 // Start the Evinced engine
4 cy.evStart();
5 });
6
7 it("Search Test", () => {
8 cy.visit("https://demo.evinced.com/");
9 const BASE_FORM_SELECTOR =
10 "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container";
11 const SELECT_HOME_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > div.dropdown.line`;
12 const SELECT_WHERE_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > div.dropdown.line`;
13 const TINY_HOME_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)`;
14 const EAST_COST_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)`;
15 cy.get(SELECT_HOME_DROPDOWN).click();
16 cy.get(TINY_HOME_OPTION).click();
17 cy.get(SELECT_WHERE_DROPDOWN).click();
18 cy.get(EAST_COST_OPTION).click();
19 });
20});

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 - after. 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 JSON format.

1context("Evinced Demo Site tests", () => {
2 before(() => {
3 // Start the Evinced engine
4 cy.evStart();
5 });
6
7 after(() => {
8 // Scan for a11y issues, create the JSON report
9 cy.evStop({ logIssues: true }).should((report) => {
10 console.log(JSON.stringify(report, null, 2));
11 });
12 });
13
14 it("Search Test", () => {
15 cy.visit("https://demo.evinced.com/");
16 const BASE_FORM_SELECTOR =
17 "#gatsby-focus-wrapper > main > div.wrapper-banner > div.filter-container";
18 const SELECT_HOME_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > div.dropdown.line`;
19 const SELECT_WHERE_DROPDOWN = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > div.dropdown.line`;
20 const TINY_HOME_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(1) > div > ul > li:nth-child(2)`;
21 const EAST_COST_OPTION = `${BASE_FORM_SELECTOR} > div:nth-child(2) > div > ul > li:nth-child(3)`;
22 cy.get(SELECT_HOME_DROPDOWN).click();
23 cy.get(TINY_HOME_OPTION).click();
24 cy.get(SELECT_WHERE_DROPDOWN).click();
25 cy.get(EAST_COST_OPTION).click();
26 });
27});

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 after method. For more information regarding reports as well as the Report object itself, please see our detailed Web Reports page.

1after(() => {
2 // Scan for a11y issues, create the JSON report, and assert on the number of critical issues found
3 cy.evStop().should((issues) => {
4 expect(issues).to.be.empty();
5 });
6});

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 JavaScript development.

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 API section for details on how to configure Axe validations to your needs.
  2. 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.