Skip to content
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

Merged
merged 9 commits into from
Jul 18, 2018

Conversation

jeeyyy
Copy link
Contributor

@jeeyyy jeeyyy commented Jun 8, 2018

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)

  • Follows the commit message policy, appropriate for next version
  • Has documentation updated, a DU ticket, or requires no documentation change
  • Includes new tests, or was unnecessary
  • Code is reviewed for security by: @WilcoFiers

@jeeyyy jeeyyy self-assigned this Jun 8, 2018
@jeeyyy jeeyyy added the rules Issue or false result from an axe-core rule label Jun 8, 2018
dylanb
dylanb previously requested changes Jun 8, 2018
Copy link
Contributor

@dylanb dylanb left a 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

if (ALLOWED_ROLES.includes(parentRole)) {
return true;
}
return false;
Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What Dylan said.

Copy link
Contributor Author

@jeeyyy jeeyyy Jun 26, 2018

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.


const parentTagName = parent.nodeName.toLowerCase();
const parentRole = (parent.getAttribute('role') || '').toLowerCase();
Copy link
Contributor

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.

@@ -1,18 +1,84 @@
var bad = [],

This comment was marked as resolved.

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

});

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dito

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my previous comment.

});

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.

Copy link
Contributor

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?

Copy link
Contributor

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.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jun 8, 2018

@dylanb
Cheers for the above, will address.

Could you expand on this comment as well (from the old PR)?
#518 (comment)

@jeeyyy jeeyyy changed the title rule: update for lists, list-items to handle role changes. fix(rule): update for lists, list-items to handle role changes. Jun 11, 2018
@jeeyyy jeeyyy changed the title fix(rule): update for lists, list-items to handle role changes. [WIP] fix(rule): update for lists, list-items to handle role changes. Jun 20, 2018
@jeeyyy jeeyyy changed the title [WIP] fix(rule): update for lists, list-items to handle role changes. fix(rule): update for lists, list-items to handle role changes. Jun 26, 2018
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.

return false;
}

const ALLOWED_ROLES = ['list'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems needlessly complicated.

if (ALLOWED_ROLES.includes(parentRole)) {
return true;
}
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What Dylan said.


const ALLOWED_TAGS = ['ul', 'ol'];
const ALLOWED_ROLES = ['list'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just complicates things.

}

const ALLOWED_TAGS = ['ul', 'ol'];
Copy link
Contributor

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.

*/
const tagName = actualNode.nodeName.toLowerCase();

switch (actualNode.nodeType) {
Copy link
Contributor

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.

const getIsListItemRole = (r, t) => {
let out = false;
out = (r === 'listitem' || (t === 'li' && !r));
return out;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What?


const getIsListItemRole = (r, t) => {
let out = false;
out = (r === 'listitem' || (t === 'li' && !r));
Copy link
Contributor

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.


switch (actualNode.nodeType) {
case 1:
if (!ALLOWED_TAGS.includes(tagName)) {
Copy link
Contributor

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.

}

return !!bad.length || hasNonEmptyTextNode;
return (
Copy link
Contributor

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.

@jeeyyy jeeyyy changed the title fix(rule): update for lists, list-items to handle role changes. [WIP] fix(rule): update for lists, list-items to handle role changes. Jun 27, 2018
@jeeyyy jeeyyy changed the title [WIP] fix(rule): update for lists, list-items to handle role changes. fix(rule): update for lists, list-items to handle role changes. Jul 3, 2018
@jeeyyy jeeyyy dismissed WilcoFiers’s stale review July 3, 2018 23:12

Please review again.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 4, 2018

@dylanb @WilcoFiers - review again.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 16, 2018

@WilcoFiers - based on our chat, this can be approved I believe.

@jeeyyy
Copy link
Contributor Author

jeeyyy commented Jul 16, 2018

@dylanb @marcysutton - review plz

return parent.nodeName.toUpperCase() === 'DL';
const parent = axe.commons.dom.getComposedParent(node);
if (!parent) {
return false;
Copy link
Contributor

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.

return false;
}

if (parentRole) {
Copy link
Contributor

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
Copy link
Contributor

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'.

Copy link
Contributor Author

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.

hasNonEmptyTextNode: false
};

const out = virtualNode.children.reduce((out, { actualNode }) => {
Copy link
Contributor

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?

@WilcoFiers WilcoFiers merged commit 3a8729b into develop Jul 18, 2018
@WilcoFiers WilcoFiers deleted the rule-update-lists branch July 18, 2018 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rules Issue or false result from an axe-core rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants