@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.
Files changed (229) hide show
  1. package/.babelrc +17 -0
  2. package/.eslintrc +44 -0
  3. package/CHANGELOG.md +774 -0
  4. package/LICENSE.md +8 -0
  5. package/README.md +423 -0
  6. package/__mocks__/IdentifierMock.js +15 -0
  7. package/__mocks__/JSXAttributeMock.js +39 -0
  8. package/__mocks__/JSXElementMock.js +37 -0
  9. package/__mocks__/JSXExpressionContainerMock.js +15 -0
  10. package/__mocks__/JSXSpreadAttributeMock.js +18 -0
  11. package/__mocks__/JSXTextMock.js +17 -0
  12. package/__mocks__/LiteralMock.js +17 -0
  13. package/__mocks__/genInteractives.js +218 -0
  14. package/__tests__/__util__/axeMapping.js +6 -0
  15. package/__tests__/__util__/helpers/getESLintCoreRule.js +9 -0
  16. package/__tests__/__util__/helpers/parsers.js +186 -0
  17. package/__tests__/__util__/parserOptionsMapper.js +53 -0
  18. package/__tests__/__util__/ruleOptionsMapperFactory.js +33 -0
  19. package/__tests__/index-test.js +40 -0
  20. package/__tests__/src/rules/accessible-emoji-test.js +66 -0
  21. package/__tests__/src/rules/alt-text-test.js +291 -0
  22. package/__tests__/src/rules/anchor-ambiguous-text-test.js +117 -0
  23. package/__tests__/src/rules/anchor-has-content-test.js +54 -0
  24. package/__tests__/src/rules/anchor-is-valid-test.js +532 -0
  25. package/__tests__/src/rules/aria-activedescendant-has-tabindex-test.js +95 -0
  26. package/__tests__/src/rules/aria-props-test.js +69 -0
  27. package/__tests__/src/rules/aria-proptypes-test.js +311 -0
  28. package/__tests__/src/rules/aria-role-test.js +118 -0
  29. package/__tests__/src/rules/aria-unsupported-elements-test.js +75 -0
  30. package/__tests__/src/rules/autocomplete-valid-test.js +77 -0
  31. package/__tests__/src/rules/click-events-have-key-events-test.js +77 -0
  32. package/__tests__/src/rules/control-has-associated-label-test.js +327 -0
  33. package/__tests__/src/rules/heading-has-content-test.js +85 -0
  34. package/__tests__/src/rules/html-has-lang-test.js +42 -0
  35. package/__tests__/src/rules/iframe-has-title-test.js +55 -0
  36. package/__tests__/src/rules/img-redundant-alt-test.js +137 -0
  37. package/__tests__/src/rules/interactive-supports-focus-test.js +267 -0
  38. package/__tests__/src/rules/label-has-associated-control-test.js +243 -0
  39. package/__tests__/src/rules/label-has-for-test.js +235 -0
  40. package/__tests__/src/rules/lang-test.js +59 -0
  41. package/__tests__/src/rules/media-has-caption-test.js +220 -0
  42. package/__tests__/src/rules/mouse-events-have-key-events-test.js +154 -0
  43. package/__tests__/src/rules/no-access-key-test.js +48 -0
  44. package/__tests__/src/rules/no-aria-hidden-on-focusable-test.js +44 -0
  45. package/__tests__/src/rules/no-autofocus-test.js +68 -0
  46. package/__tests__/src/rules/no-distracting-elements-test.js +51 -0
  47. package/__tests__/src/rules/no-interactive-element-to-noninteractive-role-test.js +405 -0
  48. package/__tests__/src/rules/no-noninteractive-element-interactions-test.js +502 -0
  49. package/__tests__/src/rules/no-noninteractive-element-to-interactive-role-test.js +500 -0
  50. package/__tests__/src/rules/no-noninteractive-tabindex-test.js +123 -0
  51. package/__tests__/src/rules/no-onchange-test.js +57 -0
  52. package/__tests__/src/rules/no-redundant-roles-test.js +98 -0
  53. package/__tests__/src/rules/no-static-element-interactions-test.js +501 -0
  54. package/__tests__/src/rules/prefer-tag-over-role-test.js +63 -0
  55. package/__tests__/src/rules/role-has-required-aria-props-test.js +134 -0
  56. package/__tests__/src/rules/role-supports-aria-props-test.js +570 -0
  57. package/__tests__/src/rules/scope-test.js +50 -0
  58. package/__tests__/src/rules/tabindex-no-positive-test.js +55 -0
  59. package/__tests__/src/util/attributesComparator-test.js +91 -0
  60. package/__tests__/src/util/getAccessibleChildText-test.js +174 -0
  61. package/__tests__/src/util/getComputedRole-test.js +71 -0
  62. package/__tests__/src/util/getElementType-test.js +154 -0
  63. package/__tests__/src/util/getExplicitRole-test.js +35 -0
  64. package/__tests__/src/util/getImplicitRole-test.js +25 -0
  65. package/__tests__/src/util/getSuggestion-test.js +33 -0
  66. package/__tests__/src/util/getTabIndex-test.js +85 -0
  67. package/__tests__/src/util/hasAccessibleChild-test.js +157 -0
  68. package/__tests__/src/util/implicitRoles/input-test.js +87 -0
  69. package/__tests__/src/util/implicitRoles/menu-test.js +20 -0
  70. package/__tests__/src/util/implicitRoles/menuitem-test.js +38 -0
  71. package/__tests__/src/util/isAbstractRole-test.js +51 -0
  72. package/__tests__/src/util/isContentEditable-test.js +52 -0
  73. package/__tests__/src/util/isDOMElement-test.js +30 -0
  74. package/__tests__/src/util/isDisabledElement-test.js +88 -0
  75. package/__tests__/src/util/isFocusable-test.js +111 -0
  76. package/__tests__/src/util/isInteractiveElement-test.js +104 -0
  77. package/__tests__/src/util/isInteractiveRole-test.js +59 -0
  78. package/__tests__/src/util/isNonInteractiveElement-test.js +97 -0
  79. package/__tests__/src/util/isNonInteractiveRole-test.js +59 -0
  80. package/__tests__/src/util/isNonLiteralProperty-test.js +52 -0
  81. package/__tests__/src/util/isSemanticRoleElement-test.js +72 -0
  82. package/__tests__/src/util/mayContainChildComponent-test.js +219 -0
  83. package/__tests__/src/util/mayHaveAccessibleLabel-test.js +256 -0
  84. package/__tests__/src/util/parserOptionsMapper-test.js +93 -0
  85. package/__tests__/src/util/schemas-test.js +35 -0
  86. package/docs/rules/accessible-emoji.md +30 -0
  87. package/docs/rules/alt-text.md +168 -0
  88. package/docs/rules/anchor-ambiguous-text.md +91 -0
  89. package/docs/rules/anchor-has-content.md +64 -0
  90. package/docs/rules/anchor-is-valid.md +270 -0
  91. package/docs/rules/aria-activedescendant-has-tabindex.md +52 -0
  92. package/docs/rules/aria-props.md +29 -0
  93. package/docs/rules/aria-proptypes.md +30 -0
  94. package/docs/rules/aria-role.md +51 -0
  95. package/docs/rules/aria-unsupported-elements.md +30 -0
  96. package/docs/rules/autocomplete-valid.md +49 -0
  97. package/docs/rules/click-events-have-key-events.md +28 -0
  98. package/docs/rules/control-has-associated-label.md +113 -0
  99. package/docs/rules/heading-has-content.md +67 -0
  100. package/docs/rules/html-has-lang.md +31 -0
  101. package/docs/rules/iframe-has-title.md +37 -0
  102. package/docs/rules/img-redundant-alt.md +48 -0
  103. package/docs/rules/interactive-supports-focus.md +156 -0
  104. package/docs/rules/label-has-associated-control.md +152 -0
  105. package/docs/rules/label-has-for.md +130 -0
  106. package/docs/rules/lang.md +31 -0
  107. package/docs/rules/media-has-caption.md +48 -0
  108. package/docs/rules/mouse-events-have-key-events.md +58 -0
  109. package/docs/rules/no-access-key.md +30 -0
  110. package/docs/rules/no-aria-hidden-on-focusable.md +37 -0
  111. package/docs/rules/no-autofocus.md +43 -0
  112. package/docs/rules/no-distracting-elements.md +41 -0
  113. package/docs/rules/no-interactive-element-to-noninteractive-role.md +73 -0
  114. package/docs/rules/no-noninteractive-element-interactions.md +145 -0
  115. package/docs/rules/no-noninteractive-element-to-interactive-role.md +76 -0
  116. package/docs/rules/no-noninteractive-tabindex.md +115 -0
  117. package/docs/rules/no-onchange.md +36 -0
  118. package/docs/rules/no-redundant-roles.md +46 -0
  119. package/docs/rules/no-static-element-interactions.md +114 -0
  120. package/docs/rules/prefer-tag-over-role.md +32 -0
  121. package/docs/rules/role-has-required-aria-props.md +31 -0
  122. package/docs/rules/role-supports-aria-props.md +39 -0
  123. package/docs/rules/scope.md +30 -0
  124. package/docs/rules/tabindex-no-positive.md +32 -0
  125. package/lib/configs/flat-config-base.js +11 -0
  126. package/lib/configs/legacy-config-base.js +9 -0
  127. package/lib/index.js +209 -0
  128. package/lib/rules/accessible-emoji.js +63 -0
  129. package/lib/rules/alt-text.js +218 -0
  130. package/lib/rules/anchor-ambiguous-text.js +64 -0
  131. package/lib/rules/anchor-has-content.js +60 -0
  132. package/lib/rules/anchor-is-valid.js +122 -0
  133. package/lib/rules/aria-activedescendant-has-tabindex.js +66 -0
  134. package/lib/rules/aria-props.js +59 -0
  135. package/lib/rules/aria-proptypes.js +114 -0
  136. package/lib/rules/aria-role.js +89 -0
  137. package/lib/rules/aria-unsupported-elements.js +64 -0
  138. package/lib/rules/autocomplete-valid.js +67 -0
  139. package/lib/rules/click-events-have-key-events.js +68 -0
  140. package/lib/rules/control-has-associated-label.js +103 -0
  141. package/lib/rules/heading-has-content.js +61 -0
  142. package/lib/rules/html-has-lang.js +50 -0
  143. package/lib/rules/iframe-has-title.js +50 -0
  144. package/lib/rules/img-redundant-alt.js +88 -0
  145. package/lib/rules/interactive-supports-focus.js +87 -0
  146. package/lib/rules/label-has-associated-control.js +127 -0
  147. package/lib/rules/label-has-for.js +150 -0
  148. package/lib/rules/lang.js +68 -0
  149. package/lib/rules/media-has-caption.js +96 -0
  150. package/lib/rules/mouse-events-have-key-events.js +94 -0
  151. package/lib/rules/no-access-key.js +43 -0
  152. package/lib/rules/no-aria-hidden-on-focusable.js +47 -0
  153. package/lib/rules/no-autofocus.js +62 -0
  154. package/lib/rules/no-distracting-elements.js +54 -0
  155. package/lib/rules/no-interactive-element-to-noninteractive-role.js +81 -0
  156. package/lib/rules/no-noninteractive-element-interactions.js +95 -0
  157. package/lib/rules/no-noninteractive-element-to-interactive-role.js +80 -0
  158. package/lib/rules/no-noninteractive-tabindex.js +109 -0
  159. package/lib/rules/no-onchange.js +52 -0
  160. package/lib/rules/no-redundant-roles.js +86 -0
  161. package/lib/rules/no-static-element-interactions.js +102 -0
  162. package/lib/rules/prefer-tag-over-role.js +75 -0
  163. package/lib/rules/role-has-required-aria-props.js +88 -0
  164. package/lib/rules/role-supports-aria-props.js +78 -0
  165. package/lib/rules/scope.js +58 -0
  166. package/lib/rules/tabindex-no-positive.js +53 -0
  167. package/lib/util/attributesComparator.js +34 -0
  168. package/lib/util/getAccessibleChildText.js +55 -0
  169. package/lib/util/getComputedRole.js +19 -0
  170. package/lib/util/getElementType.js +30 -0
  171. package/lib/util/getExplicitRole.js +27 -0
  172. package/lib/util/getImplicitRole.js +24 -0
  173. package/lib/util/getSuggestion.js +32 -0
  174. package/lib/util/getTabIndex.js +34 -0
  175. package/lib/util/hasAccessibleChild.js +30 -0
  176. package/lib/util/implicitRoles/a.js +17 -0
  177. package/lib/util/implicitRoles/area.js +17 -0
  178. package/lib/util/implicitRoles/article.js +13 -0
  179. package/lib/util/implicitRoles/aside.js +13 -0
  180. package/lib/util/implicitRoles/body.js +13 -0
  181. package/lib/util/implicitRoles/button.js +13 -0
  182. package/lib/util/implicitRoles/datalist.js +13 -0
  183. package/lib/util/implicitRoles/details.js +13 -0
  184. package/lib/util/implicitRoles/dialog.js +13 -0
  185. package/lib/util/implicitRoles/form.js +13 -0
  186. package/lib/util/implicitRoles/h1.js +13 -0
  187. package/lib/util/implicitRoles/h2.js +13 -0
  188. package/lib/util/implicitRoles/h3.js +13 -0
  189. package/lib/util/implicitRoles/h4.js +13 -0
  190. package/lib/util/implicitRoles/h5.js +13 -0
  191. package/lib/util/implicitRoles/h6.js +13 -0
  192. package/lib/util/implicitRoles/hr.js +13 -0
  193. package/lib/util/implicitRoles/img.js +31 -0
  194. package/lib/util/implicitRoles/index.js +82 -0
  195. package/lib/util/implicitRoles/input.js +38 -0
  196. package/lib/util/implicitRoles/li.js +13 -0
  197. package/lib/util/implicitRoles/link.js +17 -0
  198. package/lib/util/implicitRoles/menu.js +19 -0
  199. package/lib/util/implicitRoles/menuitem.js +28 -0
  200. package/lib/util/implicitRoles/meter.js +13 -0
  201. package/lib/util/implicitRoles/nav.js +13 -0
  202. package/lib/util/implicitRoles/ol.js +13 -0
  203. package/lib/util/implicitRoles/option.js +13 -0
  204. package/lib/util/implicitRoles/output.js +13 -0
  205. package/lib/util/implicitRoles/progress.js +13 -0
  206. package/lib/util/implicitRoles/section.js +13 -0
  207. package/lib/util/implicitRoles/select.js +13 -0
  208. package/lib/util/implicitRoles/tbody.js +13 -0
  209. package/lib/util/implicitRoles/textarea.js +13 -0
  210. package/lib/util/implicitRoles/tfoot.js +13 -0
  211. package/lib/util/implicitRoles/thead.js +13 -0
  212. package/lib/util/implicitRoles/ul.js +13 -0
  213. package/lib/util/isAbstractRole.js +23 -0
  214. package/lib/util/isContentEditable.js +13 -0
  215. package/lib/util/isDOMElement.js +15 -0
  216. package/lib/util/isDisabledElement.js +23 -0
  217. package/lib/util/isFocusable.js +23 -0
  218. package/lib/util/isHiddenFromScreenReader.js +26 -0
  219. package/lib/util/isInteractiveElement.js +116 -0
  220. package/lib/util/isInteractiveRole.js +54 -0
  221. package/lib/util/isNonInteractiveElement.js +131 -0
  222. package/lib/util/isNonInteractiveRole.js +55 -0
  223. package/lib/util/isNonLiteralProperty.js +29 -0
  224. package/lib/util/isPresentationRole.js +13 -0
  225. package/lib/util/isSemanticRoleElement.js +54 -0
  226. package/lib/util/mayContainChildComponent.js +50 -0
  227. package/lib/util/mayHaveAccessibleLabel.js +95 -0
  228. package/lib/util/schemas.js +52 -0
  229. package/package.json +120 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Enforce usage of onBlur over onChange on select menus for accessibility.
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/no-onchange';
14
+
15
+ // -----------------------------------------------------------------------------
16
+ // Tests
17
+ // -----------------------------------------------------------------------------
18
+
19
+ const ruleTester = new RuleTester();
20
+
21
+ const expectedError = {
22
+ message: 'onBlur must be used instead of onchange, unless absolutely necessary and it causes no negative consequences for keyboard only or screen reader users.',
23
+ type: 'JSXOpeningElement',
24
+ };
25
+
26
+ const componentsSettings = {
27
+ 'jsx-a11y': {
28
+ components: {
29
+ CustomOption: 'option',
30
+ Input: 'input',
31
+ },
32
+ },
33
+ };
34
+
35
+ ruleTester.run('no-onchange', rule, {
36
+ valid: parsers.all([].concat(
37
+ { code: '<select onBlur={() => {}} />;' },
38
+ { code: '<select onBlur={handleOnBlur} />;' },
39
+ { code: '<option />;' },
40
+ { code: '<option onBlur={() => {}} onChange={() => {}} />;' },
41
+ { code: '<option {...props} />' },
42
+ { code: '<input onChange={() => {}} />;' },
43
+ { code: '<input onChange={handleOnChange} />;' },
44
+ { code: '<input />;' },
45
+ { code: '<input onChange={() => {}} onChange={() => {}} />;' },
46
+ { code: '<input {...props} />' },
47
+ { code: '<Input onChange={() => {}} />;', settings: componentsSettings },
48
+ { code: '<CustomOption onChange={() => {}} />' },
49
+ )).map(parserOptionsMapper),
50
+ invalid: parsers.all([].concat(
51
+ { code: '<select onChange={() => {}} />;', errors: [expectedError] },
52
+ { code: '<select onChange={handleOnChange} />;', errors: [expectedError] },
53
+ { code: '<option onChange={() => {}} />', errors: [expectedError] },
54
+ { code: '<option onChange={() => {}} {...props} />', errors: [expectedError] },
55
+ { code: '<CustomOption onChange={() => {}} />;', errors: [expectedError], settings: componentsSettings },
56
+ )).map(parserOptionsMapper),
57
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @fileoverview Enforce explicit role property is not the
3
+ * same as implicit default role property on element.
4
+ * @author Ethan Cohen <@evcohen>
5
+ */
6
+
7
+ // -----------------------------------------------------------------------------
8
+ // Requirements
9
+ // -----------------------------------------------------------------------------
10
+
11
+ import { RuleTester } from 'eslint';
12
+ import parserOptionsMapper from '../../__util__/parserOptionsMapper';
13
+ import parsers from '../../__util__/helpers/parsers';
14
+ import rule from '../../../src/rules/no-redundant-roles';
15
+ import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
16
+
17
+ // -----------------------------------------------------------------------------
18
+ // Tests
19
+ // -----------------------------------------------------------------------------
20
+
21
+ const ruleTester = new RuleTester();
22
+
23
+ const expectedError = (element, implicitRole) => ({
24
+ message: `The element ${element} has an implicit role of ${implicitRole}. Defining this explicitly is redundant and should be avoided.`,
25
+ type: 'JSXOpeningElement',
26
+ });
27
+
28
+ const ruleName = 'jsx-a11y/no-redundant-roles';
29
+
30
+ const componentsSettings = {
31
+ 'jsx-a11y': {
32
+ components: {
33
+ Button: 'button',
34
+ },
35
+ },
36
+ };
37
+
38
+ const alwaysValid = [
39
+ { code: '<div />;' },
40
+ { code: '<button role="main" />' },
41
+ { code: '<MyComponent role="button" />' },
42
+ { code: '<button role={`${foo}button`} />' },
43
+ { code: '<Button role={`${foo}button`} />', settings: componentsSettings },
44
+ ];
45
+
46
+ const neverValid = [
47
+ { code: '<button role="button" />', errors: [expectedError('button', 'button')] },
48
+ { code: '<body role="DOCUMENT" />', errors: [expectedError('body', 'document')] },
49
+ { code: '<Button role="button" />', settings: componentsSettings, errors: [expectedError('button', 'button')] },
50
+ ];
51
+
52
+ ruleTester.run(`${ruleName}:recommended`, rule, {
53
+ valid: parsers.all([].concat(
54
+ ...alwaysValid,
55
+ { code: '<nav role="navigation" />' },
56
+ ))
57
+ .map(parserOptionsMapper),
58
+ invalid: parsers.all([].concat(
59
+ neverValid,
60
+ ))
61
+ .map(parserOptionsMapper),
62
+ });
63
+
64
+ const noNavExceptionsOptions = { nav: [] };
65
+ const listException = { ul: ['list'], ol: ['list'] };
66
+
67
+ ruleTester.run(`${ruleName}:recommended`, rule, {
68
+ valid: parsers.all([].concat(
69
+ alwaysValid
70
+ .map(ruleOptionsMapperFactory(noNavExceptionsOptions)),
71
+ ))
72
+ .map(parserOptionsMapper),
73
+ invalid: parsers.all([].concat(
74
+ ...neverValid,
75
+ { code: '<nav role="navigation" />', errors: [expectedError('nav', 'navigation')] },
76
+ ))
77
+ .map(ruleOptionsMapperFactory(noNavExceptionsOptions))
78
+ .map(parserOptionsMapper),
79
+ });
80
+
81
+ ruleTester.run(`${ruleName}:recommended (valid list role override)`, rule, {
82
+ valid: parsers.all([].concat(
83
+ { code: '<ul role="list" />' },
84
+ { code: '<ol role="list" />' },
85
+ { code: '<dl role="list" />' },
86
+ { code: '<img src="example.svg" role="img" />' },
87
+ { code: '<svg role="img" />' },
88
+ ))
89
+ .map(ruleOptionsMapperFactory(listException))
90
+ .map(parserOptionsMapper),
91
+ invalid: parsers.all([].concat(
92
+ { code: '<ul role="list" />', errors: [expectedError('ul', 'list')] },
93
+ { code: '<ol role="list" />', errors: [expectedError('ol', 'list')] },
94
+ { code: '<img role="img" />', errors: [expectedError('img', 'img')] },
95
+ { code: '<img src={someVariable} role="img" />', errors: [expectedError('img', 'img')] },
96
+ ))
97
+ .map(parserOptionsMapper),
98
+ });
@@ -0,0 +1,501 @@
1
+ /**
2
+ * @fileoverview Enforce static elements have no interactive handlers.
3
+ * @author Ethan Cohen
4
+ */
5
+
6
+ // -----------------------------------------------------------------------------
7
+ // Requirements
8
+ // -----------------------------------------------------------------------------
9
+
10
+ import { RuleTester } from 'eslint';
11
+ import { configs } from '../../../src/index';
12
+ import parserOptionsMapper from '../../__util__/parserOptionsMapper';
13
+ import parsers from '../../__util__/helpers/parsers';
14
+ import rule from '../../../src/rules/no-static-element-interactions';
15
+ import ruleOptionsMapperFactory from '../../__util__/ruleOptionsMapperFactory';
16
+
17
+ // -----------------------------------------------------------------------------
18
+ // Tests
19
+ // -----------------------------------------------------------------------------
20
+
21
+ const ruleTester = new RuleTester();
22
+
23
+ const errorMessage = 'Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element.';
24
+
25
+ const expectedError = {
26
+ message: errorMessage,
27
+ type: 'JSXOpeningElement',
28
+ };
29
+
30
+ const ruleName = 'no-static-element-interactions';
31
+
32
+ const componentsSettings = {
33
+ 'jsx-a11y': {
34
+ components: {
35
+ Button: 'button',
36
+ TestComponent: 'div',
37
+ },
38
+ },
39
+ };
40
+
41
+ const alwaysValid = [
42
+ { code: '<TestComponent onClick={doFoo} />' },
43
+ { code: '<Button onClick={doFoo} />' },
44
+ { code: '<Button onClick={doFoo} />', settings: componentsSettings },
45
+ { code: '<div />;' },
46
+ { code: '<div className="foo" />;' },
47
+ { code: '<div className="foo" {...props} />;' },
48
+ { code: '<div onClick={() => void 0} aria-hidden />;' },
49
+ { code: '<div onClick={() => void 0} aria-hidden={true} />;' },
50
+ { code: '<div onClick={null} />;' },
51
+ /* All flavors of input */
52
+ { code: '<input onClick={() => void 0} />' },
53
+ { code: '<input type="button" onClick={() => void 0} />' },
54
+ { code: '<input type="checkbox" onClick={() => void 0} />' },
55
+ { code: '<input type="color" onClick={() => void 0} />' },
56
+ { code: '<input type="date" onClick={() => void 0} />' },
57
+ { code: '<input type="datetime" onClick={() => void 0} />' },
58
+ { code: '<input type="datetime-local" onClick={() => void 0} />' },
59
+ { code: '<input type="email" onClick={() => void 0} />' },
60
+ { code: '<input type="file" onClick={() => void 0} />' },
61
+ { code: '<input type="hidden" onClick={() => void 0} />' },
62
+ { code: '<input type="image" onClick={() => void 0} />' },
63
+ { code: '<input type="month" onClick={() => void 0} />' },
64
+ { code: '<input type="number" onClick={() => void 0} />' },
65
+ { code: '<input type="password" onClick={() => void 0} />' },
66
+ { code: '<input type="radio" onClick={() => void 0} />' },
67
+ { code: '<input type="range" onClick={() => void 0} />' },
68
+ { code: '<input type="reset" onClick={() => void 0} />' },
69
+ { code: '<input type="search" onClick={() => void 0} />' },
70
+ { code: '<input type="submit" onClick={() => void 0} />' },
71
+ { code: '<input type="tel" onClick={() => void 0} />' },
72
+ { code: '<input type="text" onClick={() => void 0} />' },
73
+ { code: '<input type="time" onClick={() => void 0} />' },
74
+ { code: '<input type="url" onClick={() => void 0} />' },
75
+ { code: '<input type="week" onClick={() => void 0} />' },
76
+ /* End all flavors of input */
77
+ { code: '<button onClick={() => void 0} className="foo" />' },
78
+ { code: '<datalist onClick={() => {}} />;' },
79
+ { code: '<menuitem onClick={() => {}} />;' },
80
+ { code: '<option onClick={() => void 0} className="foo" />' },
81
+ { code: '<select onClick={() => void 0} className="foo" />' },
82
+ { code: '<textarea onClick={() => void 0} className="foo" />' },
83
+ { code: '<a onClick={() => void 0} href="http://x.y.z" />' },
84
+ { code: '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' },
85
+ { code: '<audio onClick={() => {}} />;' },
86
+ { code: '<form onClick={() => {}} />;' },
87
+ { code: '<form onSubmit={() => {}} />;' },
88
+ // { code: '<link onClick={() => {}} href="#" />;' },
89
+ /* HTML elements attributed with an interactive role */
90
+ { code: '<div role="button" onClick={() => {}} />;' },
91
+ { code: '<div role="checkbox" onClick={() => {}} />;' },
92
+ { code: '<div role="columnheader" onClick={() => {}} />;' },
93
+ { code: '<div role="combobox" onClick={() => {}} />;' },
94
+ { code: '<div role="form" onClick={() => {}} />;' },
95
+ { code: '<div role="gridcell" onClick={() => {}} />;' },
96
+ { code: '<div role="link" onClick={() => {}} />;' },
97
+ { code: '<div role="menuitem" onClick={() => {}} />;' },
98
+ { code: '<div role="menuitemcheckbox" onClick={() => {}} />;' },
99
+ { code: '<div role="menuitemradio" onClick={() => {}} />;' },
100
+ { code: '<div role="option" onClick={() => {}} />;' },
101
+ { code: '<div role="radio" onClick={() => {}} />;' },
102
+ { code: '<div role="rowheader" onClick={() => {}} />;' },
103
+ { code: '<div role="searchbox" onClick={() => {}} />;' },
104
+ { code: '<div role="slider" onClick={() => {}} />;' },
105
+ { code: '<div role="spinbutton" onClick={() => {}} />;' },
106
+ { code: '<div role="switch" onClick={() => {}} />;' },
107
+ { code: '<div role="tab" onClick={() => {}} />;' },
108
+ { code: '<div role="textbox" onClick={() => {}} />;' },
109
+ { code: '<div role="treeitem" onClick={() => {}} />;' },
110
+ /* Presentation is a special case role that indicates intentional static semantics */
111
+ { code: '<div role="presentation" onClick={() => {}} />;' },
112
+ { code: '<div role="presentation" onKeyDown={() => {}} />;' },
113
+ /* HTML elements with an inherent, non-interactive role */
114
+ { code: '<address onClick={() => {}} />;' },
115
+ { code: '<article onClick={() => {}} />;' },
116
+ { code: '<article onDblClick={() => void 0} />;' },
117
+ { code: '<aside onClick={() => {}} />;' },
118
+ { code: '<blockquote onClick={() => {}} />;' },
119
+ { code: '<br onClick={() => {}} />;' },
120
+ { code: '<canvas onClick={() => {}} />;' },
121
+ { code: '<caption onClick={() => {}} />;' },
122
+ { code: '<code onClick={() => {}} />;' },
123
+ { code: '<dd onClick={() => {}} />;' },
124
+ { code: '<del onClick={() => {}} />;' },
125
+ { code: '<details onClick={() => {}} />;' },
126
+ { code: '<dfn onClick={() => {}} />;' },
127
+ { code: '<dir onClick={() => {}} />;' },
128
+ { code: '<dl onClick={() => {}} />;' },
129
+ { code: '<dt onClick={() => {}} />;' },
130
+ { code: '<em onClick={() => {}} />;' },
131
+ { code: '<embed onClick={() => {}} />;' },
132
+ { code: '<fieldset onClick={() => {}} />;' },
133
+ { code: '<figcaption onClick={() => {}} />;' },
134
+ { code: '<figure onClick={() => {}} />;' },
135
+ { code: '<footer onClick={() => {}} />;' },
136
+ { code: '<h1 onClick={() => {}} />;' },
137
+ { code: '<h2 onClick={() => {}} />;' },
138
+ { code: '<h3 onClick={() => {}} />;' },
139
+ { code: '<h4 onClick={() => {}} />;' },
140
+ { code: '<h5 onClick={() => {}} />;' },
141
+ { code: '<h6 onClick={() => {}} />;' },
142
+ { code: '<hr onClick={() => {}} />;' },
143
+ { code: '<html onClick={() => {}} />;' },
144
+ { code: '<iframe onClick={() => {}} />;' },
145
+ { code: '<img onClick={() => {}} />;' },
146
+ { code: '<ins onClick={() => {}} />;' },
147
+ { code: '<label onClick={() => {}} />;' },
148
+ { code: '<legend onClick={() => {}} />;' },
149
+ { code: '<li onClick={() => {}} />;' },
150
+ { code: '<main onClick={() => void 0} />;' },
151
+ { code: '<mark onClick={() => {}} />;' },
152
+ { code: '<marquee onClick={() => {}} />;' },
153
+ { code: '<menu onClick={() => {}} />;' },
154
+ { code: '<meter onClick={() => {}} />;' },
155
+ { code: '<nav onClick={() => {}} />;' },
156
+ { code: '<ol onClick={() => {}} />;' },
157
+ { code: '<optgroup onClick={() => {}} />;' },
158
+ { code: '<output onClick={() => {}} />;' },
159
+ { code: '<p onClick={() => {}} />;' },
160
+ { code: '<pre onClick={() => {}} />;' },
161
+ { code: '<progress onClick={() => {}} />;' },
162
+ { code: '<ruby onClick={() => {}} />;' },
163
+ { code: '<section onClick={() => {}} aria-label="Aa" />;' },
164
+ { code: '<section onClick={() => {}} aria-labelledby="js_1" />;' },
165
+ { code: '<strong onClick={() => {}} />;' },
166
+ { code: '<sub onClick={() => {}} />;' },
167
+ { code: '<summary onClick={() => {}} />;' },
168
+ { code: '<sup onClick={() => {}} />;' },
169
+ { code: '<table onClick={() => {}} />;' },
170
+ { code: '<tbody onClick={() => {}} />;' },
171
+ { code: '<tfoot onClick={() => {}} />;' },
172
+ { code: '<th onClick={() => {}} />;' },
173
+ { code: '<thead onClick={() => {}} />;' },
174
+ { code: '<time onClick={() => {}} />;' },
175
+ { code: '<tr onClick={() => {}} />;' },
176
+ { code: '<video onClick={() => {}} />;' },
177
+ { code: '<ul onClick={() => {}} />;' },
178
+ /* HTML elements attributed with an abstract role */
179
+ { code: '<div role="command" onClick={() => {}} />;' },
180
+ { code: '<div role="composite" onClick={() => {}} />;' },
181
+ { code: '<div role="input" onClick={() => {}} />;' },
182
+ { code: '<div role="landmark" onClick={() => {}} />;' },
183
+ { code: '<div role="range" onClick={() => {}} />;' },
184
+ { code: '<div role="roletype" onClick={() => {}} />;' },
185
+ { code: '<div role="sectionhead" onClick={() => {}} />;' },
186
+ { code: '<div role="select" onClick={() => {}} />;' },
187
+ { code: '<div role="structure" onClick={() => {}} />;' },
188
+ { code: '<div role="widget" onClick={() => {}} />;' },
189
+ { code: '<div role="window" onClick={() => {}} />;' },
190
+ /* HTML elements attributed with a non-interactive role */
191
+ { code: '<div role="alert" onClick={() => {}} />;' },
192
+ { code: '<div role="alertdialog" onClick={() => {}} />;' },
193
+ { code: '<div role="application" onClick={() => {}} />;' },
194
+ { code: '<div role="article" onClick={() => {}} />;' },
195
+ { code: '<div role="banner" onClick={() => {}} />;' },
196
+ { code: '<div role="cell" onClick={() => {}} />;' },
197
+ { code: '<div role="complementary" onClick={() => {}} />;' },
198
+ { code: '<div role="contentinfo" onClick={() => {}} />;' },
199
+ { code: '<div role="definition" onClick={() => {}} />;' },
200
+ { code: '<div role="dialog" onClick={() => {}} />;' },
201
+ { code: '<div role="directory" onClick={() => {}} />;' },
202
+ { code: '<div role="document" onClick={() => {}} />;' },
203
+ { code: '<div role="feed" onClick={() => {}} />;' },
204
+ { code: '<div role="figure" onClick={() => {}} />;' },
205
+ { code: '<div role="grid" onClick={() => {}} />;' },
206
+ { code: '<div role="group" onClick={() => {}} />;' },
207
+ { code: '<div role="heading" onClick={() => {}} />;' },
208
+ { code: '<div role="img" onClick={() => {}} />;' },
209
+ { code: '<div role="list" onClick={() => {}} />;' },
210
+ { code: '<div role="listbox" onClick={() => {}} />;' },
211
+ { code: '<div role="listitem" onClick={() => {}} />;' },
212
+ { code: '<div role="log" onClick={() => {}} />;' },
213
+ { code: '<div role="main" onClick={() => {}} />;' },
214
+ { code: '<div role="marquee" onClick={() => {}} />;' },
215
+ { code: '<div role="math" onClick={() => {}} />;' },
216
+ { code: '<div role="menu" onClick={() => {}} />;' },
217
+ { code: '<div role="menubar" onClick={() => {}} />;' },
218
+ { code: '<div role="navigation" onClick={() => {}} />;' },
219
+ { code: '<div role="note" onClick={() => {}} />;' },
220
+ { code: '<div role="progressbar" onClick={() => {}} />;' },
221
+ { code: '<div role="radiogroup" onClick={() => {}} />;' },
222
+ { code: '<div role="region" onClick={() => {}} />;' },
223
+ { code: '<div role="row" onClick={() => {}} />;' },
224
+ { code: '<div role="rowgroup" onClick={() => {}} />;' },
225
+ { code: '<div role="section" onClick={() => {}} />;' },
226
+ { code: '<div role="search" onClick={() => {}} />;' },
227
+ { code: '<div role="separator" onClick={() => {}} />;' },
228
+ { code: '<div role="scrollbar" onClick={() => {}} />;' },
229
+ { code: '<div role="status" onClick={() => {}} />;' },
230
+ { code: '<div role="table" onClick={() => {}} />;' },
231
+ { code: '<div role="tablist" onClick={() => {}} />;' },
232
+ { code: '<div role="tabpanel" onClick={() => {}} />;' },
233
+ // { code: '<td onClick={() => {}} />;' },
234
+ { code: '<div role="term" onClick={() => {}} />;' },
235
+ { code: '<div role="timer" onClick={() => {}} />;' },
236
+ { code: '<div role="toolbar" onClick={() => {}} />;' },
237
+ { code: '<div role="tooltip" onClick={() => {}} />;' },
238
+ { code: '<div role="tree" onClick={() => {}} />;' },
239
+ { code: '<div role="treegrid" onClick={() => {}} />;' },
240
+ // All the possible handlers
241
+ { code: '<div onCopy={() => {}} />;' },
242
+ { code: '<div onCut={() => {}} />;' },
243
+ { code: '<div onPaste={() => {}} />;' },
244
+ { code: '<div onCompositionEnd={() => {}} />;' },
245
+ { code: '<div onCompositionStart={() => {}} />;' },
246
+ { code: '<div onCompositionUpdate={() => {}} />;' },
247
+ { code: '<div onChange={() => {}} />;' },
248
+ { code: '<div onInput={() => {}} />;' },
249
+ { code: '<div onSubmit={() => {}} />;' },
250
+ { code: '<div onSelect={() => {}} />;' },
251
+ { code: '<div onTouchCancel={() => {}} />;' },
252
+ { code: '<div onTouchEnd={() => {}} />;' },
253
+ { code: '<div onTouchMove={() => {}} />;' },
254
+ { code: '<div onTouchStart={() => {}} />;' },
255
+ { code: '<div onScroll={() => {}} />;' },
256
+ { code: '<div onWheel={() => {}} />;' },
257
+ { code: '<div onAbort={() => {}} />;' },
258
+ { code: '<div onCanPlay={() => {}} />;' },
259
+ { code: '<div onCanPlayThrough={() => {}} />;' },
260
+ { code: '<div onDurationChange={() => {}} />;' },
261
+ { code: '<div onEmptied={() => {}} />;' },
262
+ { code: '<div onEncrypted={() => {}} />;' },
263
+ { code: '<div onEnded={() => {}} />;' },
264
+ { code: '<div onError={() => {}} />;' },
265
+ { code: '<div onLoadedData={() => {}} />;' },
266
+ { code: '<div onLoadedMetadata={() => {}} />;' },
267
+ { code: '<div onLoadStart={() => {}} />;' },
268
+ { code: '<div onPause={() => {}} />;' },
269
+ { code: '<div onPlay={() => {}} />;' },
270
+ { code: '<div onPlaying={() => {}} />;' },
271
+ { code: '<div onProgress={() => {}} />;' },
272
+ { code: '<div onRateChange={() => {}} />;' },
273
+ { code: '<div onSeeked={() => {}} />;' },
274
+ { code: '<div onSeeking={() => {}} />;' },
275
+ { code: '<div onStalled={() => {}} />;' },
276
+ { code: '<div onSuspend={() => {}} />;' },
277
+ { code: '<div onTimeUpdate={() => {}} />;' },
278
+ { code: '<div onVolumeChange={() => {}} />;' },
279
+ { code: '<div onWaiting={() => {}} />;' },
280
+ { code: '<div onLoad={() => {}} />;' },
281
+ { code: '<div onError={() => {}} />;' },
282
+ { code: '<div onAnimationStart={() => {}} />;' },
283
+ { code: '<div onAnimationEnd={() => {}} />;' },
284
+ { code: '<div onAnimationIteration={() => {}} />;' },
285
+ { code: '<div onTransitionEnd={() => {}} />;' },
286
+ ];
287
+
288
+ const neverValid = [
289
+ { code: '<div onClick={() => void 0} />;', errors: [expectedError] },
290
+ { code: '<div onClick={() => void 0} role={undefined} />;', errors: [expectedError] },
291
+ { code: '<div onClick={() => void 0} {...props} />;', errors: [expectedError] },
292
+ { code: '<div onKeyUp={() => void 0} aria-hidden={false} />;', errors: [expectedError] },
293
+ /* Static elements; no inherent role */
294
+ { code: '<a onClick={() => {}} />;', errors: [expectedError] },
295
+ { code: '<a onClick={() => void 0} />', errors: [expectedError] },
296
+ { code: '<a tabIndex="0" onClick={() => void 0} />', errors: [expectedError] },
297
+ { code: '<acronym onClick={() => {}} />;', errors: [expectedError] },
298
+ { code: '<applet onClick={() => {}} />;', errors: [expectedError] },
299
+ { code: '<area onClick={() => {}} />;', errors: [expectedError] },
300
+ { code: '<b onClick={() => {}} />;', errors: [expectedError] },
301
+ { code: '<base onClick={() => {}} />;', errors: [expectedError] },
302
+ { code: '<bdi onClick={() => {}} />;', errors: [expectedError] },
303
+ { code: '<bdo onClick={() => {}} />;', errors: [expectedError] },
304
+ { code: '<big onClick={() => {}} />;', errors: [expectedError] },
305
+ { code: '<blink onClick={() => {}} />;', errors: [expectedError] },
306
+ { code: '<body onClick={() => {}} />;', errors: [expectedError] },
307
+ { code: '<center onClick={() => {}} />;', errors: [expectedError] },
308
+ { code: '<cite onClick={() => {}} />;', errors: [expectedError] },
309
+ { code: '<col onClick={() => {}} />;', errors: [expectedError] },
310
+ { code: '<colgroup onClick={() => {}} />;', errors: [expectedError] },
311
+ { code: '<content onClick={() => {}} />;', errors: [expectedError] },
312
+ { code: '<data onClick={() => {}} />;', errors: [expectedError] },
313
+ { code: '<font onClick={() => {}} />;', errors: [expectedError] },
314
+ { code: '<frame onClick={() => {}} />;', errors: [expectedError] },
315
+ { code: '<frameset onClick={() => {}} />;', errors: [expectedError] },
316
+ { code: '<head onClick={() => {}} />;', errors: [expectedError] },
317
+ { code: '<header onClick={() => {}} />;', errors: [expectedError] },
318
+ { code: '<hgroup onClick={() => {}} />;', errors: [expectedError] },
319
+ { code: '<i onClick={() => {}} />;', errors: [expectedError] },
320
+ { code: '<kbd onClick={() => {}} />;', errors: [expectedError] },
321
+ { code: '<keygen onClick={() => {}} />;', errors: [expectedError] },
322
+ { code: '<map onClick={() => {}} />;', errors: [expectedError] },
323
+ { code: '<meta onClick={() => {}} />;', errors: [expectedError] },
324
+ { code: '<noembed onClick={() => {}} />;', errors: [expectedError] },
325
+ { code: '<noscript onClick={() => {}} />;', errors: [expectedError] },
326
+ { code: '<object onClick={() => {}} />;', errors: [expectedError] },
327
+ { code: '<param onClick={() => {}} />;', errors: [expectedError] },
328
+ { code: '<picture onClick={() => {}} />;', errors: [expectedError] },
329
+ { code: '<q onClick={() => {}} />;', errors: [expectedError] },
330
+ { code: '<rp onClick={() => {}} />;', errors: [expectedError] },
331
+ { code: '<rt onClick={() => {}} />;', errors: [expectedError] },
332
+ { code: '<rtc onClick={() => {}} />;', errors: [expectedError] },
333
+ { code: '<s onClick={() => {}} />;', errors: [expectedError] },
334
+ { code: '<samp onClick={() => {}} />;', errors: [expectedError] },
335
+ { code: '<script onClick={() => {}} />;', errors: [expectedError] },
336
+ { code: '<section onClick={() => {}} />;', errors: [expectedError] },
337
+ { code: '<small onClick={() => {}} />;', errors: [expectedError] },
338
+ { code: '<source onClick={() => {}} />;', errors: [expectedError] },
339
+ { code: '<spacer onClick={() => {}} />;', errors: [expectedError] },
340
+ { code: '<span onClick={() => {}} />;', errors: [expectedError] },
341
+ { code: '<strike onClick={() => {}} />;', errors: [expectedError] },
342
+ { code: '<style onClick={() => {}} />;', errors: [expectedError] },
343
+ { code: '<title onClick={() => {}} />;', errors: [expectedError] },
344
+ { code: '<track onClick={() => {}} />;', errors: [expectedError] },
345
+ { code: '<tt onClick={() => {}} />;', errors: [expectedError] },
346
+ { code: '<u onClick={() => {}} />;', errors: [expectedError] },
347
+ { code: '<var onClick={() => {}} />;', errors: [expectedError] },
348
+ { code: '<wbr onClick={() => {}} />;', errors: [expectedError] },
349
+ { code: '<xmp onClick={() => {}} />;', errors: [expectedError] },
350
+ // Handlers
351
+ { code: '<div onKeyDown={() => {}} />;', errors: [expectedError] },
352
+ { code: '<div onKeyPress={() => {}} />;', errors: [expectedError] },
353
+ { code: '<div onKeyUp={() => {}} />;', errors: [expectedError] },
354
+ { code: '<div onClick={() => {}} />;', errors: [expectedError] },
355
+ { code: '<div onMouseDown={() => {}} />;', errors: [expectedError] },
356
+ { code: '<div onMouseUp={() => {}} />;', errors: [expectedError] },
357
+ // Custom components
358
+ { code: '<TestComponent onClick={doFoo} />', settings: componentsSettings, errors: [expectedError] },
359
+ ];
360
+
361
+ const recommendedOptions = configs.recommended.rules[`jsx-a11y/${ruleName}`][1] || {};
362
+ ruleTester.run(`${ruleName}:recommended`, rule, {
363
+ valid: parsers.all([].concat(
364
+ alwaysValid,
365
+ // All the possible handlers
366
+ { code: '<div onCopy={() => {}} />;' },
367
+ { code: '<div onCut={() => {}} />;' },
368
+ { code: '<div onPaste={() => {}} />;' },
369
+ { code: '<div onCompositionEnd={() => {}} />;' },
370
+ { code: '<div onCompositionStart={() => {}} />;' },
371
+ { code: '<div onCompositionUpdate={() => {}} />;' },
372
+ { code: '<div onFocus={() => {}} />;' },
373
+ { code: '<div onBlur={() => {}} />;' },
374
+ { code: '<div onChange={() => {}} />;' },
375
+ { code: '<div onInput={() => {}} />;' },
376
+ { code: '<div onSubmit={() => {}} />;' },
377
+ { code: '<div onContextMenu={() => {}} />;' },
378
+ { code: '<div onDblClick={() => {}} />;' },
379
+ { code: '<div onDoubleClick={() => {}} />;' },
380
+ { code: '<div onDrag={() => {}} />;' },
381
+ { code: '<div onDragEnd={() => {}} />;' },
382
+ { code: '<div onDragEnter={() => {}} />;' },
383
+ { code: '<div onDragExit={() => {}} />;' },
384
+ { code: '<div onDragLeave={() => {}} />;' },
385
+ { code: '<div onDragOver={() => {}} />;' },
386
+ { code: '<div onDragStart={() => {}} />;' },
387
+ { code: '<div onDrop={() => {}} />;' },
388
+ { code: '<div onMouseEnter={() => {}} />;' },
389
+ { code: '<div onMouseLeave={() => {}} />;' },
390
+ { code: '<div onMouseMove={() => {}} />;' },
391
+ { code: '<div onMouseOut={() => {}} />;' },
392
+ { code: '<div onMouseOver={() => {}} />;' },
393
+ { code: '<div onSelect={() => {}} />;' },
394
+ { code: '<div onTouchCancel={() => {}} />;' },
395
+ { code: '<div onTouchEnd={() => {}} />;' },
396
+ { code: '<div onTouchMove={() => {}} />;' },
397
+ { code: '<div onTouchStart={() => {}} />;' },
398
+ { code: '<div onScroll={() => {}} />;' },
399
+ { code: '<div onWheel={() => {}} />;' },
400
+ { code: '<div onAbort={() => {}} />;' },
401
+ { code: '<div onCanPlay={() => {}} />;' },
402
+ { code: '<div onCanPlayThrough={() => {}} />;' },
403
+ { code: '<div onDurationChange={() => {}} />;' },
404
+ { code: '<div onEmptied={() => {}} />;' },
405
+ { code: '<div onEncrypted={() => {}} />;' },
406
+ { code: '<div onEnded={() => {}} />;' },
407
+ { code: '<div onError={() => {}} />;' },
408
+ { code: '<div onLoadedData={() => {}} />;' },
409
+ { code: '<div onLoadedMetadata={() => {}} />;' },
410
+ { code: '<div onLoadStart={() => {}} />;' },
411
+ { code: '<div onPause={() => {}} />;' },
412
+ { code: '<div onPlay={() => {}} />;' },
413
+ { code: '<div onPlaying={() => {}} />;' },
414
+ { code: '<div onProgress={() => {}} />;' },
415
+ { code: '<div onRateChange={() => {}} />;' },
416
+ { code: '<div onSeeked={() => {}} />;' },
417
+ { code: '<div onSeeking={() => {}} />;' },
418
+ { code: '<div onStalled={() => {}} />;' },
419
+ { code: '<div onSuspend={() => {}} />;' },
420
+ { code: '<div onTimeUpdate={() => {}} />;' },
421
+ { code: '<div onVolumeChange={() => {}} />;' },
422
+ { code: '<div onWaiting={() => {}} />;' },
423
+ { code: '<div onLoad={() => {}} />;' },
424
+ { code: '<div onError={() => {}} />;' },
425
+ { code: '<div onAnimationStart={() => {}} />;' },
426
+ { code: '<div onAnimationEnd={() => {}} />;' },
427
+ { code: '<div onAnimationIteration={() => {}} />;' },
428
+ { code: '<div onTransitionEnd={() => {}} />;' },
429
+ // Expressions should pass in recommended mode
430
+ { code: '<div role={ROLE_BUTTON} onClick={() => {}} />;' },
431
+ { code: '<div {...this.props} role={this.props.role} onKeyPress={e => this.handleKeyPress(e)}>{this.props.children}</div>' },
432
+ // Cases for allowExpressionValues set to true
433
+ {
434
+ code: '<div role={BUTTON} onClick={() => {}} />;',
435
+ options: [{ allowExpressionValues: true }],
436
+ },
437
+ // Specific case for ternary operator with literals on both side
438
+ {
439
+ code: '<div role={isButton ? "button" : "link"} onClick={() => {}} />;',
440
+ options: [{ allowExpressionValues: true }],
441
+ },
442
+ {
443
+ code: '<div role={isButton ? "button" : LINK} onClick={() => {}} />;',
444
+ options: [{ allowExpressionValues: true }],
445
+ errors: [expectedError],
446
+ },
447
+ {
448
+ code: '<div role={isButton ? BUTTON : LINK} onClick={() => {}} />;',
449
+ options: [{ allowExpressionValues: true }],
450
+ errors: [expectedError],
451
+ },
452
+ ))
453
+ .map(ruleOptionsMapperFactory(recommendedOptions))
454
+ .map(parserOptionsMapper),
455
+ invalid: parsers.all([].concat(
456
+ neverValid,
457
+ ))
458
+ .map(ruleOptionsMapperFactory(recommendedOptions))
459
+ .map(parserOptionsMapper),
460
+ });
461
+
462
+ ruleTester.run(`${ruleName}:strict`, rule, {
463
+ valid: parsers.all([].concat(
464
+ alwaysValid,
465
+ )).map(parserOptionsMapper),
466
+ invalid: parsers.all([].concat(
467
+ neverValid,
468
+ // All the possible handlers
469
+ { code: '<div onContextMenu={() => {}} />;', errors: [expectedError] },
470
+ { code: '<div onDblClick={() => {}} />;', errors: [expectedError] },
471
+ { code: '<div onDoubleClick={() => {}} />;', errors: [expectedError] },
472
+ { code: '<div onDrag={() => {}} />;', errors: [expectedError] },
473
+ { code: '<div onDragEnd={() => {}} />;', errors: [expectedError] },
474
+ { code: '<div onDragEnter={() => {}} />;', errors: [expectedError] },
475
+ { code: '<div onDragExit={() => {}} />;', errors: [expectedError] },
476
+ { code: '<div onDragLeave={() => {}} />;', errors: [expectedError] },
477
+ { code: '<div onDragOver={() => {}} />;', errors: [expectedError] },
478
+ { code: '<div onDragStart={() => {}} />;', errors: [expectedError] },
479
+ { code: '<div onDrop={() => {}} />;', errors: [expectedError] },
480
+ { code: '<div onMouseEnter={() => {}} />;', errors: [expectedError] },
481
+ { code: '<div onMouseLeave={() => {}} />;', errors: [expectedError] },
482
+ { code: '<div onMouseMove={() => {}} />;', errors: [expectedError] },
483
+ { code: '<div onMouseOut={() => {}} />;', errors: [expectedError] },
484
+ { code: '<div onMouseOver={() => {}} />;', errors: [expectedError] },
485
+ // Expressions should fail in strict mode
486
+ { code: '<div role={ROLE_BUTTON} onClick={() => {}} />;', errors: [expectedError] },
487
+ { code: '<div {...this.props} role={this.props.role} onKeyPress={e => this.handleKeyPress(e)}>{this.props.children}</div>', errors: [expectedError] },
488
+ // Cases for allowExpressionValues set to false
489
+ {
490
+ code: '<div role={BUTTON} onClick={() => {}} />;',
491
+ options: [{ allowExpressionValues: false }],
492
+ errors: [expectedError],
493
+ },
494
+ // Specific case for ternary operator with literals on both side
495
+ {
496
+ code: '<div role={isButton ? "button" : "link"} onClick={() => {}} />;',
497
+ options: [{ allowExpressionValues: false }],
498
+ errors: [expectedError],
499
+ },
500
+ )).map(parserOptionsMapper),
501
+ });