diff --git a/__tests__/src/rules/div-has-apply-test.js b/__tests__/src/rules/div-has-apply-test.js new file mode 100644 index 000000000..7e1fd6e53 --- /dev/null +++ b/__tests__/src/rules/div-has-apply-test.js @@ -0,0 +1,2467 @@ +/* eslint-env jest */ +/** + * @fileoverview Discourage use of div when text is an action word + * @author Felicia Kovacs + */ + +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- + +import { RuleTester } from 'eslint'; +import parserOptionsMapper from '../../__util__/parserOptionsMapper'; +import rule from '../../../src/rules/div-has-apply'; + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +const ruleTester = new RuleTester(); + +const expectedErrorNoAttributes = { + message: 'Missing and/or incorrect attributes. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + type: 'JSXOpeningElement', +}; + +const expectedErrorNoTabindex = { + message: 'Missing or incorrect tabIndex attribute value. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + type: 'JSXOpeningElement', +}; + +const expectedErrorNoRole = { + message: 'Missing or incorrect role value. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + type: 'JSXOpeningElement', +}; +const expectedErrorCustom = { + message: 'If custom element is an action word then the text within it should also be an action word. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + type: 'JSXOpeningElement', +}; + +const components = [{ + components: ['Button', 'Apply'], +}]; + +ruleTester.run('div-has-apply', rule, { + valid: [ + // DEFAULT ELEMENT TESTS + { code: '
;' }, + { code: '
' }, // empty div is allowed + { code: '
orange
' }, // no action word within div element + { code: '
orange
' }, // any word within div that has the two attributes + + // action words within div that has the two attributes + { code: '
advise
' }, + { code: '
amplify
' }, + { code: '
apply
' }, + { code: '
arrange
' }, + { code: '
ask
' }, + { code: '
boost
' }, + { code: '
build
' }, + { code: '
call
' }, + { code: '
click
' }, + { code: '
close
' }, + { code: '
commit
' }, + { code: '
consult
' }, + { code: '
compile
' }, + { code: '
collect
' }, + { code: '
contribute
' }, + { code: '
create
' }, + { code: '
cut
' }, + { code: '
decrease
' }, + { code: '
delete
' }, + { code: '
divide
' }, + { code: '
drink
' }, + { code: '
eat
' }, + { code: '
earn
' }, + { code: '
enable
' }, + { code: '
enter
' }, + { code: '
execute
' }, + { code: '
exit
' }, + { code: '
expand
' }, + { code: '
explain
' }, + { code: '
finish
' }, + { code: '
forecast
' }, + { code: '
fix
' }, + { code: '
generate
' }, + { code: '
handle
' }, + { code: '
help
' }, + { code: '
hire
' }, + { code: '
hit
' }, + { code: '
improve
' }, + { code: '
increase
' }, + { code: '
join
' }, + { code: '
jump
' }, + { code: '
leave
' }, + { code: '
let\'/s
' }, + { code: '
list
' }, + { code: '
listen
' }, + { code: '
magnify
' }, + { code: '
make
' }, + { code: '
manage
' }, + { code: '
minimize
' }, + { code: '
move
' }, + { code: '
ok
' }, + { code: '
open
' }, + { code: '
organise
' }, + { code: '
oversee
' }, + { code: '
play
' }, + { code: '
push
' }, + { code: '
read
' }, + { code: '
reduce
' }, + { code: '
run
' }, + { code: '
save
' }, + { code: '
send
' }, + { code: '
shout
' }, + { code: '
sing
' }, + { code: '
submit
' }, + { code: '
support
' }, + { code: '
talk
' }, + { code: '
trim
' }, + { code: '
visit
' }, + { code: '
volunteer
' }, + { code: '
vote
' }, + { code: '
watch
' }, + { code: '
win
' }, + { code: '
write
' }, + + // CUSTOM ELEMENT TESTS FOR COMPONENTS OPTION + + // limitation: I only test for custom element, + // I do not test when custom element name is any other action word from the list + // any action word //has limitation + { code: 'advise', options: components }, + { code: 'amplify', options: components }, + { code: 'apply', options: components }, + { code: 'arrange', options: components }, + { code: 'ask', options: components }, + { code: 'boost', options: components }, + { code: 'build', options: components }, + { code: 'call', options: components }, + { code: 'click', options: components }, + { code: 'close', options: components }, + { code: 'commit', options: components }, + { code: 'consult', options: components }, + { code: 'compile', options: components }, + { code: 'collect', options: components }, + { code: 'contribute', options: components }, + { code: 'create', options: components }, + { code: 'cut', options: components }, + { code: 'decrease', options: components }, + { code: 'delete', options: components }, + { code: 'divide', options: components }, + { code: 'drink', options: components }, + { code: 'eat', options: components }, + { code: 'earn', options: components }, + { code: 'enable', options: components }, + { code: 'enter', options: components }, + { code: 'execute', options: components }, + { code: 'exit', options: components }, + { code: 'expand', options: components }, + { code: 'explain', options: components }, + { code: 'finish', options: components }, + { code: 'forecast', options: components }, + { code: 'fix', options: components }, + { code: 'generate', options: components }, + { code: 'handle', options: components }, + { code: 'help', options: components }, + { code: 'hire', options: components }, + { code: 'hit', options: components }, + { code: 'improve', options: components }, + { code: 'increase', options: components }, + { code: 'join', options: components }, + { code: 'jump', options: components }, + { code: 'leave', options: components }, + { code: 'let\'/s', options: components }, + { code: 'list', options: components }, + { code: 'listen', options: components }, + { code: 'magnify', options: components }, + { code: 'make', options: components }, + { code: 'manage', options: components }, + { code: 'minimize', options: components }, + { code: 'move', options: components }, + { code: 'ok', options: components }, + { code: 'open', options: components }, + { code: 'organise', options: components }, + { code: 'oversee', options: components }, + { code: 'play', options: components }, + { code: 'push', options: components }, + { code: 'read', options: components }, + { code: 'run', options: components }, + { code: 'save', options: components }, + { code: 'send', options: components }, + { code: 'shout', options: components }, + { code: 'sing', options: components }, + { code: 'submit', options: components }, + { code: 'support', options: components }, + { code: 'talk', options: components }, + { code: 'trim', options: components }, + { code: 'visit', options: components }, + { code: 'volunteer', options: components }, + { code: 'vote', options: components }, + { code: 'watch', options: components }, + { code: 'win', options: components }, + { code: 'write', options: components }, + + ].map(parserOptionsMapper), + invalid: [ + // DEFAULT ELEMENT TESTS + + // action words within div that missing the two attributes + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // undefined attributes + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // wrong attributes values -1 and navigation + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // wrong attributes values 1 and main + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // wrong attribute value: contentinfo and missing attribute: tabindex + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // wrong attribute value: tabindex="-1" and missing attribute: role="button" + { code: '
advise
', errors: [expectedErrorNoAttributes] }, + { code: '
amplify
', errors: [expectedErrorNoAttributes] }, + { code: '
apply
', errors: [expectedErrorNoAttributes] }, + { code: '
arrange
', errors: [expectedErrorNoAttributes] }, + { code: '
ask
', errors: [expectedErrorNoAttributes] }, + { code: '
boost
', errors: [expectedErrorNoAttributes] }, + { code: '
build
', errors: [expectedErrorNoAttributes] }, + { code: '
call
', errors: [expectedErrorNoAttributes] }, + { code: '
click
', errors: [expectedErrorNoAttributes] }, + { code: '
close
', errors: [expectedErrorNoAttributes] }, + { code: '
commit
', errors: [expectedErrorNoAttributes] }, + { code: '
consult
', errors: [expectedErrorNoAttributes] }, + { code: '
compile
', errors: [expectedErrorNoAttributes] }, + { code: '
collect
', errors: [expectedErrorNoAttributes] }, + { code: '
contribute
', errors: [expectedErrorNoAttributes] }, + { code: '
create
', errors: [expectedErrorNoAttributes] }, + { code: '
cut
', errors: [expectedErrorNoAttributes] }, + { code: '
decrease
', errors: [expectedErrorNoAttributes] }, + { code: '
delete
', errors: [expectedErrorNoAttributes] }, + { code: '
divide
', errors: [expectedErrorNoAttributes] }, + { code: '
drink
', errors: [expectedErrorNoAttributes] }, + { code: '
eat
', errors: [expectedErrorNoAttributes] }, + { code: '
earn
', errors: [expectedErrorNoAttributes] }, + { code: '
enable
', errors: [expectedErrorNoAttributes] }, + { code: '
enter
', errors: [expectedErrorNoAttributes] }, + { code: '
execute
', errors: [expectedErrorNoAttributes] }, + { code: '
exit
', errors: [expectedErrorNoAttributes] }, + { code: '
expand
', errors: [expectedErrorNoAttributes] }, + { code: '
explain
', errors: [expectedErrorNoAttributes] }, + { code: '
finish
', errors: [expectedErrorNoAttributes] }, + { code: '
forecast
', errors: [expectedErrorNoAttributes] }, + { code: '
fix
', errors: [expectedErrorNoAttributes] }, + { code: '
generate
', errors: [expectedErrorNoAttributes] }, + { code: '
handle
', errors: [expectedErrorNoAttributes] }, + { code: '
help
', errors: [expectedErrorNoAttributes] }, + { code: '
hire
', errors: [expectedErrorNoAttributes] }, + { code: '
hit
', errors: [expectedErrorNoAttributes] }, + { code: '
improve
', errors: [expectedErrorNoAttributes] }, + { code: '
increase
', errors: [expectedErrorNoAttributes] }, + { code: '
join
', errors: [expectedErrorNoAttributes] }, + { code: '
jump
', errors: [expectedErrorNoAttributes] }, + { code: '
leave
', errors: [expectedErrorNoAttributes] }, + { code: '
let\'/s
', errors: [expectedErrorNoAttributes] }, + { code: '
list
', errors: [expectedErrorNoAttributes] }, + { code: '
listen
', errors: [expectedErrorNoAttributes] }, + { code: '
magnify
', errors: [expectedErrorNoAttributes] }, + { code: '
make
', errors: [expectedErrorNoAttributes] }, + { code: '
manage
', errors: [expectedErrorNoAttributes] }, + { code: '
minimize
', errors: [expectedErrorNoAttributes] }, + { code: '
move
', errors: [expectedErrorNoAttributes] }, + { code: '
ok
', errors: [expectedErrorNoAttributes] }, + { code: '
open
', errors: [expectedErrorNoAttributes] }, + { code: '
organise
', errors: [expectedErrorNoAttributes] }, + { code: '
oversee
', errors: [expectedErrorNoAttributes] }, + { code: '
play
', errors: [expectedErrorNoAttributes] }, + { code: '
push
', errors: [expectedErrorNoAttributes] }, + { code: '
read
', errors: [expectedErrorNoAttributes] }, + { code: '
reduce
', errors: [expectedErrorNoAttributes] }, + { code: '
run
', errors: [expectedErrorNoAttributes] }, + { code: '
save
', errors: [expectedErrorNoAttributes] }, + { code: '
send
', errors: [expectedErrorNoAttributes] }, + { code: '
shout
', errors: [expectedErrorNoAttributes] }, + { code: '
sing
', errors: [expectedErrorNoAttributes] }, + { code: '
submit
', errors: [expectedErrorNoAttributes] }, + { code: '
support
', errors: [expectedErrorNoAttributes] }, + { code: '
talk
', errors: [expectedErrorNoAttributes] }, + { code: '
trim
', errors: [expectedErrorNoAttributes] }, + { code: '
visit
', errors: [expectedErrorNoAttributes] }, + { code: '
volunteer
', errors: [expectedErrorNoAttributes] }, + { code: '
vote
', errors: [expectedErrorNoAttributes] }, + { code: '
watch
', errors: [expectedErrorNoAttributes] }, + { code: '
win
', errors: [expectedErrorNoAttributes] }, + { code: '
write
', errors: [expectedErrorNoAttributes] }, + + // role is missing + { code: '
advise
', errors: [expectedErrorNoRole] }, + { code: '
amplify
', errors: [expectedErrorNoRole] }, + { code: '
apply
', errors: [expectedErrorNoRole] }, + { code: '
arrange
', errors: [expectedErrorNoRole] }, + { code: '
ask
', errors: [expectedErrorNoRole] }, + { code: '
boost
', errors: [expectedErrorNoRole] }, + { code: '
build
', errors: [expectedErrorNoRole] }, + { code: '
call
', errors: [expectedErrorNoRole] }, + { code: '
click
', errors: [expectedErrorNoRole] }, + { code: '
close
', errors: [expectedErrorNoRole] }, + { code: '
commit
', errors: [expectedErrorNoRole] }, + { code: '
consult
', errors: [expectedErrorNoRole] }, + { code: '
compile
', errors: [expectedErrorNoRole] }, + { code: '
collect
', errors: [expectedErrorNoRole] }, + { code: '
contribute
', errors: [expectedErrorNoRole] }, + { code: '
create
', errors: [expectedErrorNoRole] }, + { code: '
cut
', errors: [expectedErrorNoRole] }, + { code: '
decrease
', errors: [expectedErrorNoRole] }, + { code: '
delete
', errors: [expectedErrorNoRole] }, + { code: '
divide
', errors: [expectedErrorNoRole] }, + { code: '
drink
', errors: [expectedErrorNoRole] }, + { code: '
eat
', errors: [expectedErrorNoRole] }, + { code: '
earn
', errors: [expectedErrorNoRole] }, + { code: '
enable
', errors: [expectedErrorNoRole] }, + { code: '
enter
', errors: [expectedErrorNoRole] }, + { code: '
execute
', errors: [expectedErrorNoRole] }, + { code: '
exit
', errors: [expectedErrorNoRole] }, + { code: '
expand
', errors: [expectedErrorNoRole] }, + { code: '
explain
', errors: [expectedErrorNoRole] }, + { code: '
finish
', errors: [expectedErrorNoRole] }, + { code: '
forecast
', errors: [expectedErrorNoRole] }, + { code: '
fix
', errors: [expectedErrorNoRole] }, + { code: '
generate
', errors: [expectedErrorNoRole] }, + { code: '
handle
', errors: [expectedErrorNoRole] }, + { code: '
help
', errors: [expectedErrorNoRole] }, + { code: '
hire
', errors: [expectedErrorNoRole] }, + { code: '
hit
', errors: [expectedErrorNoRole] }, + { code: '
improve
', errors: [expectedErrorNoRole] }, + { code: '
increase
', errors: [expectedErrorNoRole] }, + { code: '
join
', errors: [expectedErrorNoRole] }, + { code: '
jump
', errors: [expectedErrorNoRole] }, + { code: '
leave
', errors: [expectedErrorNoRole] }, + { code: '
let\'/s
', errors: [expectedErrorNoRole] }, + { code: '
list
', errors: [expectedErrorNoRole] }, + { code: '
listen
', errors: [expectedErrorNoRole] }, + { code: '
magnify
', errors: [expectedErrorNoRole] }, + { code: '
make
', errors: [expectedErrorNoRole] }, + { code: '
manage
', errors: [expectedErrorNoRole] }, + { code: '
minimize
', errors: [expectedErrorNoRole] }, + { code: '
move
', errors: [expectedErrorNoRole] }, + { code: '
ok
', errors: [expectedErrorNoRole] }, + { code: '
open
', errors: [expectedErrorNoRole] }, + { code: '
organise
', errors: [expectedErrorNoRole] }, + { code: '
oversee
', errors: [expectedErrorNoRole] }, + { code: '
play
', errors: [expectedErrorNoRole] }, + { code: '
push
', errors: [expectedErrorNoRole] }, + { code: '
read
', errors: [expectedErrorNoRole] }, + { code: '
reduce
', errors: [expectedErrorNoRole] }, + { code: '
run
', errors: [expectedErrorNoRole] }, + { code: '
save
', errors: [expectedErrorNoRole] }, + { code: '
send
', errors: [expectedErrorNoRole] }, + { code: '
shout
', errors: [expectedErrorNoRole] }, + { code: '
sing
', errors: [expectedErrorNoRole] }, + { code: '
submit
', errors: [expectedErrorNoRole] }, + { code: '
support
', errors: [expectedErrorNoRole] }, + { code: '
talk
', errors: [expectedErrorNoRole] }, + { code: '
trim
', errors: [expectedErrorNoRole] }, + { code: '
visit
', errors: [expectedErrorNoRole] }, + { code: '
volunteer
', errors: [expectedErrorNoRole] }, + { code: '
vote
', errors: [expectedErrorNoRole] }, + { code: '
watch
', errors: [expectedErrorNoRole] }, + { code: '
win
', errors: [expectedErrorNoRole] }, + { code: '
write
', errors: [expectedErrorNoRole] }, + + // role is undefined + { code: '
advise
', errors: [expectedErrorNoRole] }, + { code: '
amplify
', errors: [expectedErrorNoRole] }, + { code: '
apply
', errors: [expectedErrorNoRole] }, + { code: '
arrange
', errors: [expectedErrorNoRole] }, + { code: '
ask
', errors: [expectedErrorNoRole] }, + { code: '
boost
', errors: [expectedErrorNoRole] }, + { code: '
build
', errors: [expectedErrorNoRole] }, + { code: '
call
', errors: [expectedErrorNoRole] }, + { code: '
click
', errors: [expectedErrorNoRole] }, + { code: '
close
', errors: [expectedErrorNoRole] }, + { code: '
commit
', errors: [expectedErrorNoRole] }, + { code: '
consult
', errors: [expectedErrorNoRole] }, + { code: '
compile
', errors: [expectedErrorNoRole] }, + { code: '
collect
', errors: [expectedErrorNoRole] }, + { code: '
contribute
', errors: [expectedErrorNoRole] }, + { code: '
create
', errors: [expectedErrorNoRole] }, + { code: '
cut
', errors: [expectedErrorNoRole] }, + { code: '
decrease
', errors: [expectedErrorNoRole] }, + { code: '
delete
', errors: [expectedErrorNoRole] }, + { code: '
divide
', errors: [expectedErrorNoRole] }, + { code: '
drink
', errors: [expectedErrorNoRole] }, + { code: '
eat
', errors: [expectedErrorNoRole] }, + { code: '
earn
', errors: [expectedErrorNoRole] }, + { code: '
enable
', errors: [expectedErrorNoRole] }, + { code: '
enter
', errors: [expectedErrorNoRole] }, + { code: '
execute
', errors: [expectedErrorNoRole] }, + { code: '
exit
', errors: [expectedErrorNoRole] }, + { code: '
expand
', errors: [expectedErrorNoRole] }, + { code: '
explain
', errors: [expectedErrorNoRole] }, + { code: '
finish
', errors: [expectedErrorNoRole] }, + { code: '
forecast
', errors: [expectedErrorNoRole] }, + { code: '
fix
', errors: [expectedErrorNoRole] }, + { code: '
generate
', errors: [expectedErrorNoRole] }, + { code: '
handle
', errors: [expectedErrorNoRole] }, + { code: '
help
', errors: [expectedErrorNoRole] }, + { code: '
hire
', errors: [expectedErrorNoRole] }, + { code: '
hit
', errors: [expectedErrorNoRole] }, + { code: '
improve
', errors: [expectedErrorNoRole] }, + { code: '
increase
', errors: [expectedErrorNoRole] }, + { code: '
join
', errors: [expectedErrorNoRole] }, + { code: '
jump
', errors: [expectedErrorNoRole] }, + { code: '
leave
', errors: [expectedErrorNoRole] }, + { code: '
let\'/s
', errors: [expectedErrorNoRole] }, + { code: '
list
', errors: [expectedErrorNoRole] }, + { code: '
listen
', errors: [expectedErrorNoRole] }, + { code: '
magnify
', errors: [expectedErrorNoRole] }, + { code: '
make
', errors: [expectedErrorNoRole] }, + { code: '
manage
', errors: [expectedErrorNoRole] }, + { code: '
minimize
', errors: [expectedErrorNoRole] }, + { code: '
move
', errors: [expectedErrorNoRole] }, + { code: '
ok
', errors: [expectedErrorNoRole] }, + { code: '
open
', errors: [expectedErrorNoRole] }, + { code: '
organise
', errors: [expectedErrorNoRole] }, + { code: '
oversee
', errors: [expectedErrorNoRole] }, + { code: '
play
', errors: [expectedErrorNoRole] }, + { code: '
push
', errors: [expectedErrorNoRole] }, + { code: '
read
', errors: [expectedErrorNoRole] }, + { code: '
reduce
', errors: [expectedErrorNoRole] }, + { code: '
run
', errors: [expectedErrorNoRole] }, + { code: '
save
', errors: [expectedErrorNoRole] }, + { code: '
send
', errors: [expectedErrorNoRole] }, + { code: '
shout
', errors: [expectedErrorNoRole] }, + { code: '
sing
', errors: [expectedErrorNoRole] }, + { code: '
submit
', errors: [expectedErrorNoRole] }, + { code: '
support
', errors: [expectedErrorNoRole] }, + { code: '
talk
', errors: [expectedErrorNoRole] }, + { code: '
trim
', errors: [expectedErrorNoRole] }, + { code: '
visit
', errors: [expectedErrorNoRole] }, + { code: '
volunteer
', errors: [expectedErrorNoRole] }, + { code: '
vote
', errors: [expectedErrorNoRole] }, + { code: '
watch
', errors: [expectedErrorNoRole] }, + { code: '
win
', errors: [expectedErrorNoRole] }, + { code: '
write
', errors: [expectedErrorNoRole] }, + + // role's value is an empty string + { code: '
advise
', errors: [expectedErrorNoRole] }, + { code: '
amplify
', errors: [expectedErrorNoRole] }, + { code: '
apply
', errors: [expectedErrorNoRole] }, + { code: '
arrange
', errors: [expectedErrorNoRole] }, + { code: '
ask
', errors: [expectedErrorNoRole] }, + { code: '
boost
', errors: [expectedErrorNoRole] }, + { code: '
build
', errors: [expectedErrorNoRole] }, + { code: '
call
', errors: [expectedErrorNoRole] }, + { code: '
click
', errors: [expectedErrorNoRole] }, + { code: '
close
', errors: [expectedErrorNoRole] }, + { code: '
commit
', errors: [expectedErrorNoRole] }, + { code: '
consult
', errors: [expectedErrorNoRole] }, + { code: '
compile
', errors: [expectedErrorNoRole] }, + { code: '
collect
', errors: [expectedErrorNoRole] }, + { code: '
contribute
', errors: [expectedErrorNoRole] }, + { code: '
create
', errors: [expectedErrorNoRole] }, + { code: '
cut
', errors: [expectedErrorNoRole] }, + { code: '
decrease
', errors: [expectedErrorNoRole] }, + { code: '
delete
', errors: [expectedErrorNoRole] }, + { code: '
divide
', errors: [expectedErrorNoRole] }, + { code: '
drink
', errors: [expectedErrorNoRole] }, + { code: '
eat
', errors: [expectedErrorNoRole] }, + { code: '
earn
', errors: [expectedErrorNoRole] }, + { code: '
enable
', errors: [expectedErrorNoRole] }, + { code: '
enter
', errors: [expectedErrorNoRole] }, + { code: '
execute
', errors: [expectedErrorNoRole] }, + { code: '
exit
', errors: [expectedErrorNoRole] }, + { code: '
expand
', errors: [expectedErrorNoRole] }, + { code: '
explain
', errors: [expectedErrorNoRole] }, + { code: '
finish
', errors: [expectedErrorNoRole] }, + { code: '
forecast
', errors: [expectedErrorNoRole] }, + { code: '
fix
', errors: [expectedErrorNoRole] }, + { code: '
generate
', errors: [expectedErrorNoRole] }, + { code: '
handle
', errors: [expectedErrorNoRole] }, + { code: '
help
', errors: [expectedErrorNoRole] }, + { code: '
hire
', errors: [expectedErrorNoRole] }, + { code: '
hit
', errors: [expectedErrorNoRole] }, + { code: '
improve
', errors: [expectedErrorNoRole] }, + { code: '
increase
', errors: [expectedErrorNoRole] }, + { code: '
join
', errors: [expectedErrorNoRole] }, + { code: '
jump
', errors: [expectedErrorNoRole] }, + { code: '
leave
', errors: [expectedErrorNoRole] }, + { code: '
let\'/s
', errors: [expectedErrorNoRole] }, + { code: '
list
', errors: [expectedErrorNoRole] }, + { code: '
listen
', errors: [expectedErrorNoRole] }, + { code: '
magnify
', errors: [expectedErrorNoRole] }, + { code: '
make
', errors: [expectedErrorNoRole] }, + { code: '
manage
', errors: [expectedErrorNoRole] }, + { code: '
minimize
', errors: [expectedErrorNoRole] }, + { code: '
move
', errors: [expectedErrorNoRole] }, + { code: '
ok
', errors: [expectedErrorNoRole] }, + { code: '
open
', errors: [expectedErrorNoRole] }, + { code: '
organise
', errors: [expectedErrorNoRole] }, + { code: '
oversee
', errors: [expectedErrorNoRole] }, + { code: '
play
', errors: [expectedErrorNoRole] }, + { code: '
push
', errors: [expectedErrorNoRole] }, + { code: '
read
', errors: [expectedErrorNoRole] }, + { code: '
reduce
', errors: [expectedErrorNoRole] }, + { code: '
run
', errors: [expectedErrorNoRole] }, + { code: '
save
', errors: [expectedErrorNoRole] }, + { code: '
send
', errors: [expectedErrorNoRole] }, + { code: '
shout
', errors: [expectedErrorNoRole] }, + { code: '
sing
', errors: [expectedErrorNoRole] }, + { code: '
submit
', errors: [expectedErrorNoRole] }, + { code: '
support
', errors: [expectedErrorNoRole] }, + { code: '
talk
', errors: [expectedErrorNoRole] }, + { code: '
trim
', errors: [expectedErrorNoRole] }, + { code: '
visit
', errors: [expectedErrorNoRole] }, + { code: '
volunteer
', errors: [expectedErrorNoRole] }, + { code: '
vote
', errors: [expectedErrorNoRole] }, + { code: '
watch
', errors: [expectedErrorNoRole] }, + { code: '
win
', errors: [expectedErrorNoRole] }, + { code: '
write
', errors: [expectedErrorNoRole] }, + + // role's value is not button + { code: '
advise
', errors: [expectedErrorNoRole] }, + { code: '
amplify
', errors: [expectedErrorNoRole] }, + { code: '
apply
', errors: [expectedErrorNoRole] }, + { code: '
arrange
', errors: [expectedErrorNoRole] }, + { code: '
ask
', errors: [expectedErrorNoRole] }, + { code: '
boost
', errors: [expectedErrorNoRole] }, + { code: '
build
', errors: [expectedErrorNoRole] }, + { code: '
call
', errors: [expectedErrorNoRole] }, + { code: '
click
', errors: [expectedErrorNoRole] }, + { code: '
close
', errors: [expectedErrorNoRole] }, + { code: '
commit
', errors: [expectedErrorNoRole] }, + { code: '
consult
', errors: [expectedErrorNoRole] }, + { code: '
compile
', errors: [expectedErrorNoRole] }, + { code: '
collect
', errors: [expectedErrorNoRole] }, + { code: '
contribute
', errors: [expectedErrorNoRole] }, + { code: '
create
', errors: [expectedErrorNoRole] }, + { code: '
cut
', errors: [expectedErrorNoRole] }, + { code: '
decrease
', errors: [expectedErrorNoRole] }, + { code: '
delete
', errors: [expectedErrorNoRole] }, + { code: '
divide
', errors: [expectedErrorNoRole] }, + { code: '
drink
', errors: [expectedErrorNoRole] }, + { code: '
eat
', errors: [expectedErrorNoRole] }, + { code: '
earn
', errors: [expectedErrorNoRole] }, + { code: '
enable
', errors: [expectedErrorNoRole] }, + { code: '
enter
', errors: [expectedErrorNoRole] }, + { code: '
execute
', errors: [expectedErrorNoRole] }, + { code: '
exit
', errors: [expectedErrorNoRole] }, + { code: '
expand
', errors: [expectedErrorNoRole] }, + { code: '
explain
', errors: [expectedErrorNoRole] }, + { code: '
finish
', errors: [expectedErrorNoRole] }, + { code: '
forecast
', errors: [expectedErrorNoRole] }, + { code: '
fix
', errors: [expectedErrorNoRole] }, + { code: '
generate
', errors: [expectedErrorNoRole] }, + { code: '
handle
', errors: [expectedErrorNoRole] }, + { code: '
help
', errors: [expectedErrorNoRole] }, + { code: '
hire
', errors: [expectedErrorNoRole] }, + { code: '
hit
', errors: [expectedErrorNoRole] }, + { code: '
improve
', errors: [expectedErrorNoRole] }, + { code: '
increase
', errors: [expectedErrorNoRole] }, + { code: '
join
', errors: [expectedErrorNoRole] }, + { code: '
jump
', errors: [expectedErrorNoRole] }, + { code: '
leave
', errors: [expectedErrorNoRole] }, + { code: '
let\'/s
', errors: [expectedErrorNoRole] }, + { code: '
list
', errors: [expectedErrorNoRole] }, + { code: '
listen
', errors: [expectedErrorNoRole] }, + { code: '
magnify
', errors: [expectedErrorNoRole] }, + { code: '
make
', errors: [expectedErrorNoRole] }, + { code: '
manage
', errors: [expectedErrorNoRole] }, + { code: '
minimize
', errors: [expectedErrorNoRole] }, + { code: '
move
', errors: [expectedErrorNoRole] }, + { code: '
ok
', errors: [expectedErrorNoRole] }, + { code: '
open
', errors: [expectedErrorNoRole] }, + { code: '
organise
', errors: [expectedErrorNoRole] }, + { code: '
oversee
', errors: [expectedErrorNoRole] }, + { code: '
play
', errors: [expectedErrorNoRole] }, + { code: '
push
', errors: [expectedErrorNoRole] }, + { code: '
read
', errors: [expectedErrorNoRole] }, + { code: '
reduce
', errors: [expectedErrorNoRole] }, + { code: '
run
', errors: [expectedErrorNoRole] }, + { code: '
save
', errors: [expectedErrorNoRole] }, + { code: '
send
', errors: [expectedErrorNoRole] }, + { code: '
shout
', errors: [expectedErrorNoRole] }, + { code: '
sing
', errors: [expectedErrorNoRole] }, + { code: '
submit
', errors: [expectedErrorNoRole] }, + { code: '
support
', errors: [expectedErrorNoRole] }, + { code: '
talk
', errors: [expectedErrorNoRole] }, + { code: '
trim
', errors: [expectedErrorNoRole] }, + { code: '
visit
', errors: [expectedErrorNoRole] }, + { code: '
volunteer
', errors: [expectedErrorNoRole] }, + { code: '
vote
', errors: [expectedErrorNoRole] }, + { code: '
watch
', errors: [expectedErrorNoRole] }, + { code: '
win
', errors: [expectedErrorNoRole] }, + { code: '
write
', errors: [expectedErrorNoRole] }, + + // tabindex is missing + { code: '
advise
', errors: [expectedErrorNoTabindex] }, + { code: '
amplify
', errors: [expectedErrorNoTabindex] }, + { code: '
apply
', errors: [expectedErrorNoTabindex] }, + { code: '
arrange
', errors: [expectedErrorNoTabindex] }, + { code: '
ask
', errors: [expectedErrorNoTabindex] }, + { code: '
boost
', errors: [expectedErrorNoTabindex] }, + { code: '
build
', errors: [expectedErrorNoTabindex] }, + { code: '
call
', errors: [expectedErrorNoTabindex] }, + { code: '
click
', errors: [expectedErrorNoTabindex] }, + { code: '
close
', errors: [expectedErrorNoTabindex] }, + { code: '
commit
', errors: [expectedErrorNoTabindex] }, + { code: '
consult
', errors: [expectedErrorNoTabindex] }, + { code: '
compile
', errors: [expectedErrorNoTabindex] }, + { code: '
collect
', errors: [expectedErrorNoTabindex] }, + { code: '
contribute
', errors: [expectedErrorNoTabindex] }, + { code: '
create
', errors: [expectedErrorNoTabindex] }, + { code: '
cut
', errors: [expectedErrorNoTabindex] }, + { code: '
decrease
', errors: [expectedErrorNoTabindex] }, + { code: '
delete
', errors: [expectedErrorNoTabindex] }, + { code: '
divide
', errors: [expectedErrorNoTabindex] }, + { code: '
drink
', errors: [expectedErrorNoTabindex] }, + { code: '
eat
', errors: [expectedErrorNoTabindex] }, + { code: '
earn
', errors: [expectedErrorNoTabindex] }, + { code: '
enable
', errors: [expectedErrorNoTabindex] }, + { code: '
enter
', errors: [expectedErrorNoTabindex] }, + { code: '
execute
', errors: [expectedErrorNoTabindex] }, + { code: '
exit
', errors: [expectedErrorNoTabindex] }, + { code: '
expand
', errors: [expectedErrorNoTabindex] }, + { code: '
explain
', errors: [expectedErrorNoTabindex] }, + { code: '
finish
', errors: [expectedErrorNoTabindex] }, + { code: '
forecast
', errors: [expectedErrorNoTabindex] }, + { code: '
fix
', errors: [expectedErrorNoTabindex] }, + { code: '
generate
', errors: [expectedErrorNoTabindex] }, + { code: '
handle
', errors: [expectedErrorNoTabindex] }, + { code: '
help
', errors: [expectedErrorNoTabindex] }, + { code: '
hire
', errors: [expectedErrorNoTabindex] }, + { code: '
hit
', errors: [expectedErrorNoTabindex] }, + { code: '
improve
', errors: [expectedErrorNoTabindex] }, + { code: '
increase
', errors: [expectedErrorNoTabindex] }, + { code: '
join
', errors: [expectedErrorNoTabindex] }, + { code: '
jump
', errors: [expectedErrorNoTabindex] }, + { code: '
leave
', errors: [expectedErrorNoTabindex] }, + { code: '
let\'/s
', errors: [expectedErrorNoTabindex] }, + { code: '
list
', errors: [expectedErrorNoTabindex] }, + { code: '
listen
', errors: [expectedErrorNoTabindex] }, + { code: '
magnify
', errors: [expectedErrorNoTabindex] }, + { code: '
make
', errors: [expectedErrorNoTabindex] }, + { code: '
manage
', errors: [expectedErrorNoTabindex] }, + { code: '
minimize
', errors: [expectedErrorNoTabindex] }, + { code: '
move
', errors: [expectedErrorNoTabindex] }, + { code: '
ok
', errors: [expectedErrorNoTabindex] }, + { code: '
open
', errors: [expectedErrorNoTabindex] }, + { code: '
organise
', errors: [expectedErrorNoTabindex] }, + { code: '
oversee
', errors: [expectedErrorNoTabindex] }, + { code: '
play
', errors: [expectedErrorNoTabindex] }, + { code: '
push
', errors: [expectedErrorNoTabindex] }, + { code: '
read
', errors: [expectedErrorNoTabindex] }, + { code: '
reduce
', errors: [expectedErrorNoTabindex] }, + { code: '
run
', errors: [expectedErrorNoTabindex] }, + { code: '
save
', errors: [expectedErrorNoTabindex] }, + { code: '
send
', errors: [expectedErrorNoTabindex] }, + { code: '
shout
', errors: [expectedErrorNoTabindex] }, + { code: '
sing
', errors: [expectedErrorNoTabindex] }, + { code: '
submit
', errors: [expectedErrorNoTabindex] }, + { code: '
support
', errors: [expectedErrorNoTabindex] }, + { code: '
talk
', errors: [expectedErrorNoTabindex] }, + { code: '
trim
', errors: [expectedErrorNoTabindex] }, + { code: '
visit
', errors: [expectedErrorNoTabindex] }, + { code: '
volunteer
', errors: [expectedErrorNoTabindex] }, + { code: '
vote
', errors: [expectedErrorNoTabindex] }, + { code: '
watch
', errors: [expectedErrorNoTabindex] }, + { code: '
win
', errors: [expectedErrorNoTabindex] }, + { code: '
write
', errors: [expectedErrorNoTabindex] }, + + // tabindex is undefined + { code: '
advise
', errors: [expectedErrorNoTabindex] }, + { code: '
amplify
', errors: [expectedErrorNoTabindex] }, + { code: '
apply
', errors: [expectedErrorNoTabindex] }, + { code: '
arrange
', errors: [expectedErrorNoTabindex] }, + { code: '
ask
', errors: [expectedErrorNoTabindex] }, + { code: '
boost
', errors: [expectedErrorNoTabindex] }, + { code: '
build
', errors: [expectedErrorNoTabindex] }, + { code: '
call
', errors: [expectedErrorNoTabindex] }, + { code: '
click
', errors: [expectedErrorNoTabindex] }, + { code: '
close
', errors: [expectedErrorNoTabindex] }, + { code: '
commit
', errors: [expectedErrorNoTabindex] }, + { code: '
consult
', errors: [expectedErrorNoTabindex] }, + { code: '
compile
', errors: [expectedErrorNoTabindex] }, + { code: '
collect
', errors: [expectedErrorNoTabindex] }, + { code: '
contribute
', errors: [expectedErrorNoTabindex] }, + { code: '
create
', errors: [expectedErrorNoTabindex] }, + { code: '
cut
', errors: [expectedErrorNoTabindex] }, + { code: '
decrease
', errors: [expectedErrorNoTabindex] }, + { code: '
delete
', errors: [expectedErrorNoTabindex] }, + { code: '
divide
', errors: [expectedErrorNoTabindex] }, + { code: '
drink
', errors: [expectedErrorNoTabindex] }, + { code: '
eat
', errors: [expectedErrorNoTabindex] }, + { code: '
earn
', errors: [expectedErrorNoTabindex] }, + { code: '
enable
', errors: [expectedErrorNoTabindex] }, + { code: '
enter
', errors: [expectedErrorNoTabindex] }, + { code: '
execute
', errors: [expectedErrorNoTabindex] }, + { code: '
exit
', errors: [expectedErrorNoTabindex] }, + { code: '
expand
', errors: [expectedErrorNoTabindex] }, + { code: '
explain
', errors: [expectedErrorNoTabindex] }, + { code: '
finish
', errors: [expectedErrorNoTabindex] }, + { code: '
forecast
', errors: [expectedErrorNoTabindex] }, + { code: '
fix
', errors: [expectedErrorNoTabindex] }, + { code: '
generate
', errors: [expectedErrorNoTabindex] }, + { code: '
handle
', errors: [expectedErrorNoTabindex] }, + { code: '
help
', errors: [expectedErrorNoTabindex] }, + { code: '
hire
', errors: [expectedErrorNoTabindex] }, + { code: '
hit
', errors: [expectedErrorNoTabindex] }, + { code: '
improve
', errors: [expectedErrorNoTabindex] }, + { code: '
increase
', errors: [expectedErrorNoTabindex] }, + { code: '
join
', errors: [expectedErrorNoTabindex] }, + { code: '
jump
', errors: [expectedErrorNoTabindex] }, + { code: '
leave
', errors: [expectedErrorNoTabindex] }, + { code: '
let\'/s
', errors: [expectedErrorNoTabindex] }, + { code: '
list
', errors: [expectedErrorNoTabindex] }, + { code: '
listen
', errors: [expectedErrorNoTabindex] }, + { code: '
magnify
', errors: [expectedErrorNoTabindex] }, + { code: '
make
', errors: [expectedErrorNoTabindex] }, + { code: '
manage
', errors: [expectedErrorNoTabindex] }, + { code: '
minimize
', errors: [expectedErrorNoTabindex] }, + { code: '
move
', errors: [expectedErrorNoTabindex] }, + { code: '
ok
', errors: [expectedErrorNoTabindex] }, + { code: '
open
', errors: [expectedErrorNoTabindex] }, + { code: '
organise
', errors: [expectedErrorNoTabindex] }, + { code: '
oversee
', errors: [expectedErrorNoTabindex] }, + { code: '
play
', errors: [expectedErrorNoTabindex] }, + { code: '
push
', errors: [expectedErrorNoTabindex] }, + { code: '
read
', errors: [expectedErrorNoTabindex] }, + { code: '
reduce
', errors: [expectedErrorNoTabindex] }, + { code: '
run
', errors: [expectedErrorNoTabindex] }, + { code: '
save
', errors: [expectedErrorNoTabindex] }, + { code: '
send
', errors: [expectedErrorNoTabindex] }, + { code: '
shout
', errors: [expectedErrorNoTabindex] }, + { code: '
sing
', errors: [expectedErrorNoTabindex] }, + { code: '
submit
', errors: [expectedErrorNoTabindex] }, + { code: '
support
', errors: [expectedErrorNoTabindex] }, + { code: '
talk
', errors: [expectedErrorNoTabindex] }, + { code: '
trim
', errors: [expectedErrorNoTabindex] }, + { code: '
visit
', errors: [expectedErrorNoTabindex] }, + { code: '
volunteer
', errors: [expectedErrorNoTabindex] }, + { code: '
vote
', errors: [expectedErrorNoTabindex] }, + { code: '
watch
', errors: [expectedErrorNoTabindex] }, + { code: '
win
', errors: [expectedErrorNoTabindex] }, + { code: '
write
', errors: [expectedErrorNoTabindex] }, + + // tabindex's value is an empty string + { code: '
advise
', errors: [expectedErrorNoTabindex] }, + { code: '
amplify
', errors: [expectedErrorNoTabindex] }, + { code: '
apply
', errors: [expectedErrorNoTabindex] }, + { code: '
arrange
', errors: [expectedErrorNoTabindex] }, + { code: '
ask
', errors: [expectedErrorNoTabindex] }, + { code: '
boost
', errors: [expectedErrorNoTabindex] }, + { code: '
build
', errors: [expectedErrorNoTabindex] }, + { code: '
call
', errors: [expectedErrorNoTabindex] }, + { code: '
click
', errors: [expectedErrorNoTabindex] }, + { code: '
close
', errors: [expectedErrorNoTabindex] }, + { code: '
commit
', errors: [expectedErrorNoTabindex] }, + { code: '
consult
', errors: [expectedErrorNoTabindex] }, + { code: '
compile
', errors: [expectedErrorNoTabindex] }, + { code: '
collect
', errors: [expectedErrorNoTabindex] }, + { code: '
contribute
', errors: [expectedErrorNoTabindex] }, + { code: '
create
', errors: [expectedErrorNoTabindex] }, + { code: '
cut
', errors: [expectedErrorNoTabindex] }, + { code: '
decrease
', errors: [expectedErrorNoTabindex] }, + { code: '
delete
', errors: [expectedErrorNoTabindex] }, + { code: '
divide
', errors: [expectedErrorNoTabindex] }, + { code: '
drink
', errors: [expectedErrorNoTabindex] }, + { code: '
eat
', errors: [expectedErrorNoTabindex] }, + { code: '
earn
', errors: [expectedErrorNoTabindex] }, + { code: '
enable
', errors: [expectedErrorNoTabindex] }, + { code: '
enter
', errors: [expectedErrorNoTabindex] }, + { code: '
execute
', errors: [expectedErrorNoTabindex] }, + { code: '
exit
', errors: [expectedErrorNoTabindex] }, + { code: '
expand
', errors: [expectedErrorNoTabindex] }, + { code: '
explain
', errors: [expectedErrorNoTabindex] }, + { code: '
finish
', errors: [expectedErrorNoTabindex] }, + { code: '
forecast
', errors: [expectedErrorNoTabindex] }, + { code: '
fix
', errors: [expectedErrorNoTabindex] }, + { code: '
generate
', errors: [expectedErrorNoTabindex] }, + { code: '
handle
', errors: [expectedErrorNoTabindex] }, + { code: '
help
', errors: [expectedErrorNoTabindex] }, + { code: '
hire
', errors: [expectedErrorNoTabindex] }, + { code: '
hit
', errors: [expectedErrorNoTabindex] }, + { code: '
improve
', errors: [expectedErrorNoTabindex] }, + { code: '
increase
', errors: [expectedErrorNoTabindex] }, + { code: '
join
', errors: [expectedErrorNoTabindex] }, + { code: '
jump
', errors: [expectedErrorNoTabindex] }, + { code: '
leave
', errors: [expectedErrorNoTabindex] }, + { code: '
let\'/s
', errors: [expectedErrorNoTabindex] }, + { code: '
list
', errors: [expectedErrorNoTabindex] }, + { code: '
listen
', errors: [expectedErrorNoTabindex] }, + { code: '
magnify
', errors: [expectedErrorNoTabindex] }, + { code: '
make
', errors: [expectedErrorNoTabindex] }, + { code: '
manage
', errors: [expectedErrorNoTabindex] }, + { code: '
minimize
', errors: [expectedErrorNoTabindex] }, + { code: '
move
', errors: [expectedErrorNoTabindex] }, + { code: '
ok
', errors: [expectedErrorNoTabindex] }, + { code: '
open
', errors: [expectedErrorNoTabindex] }, + { code: '
organise
', errors: [expectedErrorNoTabindex] }, + { code: '
oversee
', errors: [expectedErrorNoTabindex] }, + { code: '
play
', errors: [expectedErrorNoTabindex] }, + { code: '
push
', errors: [expectedErrorNoTabindex] }, + { code: '
read
', errors: [expectedErrorNoTabindex] }, + { code: '
reduce
', errors: [expectedErrorNoTabindex] }, + { code: '
run
', errors: [expectedErrorNoTabindex] }, + { code: '
save
', errors: [expectedErrorNoTabindex] }, + { code: '
send
', errors: [expectedErrorNoTabindex] }, + { code: '
shout
', errors: [expectedErrorNoTabindex] }, + { code: '
sing
', errors: [expectedErrorNoTabindex] }, + { code: '
submit
', errors: [expectedErrorNoTabindex] }, + { code: '
support
', errors: [expectedErrorNoTabindex] }, + { code: '
talk
', errors: [expectedErrorNoTabindex] }, + { code: '
trim
', errors: [expectedErrorNoTabindex] }, + { code: '
visit
', errors: [expectedErrorNoTabindex] }, + { code: '
volunteer
', errors: [expectedErrorNoTabindex] }, + { code: '
vote
', errors: [expectedErrorNoTabindex] }, + { code: '
watch
', errors: [expectedErrorNoTabindex] }, + { code: '
win
', errors: [expectedErrorNoTabindex] }, + { code: '
write
', errors: [expectedErrorNoTabindex] }, + + // tabindex's value is -1 + { code: '
advise
', errors: [expectedErrorNoTabindex] }, + { code: '
amplify
', errors: [expectedErrorNoTabindex] }, + { code: '
apply
', errors: [expectedErrorNoTabindex] }, + { code: '
arrange
', errors: [expectedErrorNoTabindex] }, + { code: '
ask
', errors: [expectedErrorNoTabindex] }, + { code: '
boost
', errors: [expectedErrorNoTabindex] }, + { code: '
build
', errors: [expectedErrorNoTabindex] }, + { code: '
call
', errors: [expectedErrorNoTabindex] }, + { code: '
click
', errors: [expectedErrorNoTabindex] }, + { code: '
close
', errors: [expectedErrorNoTabindex] }, + { code: '
commit
', errors: [expectedErrorNoTabindex] }, + { code: '
consult
', errors: [expectedErrorNoTabindex] }, + { code: '
compile
', errors: [expectedErrorNoTabindex] }, + { code: '
collect
', errors: [expectedErrorNoTabindex] }, + { code: '
contribute
', errors: [expectedErrorNoTabindex] }, + { code: '
create
', errors: [expectedErrorNoTabindex] }, + { code: '
cut
', errors: [expectedErrorNoTabindex] }, + { code: '
decrease
', errors: [expectedErrorNoTabindex] }, + { code: '
delete
', errors: [expectedErrorNoTabindex] }, + { code: '
divide
', errors: [expectedErrorNoTabindex] }, + { code: '
drink
', errors: [expectedErrorNoTabindex] }, + { code: '
eat
', errors: [expectedErrorNoTabindex] }, + { code: '
earn
', errors: [expectedErrorNoTabindex] }, + { code: '
enable
', errors: [expectedErrorNoTabindex] }, + { code: '
enter
', errors: [expectedErrorNoTabindex] }, + { code: '
execute
', errors: [expectedErrorNoTabindex] }, + { code: '
exit
', errors: [expectedErrorNoTabindex] }, + { code: '
expand
', errors: [expectedErrorNoTabindex] }, + { code: '
explain
', errors: [expectedErrorNoTabindex] }, + { code: '
finish
', errors: [expectedErrorNoTabindex] }, + { code: '
forecast
', errors: [expectedErrorNoTabindex] }, + { code: '
fix
', errors: [expectedErrorNoTabindex] }, + { code: '
generate
', errors: [expectedErrorNoTabindex] }, + { code: '
handle
', errors: [expectedErrorNoTabindex] }, + { code: '
help
', errors: [expectedErrorNoTabindex] }, + { code: '
hire
', errors: [expectedErrorNoTabindex] }, + { code: '
hit
', errors: [expectedErrorNoTabindex] }, + { code: '
improve
', errors: [expectedErrorNoTabindex] }, + { code: '
increase
', errors: [expectedErrorNoTabindex] }, + { code: '
join
', errors: [expectedErrorNoTabindex] }, + { code: '
jump
', errors: [expectedErrorNoTabindex] }, + { code: '
leave
', errors: [expectedErrorNoTabindex] }, + { code: '
let\'/s
', errors: [expectedErrorNoTabindex] }, + { code: '
list
', errors: [expectedErrorNoTabindex] }, + { code: '
listen
', errors: [expectedErrorNoTabindex] }, + { code: '
magnify
', errors: [expectedErrorNoTabindex] }, + { code: '
make
', errors: [expectedErrorNoTabindex] }, + { code: '
manage
', errors: [expectedErrorNoTabindex] }, + { code: '
minimize
', errors: [expectedErrorNoTabindex] }, + { code: '
move
', errors: [expectedErrorNoTabindex] }, + { code: '
ok
', errors: [expectedErrorNoTabindex] }, + { code: '
open
', errors: [expectedErrorNoTabindex] }, + { code: '
organise
', errors: [expectedErrorNoTabindex] }, + { code: '
oversee
', errors: [expectedErrorNoTabindex] }, + { code: '
play
', errors: [expectedErrorNoTabindex] }, + { code: '
push
', errors: [expectedErrorNoTabindex] }, + { code: '
read
', errors: [expectedErrorNoTabindex] }, + { code: '
reduce
', errors: [expectedErrorNoTabindex] }, + { code: '
run
', errors: [expectedErrorNoTabindex] }, + { code: '
save
', errors: [expectedErrorNoTabindex] }, + { code: '
send
', errors: [expectedErrorNoTabindex] }, + { code: '
shout
', errors: [expectedErrorNoTabindex] }, + { code: '
sing
', errors: [expectedErrorNoTabindex] }, + { code: '
submit
', errors: [expectedErrorNoTabindex] }, + { code: '
support
', errors: [expectedErrorNoTabindex] }, + { code: '
talk
', errors: [expectedErrorNoTabindex] }, + { code: '
trim
', errors: [expectedErrorNoTabindex] }, + { code: '
visit
', errors: [expectedErrorNoTabindex] }, + { code: '
volunteer
', errors: [expectedErrorNoTabindex] }, + { code: '
vote
', errors: [expectedErrorNoTabindex] }, + { code: '
watch
', errors: [expectedErrorNoTabindex] }, + { code: '
win
', errors: [expectedErrorNoTabindex] }, + { code: '
write
', errors: [expectedErrorNoTabindex] }, + + // tabindex's value is 1 + { code: '
advise
', errors: [expectedErrorNoTabindex] }, + { code: '
amplify
', errors: [expectedErrorNoTabindex] }, + { code: '
apply
', errors: [expectedErrorNoTabindex] }, + { code: '
arrange
', errors: [expectedErrorNoTabindex] }, + { code: '
ask
', errors: [expectedErrorNoTabindex] }, + { code: '
boost
', errors: [expectedErrorNoTabindex] }, + { code: '
build
', errors: [expectedErrorNoTabindex] }, + { code: '
call
', errors: [expectedErrorNoTabindex] }, + { code: '
click
', errors: [expectedErrorNoTabindex] }, + { code: '
close
', errors: [expectedErrorNoTabindex] }, + { code: '
commit
', errors: [expectedErrorNoTabindex] }, + { code: '
consult
', errors: [expectedErrorNoTabindex] }, + { code: '
compile
', errors: [expectedErrorNoTabindex] }, + { code: '
collect
', errors: [expectedErrorNoTabindex] }, + { code: '
contribute
', errors: [expectedErrorNoTabindex] }, + { code: '
create
', errors: [expectedErrorNoTabindex] }, + { code: '
cut
', errors: [expectedErrorNoTabindex] }, + { code: '
decrease
', errors: [expectedErrorNoTabindex] }, + { code: '
delete
', errors: [expectedErrorNoTabindex] }, + { code: '
divide
', errors: [expectedErrorNoTabindex] }, + { code: '
drink
', errors: [expectedErrorNoTabindex] }, + { code: '
eat
', errors: [expectedErrorNoTabindex] }, + { code: '
earn
', errors: [expectedErrorNoTabindex] }, + { code: '
enable
', errors: [expectedErrorNoTabindex] }, + { code: '
enter
', errors: [expectedErrorNoTabindex] }, + { code: '
execute
', errors: [expectedErrorNoTabindex] }, + { code: '
exit
', errors: [expectedErrorNoTabindex] }, + { code: '
expand
', errors: [expectedErrorNoTabindex] }, + { code: '
explain
', errors: [expectedErrorNoTabindex] }, + { code: '
finish
', errors: [expectedErrorNoTabindex] }, + { code: '
forecast
', errors: [expectedErrorNoTabindex] }, + { code: '
fix
', errors: [expectedErrorNoTabindex] }, + { code: '
generate
', errors: [expectedErrorNoTabindex] }, + { code: '
handle
', errors: [expectedErrorNoTabindex] }, + { code: '
help
', errors: [expectedErrorNoTabindex] }, + { code: '
hire
', errors: [expectedErrorNoTabindex] }, + { code: '
hit
', errors: [expectedErrorNoTabindex] }, + { code: '
improve
', errors: [expectedErrorNoTabindex] }, + { code: '
increase
', errors: [expectedErrorNoTabindex] }, + { code: '
join
', errors: [expectedErrorNoTabindex] }, + { code: '
jump
', errors: [expectedErrorNoTabindex] }, + { code: '
leave
', errors: [expectedErrorNoTabindex] }, + { code: '
let\'/s
', errors: [expectedErrorNoTabindex] }, + { code: '
list
', errors: [expectedErrorNoTabindex] }, + { code: '
listen
', errors: [expectedErrorNoTabindex] }, + { code: '
magnify
', errors: [expectedErrorNoTabindex] }, + { code: '
make
', errors: [expectedErrorNoTabindex] }, + { code: '
manage
', errors: [expectedErrorNoTabindex] }, + { code: '
minimize
', errors: [expectedErrorNoTabindex] }, + { code: '
move
', errors: [expectedErrorNoTabindex] }, + { code: '
ok
', errors: [expectedErrorNoTabindex] }, + { code: '
open
', errors: [expectedErrorNoTabindex] }, + { code: '
organise
', errors: [expectedErrorNoTabindex] }, + { code: '
oversee
', errors: [expectedErrorNoTabindex] }, + { code: '
play
', errors: [expectedErrorNoTabindex] }, + { code: '
push
', errors: [expectedErrorNoTabindex] }, + { code: '
read
', errors: [expectedErrorNoTabindex] }, + { code: '
reduce
', errors: [expectedErrorNoTabindex] }, + { code: '
run
', errors: [expectedErrorNoTabindex] }, + { code: '
save
', errors: [expectedErrorNoTabindex] }, + { code: '
send
', errors: [expectedErrorNoTabindex] }, + { code: '
shout
', errors: [expectedErrorNoTabindex] }, + { code: '
sing
', errors: [expectedErrorNoTabindex] }, + { code: '
submit
', errors: [expectedErrorNoTabindex] }, + { code: '
support
', errors: [expectedErrorNoTabindex] }, + { code: '
talk
', errors: [expectedErrorNoTabindex] }, + { code: '
trim
', errors: [expectedErrorNoTabindex] }, + { code: '
visit
', errors: [expectedErrorNoTabindex] }, + { code: '
volunteer
', errors: [expectedErrorNoTabindex] }, + { code: '
vote
', errors: [expectedErrorNoTabindex] }, + { code: '
watch
', errors: [expectedErrorNoTabindex] }, + { code: '
win
', errors: [expectedErrorNoTabindex] }, + { code: '
write
', errors: [expectedErrorNoTabindex] }, + + // CUSTOM ELEMENT TESTS FOR COMPONENTS OPTION + // If custom element is an action word then the text within it should also be an action word: + { code: 'orange', errors: [expectedErrorCustom], options: components }, + + // the below tests are the same as above for invalid + // the only difference is that instead of div I check for custom tag + + // action words within div that missing the two attributes + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // undefined attributes + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // wrong attributes values -1 and navigation + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // wrong attributes values 1 and main + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // wrong attribute value: contentinfo and missing attribute: tabindex + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // wrong attribute value: tabindex="-1" and missing attribute: role="button" + { code: ' advise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' amplify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' apply', errors: [expectedErrorNoAttributes], options: components }, + { code: ' arrange', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ask', errors: [expectedErrorNoAttributes], options: components }, + { code: ' boost', errors: [expectedErrorNoAttributes], options: components }, + { code: ' build', errors: [expectedErrorNoAttributes], options: components }, + { code: ' call', errors: [expectedErrorNoAttributes], options: components }, + { code: ' click', errors: [expectedErrorNoAttributes], options: components }, + { code: ' close', errors: [expectedErrorNoAttributes], options: components }, + { code: ' commit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' consult', errors: [expectedErrorNoAttributes], options: components }, + { code: ' compile', errors: [expectedErrorNoAttributes], options: components }, + { code: ' collect', errors: [expectedErrorNoAttributes], options: components }, + { code: ' contribute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' create', errors: [expectedErrorNoAttributes], options: components }, + { code: ' cut', errors: [expectedErrorNoAttributes], options: components }, + { code: ' decrease', errors: [expectedErrorNoAttributes], options: components }, + { code: ' delete', errors: [expectedErrorNoAttributes], options: components }, + { code: ' divide', errors: [expectedErrorNoAttributes], options: components }, + { code: ' drink', errors: [expectedErrorNoAttributes], options: components }, + { code: ' eat', errors: [expectedErrorNoAttributes], options: components }, + { code: ' earn', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enable', errors: [expectedErrorNoAttributes], options: components }, + { code: ' enter', errors: [expectedErrorNoAttributes], options: components }, + { code: ' execute', errors: [expectedErrorNoAttributes], options: components }, + { code: ' exit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' expand', errors: [expectedErrorNoAttributes], options: components }, + { code: ' explain', errors: [expectedErrorNoAttributes], options: components }, + { code: ' finish', errors: [expectedErrorNoAttributes], options: components }, + { code: ' forecast', errors: [expectedErrorNoAttributes], options: components }, + { code: ' fix', errors: [expectedErrorNoAttributes], options: components }, + { code: ' generate', errors: [expectedErrorNoAttributes], options: components }, + { code: ' handle', errors: [expectedErrorNoAttributes], options: components }, + { code: ' help', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hire', errors: [expectedErrorNoAttributes], options: components }, + { code: ' hit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' improve', errors: [expectedErrorNoAttributes], options: components }, + { code: ' increase', errors: [expectedErrorNoAttributes], options: components }, + { code: ' join', errors: [expectedErrorNoAttributes], options: components }, + { code: ' jump', errors: [expectedErrorNoAttributes], options: components }, + { code: ' leave', errors: [expectedErrorNoAttributes], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoAttributes], options: components }, + { code: ' list', errors: [expectedErrorNoAttributes], options: components }, + { code: ' listen', errors: [expectedErrorNoAttributes], options: components }, + { code: ' magnify', errors: [expectedErrorNoAttributes], options: components }, + { code: ' make', errors: [expectedErrorNoAttributes], options: components }, + { code: ' manage', errors: [expectedErrorNoAttributes], options: components }, + { code: ' minimize', errors: [expectedErrorNoAttributes], options: components }, + { code: ' move', errors: [expectedErrorNoAttributes], options: components }, + { code: ' ok', errors: [expectedErrorNoAttributes], options: components }, + { code: ' open', errors: [expectedErrorNoAttributes], options: components }, + { code: ' organise', errors: [expectedErrorNoAttributes], options: components }, + { code: ' oversee', errors: [expectedErrorNoAttributes], options: components }, + { code: ' play', errors: [expectedErrorNoAttributes], options: components }, + { code: ' push', errors: [expectedErrorNoAttributes], options: components }, + { code: ' read', errors: [expectedErrorNoAttributes], options: components }, + { code: ' reduce', errors: [expectedErrorNoAttributes], options: components }, + { code: ' run', errors: [expectedErrorNoAttributes], options: components }, + { code: ' save', errors: [expectedErrorNoAttributes], options: components }, + { code: ' send', errors: [expectedErrorNoAttributes], options: components }, + { code: ' shout', errors: [expectedErrorNoAttributes], options: components }, + { code: ' sing', errors: [expectedErrorNoAttributes], options: components }, + { code: ' submit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' support', errors: [expectedErrorNoAttributes], options: components }, + { code: ' talk', errors: [expectedErrorNoAttributes], options: components }, + { code: ' trim', errors: [expectedErrorNoAttributes], options: components }, + { code: ' visit', errors: [expectedErrorNoAttributes], options: components }, + { code: ' volunteer', errors: [expectedErrorNoAttributes], options: components }, + { code: ' vote', errors: [expectedErrorNoAttributes], options: components }, + { code: ' watch', errors: [expectedErrorNoAttributes], options: components }, + { code: ' win', errors: [expectedErrorNoAttributes], options: components }, + { code: ' write', errors: [expectedErrorNoAttributes], options: components }, + + // role is missing + { code: ' advise', errors: [expectedErrorNoRole], options: components }, + { code: ' amplify', errors: [expectedErrorNoRole], options: components }, + { code: ' apply', errors: [expectedErrorNoRole], options: components }, + { code: ' arrange', errors: [expectedErrorNoRole], options: components }, + { code: ' ask', errors: [expectedErrorNoRole], options: components }, + { code: ' boost', errors: [expectedErrorNoRole], options: components }, + { code: ' build', errors: [expectedErrorNoRole], options: components }, + { code: ' call', errors: [expectedErrorNoRole], options: components }, + { code: ' click', errors: [expectedErrorNoRole], options: components }, + { code: ' close', errors: [expectedErrorNoRole], options: components }, + { code: ' commit', errors: [expectedErrorNoRole], options: components }, + { code: ' consult', errors: [expectedErrorNoRole], options: components }, + { code: ' compile', errors: [expectedErrorNoRole], options: components }, + { code: ' collect', errors: [expectedErrorNoRole], options: components }, + { code: ' contribute', errors: [expectedErrorNoRole], options: components }, + { code: ' create', errors: [expectedErrorNoRole], options: components }, + { code: ' cut', errors: [expectedErrorNoRole], options: components }, + { code: ' decrease', errors: [expectedErrorNoRole], options: components }, + { code: ' delete', errors: [expectedErrorNoRole], options: components }, + { code: ' divide', errors: [expectedErrorNoRole], options: components }, + { code: ' drink', errors: [expectedErrorNoRole], options: components }, + { code: ' eat', errors: [expectedErrorNoRole], options: components }, + { code: ' earn', errors: [expectedErrorNoRole], options: components }, + { code: ' enable', errors: [expectedErrorNoRole], options: components }, + { code: ' enter', errors: [expectedErrorNoRole], options: components }, + { code: ' execute', errors: [expectedErrorNoRole], options: components }, + { code: ' exit', errors: [expectedErrorNoRole], options: components }, + { code: ' expand', errors: [expectedErrorNoRole], options: components }, + { code: ' explain', errors: [expectedErrorNoRole], options: components }, + { code: ' finish', errors: [expectedErrorNoRole], options: components }, + { code: ' forecast', errors: [expectedErrorNoRole], options: components }, + { code: ' fix', errors: [expectedErrorNoRole], options: components }, + { code: ' generate', errors: [expectedErrorNoRole], options: components }, + { code: ' handle', errors: [expectedErrorNoRole], options: components }, + { code: ' help', errors: [expectedErrorNoRole], options: components }, + { code: ' hire', errors: [expectedErrorNoRole], options: components }, + { code: ' hit', errors: [expectedErrorNoRole], options: components }, + { code: ' improve', errors: [expectedErrorNoRole], options: components }, + { code: ' increase', errors: [expectedErrorNoRole], options: components }, + { code: ' join', errors: [expectedErrorNoRole], options: components }, + { code: ' jump', errors: [expectedErrorNoRole], options: components }, + { code: ' leave', errors: [expectedErrorNoRole], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoRole], options: components }, + { code: ' list', errors: [expectedErrorNoRole], options: components }, + { code: ' listen', errors: [expectedErrorNoRole], options: components }, + { code: ' magnify', errors: [expectedErrorNoRole], options: components }, + { code: ' make', errors: [expectedErrorNoRole], options: components }, + { code: ' manage', errors: [expectedErrorNoRole], options: components }, + { code: ' minimize', errors: [expectedErrorNoRole], options: components }, + { code: ' move', errors: [expectedErrorNoRole], options: components }, + { code: ' ok', errors: [expectedErrorNoRole], options: components }, + { code: ' open', errors: [expectedErrorNoRole], options: components }, + { code: ' organise', errors: [expectedErrorNoRole], options: components }, + { code: ' oversee', errors: [expectedErrorNoRole], options: components }, + { code: ' play', errors: [expectedErrorNoRole], options: components }, + { code: ' push', errors: [expectedErrorNoRole], options: components }, + { code: ' read', errors: [expectedErrorNoRole], options: components }, + { code: ' reduce', errors: [expectedErrorNoRole], options: components }, + { code: ' run', errors: [expectedErrorNoRole], options: components }, + { code: ' save', errors: [expectedErrorNoRole], options: components }, + { code: ' send', errors: [expectedErrorNoRole], options: components }, + { code: ' shout', errors: [expectedErrorNoRole], options: components }, + { code: ' sing', errors: [expectedErrorNoRole], options: components }, + { code: ' submit', errors: [expectedErrorNoRole], options: components }, + { code: ' support', errors: [expectedErrorNoRole], options: components }, + { code: ' talk', errors: [expectedErrorNoRole], options: components }, + { code: ' trim', errors: [expectedErrorNoRole], options: components }, + { code: ' visit', errors: [expectedErrorNoRole], options: components }, + { code: ' volunteer', errors: [expectedErrorNoRole], options: components }, + { code: ' vote', errors: [expectedErrorNoRole], options: components }, + { code: ' watch', errors: [expectedErrorNoRole], options: components }, + { code: ' win', errors: [expectedErrorNoRole], options: components }, + { code: ' write', errors: [expectedErrorNoRole], options: components }, + + // role is undefined + { code: ' advise', errors: [expectedErrorNoRole], options: components }, + { code: ' amplify', errors: [expectedErrorNoRole], options: components }, + { code: ' apply', errors: [expectedErrorNoRole], options: components }, + { code: ' arrange', errors: [expectedErrorNoRole], options: components }, + { code: ' ask', errors: [expectedErrorNoRole], options: components }, + { code: ' boost', errors: [expectedErrorNoRole], options: components }, + { code: ' build', errors: [expectedErrorNoRole], options: components }, + { code: ' call', errors: [expectedErrorNoRole], options: components }, + { code: ' click', errors: [expectedErrorNoRole], options: components }, + { code: ' close', errors: [expectedErrorNoRole], options: components }, + { code: ' commit', errors: [expectedErrorNoRole], options: components }, + { code: ' consult', errors: [expectedErrorNoRole], options: components }, + { code: ' compile', errors: [expectedErrorNoRole], options: components }, + { code: ' collect', errors: [expectedErrorNoRole], options: components }, + { code: ' contribute', errors: [expectedErrorNoRole], options: components }, + { code: ' create', errors: [expectedErrorNoRole], options: components }, + { code: ' cut', errors: [expectedErrorNoRole], options: components }, + { code: ' decrease', errors: [expectedErrorNoRole], options: components }, + { code: ' delete', errors: [expectedErrorNoRole], options: components }, + { code: ' divide', errors: [expectedErrorNoRole], options: components }, + { code: ' drink', errors: [expectedErrorNoRole], options: components }, + { code: ' eat', errors: [expectedErrorNoRole], options: components }, + { code: ' earn', errors: [expectedErrorNoRole], options: components }, + { code: ' enable', errors: [expectedErrorNoRole], options: components }, + { code: ' enter', errors: [expectedErrorNoRole], options: components }, + { code: ' execute', errors: [expectedErrorNoRole], options: components }, + { code: ' exit', errors: [expectedErrorNoRole], options: components }, + { code: ' expand', errors: [expectedErrorNoRole], options: components }, + { code: ' explain', errors: [expectedErrorNoRole], options: components }, + { code: ' finish', errors: [expectedErrorNoRole], options: components }, + { code: ' forecast', errors: [expectedErrorNoRole], options: components }, + { code: ' fix', errors: [expectedErrorNoRole], options: components }, + { code: ' generate', errors: [expectedErrorNoRole], options: components }, + { code: ' handle', errors: [expectedErrorNoRole], options: components }, + { code: ' help', errors: [expectedErrorNoRole], options: components }, + { code: ' hire', errors: [expectedErrorNoRole], options: components }, + { code: ' hit', errors: [expectedErrorNoRole], options: components }, + { code: ' improve', errors: [expectedErrorNoRole], options: components }, + { code: ' increase', errors: [expectedErrorNoRole], options: components }, + { code: ' join', errors: [expectedErrorNoRole], options: components }, + { code: ' jump', errors: [expectedErrorNoRole], options: components }, + { code: ' leave', errors: [expectedErrorNoRole], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoRole], options: components }, + { code: ' list', errors: [expectedErrorNoRole], options: components }, + { code: ' listen', errors: [expectedErrorNoRole], options: components }, + { code: ' magnify', errors: [expectedErrorNoRole], options: components }, + { code: ' make', errors: [expectedErrorNoRole], options: components }, + { code: ' manage', errors: [expectedErrorNoRole], options: components }, + { code: ' minimize', errors: [expectedErrorNoRole], options: components }, + { code: ' move', errors: [expectedErrorNoRole], options: components }, + { code: ' ok', errors: [expectedErrorNoRole], options: components }, + { code: ' open', errors: [expectedErrorNoRole], options: components }, + { code: ' organise', errors: [expectedErrorNoRole], options: components }, + { code: ' oversee', errors: [expectedErrorNoRole], options: components }, + { code: ' play', errors: [expectedErrorNoRole], options: components }, + { code: ' push', errors: [expectedErrorNoRole], options: components }, + { code: ' read', errors: [expectedErrorNoRole], options: components }, + { code: ' reduce', errors: [expectedErrorNoRole], options: components }, + { code: ' run', errors: [expectedErrorNoRole], options: components }, + { code: ' save', errors: [expectedErrorNoRole], options: components }, + { code: ' send', errors: [expectedErrorNoRole], options: components }, + { code: ' shout', errors: [expectedErrorNoRole], options: components }, + { code: ' sing', errors: [expectedErrorNoRole], options: components }, + { code: ' submit', errors: [expectedErrorNoRole], options: components }, + { code: ' support', errors: [expectedErrorNoRole], options: components }, + { code: ' talk', errors: [expectedErrorNoRole], options: components }, + { code: ' trim', errors: [expectedErrorNoRole], options: components }, + { code: ' visit', errors: [expectedErrorNoRole], options: components }, + { code: ' volunteer', errors: [expectedErrorNoRole], options: components }, + { code: ' vote', errors: [expectedErrorNoRole], options: components }, + { code: ' watch', errors: [expectedErrorNoRole], options: components }, + { code: ' win', errors: [expectedErrorNoRole], options: components }, + { code: ' write', errors: [expectedErrorNoRole], options: components }, + + // role's value is an empty string + { code: ' advise', errors: [expectedErrorNoRole], options: components }, + { code: ' amplify', errors: [expectedErrorNoRole], options: components }, + { code: ' apply', errors: [expectedErrorNoRole], options: components }, + { code: ' arrange', errors: [expectedErrorNoRole], options: components }, + { code: ' ask', errors: [expectedErrorNoRole], options: components }, + { code: ' boost', errors: [expectedErrorNoRole], options: components }, + { code: ' build', errors: [expectedErrorNoRole], options: components }, + { code: ' call', errors: [expectedErrorNoRole], options: components }, + { code: ' click', errors: [expectedErrorNoRole], options: components }, + { code: ' close', errors: [expectedErrorNoRole], options: components }, + { code: ' commit', errors: [expectedErrorNoRole], options: components }, + { code: ' consult', errors: [expectedErrorNoRole], options: components }, + { code: ' compile', errors: [expectedErrorNoRole], options: components }, + { code: ' collect', errors: [expectedErrorNoRole], options: components }, + { code: ' contribute', errors: [expectedErrorNoRole], options: components }, + { code: ' create', errors: [expectedErrorNoRole], options: components }, + { code: ' cut', errors: [expectedErrorNoRole], options: components }, + { code: ' decrease', errors: [expectedErrorNoRole], options: components }, + { code: ' delete', errors: [expectedErrorNoRole], options: components }, + { code: ' divide', errors: [expectedErrorNoRole], options: components }, + { code: ' drink', errors: [expectedErrorNoRole], options: components }, + { code: ' eat', errors: [expectedErrorNoRole], options: components }, + { code: ' earn', errors: [expectedErrorNoRole], options: components }, + { code: ' enable', errors: [expectedErrorNoRole], options: components }, + { code: ' enter', errors: [expectedErrorNoRole], options: components }, + { code: ' execute', errors: [expectedErrorNoRole], options: components }, + { code: ' exit', errors: [expectedErrorNoRole], options: components }, + { code: ' expand', errors: [expectedErrorNoRole], options: components }, + { code: ' explain', errors: [expectedErrorNoRole], options: components }, + { code: ' finish', errors: [expectedErrorNoRole], options: components }, + { code: ' forecast', errors: [expectedErrorNoRole], options: components }, + { code: ' fix', errors: [expectedErrorNoRole], options: components }, + { code: ' generate', errors: [expectedErrorNoRole], options: components }, + { code: ' handle', errors: [expectedErrorNoRole], options: components }, + { code: ' help', errors: [expectedErrorNoRole], options: components }, + { code: ' hire', errors: [expectedErrorNoRole], options: components }, + { code: ' hit', errors: [expectedErrorNoRole], options: components }, + { code: ' improve', errors: [expectedErrorNoRole], options: components }, + { code: ' increase', errors: [expectedErrorNoRole], options: components }, + { code: ' join', errors: [expectedErrorNoRole], options: components }, + { code: ' jump', errors: [expectedErrorNoRole], options: components }, + { code: ' leave', errors: [expectedErrorNoRole], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoRole], options: components }, + { code: ' list', errors: [expectedErrorNoRole], options: components }, + { code: ' listen', errors: [expectedErrorNoRole], options: components }, + { code: ' magnify', errors: [expectedErrorNoRole], options: components }, + { code: ' make', errors: [expectedErrorNoRole], options: components }, + { code: ' manage', errors: [expectedErrorNoRole], options: components }, + { code: ' minimize', errors: [expectedErrorNoRole], options: components }, + { code: ' move', errors: [expectedErrorNoRole], options: components }, + { code: ' ok', errors: [expectedErrorNoRole], options: components }, + { code: ' open', errors: [expectedErrorNoRole], options: components }, + { code: ' organise', errors: [expectedErrorNoRole], options: components }, + { code: ' oversee', errors: [expectedErrorNoRole], options: components }, + { code: ' play', errors: [expectedErrorNoRole], options: components }, + { code: ' push', errors: [expectedErrorNoRole], options: components }, + { code: ' read', errors: [expectedErrorNoRole], options: components }, + { code: ' reduce', errors: [expectedErrorNoRole], options: components }, + { code: ' run', errors: [expectedErrorNoRole], options: components }, + { code: ' save', errors: [expectedErrorNoRole], options: components }, + { code: ' send', errors: [expectedErrorNoRole], options: components }, + { code: ' shout', errors: [expectedErrorNoRole], options: components }, + { code: ' sing', errors: [expectedErrorNoRole], options: components }, + { code: ' submit', errors: [expectedErrorNoRole], options: components }, + { code: ' support', errors: [expectedErrorNoRole], options: components }, + { code: ' talk', errors: [expectedErrorNoRole], options: components }, + { code: ' trim', errors: [expectedErrorNoRole], options: components }, + { code: ' visit', errors: [expectedErrorNoRole], options: components }, + { code: ' volunteer', errors: [expectedErrorNoRole], options: components }, + { code: ' vote', errors: [expectedErrorNoRole], options: components }, + { code: ' watch', errors: [expectedErrorNoRole], options: components }, + { code: ' win', errors: [expectedErrorNoRole], options: components }, + { code: ' write', errors: [expectedErrorNoRole], options: components }, + + // role's value is not button + { code: ' advise', errors: [expectedErrorNoRole], options: components }, + { code: ' amplify', errors: [expectedErrorNoRole], options: components }, + { code: ' apply', errors: [expectedErrorNoRole], options: components }, + { code: ' arrange', errors: [expectedErrorNoRole], options: components }, + { code: ' ask', errors: [expectedErrorNoRole], options: components }, + { code: ' boost', errors: [expectedErrorNoRole], options: components }, + { code: ' build', errors: [expectedErrorNoRole], options: components }, + { code: ' call', errors: [expectedErrorNoRole], options: components }, + { code: ' click', errors: [expectedErrorNoRole], options: components }, + { code: ' close', errors: [expectedErrorNoRole], options: components }, + { code: ' commit', errors: [expectedErrorNoRole], options: components }, + { code: ' consult', errors: [expectedErrorNoRole], options: components }, + { code: ' compile', errors: [expectedErrorNoRole], options: components }, + { code: ' collect', errors: [expectedErrorNoRole], options: components }, + { code: ' contribute', errors: [expectedErrorNoRole], options: components }, + { code: ' create', errors: [expectedErrorNoRole], options: components }, + { code: ' cut', errors: [expectedErrorNoRole], options: components }, + { code: ' decrease', errors: [expectedErrorNoRole], options: components }, + { code: ' delete', errors: [expectedErrorNoRole], options: components }, + { code: ' divide', errors: [expectedErrorNoRole], options: components }, + { code: ' drink', errors: [expectedErrorNoRole], options: components }, + { code: ' eat', errors: [expectedErrorNoRole], options: components }, + { code: ' earn', errors: [expectedErrorNoRole], options: components }, + { code: ' enable', errors: [expectedErrorNoRole], options: components }, + { code: ' enter', errors: [expectedErrorNoRole], options: components }, + { code: ' execute', errors: [expectedErrorNoRole], options: components }, + { code: ' exit', errors: [expectedErrorNoRole], options: components }, + { code: ' expand', errors: [expectedErrorNoRole], options: components }, + { code: ' explain', errors: [expectedErrorNoRole], options: components }, + { code: ' finish', errors: [expectedErrorNoRole], options: components }, + { code: ' forecast', errors: [expectedErrorNoRole], options: components }, + { code: ' fix', errors: [expectedErrorNoRole], options: components }, + { code: ' generate', errors: [expectedErrorNoRole], options: components }, + { code: ' handle', errors: [expectedErrorNoRole], options: components }, + { code: ' help', errors: [expectedErrorNoRole], options: components }, + { code: ' hire', errors: [expectedErrorNoRole], options: components }, + { code: ' hit', errors: [expectedErrorNoRole], options: components }, + { code: ' improve', errors: [expectedErrorNoRole], options: components }, + { code: ' increase', errors: [expectedErrorNoRole], options: components }, + { code: ' join', errors: [expectedErrorNoRole], options: components }, + { code: ' jump', errors: [expectedErrorNoRole], options: components }, + { code: ' leave', errors: [expectedErrorNoRole], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoRole], options: components }, + { code: ' list', errors: [expectedErrorNoRole], options: components }, + { code: ' listen', errors: [expectedErrorNoRole], options: components }, + { code: ' magnify', errors: [expectedErrorNoRole], options: components }, + { code: ' make', errors: [expectedErrorNoRole], options: components }, + { code: ' manage', errors: [expectedErrorNoRole], options: components }, + { code: ' minimize', errors: [expectedErrorNoRole], options: components }, + { code: ' move', errors: [expectedErrorNoRole], options: components }, + { code: ' ok', errors: [expectedErrorNoRole], options: components }, + { code: ' open', errors: [expectedErrorNoRole], options: components }, + { code: ' organise', errors: [expectedErrorNoRole], options: components }, + { code: ' oversee', errors: [expectedErrorNoRole], options: components }, + { code: ' play', errors: [expectedErrorNoRole], options: components }, + { code: ' push', errors: [expectedErrorNoRole], options: components }, + { code: ' read', errors: [expectedErrorNoRole], options: components }, + { code: ' reduce', errors: [expectedErrorNoRole], options: components }, + { code: ' run', errors: [expectedErrorNoRole], options: components }, + { code: ' save', errors: [expectedErrorNoRole], options: components }, + { code: ' send', errors: [expectedErrorNoRole], options: components }, + { code: ' shout', errors: [expectedErrorNoRole], options: components }, + { code: ' sing', errors: [expectedErrorNoRole], options: components }, + { code: ' submit', errors: [expectedErrorNoRole], options: components }, + { code: ' support', errors: [expectedErrorNoRole], options: components }, + { code: ' talk', errors: [expectedErrorNoRole], options: components }, + { code: ' trim', errors: [expectedErrorNoRole], options: components }, + { code: ' visit', errors: [expectedErrorNoRole], options: components }, + { code: ' volunteer', errors: [expectedErrorNoRole], options: components }, + { code: ' vote', errors: [expectedErrorNoRole], options: components }, + { code: ' watch', errors: [expectedErrorNoRole], options: components }, + { code: ' win', errors: [expectedErrorNoRole], options: components }, + { code: ' write', errors: [expectedErrorNoRole], options: components }, + + // tabindex is missing + { code: ' advise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' amplify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' apply', errors: [expectedErrorNoTabindex], options: components }, + { code: ' arrange', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ask', errors: [expectedErrorNoTabindex], options: components }, + { code: ' boost', errors: [expectedErrorNoTabindex], options: components }, + { code: ' build', errors: [expectedErrorNoTabindex], options: components }, + { code: ' call', errors: [expectedErrorNoTabindex], options: components }, + { code: ' click', errors: [expectedErrorNoTabindex], options: components }, + { code: ' close', errors: [expectedErrorNoTabindex], options: components }, + { code: ' commit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' consult', errors: [expectedErrorNoTabindex], options: components }, + { code: ' compile', errors: [expectedErrorNoTabindex], options: components }, + { code: ' collect', errors: [expectedErrorNoTabindex], options: components }, + { code: ' contribute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' create', errors: [expectedErrorNoTabindex], options: components }, + { code: ' cut', errors: [expectedErrorNoTabindex], options: components }, + { code: ' decrease', errors: [expectedErrorNoTabindex], options: components }, + { code: ' delete', errors: [expectedErrorNoTabindex], options: components }, + { code: ' divide', errors: [expectedErrorNoTabindex], options: components }, + { code: ' drink', errors: [expectedErrorNoTabindex], options: components }, + { code: ' eat', errors: [expectedErrorNoTabindex], options: components }, + { code: ' earn', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enable', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enter', errors: [expectedErrorNoTabindex], options: components }, + { code: ' execute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' exit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' expand', errors: [expectedErrorNoTabindex], options: components }, + { code: ' explain', errors: [expectedErrorNoTabindex], options: components }, + { code: ' finish', errors: [expectedErrorNoTabindex], options: components }, + { code: ' forecast', errors: [expectedErrorNoTabindex], options: components }, + { code: ' fix', errors: [expectedErrorNoTabindex], options: components }, + { code: ' generate', errors: [expectedErrorNoTabindex], options: components }, + { code: ' handle', errors: [expectedErrorNoTabindex], options: components }, + { code: ' help', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hire', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' improve', errors: [expectedErrorNoTabindex], options: components }, + { code: ' increase', errors: [expectedErrorNoTabindex], options: components }, + { code: ' join', errors: [expectedErrorNoTabindex], options: components }, + { code: ' jump', errors: [expectedErrorNoTabindex], options: components }, + { code: ' leave', errors: [expectedErrorNoTabindex], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoTabindex], options: components }, + { code: ' list', errors: [expectedErrorNoTabindex], options: components }, + { code: ' listen', errors: [expectedErrorNoTabindex], options: components }, + { code: ' magnify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' make', errors: [expectedErrorNoTabindex], options: components }, + { code: ' manage', errors: [expectedErrorNoTabindex], options: components }, + { code: ' minimize', errors: [expectedErrorNoTabindex], options: components }, + { code: ' move', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ok', errors: [expectedErrorNoTabindex], options: components }, + { code: ' open', errors: [expectedErrorNoTabindex], options: components }, + { code: ' organise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' oversee', errors: [expectedErrorNoTabindex], options: components }, + { code: ' play', errors: [expectedErrorNoTabindex], options: components }, + { code: ' push', errors: [expectedErrorNoTabindex], options: components }, + { code: ' read', errors: [expectedErrorNoTabindex], options: components }, + { code: ' reduce', errors: [expectedErrorNoTabindex], options: components }, + { code: ' run', errors: [expectedErrorNoTabindex], options: components }, + { code: ' save', errors: [expectedErrorNoTabindex], options: components }, + { code: ' send', errors: [expectedErrorNoTabindex], options: components }, + { code: ' shout', errors: [expectedErrorNoTabindex], options: components }, + { code: ' sing', errors: [expectedErrorNoTabindex], options: components }, + { code: ' submit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' support', errors: [expectedErrorNoTabindex], options: components }, + { code: ' talk', errors: [expectedErrorNoTabindex], options: components }, + { code: ' trim', errors: [expectedErrorNoTabindex], options: components }, + { code: ' visit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' volunteer', errors: [expectedErrorNoTabindex], options: components }, + { code: ' vote', errors: [expectedErrorNoTabindex], options: components }, + { code: ' watch', errors: [expectedErrorNoTabindex], options: components }, + { code: ' win', errors: [expectedErrorNoTabindex], options: components }, + { code: ' write', errors: [expectedErrorNoTabindex], options: components }, + + // tabindex is undefined + { code: ' advise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' amplify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' apply', errors: [expectedErrorNoTabindex], options: components }, + { code: ' arrange', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ask', errors: [expectedErrorNoTabindex], options: components }, + { code: ' boost', errors: [expectedErrorNoTabindex], options: components }, + { code: ' build', errors: [expectedErrorNoTabindex], options: components }, + { code: ' call', errors: [expectedErrorNoTabindex], options: components }, + { code: ' click', errors: [expectedErrorNoTabindex], options: components }, + { code: ' close', errors: [expectedErrorNoTabindex], options: components }, + { code: ' commit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' consult', errors: [expectedErrorNoTabindex], options: components }, + { code: ' compile', errors: [expectedErrorNoTabindex], options: components }, + { code: ' collect', errors: [expectedErrorNoTabindex], options: components }, + { code: ' contribute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' create', errors: [expectedErrorNoTabindex], options: components }, + { code: ' cut', errors: [expectedErrorNoTabindex], options: components }, + { code: ' decrease', errors: [expectedErrorNoTabindex], options: components }, + { code: ' delete', errors: [expectedErrorNoTabindex], options: components }, + { code: ' divide', errors: [expectedErrorNoTabindex], options: components }, + { code: ' drink', errors: [expectedErrorNoTabindex], options: components }, + { code: ' eat', errors: [expectedErrorNoTabindex], options: components }, + { code: ' earn', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enable', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enter', errors: [expectedErrorNoTabindex], options: components }, + { code: ' execute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' exit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' expand', errors: [expectedErrorNoTabindex], options: components }, + { code: ' explain', errors: [expectedErrorNoTabindex], options: components }, + { code: ' finish', errors: [expectedErrorNoTabindex], options: components }, + { code: ' forecast', errors: [expectedErrorNoTabindex], options: components }, + { code: ' fix', errors: [expectedErrorNoTabindex], options: components }, + { code: ' generate', errors: [expectedErrorNoTabindex], options: components }, + { code: ' handle', errors: [expectedErrorNoTabindex], options: components }, + { code: ' help', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hire', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' improve', errors: [expectedErrorNoTabindex], options: components }, + { code: ' increase', errors: [expectedErrorNoTabindex], options: components }, + { code: ' join', errors: [expectedErrorNoTabindex], options: components }, + { code: ' jump', errors: [expectedErrorNoTabindex], options: components }, + { code: ' leave', errors: [expectedErrorNoTabindex], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoTabindex], options: components }, + { code: ' list', errors: [expectedErrorNoTabindex], options: components }, + { code: ' listen', errors: [expectedErrorNoTabindex], options: components }, + { code: ' magnify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' make', errors: [expectedErrorNoTabindex], options: components }, + { code: ' manage', errors: [expectedErrorNoTabindex], options: components }, + { code: ' minimize', errors: [expectedErrorNoTabindex], options: components }, + { code: ' move', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ok', errors: [expectedErrorNoTabindex], options: components }, + { code: ' open', errors: [expectedErrorNoTabindex], options: components }, + { code: ' organise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' oversee', errors: [expectedErrorNoTabindex], options: components }, + { code: ' play', errors: [expectedErrorNoTabindex], options: components }, + { code: ' push', errors: [expectedErrorNoTabindex], options: components }, + { code: ' read', errors: [expectedErrorNoTabindex], options: components }, + { code: ' reduce', errors: [expectedErrorNoTabindex], options: components }, + { code: ' run', errors: [expectedErrorNoTabindex], options: components }, + { code: ' save', errors: [expectedErrorNoTabindex], options: components }, + { code: ' send', errors: [expectedErrorNoTabindex], options: components }, + { code: ' shout', errors: [expectedErrorNoTabindex], options: components }, + { code: ' sing', errors: [expectedErrorNoTabindex], options: components }, + { code: ' submit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' support', errors: [expectedErrorNoTabindex], options: components }, + { code: ' talk', errors: [expectedErrorNoTabindex], options: components }, + { code: ' trim', errors: [expectedErrorNoTabindex], options: components }, + { code: ' visit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' volunteer', errors: [expectedErrorNoTabindex], options: components }, + { code: ' vote', errors: [expectedErrorNoTabindex], options: components }, + { code: ' watch', errors: [expectedErrorNoTabindex], options: components }, + { code: ' win', errors: [expectedErrorNoTabindex], options: components }, + { code: ' write', errors: [expectedErrorNoTabindex], options: components }, + + // tabindex's value is an empty string + { code: ' advise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' amplify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' apply', errors: [expectedErrorNoTabindex], options: components }, + { code: ' arrange', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ask', errors: [expectedErrorNoTabindex], options: components }, + { code: ' boost', errors: [expectedErrorNoTabindex], options: components }, + { code: ' build', errors: [expectedErrorNoTabindex], options: components }, + { code: ' call', errors: [expectedErrorNoTabindex], options: components }, + { code: ' click', errors: [expectedErrorNoTabindex], options: components }, + { code: ' close', errors: [expectedErrorNoTabindex], options: components }, + { code: ' commit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' consult', errors: [expectedErrorNoTabindex], options: components }, + { code: ' compile', errors: [expectedErrorNoTabindex], options: components }, + { code: ' collect', errors: [expectedErrorNoTabindex], options: components }, + { code: ' contribute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' create', errors: [expectedErrorNoTabindex], options: components }, + { code: ' cut', errors: [expectedErrorNoTabindex], options: components }, + { code: ' decrease', errors: [expectedErrorNoTabindex], options: components }, + { code: ' delete', errors: [expectedErrorNoTabindex], options: components }, + { code: ' divide', errors: [expectedErrorNoTabindex], options: components }, + { code: ' drink', errors: [expectedErrorNoTabindex], options: components }, + { code: ' eat', errors: [expectedErrorNoTabindex], options: components }, + { code: ' earn', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enable', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enter', errors: [expectedErrorNoTabindex], options: components }, + { code: ' execute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' exit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' expand', errors: [expectedErrorNoTabindex], options: components }, + { code: ' explain', errors: [expectedErrorNoTabindex], options: components }, + { code: ' finish', errors: [expectedErrorNoTabindex], options: components }, + { code: ' forecast', errors: [expectedErrorNoTabindex], options: components }, + { code: ' fix', errors: [expectedErrorNoTabindex], options: components }, + { code: ' generate', errors: [expectedErrorNoTabindex], options: components }, + { code: ' handle', errors: [expectedErrorNoTabindex], options: components }, + { code: ' help', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hire', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' improve', errors: [expectedErrorNoTabindex], options: components }, + { code: ' increase', errors: [expectedErrorNoTabindex], options: components }, + { code: ' join', errors: [expectedErrorNoTabindex], options: components }, + { code: ' jump', errors: [expectedErrorNoTabindex], options: components }, + { code: ' leave', errors: [expectedErrorNoTabindex], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoTabindex], options: components }, + { code: ' list', errors: [expectedErrorNoTabindex], options: components }, + { code: ' listen', errors: [expectedErrorNoTabindex], options: components }, + { code: ' magnify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' make', errors: [expectedErrorNoTabindex], options: components }, + { code: ' manage', errors: [expectedErrorNoTabindex], options: components }, + { code: ' minimize', errors: [expectedErrorNoTabindex], options: components }, + { code: ' move', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ok', errors: [expectedErrorNoTabindex], options: components }, + { code: ' open', errors: [expectedErrorNoTabindex], options: components }, + { code: ' organise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' oversee', errors: [expectedErrorNoTabindex], options: components }, + { code: ' play', errors: [expectedErrorNoTabindex], options: components }, + { code: ' push', errors: [expectedErrorNoTabindex], options: components }, + { code: ' read', errors: [expectedErrorNoTabindex], options: components }, + { code: ' reduce', errors: [expectedErrorNoTabindex], options: components }, + { code: ' run', errors: [expectedErrorNoTabindex], options: components }, + { code: ' save', errors: [expectedErrorNoTabindex], options: components }, + { code: ' send', errors: [expectedErrorNoTabindex], options: components }, + { code: ' shout', errors: [expectedErrorNoTabindex], options: components }, + { code: ' sing', errors: [expectedErrorNoTabindex], options: components }, + { code: ' submit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' support', errors: [expectedErrorNoTabindex], options: components }, + { code: ' talk', errors: [expectedErrorNoTabindex], options: components }, + { code: ' trim', errors: [expectedErrorNoTabindex], options: components }, + { code: ' visit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' volunteer', errors: [expectedErrorNoTabindex], options: components }, + { code: ' vote', errors: [expectedErrorNoTabindex], options: components }, + { code: ' watch', errors: [expectedErrorNoTabindex], options: components }, + { code: ' win', errors: [expectedErrorNoTabindex], options: components }, + { code: ' write', errors: [expectedErrorNoTabindex], options: components }, + + // tabindex's value is -1 + { code: ' advise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' amplify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' apply', errors: [expectedErrorNoTabindex], options: components }, + { code: ' arrange', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ask', errors: [expectedErrorNoTabindex], options: components }, + { code: ' boost', errors: [expectedErrorNoTabindex], options: components }, + { code: ' build', errors: [expectedErrorNoTabindex], options: components }, + { code: ' call', errors: [expectedErrorNoTabindex], options: components }, + { code: ' click', errors: [expectedErrorNoTabindex], options: components }, + { code: ' close', errors: [expectedErrorNoTabindex], options: components }, + { code: ' commit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' consult', errors: [expectedErrorNoTabindex], options: components }, + { code: ' compile', errors: [expectedErrorNoTabindex], options: components }, + { code: ' collect', errors: [expectedErrorNoTabindex], options: components }, + { code: ' contribute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' create', errors: [expectedErrorNoTabindex], options: components }, + { code: ' cut', errors: [expectedErrorNoTabindex], options: components }, + { code: ' decrease', errors: [expectedErrorNoTabindex], options: components }, + { code: ' delete', errors: [expectedErrorNoTabindex], options: components }, + { code: ' divide', errors: [expectedErrorNoTabindex], options: components }, + { code: ' drink', errors: [expectedErrorNoTabindex], options: components }, + { code: ' eat', errors: [expectedErrorNoTabindex], options: components }, + { code: ' earn', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enable', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enter', errors: [expectedErrorNoTabindex], options: components }, + { code: ' execute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' exit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' expand', errors: [expectedErrorNoTabindex], options: components }, + { code: ' explain', errors: [expectedErrorNoTabindex], options: components }, + { code: ' finish', errors: [expectedErrorNoTabindex], options: components }, + { code: ' forecast', errors: [expectedErrorNoTabindex], options: components }, + { code: ' fix', errors: [expectedErrorNoTabindex], options: components }, + { code: ' generate', errors: [expectedErrorNoTabindex], options: components }, + { code: ' handle', errors: [expectedErrorNoTabindex], options: components }, + { code: ' help', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hire', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' improve', errors: [expectedErrorNoTabindex], options: components }, + { code: ' increase', errors: [expectedErrorNoTabindex], options: components }, + { code: ' join', errors: [expectedErrorNoTabindex], options: components }, + { code: ' jump', errors: [expectedErrorNoTabindex], options: components }, + { code: ' leave', errors: [expectedErrorNoTabindex], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoTabindex], options: components }, + { code: ' list', errors: [expectedErrorNoTabindex], options: components }, + { code: ' listen', errors: [expectedErrorNoTabindex], options: components }, + { code: ' magnify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' make', errors: [expectedErrorNoTabindex], options: components }, + { code: ' manage', errors: [expectedErrorNoTabindex], options: components }, + { code: ' minimize', errors: [expectedErrorNoTabindex], options: components }, + { code: ' move', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ok', errors: [expectedErrorNoTabindex], options: components }, + { code: ' open', errors: [expectedErrorNoTabindex], options: components }, + { code: ' organise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' oversee', errors: [expectedErrorNoTabindex], options: components }, + { code: ' play', errors: [expectedErrorNoTabindex], options: components }, + { code: ' push', errors: [expectedErrorNoTabindex], options: components }, + { code: ' read', errors: [expectedErrorNoTabindex], options: components }, + { code: ' reduce', errors: [expectedErrorNoTabindex], options: components }, + { code: ' run', errors: [expectedErrorNoTabindex], options: components }, + { code: ' save', errors: [expectedErrorNoTabindex], options: components }, + { code: ' send', errors: [expectedErrorNoTabindex], options: components }, + { code: ' shout', errors: [expectedErrorNoTabindex], options: components }, + { code: ' sing', errors: [expectedErrorNoTabindex], options: components }, + { code: ' submit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' support', errors: [expectedErrorNoTabindex], options: components }, + { code: ' talk', errors: [expectedErrorNoTabindex], options: components }, + { code: ' trim', errors: [expectedErrorNoTabindex], options: components }, + { code: ' visit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' volunteer', errors: [expectedErrorNoTabindex], options: components }, + { code: ' vote', errors: [expectedErrorNoTabindex], options: components }, + { code: ' watch', errors: [expectedErrorNoTabindex], options: components }, + { code: ' win', errors: [expectedErrorNoTabindex], options: components }, + { code: ' write', errors: [expectedErrorNoTabindex], options: components }, + + // tabindex's value is 1 + { code: ' advise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' amplify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' apply', errors: [expectedErrorNoTabindex], options: components }, + { code: ' arrange', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ask', errors: [expectedErrorNoTabindex], options: components }, + { code: ' boost', errors: [expectedErrorNoTabindex], options: components }, + { code: ' build', errors: [expectedErrorNoTabindex], options: components }, + { code: ' call', errors: [expectedErrorNoTabindex], options: components }, + { code: ' click', errors: [expectedErrorNoTabindex], options: components }, + { code: ' close', errors: [expectedErrorNoTabindex], options: components }, + { code: ' commit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' consult', errors: [expectedErrorNoTabindex], options: components }, + { code: ' compile', errors: [expectedErrorNoTabindex], options: components }, + { code: ' collect', errors: [expectedErrorNoTabindex], options: components }, + { code: ' contribute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' create', errors: [expectedErrorNoTabindex], options: components }, + { code: ' cut', errors: [expectedErrorNoTabindex], options: components }, + { code: ' decrease', errors: [expectedErrorNoTabindex], options: components }, + { code: ' delete', errors: [expectedErrorNoTabindex], options: components }, + { code: ' divide', errors: [expectedErrorNoTabindex], options: components }, + { code: ' drink', errors: [expectedErrorNoTabindex], options: components }, + { code: ' eat', errors: [expectedErrorNoTabindex], options: components }, + { code: ' earn', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enable', errors: [expectedErrorNoTabindex], options: components }, + { code: ' enter', errors: [expectedErrorNoTabindex], options: components }, + { code: ' execute', errors: [expectedErrorNoTabindex], options: components }, + { code: ' exit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' expand', errors: [expectedErrorNoTabindex], options: components }, + { code: ' explain', errors: [expectedErrorNoTabindex], options: components }, + { code: ' finish', errors: [expectedErrorNoTabindex], options: components }, + { code: ' forecast', errors: [expectedErrorNoTabindex], options: components }, + { code: ' fix', errors: [expectedErrorNoTabindex], options: components }, + { code: ' generate', errors: [expectedErrorNoTabindex], options: components }, + { code: ' handle', errors: [expectedErrorNoTabindex], options: components }, + { code: ' help', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hire', errors: [expectedErrorNoTabindex], options: components }, + { code: ' hit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' improve', errors: [expectedErrorNoTabindex], options: components }, + { code: ' increase', errors: [expectedErrorNoTabindex], options: components }, + { code: ' join', errors: [expectedErrorNoTabindex], options: components }, + { code: ' jump', errors: [expectedErrorNoTabindex], options: components }, + { code: ' leave', errors: [expectedErrorNoTabindex], options: components }, + { code: ' let\'/s', errors: [expectedErrorNoTabindex], options: components }, + { code: ' list', errors: [expectedErrorNoTabindex], options: components }, + { code: ' listen', errors: [expectedErrorNoTabindex], options: components }, + { code: ' magnify', errors: [expectedErrorNoTabindex], options: components }, + { code: ' make', errors: [expectedErrorNoTabindex], options: components }, + { code: ' manage', errors: [expectedErrorNoTabindex], options: components }, + { code: ' minimize', errors: [expectedErrorNoTabindex], options: components }, + { code: ' move', errors: [expectedErrorNoTabindex], options: components }, + { code: ' ok', errors: [expectedErrorNoTabindex], options: components }, + { code: ' open', errors: [expectedErrorNoTabindex], options: components }, + { code: ' organise', errors: [expectedErrorNoTabindex], options: components }, + { code: ' oversee', errors: [expectedErrorNoTabindex], options: components }, + { code: ' play', errors: [expectedErrorNoTabindex], options: components }, + { code: ' push', errors: [expectedErrorNoTabindex], options: components }, + { code: ' read', errors: [expectedErrorNoTabindex], options: components }, + { code: ' reduce', errors: [expectedErrorNoTabindex], options: components }, + { code: ' run', errors: [expectedErrorNoTabindex], options: components }, + { code: ' save', errors: [expectedErrorNoTabindex], options: components }, + { code: ' send', errors: [expectedErrorNoTabindex], options: components }, + { code: ' shout', errors: [expectedErrorNoTabindex], options: components }, + { code: ' sing', errors: [expectedErrorNoTabindex], options: components }, + { code: ' submit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' support', errors: [expectedErrorNoTabindex], options: components }, + { code: ' talk', errors: [expectedErrorNoTabindex], options: components }, + { code: ' trim', errors: [expectedErrorNoTabindex], options: components }, + { code: ' visit', errors: [expectedErrorNoTabindex], options: components }, + { code: ' volunteer', errors: [expectedErrorNoTabindex], options: components }, + { code: ' vote', errors: [expectedErrorNoTabindex], options: components }, + { code: ' watch', errors: [expectedErrorNoTabindex], options: components }, + { code: ' win', errors: [expectedErrorNoTabindex], options: components }, + { code: ' write', errors: [expectedErrorNoTabindex], options: components }, + + ].map(parserOptionsMapper), +}); diff --git a/__tests__/src/rules/div-has-content-test.js b/__tests__/src/rules/div-has-content-test.js new file mode 100644 index 000000000..db90219e6 --- /dev/null +++ b/__tests__/src/rules/div-has-content-test.js @@ -0,0 +1,34 @@ +/* eslint-env jest */ +/** + * @fileoverview check if div has content + * @author Felicia + */ + +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- + +import { RuleTester } from 'eslint'; +import parserOptionsMapper from '../../__util__/parserOptionsMapper'; +import rule from '../../../src/rules/div-has-content'; + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +const ruleTester = new RuleTester(); + +const expectedError = { + message: 'Div must have content and the content must be accessible by a screen reader.', + type: 'JSXOpeningElement', +}; + +ruleTester.run('div-has-content', rule, { + valid: [ + { code: '
content
;' }, + ].map(parserOptionsMapper), + invalid: [ + // DEFAULT ELEMENT TESTS + { code: '
', errors: [expectedError] }, + ].map(parserOptionsMapper), +}); diff --git a/__tests__/src/rules/heading-has-content-test.js b/__tests__/src/rules/heading-has-content-test.js index 7e762b1ff..fa8821c61 100644 --- a/__tests__/src/rules/heading-has-content-test.js +++ b/__tests__/src/rules/heading-has-content-test.js @@ -56,7 +56,7 @@ ruleTester.run('heading-has-content', rule, { invalid: [ // DEFAULT ELEMENT TESTS { code: '

', errors: [expectedError] }, - { code: '

', errors: [expectedError] }, + { code: '

', errors: [expectedError] }, { code: '

{undefined}

', errors: [expectedError] }, // CUSTOM ELEMENT TESTS FOR COMPONENTS OPTION diff --git a/docs/rules/div-has-apply.md b/docs/rules/div-has-apply.md new file mode 100644 index 000000000..677699c91 --- /dev/null +++ b/docs/rules/div-has-apply.md @@ -0,0 +1,109 @@ +# div-has-apply + +Enforcing the use of tabindex="0" role="button" attributes when a call to action verb is used in a `div` element. Furthermore, recommendation is made to use button native HTML element over the ARIA attributes following the first rule of ARIA. + +### References + + 1. eslint-plugin-jsx-a11y/docs/rule/heading-has-content + +## Rule details + +Here are the list of call to action(CTA) verbs that the rule will recognise and +indicate the line of code incorrect if one of them is in between `
` `` elements: + 'advise', 'amplify', 'apply', 'arrange', 'ask', + 'boost', 'build', + 'call', 'click', 'close', 'commit', 'consult', 'compile', 'collect', 'contribute', 'create', 'cut', + 'decrease', 'delete', 'divide', 'drink', + 'eat', 'earn', 'enable', 'enter', 'execute', 'exit', 'expand', 'explain', + 'finish', 'forecast', 'fix', + 'generate', + 'handle', 'help', 'hire', 'hit', + 'improve', 'increase', + 'join', 'jump', + 'leave', 'let\'/s', 'list', 'listen', + 'magnify', 'make', 'manage', 'minimize', 'move', + 'ok', 'open', 'organise', 'oversee', + 'play', 'push', + 'read', 'reduce', 'run', + 'save', 'send', 'shout', 'sing', 'submit', 'support', + 'talk', 'trim', + 'visit', 'volunteer', 'vote', + 'watch', 'win', 'write', + +This rule takes one optional object argument of type object: + +```json +{ + "rules": { + "jsx-a11y/heading-has-content": [ 2, { + "components": [ "Apply" ], + }], + } +} +``` +For the `components` option, these strings determine which JSX elements (**always including** `
`) should be checked for having call to action verbs content. This is a good use case when you have a wrapper component that simply renders a `button` element (like in React): + + +```js +// Apply.js +const Apply = props => { + return ( +
{ props.children }
+ ); +} + +... + +// CreateForm.js (for example) +... +return ( + Apply +); +``` + +### Succeed +```jsx +
+
// empty div is allowed +
orange
// no action word within div element +
orange
// any word within div that has the two attributes +
advise
// any of the action words e.g.: advise within div that has the two attributes +advise // If custom element is an action word then the text within it should also be an action word. +``` + +### Fail +```jsx +// when a call to action verb is between div elements: + +//both attributes are missing and/or wrong +
submit
// both attributes are missing +
apply
// both attributes are undefined +
apply
// both attributes values are wrong +
apply
// both attributes values are wrong +
apply
// wrong attribute value and missing attribute +
apply
// wrong attribute value and missing attribute + +// tabindex is missing or wrong +
apply
+
apply
+
apply
+
apply
+
apply
+ +// role is missing or wrong +
apply
+
apply
+
apply
+
apply
+
apply
+ +// custom element name is an action verb and the text in between too +apply +``` + + +## Accessibility guidelines +- [WCAG 2.4.7](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-visible.html) + +### Resources +- [axe-core, focus-order-semantics](https://dequeuniversity.com/rules/axe/3.2/focus-order-semantics) diff --git a/docs/rules/div-has-content.md b/docs/rules/div-has-content.md new file mode 100644 index 000000000..2896a4ab1 --- /dev/null +++ b/docs/rules/div-has-content.md @@ -0,0 +1,21 @@ +# div-has-content + +Write a useful explanation here! + +### References + + 1. + +## Rule details + +This rule takes no arguments. + +### Succeed +```jsx +
+``` + +### Fail +```jsx + +``` diff --git a/package.json b/package.json index cebde0124..9ff5bcd94 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "eslint-plugin-jsx-a11y", + "name": "eslint-plugin-jsx-a11y-div-seventyone", "version": "6.4.1", "description": "Static AST checker for accessibility rules on JSX elements.", "keywords": [ @@ -23,7 +23,7 @@ "lint:fix": "npm run lint -- --fix", "lint": "eslint --config .eslintrc src __tests__ __mocks__ scripts", "prepublish": "safe-publish-latest && not-in-publish || (npm run lint && npm run flow && npm run jest && npm run build)", - "pretest": "npm run lint:fix && npm run flow", + "pretest": "npm run lint:fix", "test": "npm run jest", "posttest": "aud --production", "test:ci": "npm run jest -- --ci --runInBand", @@ -69,7 +69,8 @@ "has": "^1.0.3", "jsx-ast-utils": "^3.2.0", "language-tags": "^1.0.5", - "minimatch": "^3.0.4" + "minimatch": "^3.0.4", + "proptypes": "^1.1.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7" diff --git a/src/index.js b/src/index.js index ee4a6ef64..03c3a5e40 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,8 @@ module.exports = { 'click-events-have-key-events': require('./rules/click-events-have-key-events'), 'control-has-associated-label': require('./rules/control-has-associated-label'), 'heading-has-content': require('./rules/heading-has-content'), + 'div-has-content': require('./rules/div-has-content'), + 'div-has-apply': require('./rules/div-has-apply'), 'html-has-lang': require('./rules/html-has-lang'), 'iframe-has-title': require('./rules/iframe-has-title'), 'img-redundant-alt': require('./rules/img-redundant-alt'), @@ -91,6 +93,8 @@ module.exports = { }, ], 'jsx-a11y/heading-has-content': 'error', + 'jsx-a11y/div-has-content': 'error', + 'jsx-a11y/div-has-apply': 'error', 'jsx-a11y/html-has-lang': 'error', 'jsx-a11y/iframe-has-title': 'error', 'jsx-a11y/img-redundant-alt': 'error', @@ -245,6 +249,8 @@ module.exports = { ], }], 'jsx-a11y/heading-has-content': 'error', + 'jsx-a11y/div-has-content': 'error', + 'jsx-a11y/div-has-apply': 'error', 'jsx-a11y/html-has-lang': 'error', 'jsx-a11y/iframe-has-title': 'error', 'jsx-a11y/img-redundant-alt': 'error', diff --git a/src/rules/div-has-apply.js b/src/rules/div-has-apply.js new file mode 100644 index 000000000..7ff955b32 --- /dev/null +++ b/src/rules/div-has-apply.js @@ -0,0 +1,108 @@ +/** + * @fileoverview Discourage use of div when text is an action word + * @author Felicia Kovacs + */ + +// ---------------------------------------------------------------------------- +// Rule Definition +// ---------------------------------------------------------------------------- + +import { + elementType, + getProp, + getPropValue, +} from 'jsx-ast-utils'; +import { generateObjSchema, arraySchema } from '../util/schemas'; + +// random list of action verbs in alphabetical order +const actionVerbs = [ + 'advise', 'amplify', 'apply', 'arrange', 'ask', + 'boost', 'build', + 'call', 'click', 'close', 'commit', 'consult', 'compile', 'collect', 'contribute', 'create', 'cut', + 'decrease', 'delete', 'divide', 'drink', + 'eat', 'earn', 'enable', 'enter', 'execute', 'exit', 'expand', 'explain', + 'finish', 'forecast', 'fix', + 'generate', + 'handle', 'help', 'hire', 'hit', + 'improve', 'increase', + 'join', 'jump', + 'leave', 'let\'/s', 'list', 'listen', + 'magnify', 'make', 'manage', 'minimize', 'move', + 'ok', 'open', 'organise', 'oversee', + 'play', 'push', + 'read', 'reduce', 'run', + 'save', 'send', 'shout', 'sing', 'submit', 'support', + 'talk', 'trim', + 'visit', 'volunteer', 'vote', + 'watch', 'win', 'write', +]; +const schema = generateObjSchema({ components: arraySchema }); + +module.exports = { + meta: { + docs: {}, + schema: [schema], + }, + + create: (context) => ({ + JSXOpeningElement: (node) => { + const TextChildValue = node.parent.children.find((child) => child.type === 'Literal' || child.type === 'JSXText' || child.type === 'Unknown'); // text within div elements + const options = context.options[0] || {}; // returns e.g.: [object Object] + const componentOptions = options.components || []; // returns e.g.: Apply - comming from .eslintrc.js file + const typeCheck = ['div'].concat(componentOptions); // returns e.g.: the string div, Apply + const nodeType = elementType(node); // returns e.g.: Apply + + // Only check 'div*' elements and custom types. + // for example, is the Apply custom component present in div,Apply + // answers the question: is the current node, which is Apply is defined in the componentOptions in the eslintrc.json file? + if (typeCheck.indexOf(nodeType) === -1) { + return; + } + + if ((actionVerbs.includes(nodeType.toLowerCase()) || nodeType.toLowerCase() === 'button') === true) { + if (actionVerbs.includes(TextChildValue && TextChildValue.value.toLowerCase()) === false) { + context.report({ + node, + message: 'If custom element is an action word then the text within it should also be an action word. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + }); + return; + } + } + + if (actionVerbs.includes(TextChildValue && TextChildValue.value.toLowerCase()) === false) { + return; + } + + const tabindexProp = getProp(node.attributes, 'tabIndex'); + const roleProp = getProp(node.attributes, 'role'); + const tabindexValue = getPropValue(tabindexProp); + const roleValue = getPropValue(roleProp); + // Missing and/ or incorrect tabindex and role attributes + if (((tabindexProp === undefined) && (roleProp === undefined)) || ((tabindexValue !== '0') && (roleValue !== 'button')) + || ((tabindexProp === undefined) && (roleValue !== 'button')) || ((tabindexValue !== '0') && (roleProp === undefined))) { + context.report({ + node, + message: 'Missing and/or incorrect attributes. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + }); + return; + } + + // Missing and/or incorrect tabindex attribute + if ((tabindexValue !== '0') || (tabindexProp === undefined)) { + context.report({ + node, + message: 'Missing or incorrect role attribute value. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + }); + return; + } + + // Missing and/or incorrect role attribute + if ((roleValue !== 'button') || (roleProp === undefined)) { + context.report({ + node, + message: 'Missing or incorrect role value. Action verbs should be contained preferably within a native HTML button element(see first rule of ARIA) or within a div element that has tabIndex="0" attribute and role="button" aria role. Refer to https://w3c.github.io/aria-practices/examples/button/button.html and https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#accessibility_concerns', + }); + } + }, + }), +}; diff --git a/src/rules/div-has-content.js b/src/rules/div-has-content.js new file mode 100644 index 000000000..7d02392da --- /dev/null +++ b/src/rules/div-has-content.js @@ -0,0 +1,54 @@ +/** + * @fileoverview check if div has content + * @author Felicia + * @flow + */ + +// ---------------------------------------------------------------------------- +// Rule Definition +// ---------------------------------------------------------------------------- + +import { elementType } from 'jsx-ast-utils'; +// import type { JSXOpeningElement } from 'ast-types-flow'; +import { generateObjSchema, arraySchema } from '../util/schemas'; +import hasAccessibleChild from '../util/hasAccessibleChild'; +import isHiddenFromScreenReader from '../util/isHiddenFromScreenReader'; + +const errorMessage = 'Div must have content and the content must be accessible by a screen reader.'; + +const headings = [ + 'div', +]; + +const schema = generateObjSchema({ components: arraySchema }); + +module.exports = { + meta: { + docs: {}, + schema: [schema], + }, + + create: (context) => ({ + JSXOpeningElement: (node) => { + const options = context.options[0] || {}; + const componentOptions = options.components || []; + const typeCheck = headings.concat(componentOptions); + const nodeType = elementType(node); + + // Only check 'div*' elements and custom types. + if (typeCheck.indexOf(nodeType) === -1) { + return; + } + if (hasAccessibleChild(node.parent)) { + return; + } + if (isHiddenFromScreenReader(nodeType, node.attributes)) { + return; + } + context.report({ + node, + message: errorMessage, + }); + }, + }), +}; diff --git a/src/util/hasApplyText.js b/src/util/hasApplyText.js new file mode 100644 index 000000000..f67f89694 --- /dev/null +++ b/src/util/hasApplyText.js @@ -0,0 +1,28 @@ +// @flow + +import { elementType, hasAnyProp } from 'jsx-ast-utils'; +import type { JSXElement } from 'ast-types-flow'; +import isHiddenFromScreenReader from './isHiddenFromScreenReader'; + +export default function hasApplyText(node: JSXElement): boolean { + return node.children.some((child) => { + switch (child.type) { + case 'Literal': + case 'JSXText': + // return (Boolean(child.value) && Boolean(child.value.toUpperCase() === 'APPLY')); + return Boolean(child.value); + case 'JSXElement': + return !isHiddenFromScreenReader( + elementType(child.openingElement), + child.openingElement.attributes, + ); + case 'JSXExpressionContainer': + if (child.expression.type === 'Identifier') { + return child.expression.name !== 'undefined'; + } + return true; + default: + return false; + } + }) || hasAnyProp(node.openingElement.attributes, ['dangerouslySetInnerHTML', 'children']); +}