120 lines
4.3 KiB
Plaintext
120 lines
4.3 KiB
Plaintext
|
/**
|
||
|
* @fileoverview Enforce aria role attribute is valid.
|
||
|
* @author Ethan Cohen
|
||
|
*/
|
||
|
|
||
|
// -----------------------------------------------------------------------------
|
||
|
// Requirements
|
||
|
// -----------------------------------------------------------------------------
|
||
|
|
||
|
import { roles } from 'aria-query';
|
||
|
import { RuleTester } from 'eslint';
|
||
|
import parserOptionsMapper from '../../__util__/parserOptionsMapper';
|
||
|
import parsers from '../../__util__/helpers/parsers';
|
||
|
import rule from '../../../src/rules/aria-role';
|
||
|
|
||
|
// -----------------------------------------------------------------------------
|
||
|
// Tests
|
||
|
// -----------------------------------------------------------------------------
|
||
|
|
||
|
const ruleTester = new RuleTester();
|
||
|
|
||
|
const errorMessage = {
|
||
|
message: 'Elements with ARIA roles must use a valid, non-abstract ARIA role.',
|
||
|
type: 'JSXAttribute',
|
||
|
};
|
||
|
|
||
|
const roleKeys = [...roles.keys()];
|
||
|
|
||
|
const validRoles = roleKeys.filter((role) => roles.get(role).abstract === false);
|
||
|
const invalidRoles = roleKeys.filter((role) => roles.get(role).abstract === true);
|
||
|
|
||
|
const createTests = (roleNames) => roleNames.map((role) => ({
|
||
|
code: `<div role="${role.toLowerCase()}" />`,
|
||
|
}));
|
||
|
|
||
|
const validTests = createTests(validRoles);
|
||
|
const invalidTests = createTests(invalidRoles).map((test) => {
|
||
|
const invalidTest = { ...test };
|
||
|
invalidTest.errors = [errorMessage];
|
||
|
return invalidTest;
|
||
|
});
|
||
|
|
||
|
const allowedInvalidRoles = [{
|
||
|
allowedInvalidRoles: ['invalid-role', 'other-invalid-role'],
|
||
|
}];
|
||
|
|
||
|
const ignoreNonDOMSchema = [{
|
||
|
ignoreNonDOM: true,
|
||
|
}];
|
||
|
|
||
|
const customDivSettings = {
|
||
|
'jsx-a11y': {
|
||
|
polymorphicPropName: 'asChild',
|
||
|
components: {
|
||
|
Div: 'div',
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
ruleTester.run('aria-role', rule, {
|
||
|
valid: parsers.all([].concat(
|
||
|
// Variables should pass, as we are only testing literals.
|
||
|
{ code: '<div />' },
|
||
|
{ code: '<div></div>' },
|
||
|
{ code: '<div role={role} />' },
|
||
|
{ code: '<div role={role || "button"} />' },
|
||
|
{ code: '<div role={role || "foobar"} />' },
|
||
|
{ code: '<div role="tabpanel row" />' },
|
||
|
{ code: '<div role="switch" />' },
|
||
|
{ code: '<div role="doc-abstract" />' },
|
||
|
{ code: '<div role="doc-appendix doc-bibliography" />' },
|
||
|
{ code: '<Bar baz />' },
|
||
|
{ code: '<img role="invalid-role" />', options: allowedInvalidRoles },
|
||
|
{ code: '<img role="invalid-role tabpanel" />', options: allowedInvalidRoles },
|
||
|
{ code: '<img role="invalid-role other-invalid-role" />', options: allowedInvalidRoles },
|
||
|
{ code: '<Foo role="bar" />', options: ignoreNonDOMSchema },
|
||
|
{ code: '<fakeDOM role="bar" />', options: ignoreNonDOMSchema },
|
||
|
{ code: '<img role="presentation" />', options: ignoreNonDOMSchema },
|
||
|
{
|
||
|
code: '<Div role="button" />',
|
||
|
settings: customDivSettings,
|
||
|
},
|
||
|
{
|
||
|
code: '<Box asChild="div" role="button" />',
|
||
|
settings: customDivSettings,
|
||
|
},
|
||
|
{
|
||
|
code: '<svg role="graphics-document document" />',
|
||
|
},
|
||
|
)).concat(validTests).map(parserOptionsMapper),
|
||
|
|
||
|
invalid: parsers.all([].concat(
|
||
|
{ code: '<div role="foobar" />', errors: [errorMessage] },
|
||
|
{ code: '<div role="datepicker"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role="range"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role="Button"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role=""></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role="tabpanel row foobar"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role="tabpanel row range"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role="doc-endnotes range"></div>', errors: [errorMessage] },
|
||
|
{ code: '<div role />', errors: [errorMessage] },
|
||
|
{ code: '<div role="unknown-invalid-role" />', errors: [errorMessage], options: allowedInvalidRoles },
|
||
|
{ code: '<div role={null}></div>', errors: [errorMessage] },
|
||
|
{ code: '<Foo role="datepicker" />', errors: [errorMessage] },
|
||
|
{ code: '<Foo role="Button" />', errors: [errorMessage] },
|
||
|
{ code: '<Div role="Button" />', errors: [errorMessage], settings: customDivSettings },
|
||
|
{
|
||
|
code: '<Div role="Button" />',
|
||
|
errors: [errorMessage],
|
||
|
options: ignoreNonDOMSchema,
|
||
|
settings: customDivSettings,
|
||
|
},
|
||
|
{
|
||
|
code: '<Box asChild="div" role="Button" />',
|
||
|
settings: customDivSettings,
|
||
|
errors: [errorMessage],
|
||
|
},
|
||
|
)).concat(invalidTests).map(parserOptionsMapper),
|
||
|
});
|