-
Notifications
You must be signed in to change notification settings - Fork 784
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: Add aria.getRole method #1017
Changes from 2 commits
e3b1e1d
1d2a0e4
2aab267
74aaa0e
fb2aa46
514da4d
fcb9f8c
786a62d
e79a039
56ceee9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
return !axe.commons.aria.isValidRole(node.getAttribute('role')); | ||
return !axe.commons.aria.isValidRole(node.getAttribute('role'), { | ||
allowAbstract: true | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
const parent = axe.commons.dom.getComposedParent(node); | ||
if (!parent) { | ||
return false; | ||
// Can only happen with detached DOM nodes and roots: | ||
return undefined; | ||
} | ||
|
||
const ALLOWED_TAGS = ['UL', 'OL']; | ||
const parentTagName = parent.nodeName.toUpperCase(); | ||
|
||
const parentRole = (parent.getAttribute('role') || '').toLowerCase(); | ||
if (parentRole && !axe.commons.aria.isValidRole(parentRole)) { | ||
|
||
if (parentRole === 'list') { | ||
return true; | ||
} | ||
|
||
if (parentRole && axe.commons.aria.isValidRole(parentRole)) { | ||
return false; | ||
} | ||
|
||
const isListRole = parentRole === 'list'; | ||
return ( | ||
(ALLOWED_TAGS.includes(parentTagName) && (!parentRole || isListRole)) || | ||
isListRole | ||
); | ||
return ['UL', 'OL'].includes(parentTagName); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* global aria, axe */ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add jsdoc comments please, with @return decorating what is expected. |
||
aria.getRole = function getRole( | ||
node, | ||
{ noImplicit, tokenList, abstracts, dpub } = {} | ||
) { | ||
const roleAttr = (node.getAttribute('role') || '').trim().toLowerCase(); | ||
const roleList = tokenList ? axe.utils.tokenList(roleAttr) : [roleAttr]; | ||
|
||
// Get the first valid role: | ||
const validRoles = roleList.filter(role => { | ||
if (!dpub && role.substr(0, 4) === 'doc-') { | ||
return false; | ||
} | ||
return aria.isValidRole(role, { allowAbstract: abstracts }); | ||
}); | ||
const role = validRoles[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need a length check on validRoles here, there is a chance that this can be an empty array, if role is not defined in a given node. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't matter. In that case |
||
|
||
// Get the impgit licit role, if permitted | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edit: In comment - implicit |
||
if (!role && !noImplicit) { | ||
return aria.implicitRole(node); | ||
} | ||
|
||
return role || null; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,91 @@ | ||
describe('dlitem', function () { | ||
describe('dlitem', function() { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
var checkSetup = axe.testUtils.checkSetup; | ||
var shadowSupport = axe.testUtils.shadowSupport; | ||
|
||
afterEach(function () { | ||
afterEach(function() { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should pass if the dlitem has a parent <dl>', function () { | ||
it('should pass if the dlitem has a parent <dl>', function() { | ||
var checkArgs = checkSetup('<dl><dt id="target">My list item</dl>'); | ||
|
||
assert.isTrue(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should fail if the dt element has an incorrect parent', function () { | ||
it('should fail if the dt element has an incorrect parent', function() { | ||
var checkArgs = checkSetup('<video><dt id="target">My list item</video>'); | ||
|
||
assert.isFalse(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should pass if the dt element has a parent <dl> with role="list"', function () { | ||
var checkArgs = checkSetup('<dl role="list"><dt id="target">My list item</dl>'); | ||
it('should pass if the dt element has a parent <dl> with role="list"', function() { | ||
var checkArgs = checkSetup( | ||
'<dl role="list"><dt id="target">My list item</dl>' | ||
); | ||
assert.isTrue(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}) | ||
}); | ||
|
||
it('should fail if the dt element has a parent <dl> with role="presentation"', function () { | ||
var checkArgs = checkSetup('<dl role="presentation"><dt id="target">My list item</dl>'); | ||
it('should fail if the dt element has a parent <dl> with role="presentation"', function() { | ||
var checkArgs = checkSetup( | ||
'<dl role="presentation"><dt id="target">My list item</dl>' | ||
); | ||
assert.isFalse(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should fail if the dt element has a parent <dl> with a changed role', function(){ | ||
var checkArgs = checkSetup('<dl role="menubar"><dt id="target">My list item</dl>'); | ||
it('should fail if the dt element has a parent <div> with role="list"', function() { | ||
var checkArgs = checkSetup( | ||
'<div role="list"><dt id="target">My list item</div>' | ||
); | ||
assert.isFalse(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)('should return true in a shadow DOM pass', function () { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<dt>My list item </dt>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<dl><slot></slot></dl>'; | ||
|
||
var checkArgs = checkSetup(node, 'dt'); | ||
it('should pass if the dt element has a parent <dl> with an abstract role', function() { | ||
var checkArgs = checkSetup( | ||
'<dl role="section"><dt id="target">My list item</dl>' | ||
); | ||
assert.isTrue(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)('should return false in a shadow DOM fail', function () { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<dt>My list item </dt>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<div><slot></slot></div>'; | ||
it('should pass if the dt element has a parent <dl> with an invalid role', function() { | ||
var checkArgs = checkSetup( | ||
'<dl role="invalid-role"><dt id="target">My list item</dl>' | ||
); | ||
assert.isTrue(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
var checkArgs = checkSetup(node, 'dt'); | ||
it('should fail if the dt element has a parent <dl> with a changed role', function() { | ||
var checkArgs = checkSetup( | ||
'<dl role="menubar"><dt id="target">My list item</dl>' | ||
); | ||
assert.isFalse(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)( | ||
'should return true in a shadow DOM pass', | ||
function() { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<dt>My list item </dt>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<dl><slot></slot></dl>'; | ||
|
||
var checkArgs = checkSetup(node, 'dt'); | ||
assert.isTrue(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
} | ||
); | ||
|
||
(shadowSupport.v1 ? it : xit)( | ||
'should return false in a shadow DOM fail', | ||
function() { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<dt>My list item </dt>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<div><slot></slot></div>'; | ||
|
||
var checkArgs = checkSetup(node, 'dt'); | ||
assert.isFalse(checks.dlitem.evaluate.apply(null, checkArgs)); | ||
} | ||
); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,78 @@ | ||
describe('listitem', function () { | ||
describe('listitem', function() { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
var checkSetup = axe.testUtils.checkSetup; | ||
var shadowSupport = axe.testUtils.shadowSupport; | ||
|
||
afterEach(function () { | ||
afterEach(function() { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should pass if the listitem has a parent <ol>', function () { | ||
it('should pass if the listitem has a parent <ol>', function() { | ||
var checkArgs = checkSetup('<ol><li id="target">My list item</li></ol>'); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should pass if the listitem has a parent <ul>', function () { | ||
it('should pass if the listitem has a parent <ul>', function() { | ||
var checkArgs = checkSetup('<ul><li id="target">My list item</li></ul>'); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should pass if the listitem has a parent role=list', function () { | ||
var checkArgs = checkSetup('<div role="list"><li id="target">My list item</li></div>'); | ||
it('should pass if the listitem has a parent role=list', function() { | ||
var checkArgs = checkSetup( | ||
'<div role="list"><li id="target">My list item</li></div>' | ||
); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should fail if the listitem has an incorrect parent', function () { | ||
it('should fail if the listitem has an incorrect parent', function() { | ||
var checkArgs = checkSetup('<div><li id="target">My list item</li></div>'); | ||
assert.isFalse(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
it('should fail if the listitem has a parent <ol> with changed role', function () { | ||
var checkArgs = checkSetup('<ol role="menubar"><li id="target">My list item</li></ol>'); | ||
it('should fail if the listitem has a parent <ol> with changed role', function() { | ||
var checkArgs = checkSetup( | ||
'<ol role="menubar"><li id="target">My list item</li></ol>' | ||
); | ||
assert.isFalse(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)('should return true in a shadow DOM pass', function () { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<li>My list item </li>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<ul><slot></slot></ul>'; | ||
var checkArgs = checkSetup(node, 'li'); | ||
it('should pass if the listitem has a parent <ol> with an invalid role', function() { | ||
var checkArgs = checkSetup( | ||
'<ol role="invalid-role"><li id="target">My list item</li></ol>' | ||
); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)('should return false in a shadow DOM fail', function () { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<li>My list item </li>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<div><slot></slot></div>'; | ||
var checkArgs = checkSetup(node, 'li'); | ||
assert.isFalse(checks.listitem.evaluate.apply(null, checkArgs)); | ||
it('should pass if the listitem has a parent <ol> with an abstract role', function() { | ||
var checkArgs = checkSetup( | ||
'<ol role="section"><li id="target">My list item</li></ol>' | ||
); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupport.v1 ? it : xit)( | ||
'should return true in a shadow DOM pass', | ||
function() { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<li>My list item </li>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<ul><slot></slot></ul>'; | ||
var checkArgs = checkSetup(node, 'li'); | ||
assert.isTrue(checks.listitem.evaluate.apply(null, checkArgs)); | ||
} | ||
); | ||
|
||
(shadowSupport.v1 ? it : xit)( | ||
'should return false in a shadow DOM fail', | ||
function() { | ||
var node = document.createElement('div'); | ||
node.innerHTML = '<li>My list item </li>'; | ||
var shadow = node.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<div><slot></slot></div>'; | ||
var checkArgs = checkSetup(node, 'li'); | ||
assert.isFalse(checks.listitem.evaluate.apply(null, checkArgs)); | ||
} | ||
); | ||
}); |
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.
Minor remark, shouldn't these documentation updates be a part of another build where these changes were made to the respective rules? Worth folding into a new PR?