diff --git a/lib/checks/navigation/header-present.json b/lib/checks/navigation/header-present.json index a1a256a797..9816a36a56 100644 --- a/lib/checks/navigation/header-present.json +++ b/lib/checks/navigation/header-present.json @@ -1,6 +1,7 @@ { "id": "header-present", "evaluate": "has-descendant-evaluate", + "after": "has-descendant-after", "options": { "selector": "h1:not([role]), h2:not([role]), h3:not([role]), h4:not([role]), h5:not([role]), h6:not([role]), [role=heading]" }, diff --git a/lib/rules/bypass-matches.js b/lib/rules/bypass-matches.js index 8ffae298b4..91d22f8165 100644 --- a/lib/rules/bypass-matches.js +++ b/lib/rules/bypass-matches.js @@ -1,5 +1,14 @@ +import windowIsTopMatches from './window-is-top-matches'; + function bypassMatches(node) { - return !!node.querySelector('a[href]'); + // the top level window should have an anchor + if (windowIsTopMatches(node)) { + return !!node.querySelector('a[href]'); + } + + // all iframes do not need an anchor but should be checked for bypass + // elements (headings, landmarks, etc.) + return true; } export default bypassMatches; diff --git a/test/integration/full/bypass/frames/level1-fail.html b/test/integration/full/bypass/frames/level1-fail.html new file mode 100644 index 0000000000..de743eb46d --- /dev/null +++ b/test/integration/full/bypass/frames/level1-fail.html @@ -0,0 +1,10 @@ + + + + + + + +

No h1 here either

+ + diff --git a/test/integration/full/bypass/frames/level1.html b/test/integration/full/bypass/frames/level1.html new file mode 100644 index 0000000000..c82529b42b --- /dev/null +++ b/test/integration/full/bypass/frames/level1.html @@ -0,0 +1,12 @@ + + + + + + + +

No h1 here either

+ + + + diff --git a/test/integration/full/bypass/frames/level2-a.html b/test/integration/full/bypass/frames/level2-a.html new file mode 100644 index 0000000000..60ae157bbf --- /dev/null +++ b/test/integration/full/bypass/frames/level2-a.html @@ -0,0 +1,10 @@ + + + + + + + +

This page has an h1

+ + diff --git a/test/integration/full/bypass/frames/level2.html b/test/integration/full/bypass/frames/level2.html new file mode 100644 index 0000000000..2de22fe019 --- /dev/null +++ b/test/integration/full/bypass/frames/level2.html @@ -0,0 +1,10 @@ + + + + + + + +

No h1 content in this iframe

+ + diff --git a/test/integration/full/bypass/header-iframe-fail.html b/test/integration/full/bypass/header-iframe-fail.html new file mode 100644 index 0000000000..f060e17fc1 --- /dev/null +++ b/test/integration/full/bypass/header-iframe-fail.html @@ -0,0 +1,30 @@ + + + + + + + + + + + +

No h1 content

+ + stuff +
+ + + + + diff --git a/test/integration/full/bypass/header-iframe-fail.js b/test/integration/full/bypass/header-iframe-fail.js new file mode 100644 index 0000000000..19f799fb48 --- /dev/null +++ b/test/integration/full/bypass/header-iframe-fail.js @@ -0,0 +1,38 @@ +describe('bypass iframe test fail', function() { + 'use strict'; + var results; + before(function(done) { + axe.testUtils.awaitNestedLoad(function() { + // Stop messing with my tests Mocha! + var heading = document.querySelector('#mocha h1'); + if (heading) { + heading.outerHTML = '
bypass iframe test fail
'; + } + + axe.run({ runOnly: { type: 'rule', values: ['bypass'] } }, function( + err, + r + ) { + assert.isNull(err); + results = r; + done(); + }); + }); + }); + + describe('violations', function() { + it('should find 1', function() { + assert.lengthOf(results.violations[0].nodes, 1); + }); + + it('should find #frame1', function() { + assert.deepEqual(results.violations[0].nodes[0].target, ['#fail1']); + }); + }); + + describe('passes', function() { + it('should find none', function() { + assert.lengthOf(results.passes, 0); + }); + }); +}); diff --git a/test/integration/full/bypass/header-iframe-pass.html b/test/integration/full/bypass/header-iframe-pass.html new file mode 100644 index 0000000000..3dc21f4ba1 --- /dev/null +++ b/test/integration/full/bypass/header-iframe-pass.html @@ -0,0 +1,30 @@ + + + + + + + + + + + +

No h1 content

+ + stuff +
+ + + + + diff --git a/test/integration/full/bypass/header-iframe-pass.js b/test/integration/full/bypass/header-iframe-pass.js new file mode 100644 index 0000000000..f8ca4b6ae5 --- /dev/null +++ b/test/integration/full/bypass/header-iframe-pass.js @@ -0,0 +1,39 @@ +describe('bypass iframe test pass', function() { + 'use strict'; + var results; + before(function(done) { + this.timeout = 50000; + axe.testUtils.awaitNestedLoad(function() { + // Stop messing with my tests Mocha! + var heading = document.querySelector('#mocha h1'); + if (heading) { + heading.outerHTML = '
bypass pass test fail
'; + } + + axe.run({ runOnly: { type: 'rule', values: ['bypass'] } }, function( + err, + r + ) { + assert.isNull(err); + results = r; + done(); + }); + }); + }); + + describe('violations', function() { + it('should find none', function() { + assert.lengthOf(results.violations, 0); + }); + }); + + describe('passes', function() { + it('should find 1', function() { + assert.lengthOf(results.passes[0].nodes, 1); + }); + + it('should find #pass1', function() { + assert.deepEqual(results.passes[0].nodes[0].target, ['#pass1']); + }); + }); +});