Unit Tester

The Evinced Unit Tester integrates with new or existing Jest environments to automatically detect accessibility issues. By adding just one unit test to your component library project, you can check that your component has the required accessibility semantics and that you have implemented the correct keyboard interactions. This will ensure that each tested component is fully compatible with assistive technologies (e.g. screen readers) and operable by keyboard. Since the JSDOM environment does not visually render the code, we recommend using downstream tools and/or manual review to evaluate visual requirements such as focus indication and color contrast. At the conclusion of each 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

  • Node version 14.15 or higher
  • Jest version >= 25 is installed and configured in your project. For running tests with Jasmine, Mocha, Vitest, or other testing frameworks, please contact us.
  • Testing Library for your relevant framework is installed in your project. This is required to simulate user interactions in your tests.
  • JSDOM version >= 15.2.1 is supported. If you encounter issues with JSDOM, please contact us.

Get Started

Add EvincedUT as a dependency

In your project directory install Unit Tester using npm or yarn. The Unit Tester package is not publicly available, and requires a token. Contact us to get started!

1npm install "@evinced/unit-tester"

Import Unit Tester into your test files

In your test file, import Unit Tester and initialize the EvincedUT object.

1import EvincedUT from "@evinced/unit-tester";

Import EvincedUT into your test environment

Instead of importing EvincedUT into each test file, you can make the EvincedUT object available globally in your test environment. Simply add the following lines to your Jest setup file.

1import EvincedUT from "@evinced/unit-tester";
2
3Object.defineProperty(global, "EvincedUT", {
4 value: EvincedUT,
5});

If your Jest configuration does not include a setup file, you can create one by adding the following line to your Jest configuration file. Make sure to use the setupFilesAfterEnv configuration option as the Evinced library must be initialized after Jest is loaded.

1setupFilesAfterEnv: ["<rootDir>/setup-jest.js"],

NOTE: If your eslint rules raise a no-undef error on the EvincedUT global object, you can add the following lines to your eslint.rc:

1globals: {
2 EvincedUT: "readonly";
3}

Your first test

Here are simple examples of how to add an Evinced accessibility scan to a test. Please note the inline comments that give detail on each test step.

Vanilla JS

1it("Evinced unit tester basic example", async () => {
2 // Create your component
3 const myComponent = document.createElement("div");
4 myComponent.setAttribute("role", "button");
5 myComponent.setAttribute("class", "custom-button");
6 document.body.appendChild(myComponent);
7
8 // Scan for a11y issues and assert on the results
9 const results = await EvincedUT.analyzeButton(myComponent);
10 expect(results).toHaveNoFailures();
11});

React

1import { screen, render } from "@testing-library/react";
2
3it("Evinced unit tester basic example", async () => {
4 // Render your component
5 render(<MyButton>Click Me!</MyButton>);
6 const myComponent = screen.getByRole("button");
7
8 // Scan for a11y issues and assert on the results
9 const results = await EvincedUT.analyzeButton(myComponent);
10 expect(results).toHaveNoFailures();
11});

Components summary

ComponentAPI MethodKnowledge Base
AccordionanalyzeAccordionAccordion entry
AlertanalyzeAlertAlert entry
BreadcrumbsanalyzeBreadcrumbsBreadcrumbs entry
ButtonanalyzeButtonButton entry
CheckboxanalyzeCheckboxCheckbox entry
ComboboxanalyzeComboboxCombobox entry
DisclosureanalyzeDisclosureDisclosure entry
LinkanalyzeLinkLink entry
ListboxanalyzeListboxListbox entry
ModalanalyzeModalModal entry
NavigationanalyzeNavigationNavigation entry
Radio GroupanalyzeRadioGroupRadio Group entry
SlideranalyzeSliderSlider entry
Multi Thumb SlideranalyzeSliderMultiThumbMulti Thumb Slider entry
SwitchanalyzeSwitchSwitch entry
Tab ListanalyzeTabListTab List entry
Toggle ButtonanalyzeToggleButtonToggle Button entry

API

about EvincedUT.analyzeComponent

Overview

Scans the specified component. An array is returned containing the results of each accessibility check that was performed. This is the generic API signature for most components. For more specific component types, see the following methods.

Parameters

  • locator: TargetLocator - The locator for the component to be scanned. This can be a CSS selector string, an element, or a function that returns an element.
  • options?: BaseComponentOptions - An optional object containing additional options for the scan.
    • containerElement?: Element - An optional container used as the root of the document instead of the document element
    • allowTargetReset?: boolean - An optional parameter that allows Unit Tester to pick the target element. Useful when the component is wrapped inside several containers.
    • userEventOptions?: @testing-library/user-event Options - An optional object containing options to be passed to the user-event library

Example

In the following example, a selector is passed to locate the switch component. The containerElement option is used to specify the root container for the scan. The userEventOptions option is used to specify the delay between user interactions in the test.

1const results = await EvincedUT.analyzeSwitch("#my-switch", {
2 containerElement: "#my-container",
3 userEventOptions: { delay: 10 },
4});
5expect(results).toHaveNoFailures();

Default options

1{
2 containerElement: document.documentElement;
3 allowTargetReset: false;
4 userEventOptions: undefined;
5}

Return value

1Promise<AnalysisResult[]>;

See AnalysisResult

analyzeAccordion

Overview

Scans the specified accordion container. An array is returned containing the results of each accessibility check that was performed.

This test uses the signature specified in the analyzeDisclosure section.

analyzeAlert

Overview

Scans the specified alert element. Make sure the element is visible before scanning.

An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeBreadcrumbs

Overview

Scans the specified breadcrumbs container. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeButton

Overview

Scans the specified button. An array is returned containing the results of each accessibility check that was performed.

Parameters

  • locator: TargetLocator - The locator for the component to be scanned. This can be a CSS selector string, an element, or a function that returns an element.
  • options?: AnalyzeButtonOptions - An optional object containing additional options for the scan.
    • wasActivatedCallback?: () => boolean - an optional boolean callback to evaluate whether the element was activated after interactions
    • The other parameters of the BaseComponentOptions type.

Example

1const checkActivation = () => {
2 return window.wasButtonActivated === true;
3};
4
5const results = await EvincedUT.analyzeButton('div[role="button"]', {
6 wasActivatedCallback: checkActivation,
7});
8expect(results).toHaveNoFailures();

Return value

1Promise<AnalysisResult[]>;

See AnalysisResult

analyzeCheckbox

Overview

Scans the specified checkbox. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeCombobox

Overview

Scans the specified combobox element. Currently only supports the listbox combobox pattern.

An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeDisclosure

Overview

Scans the specified disclosure button. An array is returned containing the results of each accessibility check that was performed.

Parameters

  • locator: TargetLocator - The locator for the disclosure button to be scanned. This can be a CSS selector string, an element, or a function that returns an element.
  • options?: AnalyzeDisclosureOptions - An optional object containing additional options for the scan.
    • evalEscape?: boolean - An optional boolean parameter that determines whether to evaluate the escape key accessibility. Default is false.
    • The other parameters of the BaseComponentOptions type.

Example

1const results = await EvincedUT.analyzeDisclosure('div[role="button"]', {
2 evalEscape: true,
3});
4expect(results).toHaveNoFailures();

Return value

1Promise<AnalysisResult[]>;

See AnalysisResult

Overview

Scans the specified link. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeListbox

Overview

Scans the specified listbox element. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeModal

Overview

Scans the specified modal dialog and launcher element. An array is returned containing the results of each accessibility check that was performed.

Parameters

  • launcherLocator: TargetLocator - The locator for the modal launcher. This can be a CSS selector string, an element, or a function that returns an element.
  • modalLocator: TargetLocator - The locator for the modal container. This can be a CSS selector string, an element, or a function that returns an element.
  • options?: BaseComponentOptions - An optional object containing additional options for the scan.

Example

1const results = await EvincedUT.analyzeModal(
2 buttonElement,
3 'div[role="dialog"]'
4);
5expect(results).toHaveNoFailures();

Return value

1Promise<AnalysisResult[]>;

See AnalysisResult

analyzeNavigation

Overview

Scans the specified navigation container. Supports all kinds of site navigation components.

An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeRadioGroup

Overview

Scans the specified radio group. An array is returned containing the results of each accessibility check that was performed.

Parameters

  • locator: TargetLocator - The locator for the component to be scanned. This can be a CSS selector string, an element, or a function that returns an element.
  • options?: AnalyzeRadioGroupOptions - An optional object containing additional options for the scan.
    • isToolbar?: boolean - an optional boolean parameter to specify if the radio group is part of a toolbar.
    • The other parameters of the BaseComponentOptions type.

Example

1const results = await EvincedUT.analyzeRadioGroup('div[role="radiogroup"]', {
2 isToolbar: true,
3});
4expect(results).toHaveNoFailures();

Default options

1{
2 containerElement: document.documentElement;
3 isToolbar: false;
4}

Return value

1Promise<AnalysisResult[]>;

See AnalysisResult

analyzeSlider

Overview

Scans the specified slider. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeSliderMultiThumb

Overview

Scans the specified multi thumb slider container. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeSwitch

Overview

Scans the specified switch. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeTabList

Overview

Scans the specified tablist container. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

analyzeToggleButton

Overview

Scans the specified toggle button, which is a subcategory of the button pattern. An array is returned containing the results of each accessibility check that was performed.

This test uses the generic signature specified in the About analyzeComponent section.

Assertions

toHaveNoFailures

Asserts that the scan results contain no failures. If the scan results contain failures, the test will fail and the results will be printed to the console. This assertion is useful when you want to ensure that your component has the required accessibility semantics and that you have implemented the correct keyboard interactions.

Example

1const results = await EvincedUT.analyzeButton('div[role="button"]');
2expect(results).toHaveNoFailures();

toHaveNoWarnings

Asserts that the scan results contain no warnings. If the scan results contain warnings, the test will fail and the results will be printed to the console. This assertion is a strict version of the toHaveNoFailures assertion. It is useful when you want to ensure that your component have implemented recommended accessibility semantics and keyboard interactions.

Example

1const results = await EvincedUT.analyzeButton('div[role="button"]');
2expect(results).toHaveNoWarnings();

toHaveResult

Asserts that the scan results contain a specific result. If the scan results do not contain the specified result, the test will fail and the results will be printed to the console. This assertion is useful when you want to ensure that your component complies with specific tests.

Parameters

  • expected: Partial<AnalysisResult> - The expected result. The assertion will pass if the scan results contain a result that matches the expected result.

Example

1const results = await EvincedUT.analyzeButton('div[role="button"]');
2expect(results).toHaveResult({
3 component: "Button",
4 test: "button name",
5 pass: true,
6});

Typings

TargetLocator

1string | HTMLElement | SVGElement | (() => HTMLElement | SVGElement);

AnalysisResult

1{
2 // The type of component that was scanned
3 component: string;
4
5 // The test that was run
6 test: string;
7
8 // The result of the test
9 pass: boolean;
10
11 // The message associated with the test
12 message: string;
13
14 // The element that were related to the test message
15 members?: string[];
16
17 // The actions that were related to the test message
18 actions?: string[];
19
20 // The type of the result (PASS, FAIL, WARN or SKIP)
21 type?: string;
22}

BaseComponentOptions

1{
2 // The container element to use as the root of the document
3 containerElement?: Element;
4 // An optional parameter that allows Unit Tester to pick the target element.
5 // Useful when the component is wrapped inside several containers.
6 allowTargetReset?: boolean;
7 // An optional object containing options to be passed to the user-event library
8 // https://testing-library.com/docs/user-event/options/
9 userEventOptions?: @testing-library/user-event Options;
10}

Support

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