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: better unsupported attribute support for aria-roledescription #1382

Merged
merged 11 commits into from
Feb 28, 2019
9 changes: 4 additions & 5 deletions doc/aria-supported.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ For a detailed description about how accessibility support is decided, see [How

## Attributes

| aria-attribute | axe-core support |
| -------------------- | ---------------- |
| aria-describedat | No |
| aria-details | No |
| aria-roledescription | No |
straker marked this conversation as resolved.
Show resolved Hide resolved
| aria-attribute | axe-core support |
| ---------------- | ---------------- |
| aria-describedat | No |
| aria-details | No |
33 changes: 29 additions & 4 deletions lib/checks/aria/unsupportedattr.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let unsupported = Array.from(node.attributes)
let unsupportedAttrs = Array.from(node.attributes)
.filter(candidate => {
// filter out unsupported attributes
// return unsupported attributes
return axe.commons.aria.validateAttr(candidate.name, {
flagUnsupported: true
});
Expand All @@ -9,8 +9,33 @@ let unsupported = Array.from(node.attributes)
return candidate.name.toString();
});

if (unsupported.length) {
this.data(unsupported);
if (!unsupportedAttrs.length) {
return false;
}

const nodeName = node.nodeName.toUpperCase();
const lookupTable = axe.commons.aria.lookupTable;
const role = axe.commons.aria.getRole(node);

unsupportedAttrs = unsupportedAttrs.filter(attr => {
straker marked this conversation as resolved.
Show resolved Hide resolved
const unsupported = lookupTable.attributes[attr].unsupported;

if (typeof unsupported === 'boolean' || !unsupported.allowedElements) {
return true;
}

// validate attributes and conditions (if any) from allowedElement to given node
let out = axe.commons.matches(node, unsupported.allowedElements);

// if given node type has complex condition to evaluate a given aria-role, execute the same
if (Object.keys(lookupTable.evaluateRoleForElement).includes(nodeName)) {
return !lookupTable.evaluateRoleForElement[nodeName]({ node, role, out });
}
return !out;
});

if (unsupportedAttrs.length) {
this.data(unsupportedAttrs);
return true;
}
return false;
17 changes: 16 additions & 1 deletion lib/commons/aria/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,22 @@ lookupTable.attributes = {
unsupported: false
},
'aria-roledescription': {
unsupported: true
type: 'string',
allowEmpty: true,
unsupported: {
allowedElements: [
'button',
{
nodeName: 'input',
properties: {
type: ['button', 'checkbox', 'image', 'radio', 'reset', 'submit']
}
},
'img',
'select',
'summary'
]
}
},
'aria-rowcount': {
type: 'int',
Expand Down
62 changes: 62 additions & 0 deletions test/checks/aria/unsupportedattr.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,66 @@ describe('unsupportedattr', function() {
);
assert.isFalse(check.evaluate.apply(checkContext, params));
});

it('should return false if applied to an element that matches the unsupported "allowedElements" list', function() {
axe.commons.aria.lookupTable.attributes['aria-mccheddarton'] = {
unsupported: {
allowedElements: ['button']
}
};
var params = checkSetup(
'<button id="target" aria-mccheddarton="true">Contents</div>'
);
assert.isFalse(check.evaluate.apply(checkContext, params));
});

it('should return false if applied to an element that matches the unsupported "allowedElements" list using complex conditions', function() {
axe.commons.aria.lookupTable.attributes['aria-mccheddarton'] = {
unsupported: {
allowedElements: [
{
nodeName: 'input',
properties: {
type: 'checkbox'
}
}
]
}
};
var params = checkSetup(
'<input type="checkbox" id="target" aria-mccheddarton="true">Contents</div>'
);
assert.isFalse(check.evaluate.apply(checkContext, params));
});

it('should return true if applied to an element that does not match the unsupported "allowedElements" list', function() {
axe.commons.aria.lookupTable.attributes['aria-mccheddarton'] = {
unsupported: {
allowedElements: ['button']
}
};
var params = checkSetup(
'<div id="target" aria-mccheddarton="true">Contents</div>'
);
assert.isTrue(check.evaluate.apply(checkContext, params));
});

it('should return true if applied to an element that does not match the unsupported "allowedElements" list using complex conditions', function() {
axe.commons.aria.lookupTable.attributes['aria-mccheddarton'] = {
unsupported: {
allowedElements: [
{
nodeName: 'input',
properties: {
type: 'checkbox'
}
}
]
}
};
var params = checkSetup(
'<input type="radio" id="target" aria-mccheddarton="true">Contents</div>'
);
assert.isTrue(check.evaluate.apply(checkContext, params));
});
});
17 changes: 16 additions & 1 deletion test/checks/aria/valid-attr.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('aria-valid-attr', function() {
assert.deepEqual(checkContext._data, ['aria-cats', 'aria-dogs']);
});

it('should return false if no invalid ARIA attributes are found', function() {
it('should return true if no invalid ARIA attributes are found', function() {
var node = document.createElement('div');
node.id = 'test';
node.tabIndex = 1;
Expand Down Expand Up @@ -54,6 +54,21 @@ describe('aria-valid-attr', function() {
axe.commons.aria.validateAttr = orig;
});

it('should return true for unsupported ARIA attributes', function() {
axe.commons.aria.lookupTable.attributes['aria-mccheddarton'] = {
unsupported: true
};

var node = document.createElement('div');
node.id = 'test';
node.tabIndex = 1;
node.setAttribute('aria-mccheddarton', 'true');
fixture.appendChild(node);

assert.isTrue(checks['aria-valid-attr'].evaluate.call(checkContext, node));
assert.isNull(checkContext._data);
});

describe('options', function() {
it('should exclude provided attribute names', function() {
fixture.innerHTML =
Expand Down