diff --git a/lib/checks/navigation/header-present.js b/lib/checks/navigation/header-present.js index aafe0e7c30..0140c85b6c 100644 --- a/lib/checks/navigation/header-present.js +++ b/lib/checks/navigation/header-present.js @@ -1 +1 @@ -return !!node.querySelector('h1, h2, h3, h4, h5, h6, [role="heading"]'); +return !!axe.utils.querySelectorAll(virtualNode, 'h1, h2, h3, h4, h5, h6, [role="heading"]')[0]; diff --git a/lib/checks/navigation/internal-link-present.js b/lib/checks/navigation/internal-link-present.js index 8f164ca3da..ad7fd17cb6 100644 --- a/lib/checks/navigation/internal-link-present.js +++ b/lib/checks/navigation/internal-link-present.js @@ -1 +1,2 @@ -return !!node.querySelector('a[href^="#"]'); +const links = axe.utils.querySelectorAll(virtualNode, 'a[href]'); +return links.some(vLink => vLink.actualNode.getAttribute('href')[0] === '#'); diff --git a/test/checks/aria/errormessage.js b/test/checks/aria/errormessage.js index 4605f10dba..bf1c8c193e 100644 --- a/test/checks/aria/errormessage.js +++ b/test/checks/aria/errormessage.js @@ -2,7 +2,8 @@ describe('aria-errormessage', function () { 'use strict'; var fixture = document.getElementById('fixture'); - + var shadowSupported = axe.testUtils.shadowSupport.v1; + var shadowCheckSetup = axe.testUtils.shadowCheckSetup; var checkContext = axe.testUtils.MockCheckContext(); afterEach(function () { @@ -46,4 +47,23 @@ describe('aria-errormessage', function () { target.setAttribute('aria-describedby', 'plain'); assert.isTrue(checks['aria-errormessage'].evaluate.call(checkContext, target)); }); + + (shadowSupported ? it : xit) + ('should return false if aria-errormessage value crosses shadow boundary', function () { + var params = shadowCheckSetup( + '
', + '
' + ); + assert.isFalse(checks['aria-errormessage'].evaluate.apply(checkContext, params)); + }); + + (shadowSupported ? it : xit) + ('should return true if aria-errormessage and value are inside shadow dom', function () { + var params = shadowCheckSetup( + '
', + '
' + + '
' + ); + assert.isTrue(checks['aria-errormessage'].evaluate.apply(checkContext, params)); + }); }); diff --git a/test/checks/keyboard/has-at-least-one-main.js b/test/checks/keyboard/has-at-least-one-main.js index eea12f126f..6dd7b2a59a 100644 --- a/test/checks/keyboard/has-at-least-one-main.js +++ b/test/checks/keyboard/has-at-least-one-main.js @@ -4,10 +4,13 @@ describe('has-at-least-one-main', function () { var fixture = document.getElementById('fixture'); var checkContext = new axe.testUtils.MockCheckContext(); var checkSetup = axe.testUtils.checkSetup; + var shadowSupported = axe.testUtils.shadowSupport.v1; + var shadowCheckSetup = axe.testUtils.shadowCheckSetup; afterEach(function () { fixture.innerHTML = ''; checkContext.reset(); + axe._tree = undefined; }); it('should return false if no div has role property', function() { @@ -44,6 +47,10 @@ describe('has-at-least-one-main', function () { assert.isTrue(mainIsFound); assert.equal(checkContext._data, mainIsFound); }); + + (shadowSupported ? it : xit) + ('should return true if main is inside of shadow dom', function() { + var params = shadowCheckSetup('
', '
main landmark
'); var mainIsFound = checks['has-at-least-one-main'].evaluate.apply(checkContext, params); assert.isTrue(mainIsFound); assert.equal(checkContext._data, mainIsFound); diff --git a/test/checks/navigation/header-present.js b/test/checks/navigation/header-present.js index d1b535db28..df45cac5f4 100644 --- a/test/checks/navigation/header-present.js +++ b/test/checks/navigation/header-present.js @@ -3,7 +3,9 @@ describe('header-present', function () { var fixture = document.getElementById('fixture'); var checkSetup = axe.testUtils.checkSetup; + var shadowSupported = axe.testUtils.shadowSupport.v1; var checkContext = axe.testUtils.MockCheckContext(); + var shadowCheckSetup = axe.testUtils.shadowCheckSetup; afterEach(function () { fixture.innerHTML = ''; @@ -41,4 +43,12 @@ describe('header-present', function () { assert.isFalse(checks['header-present'].evaluate.apply(checkContext, params)); }); + (shadowSupported ? it : xit) + ('should return true if heading is in shadow dom', function () { + var params = shadowCheckSetup( + '
', + '

' + ); + assert.isTrue(checks['header-present'].evaluate.apply(checkContext, params)); + }); }); diff --git a/test/checks/navigation/internal-link-present.js b/test/checks/navigation/internal-link-present.js index 964af66069..c6d372f09b 100644 --- a/test/checks/navigation/internal-link-present.js +++ b/test/checks/navigation/internal-link-present.js @@ -2,8 +2,10 @@ describe('internal-link-present', function () { 'use strict'; var fixture = document.getElementById('fixture'); + var shadowSupported = axe.testUtils.shadowSupport.v1; var checkContext = axe.testUtils.MockCheckContext(); var checkSetup = axe.testUtils.checkSetup; + var shadowCheckSetup = axe.testUtils.shadowCheckSetup; afterEach(function () { fixture.innerHTML = ''; @@ -21,4 +23,12 @@ describe('internal-link-present', function () { assert.isFalse(checks['internal-link-present'].evaluate.apply(checkContext, params)); }); + (shadowSupported ? it : xit) + ('should return true when internal link is found in shadow dom', function () { + var params = shadowCheckSetup( + '
', + 'hi' + ); + assert.isTrue(checks['internal-link-present'].evaluate.apply(checkContext, params)); + }); }); diff --git a/test/checks/navigation/p-as-heading.js b/test/checks/navigation/p-as-heading.js index 08230dd216..af3f1b7ef5 100644 --- a/test/checks/navigation/p-as-heading.js +++ b/test/checks/navigation/p-as-heading.js @@ -172,4 +172,20 @@ describe('p-as-heading', function () { assert.isTrue(checks['p-as-heading'].evaluate.apply(checkContext, params)); }); }); + + (shadowSupported ? it : xit) + ('returns undefined instead of false if the element is inside a blockquote in light dom', function () { + var params = shadowCheckSetup('
', + '

elm 1

elm 2

', + testOptions); + assert.isUndefined(checks['p-as-heading'].evaluate.apply(checkContext, params)); + }); + + (shadowSupported ? it : xit) + ('returns true over undefined from within a blockquote in light dom', function () { + var params = shadowCheckSetup('
', + '

elm 1

elm 2

', + testOptions); + assert.isTrue(checks['p-as-heading'].evaluate.apply(checkContext, params)); + }); }); \ No newline at end of file diff --git a/test/testutils.js b/test/testutils.js index 631003e41b..1a9e05c4d0 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -102,25 +102,32 @@ testUtils.checkSetup = function (content, options, target) { * * @param Node|String Stuff to go into the fixture (html string or DOM Node) * @param Node|String Stuff to go into the shadow boundary (html or node) - * @param String Target selector for the check, can be inside or outside of Shadow DOM (default: '#target') * @param Object Options argument for the check (optional, default: {}) + * @param String Target selector for the check, can be inside or outside of Shadow DOM (optional, default: '#target') * @return Array */ -testUtils.shadowCheckSetup = function (content, shadowContent, targetSelector, options) { +testUtils.shadowCheckSetup = function (content, shadowContent, options, targetSelector) { 'use strict'; - // Normalize the params + // Normalize target, allow it to be the provided string or use '#target' to query composed tree + if (typeof targetSelector !== 'string') { + targetSelector = '#target'; + } + + // Normalize the object params if (typeof options !== 'object') { options = {}; } - // Normalize target, allow it to be the provided string or use '#target' to query composed tree - targetSelector = targetSelector || '#target'; var fixture = testUtils.fixtureSetup(content); var targetCandidate = fixture.querySelector(targetSelector); var container = targetCandidate; if (!targetCandidate) { - container = fixture.firstChild; + // check if content specifies a shadow container + container = fixture.querySelector('#shadow'); + if (!container) { + container = fixture.firstChild; + } } // attach a shadowRoot with the content provided var shadowRoot = container.attachShadow({ mode: 'open' });