-
Notifications
You must be signed in to change notification settings - Fork 791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rule): update for lists, list-items to handle role changes. #949
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address the comments
lib/checks/lists/dlitem.js
Outdated
if (ALLOWED_ROLES.includes(parentRole)) { | ||
return true; | ||
} | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should check to see whether the other role is a valid ARIA role or otherwise it will not actually override the semantic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What Dylan said.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: role='fake-role' should fallback to semantic.
lib/checks/lists/listitem.js
Outdated
|
||
const parentTagName = parent.nodeName.toLowerCase(); | ||
const parentRole = (parent.getAttribute('role') || '').toLowerCase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filter roles to only accept valid ARIA roles
@@ -1,19 +1,41 @@ | |||
var bad = [], |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@@ -1,18 +1,84 @@ | |||
var bad = [], |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
test/checks/lists/only-listitems.js
Outdated
it('should return false if the list has whitespace', function () { | ||
var checkArgs = checkSetup('<ol id="target"><li>Item</li> </ol>'); | ||
|
||
assert.isFalse(checks['only-listitems'].evaluate.apply(checkContext, checkArgs)); | ||
}); | ||
|
||
it('should return false if the list has only an element with role listitem', function () { | ||
var checkArgs = checkSetup('<ol id="target"><div role="listitem">A list</div></ol>'); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JKODU why has this not yet been addressed?
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dylanb I think that's on me - I replied to it saying that Axe shouldn't be a validator. As long as it works in AT, it shouldn't matter if it's valid HTML or not.
test/checks/lists/only-listitems.js
Outdated
}); | ||
|
||
it('should return false if the list has only multiple mixed elements with role listitem', function () { | ||
var checkArgs = checkSetup('<ol id="target"><div role="listitem">list</div><li role="listitem">list</li><div role="listitem">list</div></ol>'); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dito
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my previous comment.
test/checks/lists/only-listitems.js
Outdated
}); | ||
|
||
it('should return true if <link> is used along side only li items with their roles changed', function () { | ||
var checkArgs = checkSetup('<ol id="target"><link rel="stylesheet" href="theme.css"><li role="menuitem">Not a list item</li></ol>'); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rationale for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dylanb This isn't new - we've allowed pretty much any non-content elements inside of lists from way back. If you think we should change that I propose we do it in a separate PR.
@dylanb Could you expand on this comment as well (from the old PR)? |
test/checks/lists/only-listitems.js
Outdated
it('should return false if the list has whitespace', function () { | ||
var checkArgs = checkSetup('<ol id="target"><li>Item</li> </ol>'); | ||
|
||
assert.isFalse(checks['only-listitems'].evaluate.apply(checkContext, checkArgs)); | ||
}); | ||
|
||
it('should return false if the list has only an element with role listitem', function () { | ||
var checkArgs = checkSetup('<ol id="target"><div role="listitem">A list</div></ol>'); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
lib/checks/lists/dlitem.js
Outdated
return false; | ||
} | ||
|
||
const ALLOWED_ROLES = ['list']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems needlessly complicated.
lib/checks/lists/dlitem.js
Outdated
if (ALLOWED_ROLES.includes(parentRole)) { | ||
return true; | ||
} | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What Dylan said.
lib/checks/lists/listitem.js
Outdated
|
||
const ALLOWED_TAGS = ['ul', 'ol']; | ||
const ALLOWED_ROLES = ['list']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just complicates things.
lib/checks/lists/listitem.js
Outdated
} | ||
|
||
const ALLOWED_TAGS = ['ul', 'ol']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use upper case node names.
lib/checks/lists/only-listitems.js
Outdated
*/ | ||
const tagName = actualNode.nodeName.toLowerCase(); | ||
|
||
switch (actualNode.nodeType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should just be an if statement.
lib/checks/lists/only-listitems.js
Outdated
const getIsListItemRole = (r, t) => { | ||
let out = false; | ||
out = (r === 'listitem' || (t === 'li' && !r)); | ||
return out; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What?
lib/checks/lists/only-listitems.js
Outdated
|
||
const getIsListItemRole = (r, t) => { | ||
let out = false; | ||
out = (r === 'listitem' || (t === 'li' && !r)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!r
should test that this is a valid non-abstract role, not just that it's null. This entire function could do with some cleanup. Don't use single letter variables, and just return on this line rather than assign it to a var and immediately return that.
lib/checks/lists/only-listitems.js
Outdated
|
||
switch (actualNode.nodeType) { | ||
case 1: | ||
if (!ALLOWED_TAGS.includes(tagName)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic of this block is pretty difficult to follow, far more than it needs to be.
lib/checks/lists/only-listitems.js
Outdated
} | ||
|
||
return !!bad.length || hasNonEmptyTextNode; | ||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really difficult to see if this code actually does what it should. Please break this up.
@dylanb @WilcoFiers - review again. |
@WilcoFiers - based on our chat, this can be approved I believe. |
@dylanb @marcysutton - review plz |
lib/checks/lists/dlitem.js
Outdated
return parent.nodeName.toUpperCase() === 'DL'; | ||
const parent = axe.commons.dom.getComposedParent(node); | ||
if (!parent) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the cases where there isn't a composed parent?
|
||
const parentRole = (parent.getAttribute('role') || '').toLowerCase(); | ||
|
||
if (!parentRole) { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
lib/checks/lists/dlitem.js
Outdated
return false; | ||
} | ||
|
||
if (parentRole) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this if.
['UL', 'OL'].includes(parent.nodeName.toUpperCase()) || | ||
(parent.getAttribute('role') || '').toLowerCase() === 'list' | ||
(ALLOWED_TAGS.includes(parentTagName) && (!parentRole || isListRole)) || | ||
isListRole |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just inline parentRole === 'list'
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaving as is, abstraction reads better here, as otherwise it feels repeated.
lib/checks/lists/only-dlitems.js
Outdated
hasNonEmptyTextNode: false | ||
}; | ||
|
||
const out = virtualNode.children.reduce((out, { actualNode }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use destructive assignment so that you're never using this meaningless variable name?
This rule updates list(items) to cater to role changes to either parent or child list elements.
This rule is a taken over PR from the community contribution (PR: #518 @AlmeroSteyn - thanks for the initial work).
Closes issue:
Reviewer checks
Required fields, to be filled out by PR reviewer(s)