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

feat: ARIA supported checks #1254

Merged
merged 8 commits into from
Dec 14, 2018
Merged

feat: ARIA supported checks #1254

merged 8 commits into from
Dec 14, 2018

Conversation

marcysutton
Copy link
Contributor

@marcysutton marcysutton commented Nov 21, 2018

This branch adds a new check to report unsupported ARIA attributes to the user. We have to make a decision on how to modify the rule to support it, which you can find discussed in #918.

Closes issue: #918

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

let unsupported;
if (node.hasAttributes()) {
unsupported = [].slice
.call(node.attributes)
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 use `Array.from(node.attributes) to simplify this a bit.

.call(node.attributes)
.filter(candidate => {
// skip non-ARIA attributes
if (/aria-/.test(candidate.name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You probably don't need to do this if statement. Just rely on aria.validateAttr to sort that out for you. That way you also always return. It's a little nicer to read a filter if it always returns a boolean.

if (!attrDefinition || (flagUnsupported && isAttrUnsupported)) {
return false;
}
return !!attrDefinition;
Copy link
Contributor

Choose a reason for hiding this comment

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

This function is a little difficult to read, with all the logic operations going on. This may be simpler:

const attrDefinition = aria.lookupTable.attributes[att];
if (flagUnsupported && attrDefinition) {
  return !!attrDefinition.unsupported
}
return !!attrDefinition

@@ -10,177 +10,232 @@ var aria = (commons.aria = {}),
lookupTable.attributes = {
'aria-activedescendant': {
type: 'idref',
allowEmpty: true
allowEmpty: true,
unsupported: false
Copy link
Contributor

Choose a reason for hiding this comment

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

I know we did this for all the roles too, but do we really need to set these explicitly? I think that's the virtue of using unsupported over supported, you don't have to specify it to be falsey. I'd have a slight preference for only setting it if it's true.

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 them off and using falsey values instead sounds fine to me!

allowEmpty: true,
unsupported: false
},
'aria-describedat': {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is one of the attributes that was proposed for ARIA but never made it into the spec. Did you mean to add a non-standard attribute in here? I can see a use case for including attributes that were at one point proposed but never made it into the spec. We would have to be explicit about it though, and we'd have to put some sort of "unstandardised" flag on it. That's probably out of scope for this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can leave it off, I only added it because it was mentioned in the aria-supported diff. But if we did include it, if someone tried to use it they'd see it was unsupported. I like the idea of an "unstandardized" flag in here.

let attrs = node.attributes;
for (let i = 0, l = attrs.length; i < l; i++) {
if (aria.test(attrs[i].name)) {
return true;
Copy link
Contributor

Choose a reason for hiding this comment

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

We can simplify this quite a bit. There's also no reason for this hasAttributes thing. There is no performance benefit to using DOM has methods. Only use them if you're not interested in the actual content of the attribute.

return Array.from(node.attributes)
  .some(({ name }) => /^aria-/.test(name))

@@ -7,6 +7,6 @@
"help": "Elements must only use allowed ARIA attributes"
},
"all": [],
"any": ["aria-allowed-attr"],
"any": ["aria-allowed-attr", "aria-unsupported-attr"],
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reasoning behind adding this to aria-allowed-attr instead of to aria-valid-attr? I haven't quite figured out which place I think is best, so I'd like to know your reasoning for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a really fine line. I went for "allowed" because technically these attributes are valid, but we're recommending they not be used because of support purposes. Both aria-allowed-attr and aria-valid-attr use the same commons method to validate, except aria-allowed-attr has some more logic to check the role. The new unsupported check could go in either rule, really.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I still believe that the correct rule for this behavior is aria-allowed-attr rather than aria-valid-attr, so we can get the correct messaging. I'm going to move forward with the change to the matches function so we can keep this rolling.

this.data(unsupported);
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.

I'm not sure the logic works here. Shouldn't you return true when this passes? I would also think that this needs to be in all instead of any in the rule. That decision may be why you used this strange logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@WilcoFiers the aria-roles unsupported stuff works on none. I would actually think that should be the case here as well.

@marcysutton marcysutton changed the title WIP: ARIA supported checks ARIA supported checks Dec 11, 2018
@marcysutton
Copy link
Contributor Author

marcysutton commented Dec 11, 2018

This is ready for another review.

Test failure on CircleCI is unrelated:

>> URL: http://localhost:9876/test/integration/full/landmark-contentinfo-is-top-level/landmark-contentinfo-is-top-level-fail.html
>> Describe: landmark-contentinfo-is-top-level test fail
>> it "before all" hook
>> Error: Timeout of 10000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

Warning: Task "test-webdriver:chrome-mobile" failed.� Use --force to continue.

@@ -40,7 +40,6 @@ describe('description', function() {
shadow.innerHTML = '<video><slot></slot></video>';

var checkArgs = checkSetup(node, {}, 'video');
axe.log(checkArgs);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This commit should have test in the scope, and is unrelated to this PR. But it kept irritating me when running tests.

@WilcoFiers WilcoFiers dismissed their stale review December 11, 2018 16:11

PR updated

Copy link
Contributor

@WilcoFiers WilcoFiers left a comment

Choose a reason for hiding this comment

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

Only small stuff left.

if (node.hasAttributes()) {
let attrs = node.attributes;
for (let i = 0, l = attrs.length; i < l; i++) {
if (aria.test(attrs[i].name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, should have noticed this in my first review. It seems like you're not filtering out elements with only invalid ARIA attributes:

<input aria-invalidattr="foo" />

This element shouldn't be applicable to this rule. It's a pretty minor bug, so I'll leave it for you to decide if you want to bother with it. The fix is to use axe.commons.aria.validateAttr in the if statement here.

@marcysutton marcysutton changed the title ARIA supported checks feat: ARIA supported checks Dec 12, 2018
@WilcoFiers WilcoFiers merged commit 51a18a8 into develop Dec 14, 2018
@jeeyyy jeeyyy deleted the aria-supported-checks branch December 17, 2018 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants