@arcaauth/eslint-plugin-jsx-a11y 6.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +17 -0
- package/.eslintrc +44 -0
- package/CHANGELOG.md +774 -0
- package/LICENSE.md +8 -0
- package/README.md +423 -0
- package/__mocks__/IdentifierMock.js +15 -0
- package/__mocks__/JSXAttributeMock.js +39 -0
- package/__mocks__/JSXElementMock.js +37 -0
- package/__mocks__/JSXExpressionContainerMock.js +15 -0
- package/__mocks__/JSXSpreadAttributeMock.js +18 -0
- package/__mocks__/JSXTextMock.js +17 -0
- package/__mocks__/LiteralMock.js +17 -0
- package/__mocks__/genInteractives.js +218 -0
- package/__tests__/__util__/axeMapping.js +6 -0
- package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
- package/__tests__/__util__/helpers/parsers.js +186 -0
- package/__tests__/__util__/parserOptionsMapper.js +53 -0
- package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
- package/__tests__/index-test.js +40 -0
- package/__tests__/src/rules/accessible-emoji-test.js +66 -0
- package/__tests__/src/rules/alt-text-test.js +291 -0
- package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
- package/__tests__/src/rules/anchor-has-content-test.js +54 -0
- package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
- package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
- package/__tests__/src/rules/aria-props-test.js +69 -0
- package/__tests__/src/rules/aria-proptypes-test.js +311 -0
- package/__tests__/src/rules/aria-role-test.js +118 -0
- package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
- package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
- package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
- package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
- package/__tests__/src/rules/heading-has-content-test.js +85 -0
- package/__tests__/src/rules/html-has-lang-test.js +42 -0
- package/__tests__/src/rules/iframe-has-title-test.js +55 -0
- package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
- package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
- package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
- package/__tests__/src/rules/label-has-for-test.js +235 -0
- package/__tests__/src/rules/lang-test.js +59 -0
- package/__tests__/src/rules/media-has-caption-test.js +220 -0
- package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
- package/__tests__/src/rules/no-access-key-test.js +48 -0
- package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
- package/__tests__/src/rules/no-autofocus-test.js +68 -0
- package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
- package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
- package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
- package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
- package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
- package/__tests__/src/rules/no-onchange-test.js +57 -0
- package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
- package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
- package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
- package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
- package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
- package/__tests__/src/rules/scope-test.js +50 -0
- package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
- package/__tests__/src/util/attributesComparator-test.js +91 -0
- package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
- package/__tests__/src/util/getComputedRole-test.js +71 -0
- package/__tests__/src/util/getElementType-test.js +154 -0
- package/__tests__/src/util/getExplicitRole-test.js +35 -0
- package/__tests__/src/util/getImplicitRole-test.js +25 -0
- package/__tests__/src/util/getSuggestion-test.js +33 -0
- package/__tests__/src/util/getTabIndex-test.js +85 -0
- package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
- package/__tests__/src/util/implicitRoles/input-test.js +87 -0
- package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
- package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
- package/__tests__/src/util/isAbstractRole-test.js +51 -0
- package/__tests__/src/util/isContentEditable-test.js +52 -0
- package/__tests__/src/util/isDOMElement-test.js +30 -0
- package/__tests__/src/util/isDisabledElement-test.js +88 -0
- package/__tests__/src/util/isFocusable-test.js +111 -0
- package/__tests__/src/util/isInteractiveElement-test.js +104 -0
- package/__tests__/src/util/isInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
- package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
- package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
- package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
- package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
- package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
- package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
- package/__tests__/src/util/schemas-test.js +35 -0
- package/docs/rules/accessible-emoji.md +30 -0
- package/docs/rules/alt-text.md +168 -0
- package/docs/rules/anchor-ambiguous-text.md +91 -0
- package/docs/rules/anchor-has-content.md +64 -0
- package/docs/rules/anchor-is-valid.md +270 -0
- package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
- package/docs/rules/aria-props.md +29 -0
- package/docs/rules/aria-proptypes.md +30 -0
- package/docs/rules/aria-role.md +51 -0
- package/docs/rules/aria-unsupported-elements.md +30 -0
- package/docs/rules/autocomplete-valid.md +49 -0
- package/docs/rules/click-events-have-key-events.md +28 -0
- package/docs/rules/control-has-associated-label.md +113 -0
- package/docs/rules/heading-has-content.md +67 -0
- package/docs/rules/html-has-lang.md +31 -0
- package/docs/rules/iframe-has-title.md +37 -0
- package/docs/rules/img-redundant-alt.md +48 -0
- package/docs/rules/interactive-supports-focus.md +156 -0
- package/docs/rules/label-has-associated-control.md +152 -0
- package/docs/rules/label-has-for.md +130 -0
- package/docs/rules/lang.md +31 -0
- package/docs/rules/media-has-caption.md +48 -0
- package/docs/rules/mouse-events-have-key-events.md +58 -0
- package/docs/rules/no-access-key.md +30 -0
- package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
- package/docs/rules/no-autofocus.md +43 -0
- package/docs/rules/no-distracting-elements.md +41 -0
- package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
- package/docs/rules/no-noninteractive-element-interactions.md +145 -0
- package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
- package/docs/rules/no-noninteractive-tabindex.md +115 -0
- package/docs/rules/no-onchange.md +36 -0
- package/docs/rules/no-redundant-roles.md +46 -0
- package/docs/rules/no-static-element-interactions.md +114 -0
- package/docs/rules/prefer-tag-over-role.md +32 -0
- package/docs/rules/role-has-required-aria-props.md +31 -0
- package/docs/rules/role-supports-aria-props.md +39 -0
- package/docs/rules/scope.md +30 -0
- package/docs/rules/tabindex-no-positive.md +32 -0
- package/lib/configs/flat-config-base.js +11 -0
- package/lib/configs/legacy-config-base.js +9 -0
- package/lib/index.js +209 -0
- package/lib/rules/accessible-emoji.js +63 -0
- package/lib/rules/alt-text.js +218 -0
- package/lib/rules/anchor-ambiguous-text.js +64 -0
- package/lib/rules/anchor-has-content.js +60 -0
- package/lib/rules/anchor-is-valid.js +122 -0
- package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
- package/lib/rules/aria-props.js +59 -0
- package/lib/rules/aria-proptypes.js +114 -0
- package/lib/rules/aria-role.js +89 -0
- package/lib/rules/aria-unsupported-elements.js +64 -0
- package/lib/rules/autocomplete-valid.js +67 -0
- package/lib/rules/click-events-have-key-events.js +68 -0
- package/lib/rules/control-has-associated-label.js +103 -0
- package/lib/rules/heading-has-content.js +61 -0
- package/lib/rules/html-has-lang.js +50 -0
- package/lib/rules/iframe-has-title.js +50 -0
- package/lib/rules/img-redundant-alt.js +88 -0
- package/lib/rules/interactive-supports-focus.js +87 -0
- package/lib/rules/label-has-associated-control.js +127 -0
- package/lib/rules/label-has-for.js +150 -0
- package/lib/rules/lang.js +68 -0
- package/lib/rules/media-has-caption.js +96 -0
- package/lib/rules/mouse-events-have-key-events.js +94 -0
- package/lib/rules/no-access-key.js +43 -0
- package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
- package/lib/rules/no-autofocus.js +62 -0
- package/lib/rules/no-distracting-elements.js +54 -0
- package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
- package/lib/rules/no-noninteractive-element-interactions.js +95 -0
- package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
- package/lib/rules/no-noninteractive-tabindex.js +109 -0
- package/lib/rules/no-onchange.js +52 -0
- package/lib/rules/no-redundant-roles.js +86 -0
- package/lib/rules/no-static-element-interactions.js +102 -0
- package/lib/rules/prefer-tag-over-role.js +75 -0
- package/lib/rules/role-has-required-aria-props.js +88 -0
- package/lib/rules/role-supports-aria-props.js +78 -0
- package/lib/rules/scope.js +58 -0
- package/lib/rules/tabindex-no-positive.js +53 -0
- package/lib/util/attributesComparator.js +34 -0
- package/lib/util/getAccessibleChildText.js +55 -0
- package/lib/util/getComputedRole.js +19 -0
- package/lib/util/getElementType.js +30 -0
- package/lib/util/getExplicitRole.js +27 -0
- package/lib/util/getImplicitRole.js +24 -0
- package/lib/util/getSuggestion.js +32 -0
- package/lib/util/getTabIndex.js +34 -0
- package/lib/util/hasAccessibleChild.js +30 -0
- package/lib/util/implicitRoles/a.js +17 -0
- package/lib/util/implicitRoles/area.js +17 -0
- package/lib/util/implicitRoles/article.js +13 -0
- package/lib/util/implicitRoles/aside.js +13 -0
- package/lib/util/implicitRoles/body.js +13 -0
- package/lib/util/implicitRoles/button.js +13 -0
- package/lib/util/implicitRoles/datalist.js +13 -0
- package/lib/util/implicitRoles/details.js +13 -0
- package/lib/util/implicitRoles/dialog.js +13 -0
- package/lib/util/implicitRoles/form.js +13 -0
- package/lib/util/implicitRoles/h1.js +13 -0
- package/lib/util/implicitRoles/h2.js +13 -0
- package/lib/util/implicitRoles/h3.js +13 -0
- package/lib/util/implicitRoles/h4.js +13 -0
- package/lib/util/implicitRoles/h5.js +13 -0
- package/lib/util/implicitRoles/h6.js +13 -0
- package/lib/util/implicitRoles/hr.js +13 -0
- package/lib/util/implicitRoles/img.js +31 -0
- package/lib/util/implicitRoles/index.js +82 -0
- package/lib/util/implicitRoles/input.js +38 -0
- package/lib/util/implicitRoles/li.js +13 -0
- package/lib/util/implicitRoles/link.js +17 -0
- package/lib/util/implicitRoles/menu.js +19 -0
- package/lib/util/implicitRoles/menuitem.js +28 -0
- package/lib/util/implicitRoles/meter.js +13 -0
- package/lib/util/implicitRoles/nav.js +13 -0
- package/lib/util/implicitRoles/ol.js +13 -0
- package/lib/util/implicitRoles/option.js +13 -0
- package/lib/util/implicitRoles/output.js +13 -0
- package/lib/util/implicitRoles/progress.js +13 -0
- package/lib/util/implicitRoles/section.js +13 -0
- package/lib/util/implicitRoles/select.js +13 -0
- package/lib/util/implicitRoles/tbody.js +13 -0
- package/lib/util/implicitRoles/textarea.js +13 -0
- package/lib/util/implicitRoles/tfoot.js +13 -0
- package/lib/util/implicitRoles/thead.js +13 -0
- package/lib/util/implicitRoles/ul.js +13 -0
- package/lib/util/isAbstractRole.js +23 -0
- package/lib/util/isContentEditable.js +13 -0
- package/lib/util/isDOMElement.js +15 -0
- package/lib/util/isDisabledElement.js +23 -0
- package/lib/util/isFocusable.js +23 -0
- package/lib/util/isHiddenFromScreenReader.js +26 -0
- package/lib/util/isInteractiveElement.js +116 -0
- package/lib/util/isInteractiveRole.js +54 -0
- package/lib/util/isNonInteractiveElement.js +131 -0
- package/lib/util/isNonInteractiveRole.js +55 -0
- package/lib/util/isNonLiteralProperty.js +29 -0
- package/lib/util/isPresentationRole.js +13 -0
- package/lib/util/isSemanticRoleElement.js +54 -0
- package/lib/util/mayContainChildComponent.js +50 -0
- package/lib/util/mayHaveAccessibleLabel.js +95 -0
- package/lib/util/schemas.js +52 -0
- package/package.json +120 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Enforce that an element does not have an unsupported ARIA attribute.
|
|
3
|
+
* @author Ethan Cohen
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
// Requirements
|
|
8
|
+
// -----------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
aria,
|
|
12
|
+
roles,
|
|
13
|
+
} from 'aria-query';
|
|
14
|
+
import { RuleTester } from 'eslint';
|
|
15
|
+
import { version as eslintVersion } from 'eslint/package.json';
|
|
16
|
+
import semver from 'semver';
|
|
17
|
+
|
|
18
|
+
import parserOptionsMapper from '../../__util__/parserOptionsMapper';
|
|
19
|
+
import parsers from '../../__util__/helpers/parsers';
|
|
20
|
+
import rule from '../../../src/rules/role-supports-aria-props';
|
|
21
|
+
|
|
22
|
+
// -----------------------------------------------------------------------------
|
|
23
|
+
// Tests
|
|
24
|
+
// -----------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
const ruleTester = new RuleTester();
|
|
27
|
+
|
|
28
|
+
const generateErrorMessage = (attr, role, tag, isImplicit) => {
|
|
29
|
+
if (isImplicit) {
|
|
30
|
+
return `The attribute ${attr} is not supported by the role ${role}. This role is implicit on the element ${tag}.`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `The attribute ${attr} is not supported by the role ${role}.`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const errorMessage = (attr, role, tag, isImplicit) => ({
|
|
37
|
+
message: generateErrorMessage(attr, role, tag, isImplicit),
|
|
38
|
+
type: 'JSXOpeningElement',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const componentsSettings = {
|
|
42
|
+
'jsx-a11y': {
|
|
43
|
+
components: {
|
|
44
|
+
Link: 'a',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const nonAbstractRoles = roles.keys().filter((role) => roles.get(role).abstract === false);
|
|
50
|
+
|
|
51
|
+
const createTests = (rolesNames) => rolesNames.reduce((tests, role) => {
|
|
52
|
+
const {
|
|
53
|
+
props: propKeyValues,
|
|
54
|
+
} = roles.get(role);
|
|
55
|
+
const validPropsForRole = Object.keys(propKeyValues);
|
|
56
|
+
const invalidPropsForRole = aria.keys()
|
|
57
|
+
.map((attribute) => attribute.toLowerCase())
|
|
58
|
+
.filter((attribute) => validPropsForRole.indexOf(attribute) === -1);
|
|
59
|
+
const normalRole = role.toLowerCase();
|
|
60
|
+
|
|
61
|
+
return [
|
|
62
|
+
tests[0].concat(validPropsForRole.map((prop) => ({
|
|
63
|
+
code: `<div role="${normalRole}" ${prop.toLowerCase()} />`,
|
|
64
|
+
}))),
|
|
65
|
+
tests[1].concat(invalidPropsForRole.map((prop) => ({
|
|
66
|
+
code: `<div role="${normalRole}" ${prop.toLowerCase()} />`,
|
|
67
|
+
errors: [errorMessage(prop.toLowerCase(), normalRole, 'div', false)],
|
|
68
|
+
}))),
|
|
69
|
+
];
|
|
70
|
+
}, [[], []]);
|
|
71
|
+
|
|
72
|
+
const [validTests, invalidTests] = createTests(nonAbstractRoles);
|
|
73
|
+
|
|
74
|
+
ruleTester.run('role-supports-aria-props', rule, {
|
|
75
|
+
valid: parsers.all([].concat(
|
|
76
|
+
{ code: '<Foo bar />' },
|
|
77
|
+
{ code: '<div />' },
|
|
78
|
+
{ code: '<div id="main" />' },
|
|
79
|
+
{ code: '<div role />' },
|
|
80
|
+
{ code: '<div role="presentation" {...props} />' },
|
|
81
|
+
{ code: '<Foo.Bar baz={true} />' },
|
|
82
|
+
{ code: '<Link href="#" aria-checked />' },
|
|
83
|
+
|
|
84
|
+
// IMPLICIT ROLE TESTS
|
|
85
|
+
// A TESTS - implicit role is `link`
|
|
86
|
+
{ code: '<a href="#" aria-expanded />' },
|
|
87
|
+
{ code: '<a href="#" aria-atomic />' },
|
|
88
|
+
{ code: '<a href="#" aria-busy />' },
|
|
89
|
+
{ code: '<a href="#" aria-controls />' },
|
|
90
|
+
{ code: '<a href="#" aria-current />' },
|
|
91
|
+
{ code: '<a href="#" aria-describedby />' },
|
|
92
|
+
{ code: '<a href="#" aria-disabled />' },
|
|
93
|
+
{ code: '<a href="#" aria-dropeffect />' },
|
|
94
|
+
{ code: '<a href="#" aria-flowto />' },
|
|
95
|
+
{ code: '<a href="#" aria-haspopup />' },
|
|
96
|
+
{ code: '<a href="#" aria-grabbed />' },
|
|
97
|
+
{ code: '<a href="#" aria-hidden />' },
|
|
98
|
+
{ code: '<a href="#" aria-label />' },
|
|
99
|
+
{ code: '<a href="#" aria-labelledby />' },
|
|
100
|
+
{ code: '<a href="#" aria-live />' },
|
|
101
|
+
{ code: '<a href="#" aria-owns />' },
|
|
102
|
+
{ code: '<a href="#" aria-relevant />' },
|
|
103
|
+
|
|
104
|
+
// this will have global
|
|
105
|
+
{ code: '<a aria-checked />' },
|
|
106
|
+
|
|
107
|
+
// AREA TESTS - implicit role is `link`
|
|
108
|
+
{ code: '<area href="#" aria-expanded />' },
|
|
109
|
+
{ code: '<area href="#" aria-atomic />' },
|
|
110
|
+
{ code: '<area href="#" aria-busy />' },
|
|
111
|
+
{ code: '<area href="#" aria-controls />' },
|
|
112
|
+
{ code: '<area href="#" aria-describedby />' },
|
|
113
|
+
{ code: '<area href="#" aria-disabled />' },
|
|
114
|
+
{ code: '<area href="#" aria-dropeffect />' },
|
|
115
|
+
{ code: '<area href="#" aria-flowto />' },
|
|
116
|
+
{ code: '<area href="#" aria-grabbed />' },
|
|
117
|
+
{ code: '<area href="#" aria-haspopup />' },
|
|
118
|
+
{ code: '<area href="#" aria-hidden />' },
|
|
119
|
+
{ code: '<area href="#" aria-label />' },
|
|
120
|
+
{ code: '<area href="#" aria-labelledby />' },
|
|
121
|
+
{ code: '<area href="#" aria-live />' },
|
|
122
|
+
{ code: '<area href="#" aria-owns />' },
|
|
123
|
+
{ code: '<area href="#" aria-relevant />' },
|
|
124
|
+
|
|
125
|
+
// this will have global
|
|
126
|
+
{ code: '<area aria-checked />' },
|
|
127
|
+
|
|
128
|
+
// LINK TESTS - implicit role is `link`
|
|
129
|
+
{ code: '<link href="#" aria-expanded />' },
|
|
130
|
+
{ code: '<link href="#" aria-atomic />' },
|
|
131
|
+
{ code: '<link href="#" aria-busy />' },
|
|
132
|
+
{ code: '<link href="#" aria-controls />' },
|
|
133
|
+
{ code: '<link href="#" aria-describedby />' },
|
|
134
|
+
{ code: '<link href="#" aria-disabled />' },
|
|
135
|
+
{ code: '<link href="#" aria-dropeffect />' },
|
|
136
|
+
{ code: '<link href="#" aria-flowto />' },
|
|
137
|
+
{ code: '<link href="#" aria-grabbed />' },
|
|
138
|
+
{ code: '<link href="#" aria-hidden />' },
|
|
139
|
+
{ code: '<link href="#" aria-haspopup />' },
|
|
140
|
+
{ code: '<link href="#" aria-label />' },
|
|
141
|
+
{ code: '<link href="#" aria-labelledby />' },
|
|
142
|
+
{ code: '<link href="#" aria-live />' },
|
|
143
|
+
{ code: '<link href="#" aria-owns />' },
|
|
144
|
+
{ code: '<link href="#" aria-relevant />' },
|
|
145
|
+
|
|
146
|
+
// this will have global
|
|
147
|
+
{ code: '<link aria-checked />' },
|
|
148
|
+
|
|
149
|
+
// IMG TESTS - no implicit role
|
|
150
|
+
{ code: '<img alt="" aria-checked />' },
|
|
151
|
+
|
|
152
|
+
// this will have role of `img`
|
|
153
|
+
{ code: '<img alt="foobar" aria-busy />' },
|
|
154
|
+
|
|
155
|
+
// MENU TESTS - implicit role is `toolbar` when `type="toolbar"`
|
|
156
|
+
{ code: '<menu type="toolbar" aria-activedescendant />' },
|
|
157
|
+
{ code: '<menu type="toolbar" aria-atomic />' },
|
|
158
|
+
{ code: '<menu type="toolbar" aria-busy />' },
|
|
159
|
+
{ code: '<menu type="toolbar" aria-controls />' },
|
|
160
|
+
{ code: '<menu type="toolbar" aria-describedby />' },
|
|
161
|
+
{ code: '<menu type="toolbar" aria-disabled />' },
|
|
162
|
+
{ code: '<menu type="toolbar" aria-dropeffect />' },
|
|
163
|
+
{ code: '<menu type="toolbar" aria-flowto />' },
|
|
164
|
+
{ code: '<menu type="toolbar" aria-grabbed />' },
|
|
165
|
+
{ code: '<menu type="toolbar" aria-hidden />' },
|
|
166
|
+
{ code: '<menu type="toolbar" aria-label />' },
|
|
167
|
+
{ code: '<menu type="toolbar" aria-labelledby />' },
|
|
168
|
+
{ code: '<menu type="toolbar" aria-live />' },
|
|
169
|
+
{ code: '<menu type="toolbar" aria-owns />' },
|
|
170
|
+
{ code: '<menu type="toolbar" aria-relevant />' },
|
|
171
|
+
|
|
172
|
+
// this will have global
|
|
173
|
+
{ code: '<menu aria-checked />' },
|
|
174
|
+
|
|
175
|
+
// MENUITEM TESTS
|
|
176
|
+
// when `type="command`, the implicit role is `menuitem`
|
|
177
|
+
{ code: '<menuitem type="command" aria-atomic />' },
|
|
178
|
+
{ code: '<menuitem type="command" aria-busy />' },
|
|
179
|
+
{ code: '<menuitem type="command" aria-controls />' },
|
|
180
|
+
{ code: '<menuitem type="command" aria-describedby />' },
|
|
181
|
+
{ code: '<menuitem type="command" aria-disabled />' },
|
|
182
|
+
{ code: '<menuitem type="command" aria-dropeffect />' },
|
|
183
|
+
{ code: '<menuitem type="command" aria-flowto />' },
|
|
184
|
+
{ code: '<menuitem type="command" aria-grabbed />' },
|
|
185
|
+
{ code: '<menuitem type="command" aria-haspopup />' },
|
|
186
|
+
{ code: '<menuitem type="command" aria-hidden />' },
|
|
187
|
+
{ code: '<menuitem type="command" aria-label />' },
|
|
188
|
+
{ code: '<menuitem type="command" aria-labelledby />' },
|
|
189
|
+
{ code: '<menuitem type="command" aria-live />' },
|
|
190
|
+
{ code: '<menuitem type="command" aria-owns />' },
|
|
191
|
+
{ code: '<menuitem type="command" aria-relevant />' },
|
|
192
|
+
// when `type="checkbox`, the implicit role is `menuitemcheckbox`
|
|
193
|
+
{ code: '<menuitem type="checkbox" aria-checked />' },
|
|
194
|
+
{ code: '<menuitem type="checkbox" aria-atomic />' },
|
|
195
|
+
{ code: '<menuitem type="checkbox" aria-busy />' },
|
|
196
|
+
{ code: '<menuitem type="checkbox" aria-controls />' },
|
|
197
|
+
{ code: '<menuitem type="checkbox" aria-describedby />' },
|
|
198
|
+
{ code: '<menuitem type="checkbox" aria-disabled />' },
|
|
199
|
+
{ code: '<menuitem type="checkbox" aria-dropeffect />' },
|
|
200
|
+
{ code: '<menuitem type="checkbox" aria-flowto />' },
|
|
201
|
+
{ code: '<menuitem type="checkbox" aria-grabbed />' },
|
|
202
|
+
{ code: '<menuitem type="checkbox" aria-haspopup />' },
|
|
203
|
+
{ code: '<menuitem type="checkbox" aria-hidden />' },
|
|
204
|
+
{ code: '<menuitem type="checkbox" aria-invalid />' },
|
|
205
|
+
{ code: '<menuitem type="checkbox" aria-label />' },
|
|
206
|
+
{ code: '<menuitem type="checkbox" aria-labelledby />' },
|
|
207
|
+
{ code: '<menuitem type="checkbox" aria-live />' },
|
|
208
|
+
{ code: '<menuitem type="checkbox" aria-owns />' },
|
|
209
|
+
{ code: '<menuitem type="checkbox" aria-relevant />' },
|
|
210
|
+
// when `type="radio`, the implicit role is `menuitemradio`
|
|
211
|
+
{ code: '<menuitem type="radio" aria-checked />' },
|
|
212
|
+
{ code: '<menuitem type="radio" aria-atomic />' },
|
|
213
|
+
{ code: '<menuitem type="radio" aria-busy />' },
|
|
214
|
+
{ code: '<menuitem type="radio" aria-controls />' },
|
|
215
|
+
{ code: '<menuitem type="radio" aria-describedby />' },
|
|
216
|
+
{ code: '<menuitem type="radio" aria-disabled />' },
|
|
217
|
+
{ code: '<menuitem type="radio" aria-dropeffect />' },
|
|
218
|
+
{ code: '<menuitem type="radio" aria-flowto />' },
|
|
219
|
+
{ code: '<menuitem type="radio" aria-grabbed />' },
|
|
220
|
+
{ code: '<menuitem type="radio" aria-haspopup />' },
|
|
221
|
+
{ code: '<menuitem type="radio" aria-hidden />' },
|
|
222
|
+
{ code: '<menuitem type="radio" aria-invalid />' },
|
|
223
|
+
{ code: '<menuitem type="radio" aria-label />' },
|
|
224
|
+
{ code: '<menuitem type="radio" aria-labelledby />' },
|
|
225
|
+
{ code: '<menuitem type="radio" aria-live />' },
|
|
226
|
+
{ code: '<menuitem type="radio" aria-owns />' },
|
|
227
|
+
{ code: '<menuitem type="radio" aria-relevant />' },
|
|
228
|
+
{ code: '<menuitem type="radio" aria-posinset />' },
|
|
229
|
+
{ code: '<menuitem type="radio" aria-setsize />' },
|
|
230
|
+
|
|
231
|
+
// these will have global
|
|
232
|
+
{ code: '<menuitem aria-checked />' },
|
|
233
|
+
{ code: '<menuitem type="foo" aria-checked />' },
|
|
234
|
+
|
|
235
|
+
// INPUT TESTS
|
|
236
|
+
// when `type="button"`, the implicit role is `button`
|
|
237
|
+
{ code: '<input type="button" aria-expanded />' },
|
|
238
|
+
{ code: '<input type="button" aria-pressed />' },
|
|
239
|
+
{ code: '<input type="button" aria-atomic />' },
|
|
240
|
+
{ code: '<input type="button" aria-busy />' },
|
|
241
|
+
{ code: '<input type="button" aria-controls />' },
|
|
242
|
+
{ code: '<input type="button" aria-describedby />' },
|
|
243
|
+
{ code: '<input type="button" aria-disabled />' },
|
|
244
|
+
{ code: '<input type="button" aria-dropeffect />' },
|
|
245
|
+
{ code: '<input type="button" aria-flowto />' },
|
|
246
|
+
{ code: '<input type="button" aria-grabbed />' },
|
|
247
|
+
{ code: '<input type="button" aria-haspopup />' },
|
|
248
|
+
{ code: '<input type="button" aria-hidden />' },
|
|
249
|
+
{ code: '<input type="button" aria-label />' },
|
|
250
|
+
{ code: '<input type="button" aria-labelledby />' },
|
|
251
|
+
{ code: '<input type="button" aria-live />' },
|
|
252
|
+
{ code: '<input type="button" aria-owns />' },
|
|
253
|
+
{ code: '<input type="button" aria-relevant />' },
|
|
254
|
+
// when `type="image"`, the implicit role is `button`
|
|
255
|
+
{ code: '<input type="image" aria-expanded />' },
|
|
256
|
+
{ code: '<input type="image" aria-pressed />' },
|
|
257
|
+
{ code: '<input type="image" aria-atomic />' },
|
|
258
|
+
{ code: '<input type="image" aria-busy />' },
|
|
259
|
+
{ code: '<input type="image" aria-controls />' },
|
|
260
|
+
{ code: '<input type="image" aria-describedby />' },
|
|
261
|
+
{ code: '<input type="image" aria-disabled />' },
|
|
262
|
+
{ code: '<input type="image" aria-dropeffect />' },
|
|
263
|
+
{ code: '<input type="image" aria-flowto />' },
|
|
264
|
+
{ code: '<input type="image" aria-grabbed />' },
|
|
265
|
+
{ code: '<input type="image" aria-haspopup />' },
|
|
266
|
+
{ code: '<input type="image" aria-hidden />' },
|
|
267
|
+
{ code: '<input type="image" aria-label />' },
|
|
268
|
+
{ code: '<input type="image" aria-labelledby />' },
|
|
269
|
+
{ code: '<input type="image" aria-live />' },
|
|
270
|
+
{ code: '<input type="image" aria-owns />' },
|
|
271
|
+
{ code: '<input type="image" aria-relevant />' },
|
|
272
|
+
// when `type="reset"`, the implicit role is `button`
|
|
273
|
+
{ code: '<input type="reset" aria-expanded />' },
|
|
274
|
+
{ code: '<input type="reset" aria-pressed />' },
|
|
275
|
+
{ code: '<input type="reset" aria-atomic />' },
|
|
276
|
+
{ code: '<input type="reset" aria-busy />' },
|
|
277
|
+
{ code: '<input type="reset" aria-controls />' },
|
|
278
|
+
{ code: '<input type="reset" aria-describedby />' },
|
|
279
|
+
{ code: '<input type="reset" aria-disabled />' },
|
|
280
|
+
{ code: '<input type="reset" aria-dropeffect />' },
|
|
281
|
+
{ code: '<input type="reset" aria-flowto />' },
|
|
282
|
+
{ code: '<input type="reset" aria-grabbed />' },
|
|
283
|
+
{ code: '<input type="reset" aria-haspopup />' },
|
|
284
|
+
{ code: '<input type="reset" aria-hidden />' },
|
|
285
|
+
{ code: '<input type="reset" aria-label />' },
|
|
286
|
+
{ code: '<input type="reset" aria-labelledby />' },
|
|
287
|
+
{ code: '<input type="reset" aria-live />' },
|
|
288
|
+
{ code: '<input type="reset" aria-owns />' },
|
|
289
|
+
{ code: '<input type="reset" aria-relevant />' },
|
|
290
|
+
// when `type="submit"`, the implicit role is `button`
|
|
291
|
+
{ code: '<input type="submit" aria-expanded />' },
|
|
292
|
+
{ code: '<input type="submit" aria-pressed />' },
|
|
293
|
+
{ code: '<input type="submit" aria-atomic />' },
|
|
294
|
+
{ code: '<input type="submit" aria-busy />' },
|
|
295
|
+
{ code: '<input type="submit" aria-controls />' },
|
|
296
|
+
{ code: '<input type="submit" aria-describedby />' },
|
|
297
|
+
{ code: '<input type="submit" aria-disabled />' },
|
|
298
|
+
{ code: '<input type="submit" aria-dropeffect />' },
|
|
299
|
+
{ code: '<input type="submit" aria-flowto />' },
|
|
300
|
+
{ code: '<input type="submit" aria-grabbed />' },
|
|
301
|
+
{ code: '<input type="submit" aria-haspopup />' },
|
|
302
|
+
{ code: '<input type="submit" aria-hidden />' },
|
|
303
|
+
{ code: '<input type="submit" aria-label />' },
|
|
304
|
+
{ code: '<input type="submit" aria-labelledby />' },
|
|
305
|
+
{ code: '<input type="submit" aria-live />' },
|
|
306
|
+
{ code: '<input type="submit" aria-owns />' },
|
|
307
|
+
{ code: '<input type="submit" aria-relevant />' },
|
|
308
|
+
// when `type="checkbox"`, the implicit role is `checkbox`
|
|
309
|
+
{ code: '<input type="checkbox" aria-atomic />' },
|
|
310
|
+
{ code: '<input type="checkbox" aria-busy />' },
|
|
311
|
+
{ code: '<input type="checkbox" aria-checked />' },
|
|
312
|
+
{ code: '<input type="checkbox" aria-controls />' },
|
|
313
|
+
{ code: '<input type="checkbox" aria-describedby />' },
|
|
314
|
+
{ code: '<input type="checkbox" aria-disabled />' },
|
|
315
|
+
{ code: '<input type="checkbox" aria-dropeffect />' },
|
|
316
|
+
{ code: '<input type="checkbox" aria-flowto />' },
|
|
317
|
+
{ code: '<input type="checkbox" aria-grabbed />' },
|
|
318
|
+
{ code: '<input type="checkbox" aria-hidden />' },
|
|
319
|
+
{ code: '<input type="checkbox" aria-invalid />' },
|
|
320
|
+
{ code: '<input type="checkbox" aria-label />' },
|
|
321
|
+
{ code: '<input type="checkbox" aria-labelledby />' },
|
|
322
|
+
{ code: '<input type="checkbox" aria-live />' },
|
|
323
|
+
{ code: '<input type="checkbox" aria-owns />' },
|
|
324
|
+
{ code: '<input type="checkbox" aria-relevant />' },
|
|
325
|
+
// when `type="radio"`, the implicit role is `radio`
|
|
326
|
+
{ code: '<input type="radio" aria-atomic />' },
|
|
327
|
+
{ code: '<input type="radio" aria-busy />' },
|
|
328
|
+
{ code: '<input type="radio" aria-checked />' },
|
|
329
|
+
{ code: '<input type="radio" aria-controls />' },
|
|
330
|
+
{ code: '<input type="radio" aria-describedby />' },
|
|
331
|
+
{ code: '<input type="radio" aria-disabled />' },
|
|
332
|
+
{ code: '<input type="radio" aria-dropeffect />' },
|
|
333
|
+
{ code: '<input type="radio" aria-flowto />' },
|
|
334
|
+
{ code: '<input type="radio" aria-grabbed />' },
|
|
335
|
+
{ code: '<input type="radio" aria-hidden />' },
|
|
336
|
+
{ code: '<input type="radio" aria-label />' },
|
|
337
|
+
{ code: '<input type="radio" aria-labelledby />' },
|
|
338
|
+
{ code: '<input type="radio" aria-live />' },
|
|
339
|
+
{ code: '<input type="radio" aria-owns />' },
|
|
340
|
+
{ code: '<input type="radio" aria-relevant />' },
|
|
341
|
+
{ code: '<input type="radio" aria-posinset />' },
|
|
342
|
+
{ code: '<input type="radio" aria-setsize />' },
|
|
343
|
+
// when `type="range"`, the implicit role is `slider`
|
|
344
|
+
{ code: '<input type="range" aria-valuemax />' },
|
|
345
|
+
{ code: '<input type="range" aria-valuemin />' },
|
|
346
|
+
{ code: '<input type="range" aria-valuenow />' },
|
|
347
|
+
{ code: '<input type="range" aria-orientation />' },
|
|
348
|
+
{ code: '<input type="range" aria-atomic />' },
|
|
349
|
+
{ code: '<input type="range" aria-busy />' },
|
|
350
|
+
{ code: '<input type="range" aria-controls />' },
|
|
351
|
+
{ code: '<input type="range" aria-describedby />' },
|
|
352
|
+
{ code: '<input type="range" aria-disabled />' },
|
|
353
|
+
{ code: '<input type="range" aria-dropeffect />' },
|
|
354
|
+
{ code: '<input type="range" aria-flowto />' },
|
|
355
|
+
{ code: '<input type="range" aria-grabbed />' },
|
|
356
|
+
{ code: '<input type="range" aria-haspopup />' },
|
|
357
|
+
{ code: '<input type="range" aria-hidden />' },
|
|
358
|
+
{ code: '<input type="range" aria-invalid />' },
|
|
359
|
+
{ code: '<input type="range" aria-label />' },
|
|
360
|
+
{ code: '<input type="range" aria-labelledby />' },
|
|
361
|
+
{ code: '<input type="range" aria-live />' },
|
|
362
|
+
{ code: '<input type="range" aria-owns />' },
|
|
363
|
+
{ code: '<input type="range" aria-relevant />' },
|
|
364
|
+
{ code: '<input type="range" aria-valuetext />' },
|
|
365
|
+
|
|
366
|
+
// these will have role of `textbox`,
|
|
367
|
+
{ code: '<input type="email" aria-disabled />' },
|
|
368
|
+
{ code: '<input type="password" aria-disabled />' },
|
|
369
|
+
{ code: '<input type="search" aria-disabled />' },
|
|
370
|
+
{ code: '<input type="tel" aria-disabled />' },
|
|
371
|
+
{ code: '<input type="url" aria-disabled />' },
|
|
372
|
+
{ code: '<input aria-disabled />' },
|
|
373
|
+
|
|
374
|
+
// Allow null/undefined values regardless of role
|
|
375
|
+
{ code: '<h2 role="presentation" aria-level={null} />' },
|
|
376
|
+
{ code: '<h2 role="presentation" aria-level={undefined} />' },
|
|
377
|
+
|
|
378
|
+
// OTHER TESTS
|
|
379
|
+
{ code: '<button aria-pressed />' },
|
|
380
|
+
{ code: '<form aria-hidden />' },
|
|
381
|
+
{ code: '<h1 aria-hidden />' },
|
|
382
|
+
{ code: '<h2 aria-hidden />' },
|
|
383
|
+
{ code: '<h3 aria-hidden />' },
|
|
384
|
+
{ code: '<h4 aria-hidden />' },
|
|
385
|
+
{ code: '<h5 aria-hidden />' },
|
|
386
|
+
{ code: '<h6 aria-hidden />' },
|
|
387
|
+
{ code: '<hr aria-hidden />' },
|
|
388
|
+
{ code: '<li aria-current />' },
|
|
389
|
+
{ code: '<meter aria-atomic />' },
|
|
390
|
+
{ code: '<option aria-atomic />' },
|
|
391
|
+
{ code: '<progress aria-atomic />' },
|
|
392
|
+
{ code: '<textarea aria-hidden />' },
|
|
393
|
+
{ code: '<select aria-expanded />' },
|
|
394
|
+
{ code: '<datalist aria-expanded />' },
|
|
395
|
+
{ code: '<div role="heading" aria-level />' },
|
|
396
|
+
{ code: '<div role="heading" aria-level="1" />' },
|
|
397
|
+
|
|
398
|
+
semver.satisfies(eslintVersion, '>= 6') ? {
|
|
399
|
+
code: `
|
|
400
|
+
const HelloThere = () => (
|
|
401
|
+
<Hello
|
|
402
|
+
role="searchbox"
|
|
403
|
+
frag={
|
|
404
|
+
<>
|
|
405
|
+
<div>Hello</div>
|
|
406
|
+
<div>There</div>
|
|
407
|
+
</>
|
|
408
|
+
}
|
|
409
|
+
/>
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
const Hello = (props) => <div>{props.frag}</div>;
|
|
413
|
+
`,
|
|
414
|
+
} : [],
|
|
415
|
+
validTests,
|
|
416
|
+
)).map(parserOptionsMapper),
|
|
417
|
+
|
|
418
|
+
invalid: parsers.all([].concat(
|
|
419
|
+
// implicit basic checks
|
|
420
|
+
{
|
|
421
|
+
code: '<a href="#" aria-checked />',
|
|
422
|
+
errors: [errorMessage('aria-checked', 'link', 'a', true)],
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
code: '<area href="#" aria-checked />',
|
|
426
|
+
errors: [errorMessage('aria-checked', 'link', 'area', true)],
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
code: '<link href="#" aria-checked />',
|
|
430
|
+
errors: [errorMessage('aria-checked', 'link', 'link', true)],
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
code: '<img alt="foobar" aria-checked />',
|
|
434
|
+
errors: [errorMessage('aria-checked', 'img', 'img', true)],
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
code: '<menu type="toolbar" aria-checked />',
|
|
438
|
+
errors: [errorMessage('aria-checked', 'toolbar', 'menu', true)],
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
code: '<aside aria-checked />',
|
|
442
|
+
errors: [errorMessage('aria-checked', 'complementary', 'aside', true)],
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
code: '<ul aria-expanded />',
|
|
446
|
+
errors: [errorMessage('aria-expanded', 'list', 'ul', true)],
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
code: '<details aria-expanded />',
|
|
450
|
+
errors: [errorMessage('aria-expanded', 'group', 'details', true)],
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
code: '<dialog aria-expanded />',
|
|
454
|
+
errors: [errorMessage('aria-expanded', 'dialog', 'dialog', true)],
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
code: '<aside aria-expanded />',
|
|
458
|
+
errors: [errorMessage('aria-expanded', 'complementary', 'aside', true)],
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
code: '<article aria-expanded />',
|
|
462
|
+
errors: [errorMessage('aria-expanded', 'article', 'article', true)],
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
code: '<body aria-expanded />',
|
|
466
|
+
errors: [errorMessage('aria-expanded', 'document', 'body', true)],
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
code: '<li aria-expanded />',
|
|
470
|
+
errors: [errorMessage('aria-expanded', 'listitem', 'li', true)],
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
code: '<nav aria-expanded />',
|
|
474
|
+
errors: [errorMessage('aria-expanded', 'navigation', 'nav', true)],
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
code: '<ol aria-expanded />',
|
|
478
|
+
errors: [errorMessage('aria-expanded', 'list', 'ol', true)],
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
code: '<output aria-expanded />',
|
|
482
|
+
errors: [errorMessage('aria-expanded', 'status', 'output', true)],
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
code: '<section aria-expanded />',
|
|
486
|
+
errors: [errorMessage('aria-expanded', 'region', 'section', true)],
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
code: '<tbody aria-expanded />',
|
|
490
|
+
errors: [errorMessage('aria-expanded', 'rowgroup', 'tbody', true)],
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
code: '<tfoot aria-expanded />',
|
|
494
|
+
errors: [errorMessage('aria-expanded', 'rowgroup', 'tfoot', true)],
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
code: '<thead aria-expanded />',
|
|
498
|
+
errors: [errorMessage('aria-expanded', 'rowgroup', 'thead', true)],
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
code: '<input type="radio" aria-invalid />',
|
|
502
|
+
errors: [errorMessage('aria-invalid', 'radio', 'input', true)],
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
code: '<input type="radio" aria-selected />',
|
|
506
|
+
errors: [errorMessage('aria-selected', 'radio', 'input', true)],
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
code: '<input type="radio" aria-haspopup />',
|
|
510
|
+
errors: [errorMessage('aria-haspopup', 'radio', 'input', true)],
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
code: '<input type="checkbox" aria-haspopup />',
|
|
514
|
+
errors: [errorMessage('aria-haspopup', 'checkbox', 'input', true)],
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
code: '<input type="reset" aria-invalid />',
|
|
518
|
+
errors: [errorMessage('aria-invalid', 'button', 'input', true)],
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
code: '<input type="submit" aria-invalid />',
|
|
522
|
+
errors: [errorMessage('aria-invalid', 'button', 'input', true)],
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
code: '<input type="image" aria-invalid />',
|
|
526
|
+
errors: [errorMessage('aria-invalid', 'button', 'input', true)],
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
code: '<input type="button" aria-invalid />',
|
|
530
|
+
errors: [errorMessage('aria-invalid', 'button', 'input', true)],
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
code: '<menuitem type="command" aria-invalid />',
|
|
534
|
+
errors: [errorMessage('aria-invalid', 'menuitem', 'menuitem', true)],
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
code: '<menuitem type="radio" aria-selected />',
|
|
538
|
+
errors: [errorMessage('aria-selected', 'menuitemradio', 'menuitem', true)],
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
code: '<menu type="toolbar" aria-haspopup />',
|
|
542
|
+
errors: [errorMessage('aria-haspopup', 'toolbar', 'menu', true)],
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
code: '<menu type="toolbar" aria-invalid />',
|
|
546
|
+
errors: [errorMessage('aria-invalid', 'toolbar', 'menu', true)],
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
code: '<menu type="toolbar" aria-expanded />',
|
|
550
|
+
errors: [errorMessage('aria-expanded', 'toolbar', 'menu', true)],
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
code: '<link href="#" aria-invalid />',
|
|
554
|
+
errors: [errorMessage('aria-invalid', 'link', 'link', true)],
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
code: '<area href="#" aria-invalid />',
|
|
558
|
+
errors: [errorMessage('aria-invalid', 'link', 'area', true)],
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
code: '<a href="#" aria-invalid />',
|
|
562
|
+
errors: [errorMessage('aria-invalid', 'link', 'a', true)],
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
code: '<Link href="#" aria-checked />',
|
|
566
|
+
errors: [errorMessage('aria-checked', 'link', 'a', true)],
|
|
567
|
+
settings: componentsSettings,
|
|
568
|
+
},
|
|
569
|
+
)).concat(invalidTests).map(parserOptionsMapper),
|
|
570
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Enforce scope prop is only used on <th> elements.
|
|
3
|
+
* @author Ethan Cohen
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
// Requirements
|
|
8
|
+
// -----------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import { RuleTester } from 'eslint';
|
|
11
|
+
import parserOptionsMapper from '../../__util__/parserOptionsMapper';
|
|
12
|
+
import parsers from '../../__util__/helpers/parsers';
|
|
13
|
+
import rule from '../../../src/rules/scope';
|
|
14
|
+
|
|
15
|
+
// -----------------------------------------------------------------------------
|
|
16
|
+
// Tests
|
|
17
|
+
// -----------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const ruleTester = new RuleTester();
|
|
20
|
+
|
|
21
|
+
const expectedError = {
|
|
22
|
+
message: 'The scope prop can only be used on <th> elements.',
|
|
23
|
+
type: 'JSXAttribute',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const componentsSettings = {
|
|
27
|
+
'jsx-a11y': {
|
|
28
|
+
components: {
|
|
29
|
+
Foo: 'div',
|
|
30
|
+
TableHeader: 'th',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
ruleTester.run('scope', rule, {
|
|
36
|
+
valid: parsers.all([].concat(
|
|
37
|
+
{ code: '<div />;' },
|
|
38
|
+
{ code: '<div foo />;' },
|
|
39
|
+
{ code: '<th scope />' },
|
|
40
|
+
{ code: '<th scope="row" />' },
|
|
41
|
+
{ code: '<th scope={foo} />' },
|
|
42
|
+
{ code: '<th scope={"col"} {...props} />' },
|
|
43
|
+
{ code: '<Foo scope="bar" {...props} />' },
|
|
44
|
+
{ code: '<TableHeader scope="row" />', settings: componentsSettings },
|
|
45
|
+
)).map(parserOptionsMapper),
|
|
46
|
+
invalid: parsers.all([].concat(
|
|
47
|
+
{ code: '<div scope />', errors: [expectedError] },
|
|
48
|
+
{ code: '<Foo scope="bar" />', settings: componentsSettings, errors: [expectedError] },
|
|
49
|
+
)).map(parserOptionsMapper),
|
|
50
|
+
});
|