@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,219 @@
1
+ import test from 'tape';
2
+
3
+ import mayContainChildComponent from '../../../src/util/mayContainChildComponent';
4
+ import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
5
+ import JSXElementMock from '../../../__mocks__/JSXElementMock';
6
+ import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
7
+
8
+ test('mayContainChildComponent', (t) => {
9
+ t.equal(
10
+ mayContainChildComponent(
11
+ JSXElementMock('div', [], [
12
+ JSXElementMock('div', [], [
13
+ JSXElementMock('span', [], []),
14
+ JSXElementMock('span', [], [
15
+ JSXElementMock('span', [], []),
16
+ JSXElementMock('span', [], [
17
+ JSXElementMock('span', [], []),
18
+ ]),
19
+ ]),
20
+ ]),
21
+ JSXElementMock('span', [], []),
22
+ JSXElementMock('img', [
23
+ JSXAttributeMock('src', 'some/path'),
24
+ ]),
25
+ ]),
26
+ 'FancyComponent',
27
+ 5,
28
+ ),
29
+ false,
30
+ 'no FancyComponent returns false',
31
+ );
32
+
33
+ t.test('contains an indicated component', (st) => {
34
+ st.equal(
35
+ mayContainChildComponent(
36
+ JSXElementMock('div', [], [
37
+ JSXElementMock('input'),
38
+ ]),
39
+ 'input',
40
+ ),
41
+ true,
42
+ 'returns true',
43
+ );
44
+
45
+ st.equal(
46
+ mayContainChildComponent(
47
+ JSXElementMock('div', [], [
48
+ JSXElementMock('FancyComponent'),
49
+ ]),
50
+ 'FancyComponent',
51
+ ),
52
+ true,
53
+ 'returns true',
54
+ );
55
+
56
+ st.equal(
57
+ mayContainChildComponent(
58
+ JSXElementMock('div', [], [
59
+ JSXElementMock('div', [], [
60
+ JSXElementMock('FancyComponent'),
61
+ ]),
62
+ ]),
63
+ 'FancyComponent',
64
+ ),
65
+ false,
66
+ 'FancyComponent is outside of default depth, should return false',
67
+ );
68
+
69
+ st.equal(
70
+ mayContainChildComponent(
71
+ JSXElementMock('div', [], [
72
+ JSXElementMock('div', [], [
73
+ JSXElementMock('FancyComponent'),
74
+ ]),
75
+ ]),
76
+ 'FancyComponent',
77
+ 2,
78
+ ),
79
+ true,
80
+ 'FancyComponent is inside of custom depth, should return true',
81
+ );
82
+
83
+ st.equal(
84
+ mayContainChildComponent(
85
+ JSXElementMock('div', [], [
86
+ JSXElementMock('div', [], [
87
+ JSXElementMock('span', [], []),
88
+ JSXElementMock('span', [], [
89
+ JSXElementMock('span', [], []),
90
+ JSXElementMock('span', [], [
91
+ JSXElementMock('span', [], [
92
+ JSXElementMock('span', [], [
93
+ JSXElementMock('FancyComponent'),
94
+ ]),
95
+ ]),
96
+ ]),
97
+ ]),
98
+ ]),
99
+ JSXElementMock('span', [], []),
100
+ JSXElementMock('img', [
101
+ JSXAttributeMock('src', 'some/path'),
102
+ ]),
103
+ ]),
104
+ 'FancyComponent',
105
+ 6,
106
+ ),
107
+ true,
108
+ 'deep nesting, returns true',
109
+ );
110
+
111
+ st.end();
112
+ });
113
+
114
+ t.equal(
115
+ mayContainChildComponent(
116
+ JSXElementMock('div', [], [
117
+ JSXExpressionContainerMock('mysteryBox'),
118
+ ]),
119
+ 'FancyComponent',
120
+ ),
121
+ true,
122
+ 'Intederminate situations + expression container children - returns true',
123
+ );
124
+
125
+ t.test('Glob name matching - component name contains question mark ? - match any single character', (st) => {
126
+ st.equal(
127
+ mayContainChildComponent(
128
+ JSXElementMock('div', [], [
129
+ JSXElementMock('FancyComponent'),
130
+ ]),
131
+ 'Fanc?Co??onent',
132
+ ),
133
+ true,
134
+ 'returns true',
135
+ );
136
+
137
+ st.equal(
138
+ mayContainChildComponent(
139
+ JSXElementMock('div', [], [
140
+ JSXElementMock('FancyComponent'),
141
+ ]),
142
+ 'FancyComponent?',
143
+ ),
144
+ false,
145
+ 'returns false',
146
+ );
147
+
148
+ st.test('component name contains asterisk * - match zero or more characters', (s2t) => {
149
+ s2t.equal(
150
+ mayContainChildComponent(
151
+ JSXElementMock('div', [], [
152
+ JSXElementMock('FancyComponent'),
153
+ ]),
154
+ 'Fancy*',
155
+ ),
156
+ true,
157
+ 'returns true',
158
+ );
159
+
160
+ s2t.equal(
161
+ mayContainChildComponent(
162
+ JSXElementMock('div', [], [
163
+ JSXElementMock('FancyComponent'),
164
+ ]),
165
+ '*Component',
166
+ ),
167
+ true,
168
+ 'returns true',
169
+ );
170
+
171
+ s2t.equal(
172
+ mayContainChildComponent(
173
+ JSXElementMock('div', [], [
174
+ JSXElementMock('FancyComponent'),
175
+ ]),
176
+ 'Fancy*C*t',
177
+ ),
178
+ true,
179
+ 'returns true',
180
+ );
181
+
182
+ s2t.end();
183
+ });
184
+
185
+ st.end();
186
+ });
187
+
188
+ t.test('using a custom elementType function', (st) => {
189
+ st.equal(
190
+ mayContainChildComponent(
191
+ JSXElementMock('div', [], [
192
+ JSXElementMock('CustomInput'),
193
+ ]),
194
+ 'input',
195
+ 2,
196
+ () => 'input',
197
+ ),
198
+ true,
199
+ 'returns true when the custom elementType returns the proper name',
200
+ );
201
+
202
+ st.equal(
203
+ mayContainChildComponent(
204
+ JSXElementMock('div', [], [
205
+ JSXElementMock('CustomInput'),
206
+ ]),
207
+ 'input',
208
+ 2,
209
+ () => 'button',
210
+ ),
211
+ false,
212
+ 'returns false when the custom elementType returns a wrong name',
213
+ );
214
+
215
+ st.end();
216
+ });
217
+
218
+ t.end();
219
+ });
@@ -0,0 +1,256 @@
1
+ import test from 'tape';
2
+
3
+ import mayHaveAccessibleLabel from '../../../src/util/mayHaveAccessibleLabel';
4
+ import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock';
5
+ import JSXElementMock from '../../../__mocks__/JSXElementMock';
6
+ import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock';
7
+ import JSXSpreadAttributeMock from '../../../__mocks__/JSXSpreadAttributeMock';
8
+ import JSXTextMock from '../../../__mocks__/JSXTextMock';
9
+ import LiteralMock from '../../../__mocks__/LiteralMock';
10
+
11
+ test('mayHaveAccessibleLabel', (t) => {
12
+ t.equal(
13
+ mayHaveAccessibleLabel(
14
+ JSXElementMock('div', [], [
15
+ JSXElementMock('div', [], [
16
+ JSXElementMock('span', [], []),
17
+ JSXElementMock('span', [], [
18
+ JSXElementMock('span', [], []),
19
+ JSXElementMock('span', [], [
20
+ JSXElementMock('span', [], []),
21
+ ]),
22
+ ]),
23
+ ]),
24
+ JSXElementMock('span', [], []),
25
+ JSXElementMock('img', [
26
+ JSXAttributeMock('src', 'some/path'),
27
+ ]),
28
+ ]),
29
+ 5,
30
+ ),
31
+ false,
32
+ 'no label returns false',
33
+ );
34
+
35
+ t.test('label via attributes', (st) => {
36
+ st.equal(
37
+ mayHaveAccessibleLabel(JSXElementMock('div', [
38
+ JSXAttributeMock('aria-label', 'A delicate label'),
39
+ ], [])),
40
+ true,
41
+ 'aria-label returns true',
42
+ );
43
+
44
+ st.equal(
45
+ mayHaveAccessibleLabel(JSXElementMock('div', [
46
+ JSXAttributeMock('aria-label', ''),
47
+ ], [])),
48
+ false,
49
+ 'aria-label without content returns false',
50
+ );
51
+
52
+ st.equal(
53
+ mayHaveAccessibleLabel(JSXElementMock('div', [
54
+ JSXAttributeMock('aria-label', ' '),
55
+ ], [])),
56
+ false,
57
+ 'aria-label with only spaces whitespace, should return false',
58
+ );
59
+ st.equal(
60
+ mayHaveAccessibleLabel(JSXElementMock('div', [
61
+ JSXAttributeMock('aria-label', '\n'),
62
+ ], [])),
63
+ false,
64
+ 'aria-label with only newline whitespace, should return false',
65
+ );
66
+
67
+ st.equal(
68
+ mayHaveAccessibleLabel(JSXElementMock('div', [
69
+ JSXAttributeMock('aria-labelledby', 'elementId'),
70
+ ], [])),
71
+ true,
72
+ 'aria-labelledby returns true',
73
+ );
74
+
75
+ st.equal(
76
+ mayHaveAccessibleLabel(JSXElementMock('div', [
77
+ JSXAttributeMock('aria-labelledby', ''),
78
+ ], [])),
79
+ false,
80
+ 'aria-labelledby without content returns false',
81
+ );
82
+
83
+ st.equal(
84
+ mayHaveAccessibleLabel(JSXElementMock('div', [
85
+ JSXAttributeMock('aria-labelledby', 'elementId', true),
86
+ ], [])),
87
+ true,
88
+ 'aria-labelledby with an expression container, should return true',
89
+ );
90
+
91
+ st.end();
92
+ });
93
+
94
+ t.test('label via custom label attribute', (st) => {
95
+ const customLabelProp = 'cowbell';
96
+
97
+ st.equal(
98
+ mayHaveAccessibleLabel(
99
+ JSXElementMock('div', [
100
+ JSXAttributeMock(customLabelProp, 'A delicate label'),
101
+ ], []),
102
+ 1,
103
+ [customLabelProp],
104
+ ),
105
+ true,
106
+ 'aria-label returns true',
107
+ );
108
+
109
+ st.end();
110
+ });
111
+
112
+ t.test('text label', (st) => {
113
+ st.equal(
114
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
115
+ LiteralMock('A fancy label'),
116
+ ])),
117
+ true,
118
+ 'Literal text, returns true',
119
+ );
120
+
121
+ st.equal(
122
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
123
+ LiteralMock(' '),
124
+ ])),
125
+ false,
126
+ 'Literal spaces whitespace, returns false',
127
+ );
128
+
129
+ st.equal(
130
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
131
+ LiteralMock('\n'),
132
+ ])),
133
+ false,
134
+ 'Literal newline whitespace, returns false',
135
+ );
136
+
137
+ st.equal(
138
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
139
+ JSXTextMock('A fancy label'),
140
+ ])),
141
+ true,
142
+ 'JSXText, returns true',
143
+ );
144
+
145
+ st.equal(
146
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
147
+ JSXElementMock('div', [], [
148
+ JSXTextMock('A fancy label'),
149
+ ]),
150
+ ])),
151
+ false,
152
+ 'label is outside of default depth, returns false',
153
+ );
154
+
155
+ st.equal(
156
+ mayHaveAccessibleLabel(
157
+ JSXElementMock('div', [], [
158
+ JSXElementMock('div', [], [
159
+ JSXTextMock('A fancy label'),
160
+ ]),
161
+ ]),
162
+ 2,
163
+ ),
164
+ true,
165
+ 'label is inside of custom depth, returns true',
166
+ );
167
+
168
+ st.equal(
169
+ mayHaveAccessibleLabel(
170
+ JSXElementMock('div', [], [
171
+ JSXElementMock('div', [], [
172
+ JSXElementMock('span', [], []),
173
+ JSXElementMock('span', [], [
174
+ JSXElementMock('span', [], []),
175
+ JSXElementMock('span', [], [
176
+ JSXElementMock('span', [], [
177
+ JSXElementMock('span', [], [
178
+ JSXTextMock('A fancy label'),
179
+ ]),
180
+ ]),
181
+ ]),
182
+ ]),
183
+ ]),
184
+ JSXElementMock('span', [], []),
185
+ JSXElementMock('img', [
186
+ JSXAttributeMock('src', 'some/path'),
187
+ ]),
188
+ ]),
189
+ 6,
190
+ ),
191
+ true,
192
+ 'deep nesting, returns true',
193
+ );
194
+
195
+ st.end();
196
+ });
197
+
198
+ t.test('image content', (st) => {
199
+ st.equal(
200
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
201
+ JSXElementMock('img', [
202
+ JSXAttributeMock('src', 'some/path'),
203
+ ]),
204
+ ])),
205
+ false,
206
+ 'without alt, returns true',
207
+ );
208
+
209
+ st.equal(
210
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
211
+ JSXElementMock('img', [
212
+ JSXAttributeMock('src', 'some/path'),
213
+ JSXAttributeMock('alt', 'A sensible label'),
214
+ ]),
215
+ ])),
216
+ true,
217
+ 'with alt, returns true',
218
+ );
219
+
220
+ st.equal(
221
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
222
+ JSXElementMock('img', [
223
+ JSXAttributeMock('src', 'some/path'),
224
+ JSXAttributeMock('aria-label', 'A sensible label'),
225
+ ]),
226
+ ])),
227
+ true,
228
+ 'with aria-label, returns true',
229
+ );
230
+
231
+ st.end();
232
+ });
233
+
234
+ t.test('Intederminate situations', (st) => {
235
+ st.equal(
236
+ mayHaveAccessibleLabel(JSXElementMock('div', [], [
237
+ JSXExpressionContainerMock('mysteryBox'),
238
+ ])),
239
+ true,
240
+ 'expression container children, returns true',
241
+ );
242
+
243
+ st.equal(
244
+ mayHaveAccessibleLabel(JSXElementMock('div', [
245
+ JSXAttributeMock('style', 'some-junk'),
246
+ JSXSpreadAttributeMock('props'),
247
+ ], [])),
248
+ true,
249
+ 'spread operator in attributes, returns true',
250
+ );
251
+
252
+ st.end();
253
+ });
254
+
255
+ t.end();
256
+ });
@@ -0,0 +1,93 @@
1
+ import { version as eslintVersion } from 'eslint/package.json';
2
+ import test from 'tape';
3
+ import semver from 'semver';
4
+
5
+ import parserOptionsMapper from '../../__util__/parserOptionsMapper';
6
+
7
+ const usingLegacy = semver.major(eslintVersion) < 9;
8
+
9
+ test('parserOptionsMapper', (t) => {
10
+ const expectedResult = usingLegacy
11
+ ? {
12
+ code: '<div />',
13
+ errors: [],
14
+ options: {},
15
+ parserOptions: {
16
+ ecmaVersion: 2018,
17
+ ecmaFeatures: {
18
+ experimentalObjectRestSpread: true,
19
+ jsx: true,
20
+ },
21
+ },
22
+ settings: {},
23
+ }
24
+ : {
25
+ code: '<div />',
26
+ errors: [],
27
+ options: {},
28
+ languageOptions: {
29
+ ecmaVersion: 'latest',
30
+ parserOptions: {
31
+ ecmaFeatures: {
32
+ experimentalObjectRestSpread: true,
33
+ jsx: true,
34
+ },
35
+ },
36
+ },
37
+ settings: {},
38
+ };
39
+
40
+ t.deepEqual(
41
+ parserOptionsMapper({
42
+ code: '<div />',
43
+ errors: [],
44
+ options: {},
45
+ }),
46
+ expectedResult,
47
+ 'returns a test case object',
48
+ );
49
+
50
+ const expectedResult2 = usingLegacy
51
+ ? {
52
+ code: '<div />',
53
+ errors: [],
54
+ options: {},
55
+ parserOptions: {
56
+ ecmaVersion: 5,
57
+ ecmaFeatures: {
58
+ experimentalObjectRestSpread: true,
59
+ jsx: true,
60
+ },
61
+ },
62
+ settings: {},
63
+ }
64
+ : {
65
+ code: '<div />',
66
+ errors: [],
67
+ options: {},
68
+ languageOptions: {
69
+ ecmaVersion: 5,
70
+ parserOptions: {
71
+ ecmaFeatures: {
72
+ experimentalObjectRestSpread: true,
73
+ jsx: true,
74
+ },
75
+ },
76
+ },
77
+ settings: {},
78
+ };
79
+ t.deepEqual(
80
+ parserOptionsMapper({
81
+ code: '<div />',
82
+ errors: [],
83
+ options: {},
84
+ languageOptions: {
85
+ ecmaVersion: 5,
86
+ },
87
+ }),
88
+ expectedResult2,
89
+ 'allows for overriding parserOptions',
90
+ );
91
+
92
+ t.end();
93
+ });
@@ -0,0 +1,35 @@
1
+ import test from 'tape';
2
+
3
+ import { generateObjSchema, arraySchema, enumArraySchema } from '../../../src/util/schemas';
4
+
5
+ test('schemas', (t) => {
6
+ t.test('should generate an object schema with correct properties', (st) => {
7
+ const schema = generateObjSchema({
8
+ foo: 'bar',
9
+ baz: arraySchema,
10
+ });
11
+ const properties = schema.properties || {};
12
+
13
+ st.deepEqual(properties.foo, properties.foo, 'bar');
14
+ st.deepEqual(properties.baz.type, 'array');
15
+
16
+ st.end();
17
+ });
18
+
19
+ t.deepEqual(
20
+ enumArraySchema(),
21
+ {
22
+ additionalItems: false,
23
+ items: {
24
+ enum: [],
25
+ type: 'string',
26
+ },
27
+ minItems: 0,
28
+ type: 'array',
29
+ uniqueItems: true,
30
+ },
31
+ 'enumArraySchema works with no arguments',
32
+ );
33
+
34
+ t.end();
35
+ });
@@ -0,0 +1,30 @@
1
+ # jsx-a11y/accessible-emoji
2
+
3
+ ❌ This rule is deprecated.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ Emoji have become a common way of communicating content to the end user. To a person using a screen reader, however, they may not be aware that this content is there at all. By wrapping the emoji in a `<span>`, giving it the `role="img"`, and providing a useful description in `aria-label`, the screen reader will treat the emoji as an image in the accessibility tree with an accessible name for the end user.
8
+
9
+ ## Rule details
10
+
11
+ This rule takes no arguments.
12
+
13
+ ### Succeed
14
+ ```jsx
15
+ <span role="img" aria-label="Snowman">&#9731;</span>
16
+ <span role="img" aria-label="Panda">🐼</span>
17
+ <span role="img" aria-labelledby="panda1">🐼</span>
18
+ ```
19
+
20
+ ### Fail
21
+ ```jsx
22
+ <span>🐼</span>
23
+ <i role="img" aria-label="Panda">🐼</i>
24
+ ```
25
+
26
+ ## Accessibility guidelines
27
+ - [WCAG 1.1.1](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html)
28
+
29
+ ### Resources
30
+ - [Léonie Watson, Accessible Emoji](https://tink.uk/accessible-emoji/)