-
Notifications
You must be signed in to change notification settings - Fork 783
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(landmark-contentinfo-is-top-level): add rule ensuring top level …
…contentinfo
- Loading branch information
1 parent
7c0cf8e
commit 5692e7d
Showing
12 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const landmarks = axe.commons.aria.getRolesByType('landmark'); | ||
const sectioning = ['article', 'aside', 'main', 'navigation', 'section']; | ||
const nodeIsHeader = node.tagName.toLowerCase() === 'footer' && node.getAttribute('role') !== 'contentinfo'; | ||
var parent = axe.commons.dom.getComposedParent(node); | ||
|
||
while (parent){ | ||
var role = parent.getAttribute('role'); | ||
if (!role && (parent.tagName.toLowerCase() !== 'form')){ | ||
role = axe.commons.aria.implicitRole(parent); | ||
} | ||
if (role && nodeIsHeader && sectioning.includes(role)){ | ||
return true; | ||
} | ||
if (role && landmarks.includes(role)){ | ||
return false; | ||
} | ||
parent = axe.commons.dom.getComposedParent(parent); | ||
} | ||
return true; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"id": "contentinfo-is-top-level", | ||
"evaluate": "contentinfo-is-top-level.js", | ||
"metadata": { | ||
"impact": "moderate", | ||
"messages": { | ||
"pass": "Contentinfo landmark is top level or footer element is not contentinfo", | ||
"fail": "Contentinfo landmark is not top level" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"id": "landmark-contentinfo-is-top-level", | ||
"selector": "[role=contentinfo], footer", | ||
"tags": [ | ||
"best-practice" | ||
], | ||
"metadata": { | ||
"description": "A contentinfo landmark is a way to identify common information at the bottom of each page within a website", | ||
"help": "Contentinfo landmark must be at top level" | ||
}, | ||
"all": [], | ||
"any": [ | ||
"contentinfo-is-top-level" | ||
], | ||
"none": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
describe('contentinfo-is-top-level', function () { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
|
||
var checkSetup = axe.testUtils.checkSetup; | ||
var shadowSupported = axe.testUtils.shadowSupport.v1; | ||
|
||
afterEach(function () { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should return false if contentinfo landmark is in main element', function() { | ||
var main = document.createElement('main'); | ||
var contentinfo = document.createElement('div'); | ||
contentinfo.setAttribute('role','contentinfo'); | ||
main.appendChild(contentinfo); | ||
fixture.appendChild(main); | ||
assert.isFalse(checks['contentinfo-is-top-level'].evaluate(contentinfo)); | ||
}); | ||
|
||
it('should return false if contentinfo landmark is in main element', function () { | ||
var main = document.createElement('main'); | ||
var contentinfo = document.createElement('div'); | ||
contentinfo.setAttribute('role','contentinfo'); | ||
main.appendChild(contentinfo); | ||
fixture.appendChild(main); | ||
assert.isFalse(checks['contentinfo-is-top-level'].evaluate(contentinfo)); | ||
}); | ||
|
||
it('should return false if contentinfo landmark is in div with role main', function () { | ||
var main = document.createElement('div'); | ||
main.setAttribute('role','main'); | ||
var contentinfo = document.createElement('div'); | ||
contentinfo.setAttribute('role','contentinfo'); | ||
main.appendChild(contentinfo); | ||
fixture.appendChild(main); | ||
assert.isFalse(checks['contentinfo-is-top-level'].evaluate(contentinfo)); | ||
}); | ||
|
||
it('should return false if footer is not sectioning element and in div with role search', function () { | ||
var search = document.createElement('div'); | ||
search.setAttribute('role','search'); | ||
var contentinfo = document.createElement('footer'); | ||
search.appendChild(contentinfo); | ||
fixture.appendChild(search); | ||
assert.isFalse(checks['contentinfo-is-top-level'].evaluate(contentinfo)); | ||
}); | ||
|
||
|
||
it('should return true if contentinfo landmark is not contained in another landmark', function () { | ||
var contentinfo = document.createElement('div'); | ||
contentinfo.setAttribute('role','contentinfo'); | ||
fixture.appendChild(contentinfo); | ||
assert.isTrue(checks['contentinfo-is-top-level'].evaluate(contentinfo)); | ||
}); | ||
|
||
it('should return true if footer element is not sectioning element and not contained in landmark', function () { | ||
var footer = document.createElement('footer'); | ||
fixture.appendChild(footer); | ||
assert.isTrue(checks['contentinfo-is-top-level'].evaluate(footer)); | ||
}); | ||
|
||
it('should return true if footer element is in sectioning element', function () { | ||
var footer = document.createElement('footer'); | ||
var article = document.createElement('div'); | ||
article.setAttribute('role', 'main'); | ||
article.appendChild(footer); | ||
fixture.appendChild(article); | ||
assert.isTrue(checks['contentinfo-is-top-level'].evaluate(footer)); | ||
}); | ||
|
||
(shadowSupported ? it : xit)('should test if contentinfo in shadow DOM is top level', function () { | ||
var div = document.createElement('div'); | ||
var shadow = div.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<div role="contentinfo">contentinfo landmark</div>'; | ||
var checkArgs = checkSetup(shadow.querySelector('[role=contentinfo], footer')); | ||
assert.isTrue(checks['contentinfo-is-top-level'].evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
(shadowSupported ? it : xit)('should test if footer in shadow DOM is top level', function () { | ||
var div = document.createElement('div'); | ||
var shadow = div.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<footer>contentinfo landmark</footer>'; | ||
var checkArgs = checkSetup(shadow.querySelector('[role=contentinfo], footer')); | ||
assert.isTrue(checks['contentinfo-is-top-level'].evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
}); |
15 changes: 15 additions & 0 deletions
15
test/integration/full/landmark-contentinfo-is-top-level/frames/level1-fail.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
<html id="violation2"> | ||
<head> | ||
<meta charset="utf8"> | ||
<script src="/axe.js"></script> | ||
</head> | ||
<body> | ||
<p>This iframe should fail, too</p> | ||
<div role="complementary"> | ||
<footer> | ||
<p>This footer is in a complementary landmark</p> | ||
</footer> | ||
</div> | ||
</body> | ||
</html> |
27 changes: 27 additions & 0 deletions
27
test/integration/full/landmark-contentinfo-is-top-level/frames/level1.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!doctype html> | ||
<html id="pass2"> | ||
<head> | ||
<meta charset="utf8"> | ||
<script src="/axe.js"></script> | ||
</head> | ||
<body> | ||
<p>This iframe should pass, too</p> | ||
|
||
<div role="navigation"> | ||
<p>This div has role navigation</p> | ||
</div> | ||
<footer> | ||
<p>This footer is not within another landmark</p> | ||
</footer> | ||
<div role="complementary"> | ||
<p>This div has role complementary</p> | ||
</div> | ||
<div role="search"> | ||
<p>This div has role search</p> | ||
</div> | ||
<div role="form"> | ||
<p>This div has role form<p> | ||
</div> | ||
<iframe id="frame2" src="level2.html"></iframe> | ||
</body> | ||
</html> |
15 changes: 15 additions & 0 deletions
15
test/integration/full/landmark-contentinfo-is-top-level/frames/level2.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
<html id="pass3"> | ||
<head> | ||
<meta charset="utf8"> | ||
<script src="/axe.js"></script> | ||
</head> | ||
<body> | ||
<p>This iframe should pass<p> | ||
<main> | ||
<footer> | ||
<p>This footer is in a main landmark</p> | ||
</footer> | ||
</main> | ||
</body> | ||
</html> |
29 changes: 29 additions & 0 deletions
29
...ration/full/landmark-contentinfo-is-top-level/landmark-contentinfo-is-top-level-fail.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!doctype html> | ||
<html lang="en" id="violation1"> | ||
<head> | ||
<title>landmark-contentinfo-is-top-level test</title> | ||
<meta charset="utf8"> | ||
<link rel="stylesheet" type="text/css" href="/node_modules/mocha/mocha.css" /> | ||
<script src="/node_modules/mocha/mocha.js"></script> | ||
<script src="/node_modules/chai/chai.js"></script> | ||
<script src="/axe.js"></script> | ||
<script> | ||
mocha.setup({ | ||
timeout: 10000, | ||
ui: 'bdd' | ||
}); | ||
var assert = chai.assert; | ||
</script> | ||
</head> | ||
<body> | ||
<div role="navigation"> | ||
<div role="contentinfo"> | ||
<p>This is going to fail</p> | ||
</div> | ||
</div> | ||
<iframe id="frame1" src="frames/level1-fail.html"></iframe> | ||
<div id="mocha"></div> | ||
<script src="landmark-contentinfo-is-top-level-fail.js"></script> | ||
<script src="/test/integration/adapter.js"></script> | ||
</body> | ||
</html> |
40 changes: 40 additions & 0 deletions
40
...egration/full/landmark-contentinfo-is-top-level/landmark-contentinfo-is-top-level-fail.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
describe('landmark-contentinfo-is-top-level test fail', function () { | ||
'use strict'; | ||
var results; | ||
before(function (done) { | ||
window.addEventListener('load', function () { | ||
axe.run({ runOnly: { type: 'rule', values: ['landmark-contentinfo-is-top-level'] } }, function (err, r) { | ||
assert.isNull(err); | ||
results = r; | ||
done(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('violations', function () { | ||
it('should find 1', function () { | ||
assert.lengthOf(results.violations, 1); | ||
}); | ||
|
||
it('should find 2 nodes', function () { | ||
assert.lengthOf(results.violations[0].nodes, 2); | ||
}); | ||
}); | ||
|
||
describe('passes', function () { | ||
it('should find none', function () { | ||
assert.lengthOf(results.passes, 0); | ||
}); | ||
|
||
}); | ||
|
||
|
||
it('should find 0 inapplicable', function () { | ||
assert.lengthOf(results.inapplicable, 0); | ||
}); | ||
|
||
it('should find 0 incomplete', function () { | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
}); |
39 changes: 39 additions & 0 deletions
39
...ration/full/landmark-contentinfo-is-top-level/landmark-contentinfo-is-top-level-pass.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<!doctype html> | ||
<html lang="en" id="pass1"> | ||
<head> | ||
<title>landmark-contentinfo-is-top-level test</title> | ||
<meta charset="utf8"> | ||
<link rel="stylesheet" type="text/css" href="/node_modules/mocha/mocha.css" /> | ||
<script src="/node_modules/mocha/mocha.js"></script> | ||
<script src="/node_modules/chai/chai.js"></script> | ||
<script src="/axe.js"></script> | ||
<script> | ||
mocha.setup({ | ||
timeout: 10000, | ||
ui: 'bdd' | ||
}); | ||
var assert = chai.assert; | ||
</script> | ||
</head> | ||
<body> | ||
<div role="navigation"> | ||
<p>This div has role navigation</p> | ||
</div> | ||
<div role="contentinfo"> | ||
<p>This contentinfo is not within another landmark</p> | ||
</div> | ||
<div role="complementary"> | ||
<p>This div has role complementary</p> | ||
</div> | ||
<div role="search"> | ||
<p>This div has role search</p> | ||
</div> | ||
<div role="form"> | ||
<p>This div has role form<p> | ||
</div> | ||
<iframe id="frame1" src="frames/level1.html"></iframe> | ||
<div id="mocha"></div> | ||
<script src="landmark-contentinfo-is-top-level-pass.js"></script> | ||
<script src="/test/integration/adapter.js"></script> | ||
</body> | ||
</html> |
34 changes: 34 additions & 0 deletions
34
...egration/full/landmark-contentinfo-is-top-level/landmark-contentinfo-is-top-level-pass.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
describe('landmark-contentinfo-is-top-level test pass', function () { | ||
'use strict'; | ||
var results; | ||
before(function (done) { | ||
window.addEventListener('load', function () { | ||
axe.run({ runOnly: { type: 'rule', values: ['landmark-contentinfo-is-top-level'] } }, function (err, r) { | ||
assert.isNull(err); | ||
results = r; | ||
done(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('violations', function () { | ||
it('should find 0', function () { | ||
assert.lengthOf(results.violations, 0); | ||
}); | ||
}); | ||
|
||
describe('passes', function () { | ||
it('should find 3', function () { | ||
assert.lengthOf(results.passes[0].nodes, 3); | ||
}); | ||
}); | ||
|
||
it('should find 0 inapplicable', function () { | ||
assert.lengthOf(results.inapplicable, 0); | ||
}); | ||
|
||
it('should find 0 incomplete', function () { | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
}); |