-
Notifications
You must be signed in to change notification settings - Fork 779
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
Add rule, landmark-main-is-top-level #462
Changes from 15 commits
edeb860
3d37aab
4e1b18b
2840b02
fa6069d
6eb553b
094e251
2c55cbb
b9b1bf5
bf85e0d
747990d
9c0e75c
824ee2d
05ee0a7
73ed9cf
f82c667
34407e9
3e5c6ad
ff463ef
03e5434
56ad598
00b10c1
f936751
12b1903
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 |
---|---|---|
@@ -0,0 +1,13 @@ | ||
var landmarks = axe.commons.aria.getRolesByType('landmark'); | ||
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); | ||
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. I think this is too strict. There are roles that can certainly be permitted, off the top of my head: 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. WIlco,
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. @jongund Both of those suggestions make sense to me. Seeing as it's still an open discussion if forms should be a landmark, make an exception for this rule. That one is particularly relevant for the 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. Wilco, We will modify the file lib/commons/aria/index for role application: role presentation is already has type: 'structure' so no change need for it. |
||
} | ||
if (role && landmarks.includes(role)){ | ||
return false; | ||
} | ||
parent = axe.commons.dom.getComposedParent(parent); | ||
} | ||
return true; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"id": "main-is-top-level", | ||
"evaluate": "main-is-top-level.js", | ||
"metadata": { | ||
"impact": "moderate", | ||
"messages": { | ||
"pass": "The main landmark is at the top level.", | ||
"fail": "The main landmark is contained in another landmark." | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -189,7 +189,7 @@ lookupTables.role = { | |
context: null | ||
}, | ||
'application': { | ||
type: 'landmark', | ||
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. This is causing the following test to fail, be sure to fix that:
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. @WilcoFiers |
||
type: 'structure', | ||
attributes: { | ||
allowed: ['aria-expanded'] | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"id": "landmark-main-is-top-level", | ||
"selector": "main,[role=main]", | ||
"tags": [ | ||
"best-practice" | ||
], | ||
"metadata": { | ||
"description": "The main landmark should not be contained in another landmark", | ||
"help": "Main landmark is not at top level" | ||
}, | ||
"all": [], | ||
"any": [ | ||
"main-is-top-level" | ||
], | ||
"none": [] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
describe('main-is-top-level', function () { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
|
||
var shadowSupported = axe.testUtils.shadowSupport.v1; | ||
var checkSetup = axe.testUtils.checkSetup; | ||
|
||
afterEach(function () { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should return false if main landmark is in another landmark', function () { | ||
var mainLandmark = document.createElement('main'); | ||
var bannerDiv = document.createElement('div'); | ||
bannerDiv.setAttribute('role','banner'); | ||
bannerDiv.appendChild(mainLandmark); | ||
fixture.appendChild(bannerDiv); | ||
assert.isFalse(checks['main-is-top-level'].evaluate(mainLandmark)); | ||
}); | ||
|
||
it('should return false if div with role set to main is in another landmark', function () { | ||
var mainDiv = document.createElement('div'); | ||
mainDiv.setAttribute('role','main'); | ||
var navDiv = document.createElement('div'); | ||
navDiv.setAttribute('role','navigation'); | ||
navDiv.appendChild(mainDiv); | ||
fixture.appendChild(navDiv); | ||
assert.isFalse(checks['main-is-top-level'].evaluate(mainDiv)); | ||
}); | ||
|
||
it('should return true if main landmark is not in another landmark', function () { | ||
var mainLandmark = document.createElement('main'); | ||
var bannerDiv = document.createElement('div'); | ||
bannerDiv.setAttribute('role','banner'); | ||
fixture.appendChild(bannerDiv); | ||
fixture.appendChild(mainLandmark); | ||
assert.isTrue(checks['main-is-top-level'].evaluate(mainLandmark)); | ||
}); | ||
|
||
it('should return true if div with role set to main is not in another landmark', function () { | ||
var mainDiv = document.createElement('div'); | ||
mainDiv.setAttribute('role','main'); | ||
var navDiv = document.createElement('div'); | ||
navDiv.setAttribute('role','navigation'); | ||
fixture.appendChild(navDiv); | ||
fixture.appendChild(mainDiv); | ||
assert.isTrue(checks['main-is-top-level'].evaluate(mainDiv)); | ||
}); | ||
|
||
|
||
(shadowSupported ? it : xit)('should test if main in shadow DOM is top level', function () { | ||
var div = document.createElement('div'); | ||
var shadow = div.attachShadow({ mode: 'open' }); | ||
shadow.innerHTML = '<main>Main content</main>'; | ||
var checkArgs = checkSetup(div); | ||
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. This will select the div, not the |
||
assert.isTrue(checks['main-is-top-level'].evaluate.apply(null, checkArgs)); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!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"> | ||
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. Please don't use spaces in attributes. |
||
<div role = "main"> | ||
<p>This main landmark is in a complementary landmark</p> | ||
</div> | ||
</div> | ||
<iframe id = "frame2" src = "level2.html"></iframe> | ||
<iframe id = "frame3" src = "level2-a.html"></iframe> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!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 = "banner"> | ||
<p>This div has role banner</p> | ||
</div> | ||
<div role = "navigation"> | ||
<p>This div has role navigation</p> | ||
</div> | ||
<div role = "main"> | ||
<p>This main content 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> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
<html id="violation4"> | ||
<head> | ||
<meta charset="utf8"> | ||
<script src="/axe.js"></script> | ||
</head> | ||
<body> | ||
<p>This iframe is also a violation</p> | ||
<div role = "form"> | ||
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. This shouldn't be a failure. Neither should role="application". Make sure there is a test for that too. |
||
<main> | ||
<p>This main landmark is in a form landmark</p> | ||
</main> | ||
</div> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
<html id="violation3"> | ||
<head> | ||
<meta charset="utf8"> | ||
<script src="/axe.js"></script> | ||
</head> | ||
<body> | ||
<p>This iframe is another violation<p> | ||
<div role = "search"> | ||
<main> | ||
<p>This main landmark is in a search landmark</p> | ||
</main> | ||
</div> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!doctype html> | ||
<html lang="en" id="violation1"> | ||
<head> | ||
<title>landmark-main-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 = "main"> | ||
<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-main-is-top-level-fail.js"></script> | ||
<script src="/test/integration/adapter.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
|
||
describe('landmark-main-is-top-level test fail', function () { | ||
'use strict'; | ||
var results; | ||
before(function (done) { | ||
window.addEventListener('load', function () { | ||
axe.run({ runOnly: { type: 'rule', values: ['landmark-main-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); | ||
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 a node count check too:
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. @ssanaul This issue isn't addressed yet. 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. I thought 3e5c6ad resolved it. It checks for 4 nodes because I believe there are 4 violations. @WilcoFiers |
||
}); | ||
}); | ||
|
||
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); | ||
}); | ||
|
||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<!doctype html> | ||
<html lang="en" id="pass1"> | ||
<head> | ||
<title>landmark-main-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 = "banner"> | ||
<p>This div has role banner</p> | ||
</div> | ||
<div role = "navigation"> | ||
<p>This div has role navigation</p> | ||
</div> | ||
<main> | ||
<p>This main content is not within another landmark</p> | ||
</main> | ||
<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-main-is-top-level-pass.js"></script> | ||
<script src="/test/integration/adapter.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
|
||
describe('landmark-main-is-top-level test pass', function () { | ||
'use strict'; | ||
var results; | ||
before(function (done) { | ||
window.addEventListener('load', function () { | ||
axe.run({ runOnly: { type: 'rule', values: ['landmark-main-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 2', function () { | ||
assert.lengthOf(results.passes[0].nodes, 2); | ||
}); | ||
}); | ||
|
||
it('should find 0 inapplicable', function () { | ||
assert.lengthOf(results.inapplicable, 0); | ||
}); | ||
|
||
it('should find 0 incomplete', function () { | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
}); | ||
|
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.
This needs to work with
role=form
too.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.
Does line 5 not accomplish that?