1
1
/* eslint-env jest */
2
2
/**
3
- * @fileoverview $DESCRIPTION
4
- * @author $AUTHOR
3
+ * @fileoverview Enforce non-interactive elements have no interactive handlers.
4
+ * @author Ethan Cohen
5
5
*/
6
6
7
7
// -----------------------------------------------------------------------------
@@ -18,21 +18,21 @@ import rule from '../../../src/rules/no-noninteractive-element-handlers';
18
18
19
19
const ruleTester = new RuleTester ( ) ;
20
20
21
+ const errorMessage =
22
+ 'Visible, non-interactive elements should not have mouse or keyboard event listeners' ;
23
+
21
24
const expectedError = {
22
- message : '' ,
25
+ message : errorMessage ,
23
26
type : 'JSXOpeningElement' ,
24
27
} ;
25
28
26
29
ruleTester . run ( 'no-noninteractive-element-handlers' , rule , {
27
30
valid : [
31
+ { code : '<div />;' } ,
28
32
{ code : '<div className="foo" />;' } ,
29
33
{ code : '<div className="foo" {...props} />;' } ,
30
34
{ code : '<div onClick={() => void 0} aria-hidden />;' } ,
31
35
{ code : '<div onClick={() => void 0} aria-hidden={true} />;' } ,
32
- { code : '<div onClick={() => void 0} />;' } ,
33
- { code : '<div onClick={() => void 0} role={undefined} />;' } ,
34
- { code : '<div onClick={() => void 0} {...props} />;' } ,
35
- { code : '<div onKeyUp={() => void 0} aria-hidden={false} />;' } ,
36
36
/* All flavors of input */
37
37
{ code : '<input onClick={() => void 0} />' } ,
38
38
{ code : '<input type="button" onClick={() => void 0} />' } ,
@@ -68,9 +68,6 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
68
68
{ code : '<a onClick={() => void 0} href="http://x.y.z" tabIndex="0" />' } ,
69
69
{ code : '<input onClick={() => void 0} type="hidden" />;' } ,
70
70
{ code : '<form onClick={() => {}} />;' } ,
71
- { code : '<section onClick={() => void 0} />;' } ,
72
- { code : '<header onKeyDown={() => void 0} />;' } ,
73
- { code : '<footer onKeyPress={() => void 0} />;' } ,
74
71
{ code : '<TestComponent onClick={doFoo} />' } ,
75
72
{ code : '<Button onClick={doFoo} />' } ,
76
73
/* HTML elements attributed with an interactive role */
@@ -96,8 +93,120 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
96
93
{ code : '<div role="treeitem" onClick={() => {}} />;' } ,
97
94
/* Presentation is a special case role that indicates intentional static semantics */
98
95
{ code : '<div role="presentation" onClick={() => {}} />;' } ,
96
+ /* HTML elements attributed with an abstract role */
97
+ { code : '<div role="command" onClick={() => {}} />;' } ,
98
+ { code : '<div role="composite" onClick={() => {}} />;' } ,
99
+ { code : '<div role="input" onClick={() => {}} />;' } ,
100
+ { code : '<div role="landmark" onClick={() => {}} />;' } ,
101
+ { code : '<div role="range" onClick={() => {}} />;' } ,
102
+ { code : '<div role="roletype" onClick={() => {}} />;' } ,
103
+ { code : '<div role="section" onClick={() => {}} />;' } ,
104
+ { code : '<div role="sectionhead" onClick={() => {}} />;' } ,
105
+ { code : '<div role="select" onClick={() => {}} />;' } ,
106
+ { code : '<div role="structure" onClick={() => {}} />;' } ,
107
+ { code : '<div role="widget" onClick={() => {}} />;' } ,
108
+ { code : '<div role="window" onClick={() => {}} />;' } ,
99
109
] . map ( parserOptionsMapper ) ,
100
110
invalid : [
111
+ { code : '<div onClick={() => void 0} />;' , errors : [ expectedError ] } ,
112
+ { code : '<div onClick={() => void 0} role={undefined} />;' , errors : [ expectedError ] } ,
113
+ { code : '<div onClick={() => void 0} {...props} />;' , errors : [ expectedError ] } ,
114
+ { code : '<div onKeyUp={() => void 0} aria-hidden={false} />;' , errors : [ expectedError ] } ,
115
+ /* Static elements; no inherent role */
116
+ { code : '<acronym onClick={() => {}} />;' , errors : [ expectedError ] } ,
117
+ { code : '<address onClick={() => {}} />;' , errors : [ expectedError ] } ,
118
+ { code : '<applet onClick={() => {}} />;' , errors : [ expectedError ] } ,
119
+ { code : '<aside onClick={() => {}} />;' , errors : [ expectedError ] } ,
120
+ { code : '<audio onClick={() => {}} />;' , errors : [ expectedError ] } ,
121
+ { code : '<b onClick={() => {}} />;' , errors : [ expectedError ] } ,
122
+ { code : '<base onClick={() => {}} />;' , errors : [ expectedError ] } ,
123
+ { code : '<bdi onClick={() => {}} />;' , errors : [ expectedError ] } ,
124
+ { code : '<bdo onClick={() => {}} />;' , errors : [ expectedError ] } ,
125
+ { code : '<big onClick={() => {}} />;' , errors : [ expectedError ] } ,
126
+ { code : '<blink onClick={() => {}} />;' , errors : [ expectedError ] } ,
127
+ { code : '<blockquote onClick={() => {}} />;' , errors : [ expectedError ] } ,
128
+ { code : '<body onClick={() => {}} />;' , errors : [ expectedError ] } ,
129
+ { code : '<br onClick={() => {}} />;' , errors : [ expectedError ] } ,
130
+ { code : '<canvas onClick={() => {}} />;' , errors : [ expectedError ] } ,
131
+ { code : '<caption onClick={() => {}} />;' , errors : [ expectedError ] } ,
132
+ { code : '<center onClick={() => {}} />;' , errors : [ expectedError ] } ,
133
+ { code : '<cite onClick={() => {}} />;' , errors : [ expectedError ] } ,
134
+ { code : '<code onClick={() => {}} />;' , errors : [ expectedError ] } ,
135
+ { code : '<col onClick={() => {}} />;' , errors : [ expectedError ] } ,
136
+ { code : '<colgroup onClick={() => {}} />;' , errors : [ expectedError ] } ,
137
+ { code : '<content onClick={() => {}} />;' , errors : [ expectedError ] } ,
138
+ { code : '<data onClick={() => {}} />;' , errors : [ expectedError ] } ,
139
+ { code : '<datalist onClick={() => {}} />;' , errors : [ expectedError ] } ,
140
+ { code : '<del onClick={() => {}} />;' , errors : [ expectedError ] } ,
141
+ { code : '<details onClick={() => {}} />;' , errors : [ expectedError ] } ,
142
+ { code : '<dir onClick={() => {}} />;' , errors : [ expectedError ] } ,
143
+ { code : '<div onClick={() => {}} />;' , errors : [ expectedError ] } ,
144
+ { code : '<dl onClick={() => {}} />;' , errors : [ expectedError ] } ,
145
+ { code : '<em onClick={() => {}} />;' , errors : [ expectedError ] } ,
146
+ { code : '<embed onClick={() => {}} />;' , errors : [ expectedError ] } ,
147
+ { code : '<figcaption onClick={() => {}} />;' , errors : [ expectedError ] } ,
148
+ { code : '<font onClick={() => {}} />;' , errors : [ expectedError ] } ,
149
+ { code : '<footer onClick={() => {}} />;' , errors : [ expectedError ] } ,
150
+ { code : '<frameset onClick={() => {}} />;' , errors : [ expectedError ] } ,
151
+ { code : '<head onClick={() => {}} />;' , errors : [ expectedError ] } ,
152
+ { code : '<header onClick={() => {}} />;' , errors : [ expectedError ] } ,
153
+ { code : '<hgroup onClick={() => {}} />;' , errors : [ expectedError ] } ,
154
+ { code : '<html onClick={() => {}} />;' , errors : [ expectedError ] } ,
155
+ { code : '<i onClick={() => {}} />;' , errors : [ expectedError ] } ,
156
+ { code : '<iframe onClick={() => {}} />;' , errors : [ expectedError ] } ,
157
+ { code : '<ins onClick={() => {}} />;' , errors : [ expectedError ] } ,
158
+ { code : '<kbd onClick={() => {}} />;' , errors : [ expectedError ] } ,
159
+ { code : '<keygen onClick={() => {}} />;' , errors : [ expectedError ] } ,
160
+ { code : '<label onClick={() => {}} />;' , errors : [ expectedError ] } ,
161
+ { code : '<legend onClick={() => {}} />;' , errors : [ expectedError ] } ,
162
+ { code : '<link onClick={() => {}} />;' , errors : [ expectedError ] } ,
163
+ { code : '<map onClick={() => {}} />;' , errors : [ expectedError ] } ,
164
+ { code : '<mark onClick={() => {}} />;' , errors : [ expectedError ] } ,
165
+ { code : '<marquee onClick={() => {}} />;' , errors : [ expectedError ] } ,
166
+ { code : '<menu onClick={() => {}} />;' , errors : [ expectedError ] } ,
167
+ { code : '<menuitem onClick={() => {}} />;' , errors : [ expectedError ] } ,
168
+ { code : '<meta onClick={() => {}} />;' , errors : [ expectedError ] } ,
169
+ { code : '<meter onClick={() => {}} />;' , errors : [ expectedError ] } ,
170
+ { code : '<noembed onClick={() => {}} />;' , errors : [ expectedError ] } ,
171
+ { code : '<noscript onClick={() => {}} />;' , errors : [ expectedError ] } ,
172
+ { code : '<object onClick={() => {}} />;' , errors : [ expectedError ] } ,
173
+ { code : '<optgroup onClick={() => {}} />;' , errors : [ expectedError ] } ,
174
+ { code : '<output onClick={() => {}} />;' , errors : [ expectedError ] } ,
175
+ { code : '<p onClick={() => {}} />;' , errors : [ expectedError ] } ,
176
+ { code : '<param onClick={() => {}} />;' , errors : [ expectedError ] } ,
177
+ { code : '<picture onClick={() => {}} />;' , errors : [ expectedError ] } ,
178
+ { code : '<pre onClick={() => {}} />;' , errors : [ expectedError ] } ,
179
+ { code : '<progress onClick={() => {}} />;' , errors : [ expectedError ] } ,
180
+ { code : '<q onClick={() => {}} />;' , errors : [ expectedError ] } ,
181
+ { code : '<rp onClick={() => {}} />;' , errors : [ expectedError ] } ,
182
+ { code : '<rt onClick={() => {}} />;' , errors : [ expectedError ] } ,
183
+ { code : '<rtc onClick={() => {}} />;' , errors : [ expectedError ] } ,
184
+ { code : '<ruby onClick={() => {}} />;' , errors : [ expectedError ] } ,
185
+ { code : '<s onClick={() => {}} />;' , errors : [ expectedError ] } ,
186
+ { code : '<samp onClick={() => {}} />;' , errors : [ expectedError ] } ,
187
+ { code : '<script onClick={() => {}} />;' , errors : [ expectedError ] } ,
188
+ { code : '<section onClick={() => {}} />;' , errors : [ expectedError ] } ,
189
+ { code : '<small onClick={() => {}} />;' , errors : [ expectedError ] } ,
190
+ { code : '<source onClick={() => {}} />;' , errors : [ expectedError ] } ,
191
+ { code : '<spacer onClick={() => {}} />;' , errors : [ expectedError ] } ,
192
+ { code : '<span onClick={() => {}} />;' , errors : [ expectedError ] } ,
193
+ { code : '<strike onClick={() => {}} />;' , errors : [ expectedError ] } ,
194
+ { code : '<strong onClick={() => {}} />;' , errors : [ expectedError ] } ,
195
+ { code : '<style onClick={() => {}} />;' , errors : [ expectedError ] } ,
196
+ { code : '<sub onClick={() => {}} />;' , errors : [ expectedError ] } ,
197
+ { code : '<summary onClick={() => {}} />;' , errors : [ expectedError ] } ,
198
+ { code : '<sup onClick={() => {}} />;' , errors : [ expectedError ] } ,
199
+ { code : '<td onClick={() => {}} />;' , errors : [ expectedError ] } ,
200
+ { code : '<th onClick={() => {}} />;' , errors : [ expectedError ] } ,
201
+ { code : '<time onClick={() => {}} />;' , errors : [ expectedError ] } ,
202
+ { code : '<title onClick={() => {}} />;' , errors : [ expectedError ] } ,
203
+ { code : '<track onClick={() => {}} />;' , errors : [ expectedError ] } ,
204
+ { code : '<tt onClick={() => {}} />;' , errors : [ expectedError ] } ,
205
+ { code : '<u onClick={() => {}} />;' , errors : [ expectedError ] } ,
206
+ { code : '<var onClick={() => {}} />;' , errors : [ expectedError ] } ,
207
+ { code : '<video onClick={() => {}} />;' , errors : [ expectedError ] } ,
208
+ { code : '<wbr onClick={() => {}} />;' , errors : [ expectedError ] } ,
209
+ { code : '<xmp onClick={() => {}} />;' , errors : [ expectedError ] } ,
101
210
/* HTML elements with an inherent, non-interactive role */
102
211
{ code : '<main onClick={() => void 0} />;' , errors : [ expectedError ] } ,
103
212
{ code : '<a onClick={() => void 0} />' , errors : [ expectedError ] } ,
@@ -135,9 +244,7 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
135
244
{ code : '<div role="article" onClick={() => {}} />;' , errors : [ expectedError ] } ,
136
245
{ code : '<div role="banner" onClick={() => {}} />;' , errors : [ expectedError ] } ,
137
246
{ code : '<div role="cell" onClick={() => {}} />;' , errors : [ expectedError ] } ,
138
- { code : '<div role="command" onClick={() => {}} />;' , errors : [ expectedError ] } ,
139
247
{ code : '<div role="complementary" onClick={() => {}} />;' , errors : [ expectedError ] } ,
140
- { code : '<div role="composite" onClick={() => {}} />;' , errors : [ expectedError ] } ,
141
248
{ code : '<div role="contentinfo" onClick={() => {}} />;' , errors : [ expectedError ] } ,
142
249
{ code : '<div role="definition" onClick={() => {}} />;' , errors : [ expectedError ] } ,
143
250
{ code : '<div role="dialog" onClick={() => {}} />;' , errors : [ expectedError ] } ,
@@ -149,8 +256,6 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
149
256
{ code : '<div role="group" onClick={() => {}} />;' , errors : [ expectedError ] } ,
150
257
{ code : '<div role="heading" onClick={() => {}} />;' , errors : [ expectedError ] } ,
151
258
{ code : '<div role="img" onClick={() => {}} />;' , errors : [ expectedError ] } ,
152
- { code : '<div role="input" onClick={() => {}} />;' , errors : [ expectedError ] } ,
153
- { code : '<div role="landmark" onClick={() => {}} />;' , errors : [ expectedError ] } ,
154
259
{ code : '<div role="list" onClick={() => {}} />;' , errors : [ expectedError ] } ,
155
260
{ code : '<div role="listbox" onClick={() => {}} />;' , errors : [ expectedError ] } ,
156
261
{ code : '<div role="listitem" onClick={() => {}} />;' , errors : [ expectedError ] } ,
@@ -164,19 +269,13 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
164
269
{ code : '<div role="note" onClick={() => {}} />;' , errors : [ expectedError ] } ,
165
270
{ code : '<div role="progressbar" onClick={() => {}} />;' , errors : [ expectedError ] } ,
166
271
{ code : '<div role="radiogroup" onClick={() => {}} />;' , errors : [ expectedError ] } ,
167
- { code : '<div role="range" onClick={() => {}} />;' , errors : [ expectedError ] } ,
168
272
{ code : '<div role="region" onClick={() => {}} />;' , errors : [ expectedError ] } ,
169
- { code : '<div role="roletype" onClick={() => {}} />;' , errors : [ expectedError ] } ,
170
273
{ code : '<div role="row" onClick={() => {}} />;' , errors : [ expectedError ] } ,
171
274
{ code : '<div role="rowgroup" onClick={() => {}} />;' , errors : [ expectedError ] } ,
172
275
{ code : '<div role="search" onClick={() => {}} />;' , errors : [ expectedError ] } ,
173
- { code : '<div role="section" onClick={() => {}} />;' , errors : [ expectedError ] } ,
174
- { code : '<div role="sectionhead" onClick={() => {}} />;' , errors : [ expectedError ] } ,
175
- { code : '<div role="select" onClick={() => {}} />;' , errors : [ expectedError ] } ,
176
276
{ code : '<div role="separator" onClick={() => {}} />;' , errors : [ expectedError ] } ,
177
277
{ code : '<div role="scrollbar" onClick={() => {}} />;' , errors : [ expectedError ] } ,
178
278
{ code : '<div role="status" onClick={() => {}} />;' , errors : [ expectedError ] } ,
179
- { code : '<div role="structure" onClick={() => {}} />;' , errors : [ expectedError ] } ,
180
279
{ code : '<div role="table" onClick={() => {}} />;' , errors : [ expectedError ] } ,
181
280
{ code : '<div role="tablist" onClick={() => {}} />;' , errors : [ expectedError ] } ,
182
281
{ code : '<div role="tabpanel" onClick={() => {}} />;' , errors : [ expectedError ] } ,
@@ -186,7 +285,5 @@ ruleTester.run('no-noninteractive-element-handlers', rule, {
186
285
{ code : '<div role="tooltip" onClick={() => {}} />;' , errors : [ expectedError ] } ,
187
286
{ code : '<div role="tree" onClick={() => {}} />;' , errors : [ expectedError ] } ,
188
287
{ code : '<div role="treegrid" onClick={() => {}} />;' , errors : [ expectedError ] } ,
189
- { code : '<div role="widget" onClick={() => {}} />;' , errors : [ expectedError ] } ,
190
- { code : '<div role="window" onClick={() => {}} />;' , errors : [ expectedError ] } ,
191
288
] . map ( parserOptionsMapper ) ,
192
289
} ) ;
0 commit comments