From 7c23dbd1d04d95e3bd2b56a0bd14571f906eb3d5 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Wed, 1 Jul 2020 09:37:41 -0600 Subject: [PATCH] fix(bypass): find headings in iframes (#2310) * fix(bypass): find headings in iframes * name tests * fix test * test * ci fail * i think i found the issue * put back pageLevel * fix test * Remove leading "./" from axe-linter excludes * Revert "Remove leading "./" from axe-linter excludes" This reverts commit be62002f876b32cc02f361bee7533419b3811f14. Co-authored-by: Stephen Mathieson --- lib/checks/navigation/header-present.json | 1 + lib/rules/bypass-matches.js | 11 +++++- .../full/bypass/frames/level1-fail.html | 10 +++++ .../full/bypass/frames/level1.html | 12 ++++++ .../full/bypass/frames/level2-a.html | 10 +++++ .../full/bypass/frames/level2.html | 10 +++++ .../full/bypass/header-iframe-fail.html | 30 ++++++++++++++ .../full/bypass/header-iframe-fail.js | 38 ++++++++++++++++++ .../full/bypass/header-iframe-pass.html | 30 ++++++++++++++ .../full/bypass/header-iframe-pass.js | 39 +++++++++++++++++++ 10 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 test/integration/full/bypass/frames/level1-fail.html create mode 100644 test/integration/full/bypass/frames/level1.html create mode 100644 test/integration/full/bypass/frames/level2-a.html create mode 100644 test/integration/full/bypass/frames/level2.html create mode 100644 test/integration/full/bypass/header-iframe-fail.html create mode 100644 test/integration/full/bypass/header-iframe-fail.js create mode 100644 test/integration/full/bypass/header-iframe-pass.html create mode 100644 test/integration/full/bypass/header-iframe-pass.js 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']); + }); + }); +});