Skip to content

Commit

Permalink
test(loading): add a11y tests (#4621)
Browse files Browse the repository at this point in the history
* test(loader): stub out initial test

* test(loader): add aria-live test

* test(loading): break tests into categories and add AAT

* test(loading): add beforeEach block

* test(Loading): add DAP AAT and update Axe matcher naming

* test(loading): add offline mirrors and test results

* test(loading): fix faulty DAP assertion

* test(loading): update DAP, update .gitignore, add aatconfig

* test(Loading): add enzyme attatchTo and un-breakout a11y tests

* test(Loading): untracking results folder

* test(Loading): add results folder to .gitignore

* test(Loading): add comments, lower timeout

* test(Loading): remove accidental important, add test helpers

* fix(Tag): add role=button to span for screenreaders

* Update packages/react/src/components/Loading/Loading-test.js

Co-Authored-By: Josh Black <josh@josh.black>

* Update packages/react/src/components/Loading/Loading-test.js

Co-Authored-By: Josh Black <josh@josh.black>

* test(Loading): fix casing and use render over enzyme

* test(Loading): update how we grab elements

* test(loading): update DAP version

* chore(project): sync offline mirror
  • Loading branch information
dakahn authored and joshblack committed Dec 6, 2019
1 parent fba393b commit a0f1d75
Show file tree
Hide file tree
Showing 26 changed files with 255 additions and 33 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ node_modules

# Generated by npm@5, but project currently uses Yarn
package-lock.json

# AAT test results from DAP/Axe
results/
Binary file added .yarn/offline-mirror/chromedriver-77.0.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/debug-4.1.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/deep-diff-0.3.8.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/del-4.1.1.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/ibma-aat-2.0.3-alpha.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/ip-regex-2.1.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/is-path-cwd-2.2.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/is-path-in-cwd-2.1.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/is-path-inside-2.1.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/is-url-1.2.4.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/is2-2.0.1.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/proxy-from-env-1.0.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/puppeteer-1.20.0.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/tcp-port-used-1.0.1.tgz
Binary file not shown.
Binary file added .yarn/offline-mirror/ws-6.2.1.tgz
Binary file not shown.
46 changes: 46 additions & 0 deletions aat/aat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module.exports = {
// optional - Specify the rule archive
// Default: latest
// Run `npx aat archives` for a list of valid ruleArchive ids and policy ids
ruleArchive: '2019SeptDeploy',

// optional - Specify one or many policies to scan.
// Run `npx aat archives` for a list of valid ruleArchive ids and policy ids
policies: ['IBM_Accessibility'],

// optional - Specify one or many violation levels on which to fail the test
// i.e. If specified violation then the testcase will only fail if
// a violation is found during the scan.
// i.e. failLevels: ["violation"]
// i.e. failLevels: ["violation","potential violation"] or refer to below as a list
// Default: ["violation","potential violation"]
failLevels: ['violation'],

// optional - Specify one or many violation levels which should be reported
// i.e. If specified violation then in the report it would only contain
// results which are level of violation.
// i.e. reportLevels: ["violation"]
// Valid values: violation, potentialviolation, recommendation, potentialrecommendation, manual
// Default: ["violation","potential violation"]
reportLevels: ['violation'],

// Optional - Which type should the results be outputted to
// Valid values: json, csv
// Default: json
outputFormat: ['json'],

// Optional - Specify labels that you would like associated to your scan
//
// i.e.
// label: ["Firefox","master","V12","Linux"]
// Default: N/A
label: [],

// optional - Where the scan results should be saved.
// Default: results
outputFolder: '.aat/results',

// optional - Where the baseline results should be loaded from
// Default: baselines
baselineFolder: '.aat/baselines',
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@carbon/cli": "10.5.0",
"@commitlint/cli": "^7.5.2",
"@commitlint/config-conventional": "^7.5.0",
"@ibma/aat": "https://able.ibm.com/tools/dist/ibma-aat-2.0.3-alpha.tgz",
"alex": "^8.0.0",
"axe-core": "^3.3.2",
"babel-jest": "^24.8.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ describe('Accordion', () => {
</Accordion>
);

await expect(document).toHaveNoViolations();
await expect(document).toHaveNoAxeViolations();
});
});
72 changes: 48 additions & 24 deletions packages/react/src/components/Loading/Loading-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,57 @@ import React from 'react';
import Loading from '../Loading';
import { mount } from 'enzyme';
import { settings } from 'carbon-components';
import { render, cleanup } from '@carbon/test-utils/react';
import { afterEach } from 'jest-circus';

const { prefix } = settings;

describe('Loading', () => {
describe('Renders as expected', () => {
afterEach(cleanup);

describe('automated accessibility testing', () => {
it('should have no Axe violations', async () => {
const { container } = render(<Loading />);
await expect(container).toHaveNoAxeViolations();
});

it('should have no DAP violations', async () => {
const { container } = render(<Loading />);
await expect(container).toHaveNoDAPViolations('Loading');
});
});

describe('with a screenreader', () => {
afterEach(cleanup);

// https://www.w3.org/TR/WCAG21/#headings-and-labels
it('should have a label on the live region', () => {
const { container } = render(<Loading />);
const liveRegion = container.querySelector('[aria-live]');
expect(liveRegion).toBeInstanceOf(HTMLElement);

const id = liveRegion.getAttribute('aria-labelledby');
expect(id).toBeDefined();

const label = document.getElementById(id);
expect(label).toBeDefined();
expect(typeof label.textContent).toBe('string');
});

// https://www.w3.org/TR/WCAG21/#status-messages
it('should announce a loading status', () => {
const { container } = render(<Loading />);
const liveRegion = container.querySelector('[aria-live]');
expect(liveRegion).toBeInstanceOf(HTMLElement);

const atomicBoolean = liveRegion.getAttribute('aria-atomic');
expect(atomicBoolean).toBe('true');

const ariaLiveValue = liveRegion.getAttribute('aria-live');
expect(ariaLiveValue).toEqual('assertive');
});
});
describe('renders as expected', () => {
const wrapper = mount(<Loading className="extra-class" />);
const overlay = wrapper.find(`.${prefix}--loading-overlay`);
const loader = wrapper.find(`.${prefix}--loading`);
Expand Down Expand Up @@ -48,7 +94,7 @@ describe('Loading', () => {
});
});

describe('Sets props and state as expected', () => {
describe('sets props and state as expected', () => {
const wrapper = mount(<Loading className="extra-class" />);

it(`should remove and add ${prefix}--loading--stop class`, () => {
Expand All @@ -67,27 +113,5 @@ describe('Loading', () => {
const overlay = wrapper.find(`.${prefix}--loading-overlay`);
expect(overlay.length).toEqual(0);
});

it('should be an assertive live region when active', () => {
const wrapper = mount(<Loading active={false} />);
const getLiveRegion = () => wrapper.find('[aria-live]');

expect(getLiveRegion().prop('aria-atomic')).toBe('true');
expect(getLiveRegion().prop('aria-live')).toBe('off');
expect(getLiveRegion().prop('aria-labelledby')).toBeDefined();

wrapper.setProps({ active: true });
expect(getLiveRegion().prop('aria-live')).toBe('assertive');

wrapper.setProps({ active: false });
expect(getLiveRegion().prop('aria-live')).toBe('off');
});

it('should have an associated label for the live region', () => {
const wrapper = mount(<Loading />);
const node = wrapper.find('[aria-live][aria-labelledby]');
const id = node.prop('aria-labelledby');
expect(wrapper.find(`#${id}`)).toBeDefined();
});
});
});
1 change: 1 addition & 0 deletions packages/react/src/components/Tag/Tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const Tag = ({
});
return filter ? (
<span
role="button"
className={tagClasses}
title={title || 'Clear filter'}
tabIndex="0" // eslint-disable-line jsx-a11y/no-noninteractive-tabindex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const defaultOptions = {
},
};

function toHaveNoViolations(node, options = {}) {
function toHaveNoAxeViolations(node, options = {}) {
return new Promise(resolve => {
axe.run(
node,
Expand Down Expand Up @@ -79,4 +79,4 @@ ${divider}
${nodes.join('\n')}`;
}

module.exports = toHaveNoViolations;
module.exports = toHaveNoAxeViolations;
26 changes: 26 additions & 0 deletions tasks/jest/matchers/toHaveNoDAPViolations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright IBM Corp. 2019
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

const AAT = require('@ibma/aat');

async function toHaveNoDAPViolations(node, label) {
const results = await AAT.getCompliance(node, label);
if (AAT.assertCompliance(results.report) === 0) {
return {
pass: true,
};
} else {
return {
pass: false,
message: () => AAT.stringifyResults(results.report),
};
}
}

module.exports = toHaveNoDAPViolations;
2 changes: 2 additions & 0 deletions tasks/jest/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

global.__DEV__ = true;

jest.setTimeout(20000);

global.requestAnimationFrame = function requestAnimationFrame(callback) {
// TODO: replace with async version
// setTimeout(callback);
Expand Down
5 changes: 3 additions & 2 deletions tasks/jest/setupAfterEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

const toHaveNoViolations = require('./matchers/toHaveNoViolations');
const toHaveNoAxeViolations = require('./matchers/toHaveNoAxeViolations');
const toHaveNoDAPViolations = require('./matchers/toHaveNoDAPViolations');

// We can extend `expect` using custom matchers as defined by:
// https://jest-bot.github.io/jest/docs/expect.html#expectextendmatchers
Expand All @@ -18,4 +19,4 @@ const toHaveNoViolations = require('./matchers/toHaveNoViolations');
//
// For more information, check out the docs here:
// https://jestjs.io/docs/en/configuration.html#setupfilesafterenv-array
expect.extend({ toHaveNoViolations });
expect.extend({ toHaveNoAxeViolations, toHaveNoDAPViolations });

0 comments on commit a0f1d75

Please sign in to comment.