Skip to content

Commit 0e48413

Browse files
author
Marcy Sutton
committed
fix: add shadow dom coverage to all checks
Closes #690
1 parent 6145f7e commit 0e48413

File tree

8 files changed

+80
-9
lines changed

8 files changed

+80
-9
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
return !!node.querySelector('h1, h2, h3, h4, h5, h6, [role="heading"]');
1+
return !!axe.utils.querySelectorAll(virtualNode, 'h1, h2, h3, h4, h5, h6, [role="heading"]')[0];
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
return !!node.querySelector('a[href^="#"]');
1+
const links = axe.utils.querySelectorAll(virtualNode, 'a[href]');
2+
return links.some(vLink => vLink.actualNode.getAttribute('href')[0] === '#');

test/checks/aria/errormessage.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ describe('aria-errormessage', function () {
22
'use strict';
33

44
var fixture = document.getElementById('fixture');
5-
5+
var shadowSupported = axe.testUtils.shadowSupport.v1;
6+
var shadowCheckSetup = axe.testUtils.shadowCheckSetup;
67
var checkContext = axe.testUtils.MockCheckContext();
78

89
afterEach(function () {
@@ -46,4 +47,23 @@ describe('aria-errormessage', function () {
4647
target.setAttribute('aria-describedby', 'plain');
4748
assert.isTrue(checks['aria-errormessage'].evaluate.call(checkContext, target));
4849
});
50+
51+
(shadowSupported ? it : xit)
52+
('should return false if aria-errormessage value crosses shadow boundary', function () {
53+
var params = shadowCheckSetup(
54+
'<div id="target" aria-errormessage="live"></div>',
55+
'<div id="live" aria-live="assertive"></div>'
56+
);
57+
assert.isFalse(checks['aria-errormessage'].evaluate.apply(checkContext, params));
58+
});
59+
60+
(shadowSupported ? it : xit)
61+
('should return true if aria-errormessage and value are inside shadow dom', function () {
62+
var params = shadowCheckSetup(
63+
'<div></div>',
64+
'<div id="target" aria-errormessage="live"</div>' +
65+
'<div id="live" aria-live="assertive"></div>'
66+
);
67+
assert.isTrue(checks['aria-errormessage'].evaluate.apply(checkContext, params));
68+
});
4969
});

test/checks/keyboard/has-at-least-one-main.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ describe('has-at-least-one-main', function () {
44
var fixture = document.getElementById('fixture');
55
var checkContext = new axe.testUtils.MockCheckContext();
66
var checkSetup = axe.testUtils.checkSetup;
7+
var shadowSupported = axe.testUtils.shadowSupport.v1;
8+
var shadowCheckSetup = axe.testUtils.shadowCheckSetup;
79

810
afterEach(function () {
911
fixture.innerHTML = '';
1012
checkContext.reset();
13+
axe._tree = undefined;
1114
});
1215

1316
it('should return false if no div has role property', function() {
@@ -44,6 +47,10 @@ describe('has-at-least-one-main', function () {
4447
assert.isTrue(mainIsFound);
4548
assert.equal(checkContext._data, mainIsFound);
4649
});
50+
51+
(shadowSupported ? it : xit)
52+
('should return true if main is inside of shadow dom', function() {
53+
var params = shadowCheckSetup('<div id="target"></div>', '<main>main landmark</main>');
4754
var mainIsFound = checks['has-at-least-one-main'].evaluate.apply(checkContext, params);
4855
assert.isTrue(mainIsFound);
4956
assert.equal(checkContext._data, mainIsFound);

test/checks/navigation/header-present.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ describe('header-present', function () {
33

44
var fixture = document.getElementById('fixture');
55
var checkSetup = axe.testUtils.checkSetup;
6+
var shadowSupported = axe.testUtils.shadowSupport.v1;
67
var checkContext = axe.testUtils.MockCheckContext();
8+
var shadowCheckSetup = axe.testUtils.shadowCheckSetup;
79

810
afterEach(function () {
911
fixture.innerHTML = '';
@@ -41,4 +43,12 @@ describe('header-present', function () {
4143
assert.isFalse(checks['header-present'].evaluate.apply(checkContext, params));
4244
});
4345

46+
(shadowSupported ? it : xit)
47+
('should return true if heading is in shadow dom', function () {
48+
var params = shadowCheckSetup(
49+
'<div id="target"><div>',
50+
'<h1></h1>'
51+
);
52+
assert.isTrue(checks['header-present'].evaluate.apply(checkContext, params));
53+
});
4454
});

test/checks/navigation/internal-link-present.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ describe('internal-link-present', function () {
22
'use strict';
33

44
var fixture = document.getElementById('fixture');
5+
var shadowSupported = axe.testUtils.shadowSupport.v1;
56
var checkContext = axe.testUtils.MockCheckContext();
67
var checkSetup = axe.testUtils.checkSetup;
8+
var shadowCheckSetup = axe.testUtils.shadowCheckSetup;
79

810
afterEach(function () {
911
fixture.innerHTML = '';
@@ -21,4 +23,12 @@ describe('internal-link-present', function () {
2123
assert.isFalse(checks['internal-link-present'].evaluate.apply(checkContext, params));
2224
});
2325

26+
(shadowSupported ? it : xit)
27+
('should return true when internal link is found in shadow dom', function () {
28+
var params = shadowCheckSetup(
29+
'<div id="target"></div>',
30+
'<a href="#haha">hi</a>'
31+
);
32+
assert.isTrue(checks['internal-link-present'].evaluate.apply(checkContext, params));
33+
});
2434
});

test/checks/navigation/p-as-heading.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,20 @@ describe('p-as-heading', function () {
172172
assert.isTrue(checks['p-as-heading'].evaluate.apply(checkContext, params));
173173
});
174174
});
175+
176+
(shadowSupported ? it : xit)
177+
('returns undefined instead of false if the element is inside a blockquote in light dom', function () {
178+
var params = shadowCheckSetup('<blockquote></blockquote>',
179+
'<p style="font-weight:bold" id="target">elm 1</p> <p>elm 2</p>',
180+
testOptions);
181+
assert.isUndefined(checks['p-as-heading'].evaluate.apply(checkContext, params));
182+
});
183+
184+
(shadowSupported ? it : xit)
185+
('returns true over undefined from within a blockquote in light dom', function () {
186+
var params = shadowCheckSetup('<blockquote></blockquote>',
187+
'<p id="target">elm 1</p> <p>elm 2</p>',
188+
testOptions);
189+
assert.isTrue(checks['p-as-heading'].evaluate.apply(checkContext, params));
190+
});
175191
});

test/testutils.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,32 @@ testUtils.checkSetup = function (content, options, target) {
102102
*
103103
* @param Node|String Stuff to go into the fixture (html string or DOM Node)
104104
* @param Node|String Stuff to go into the shadow boundary (html or node)
105-
* @param String Target selector for the check, can be inside or outside of Shadow DOM (default: '#target')
106105
* @param Object Options argument for the check (optional, default: {})
106+
* @param String Target selector for the check, can be inside or outside of Shadow DOM (optional, default: '#target')
107107
* @return Array
108108
*/
109-
testUtils.shadowCheckSetup = function (content, shadowContent, targetSelector, options) {
109+
testUtils.shadowCheckSetup = function (content, shadowContent, options, targetSelector) {
110110
'use strict';
111111

112-
// Normalize the params
112+
// Normalize target, allow it to be the provided string or use '#target' to query composed tree
113+
if (typeof targetSelector !== 'string') {
114+
targetSelector = '#target';
115+
}
116+
117+
// Normalize the object params
113118
if (typeof options !== 'object') {
114119
options = {};
115120
}
116-
// Normalize target, allow it to be the provided string or use '#target' to query composed tree
117-
targetSelector = targetSelector || '#target';
118121

119122
var fixture = testUtils.fixtureSetup(content);
120123
var targetCandidate = fixture.querySelector(targetSelector);
121124
var container = targetCandidate;
122125
if (!targetCandidate) {
123-
container = fixture.firstChild;
126+
// check if content specifies a shadow container
127+
container = fixture.querySelector('#shadow');
128+
if (!container) {
129+
container = fixture.firstChild;
130+
}
124131
}
125132
// attach a shadowRoot with the content provided
126133
var shadowRoot = container.attachShadow({ mode: 'open' });

0 commit comments

Comments
 (0)