Skip to content

Commit

Permalink
feat(closest): VirtualNode implementation of Element.closest. Depreca…
Browse files Browse the repository at this point in the history
…te commons.dom.findUp and commons.dom.findUpVirtual (#2139)

* feat(closest): VirtualNode implementation of Element.closest. Deprecate commons.dom.findUp and commons.dom.findUpVirtual

* add shadow support
  • Loading branch information
straker committed Mar 31, 2020
1 parent 8c92472 commit 493dd22
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/commons/dom/find-up.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @method findUp
* @memberof axe.commons.dom
* @instance
* @deprecated use axe.utils.closest
* @param {HTMLElement} element The starting HTMLElement
* @param {String} target The selector for the HTMLElement
* @return {HTMLElement|null} Either the matching HTMLElement or `null` if there was no match
Expand All @@ -21,6 +22,7 @@ dom.findUp = function(element, target) {
* @method findUpVirtual
* @memberof axe.commons.dom
* @instance
* @deprecated use axe.utils.closest
* @param {VirtualNode} element The starting virtualNode
* @param {String} target The selector for the HTMLElement
* @return {HTMLElement|null} Either the matching HTMLElement or `null` if there was no match
Expand Down
20 changes: 20 additions & 0 deletions lib/core/utils/closest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* closest implementation that operates on a VirtualNode
*
* @method closest
* @memberof axe.utils
* @param {VirtualNode} vNode VirtualNode to match
* @param {String} selector CSS selector string
* @return {Boolean}
*/
axe.utils.closest = function closest(vNode, selector) {
while (vNode) {
if (axe.utils.matches(vNode, selector)) {
return vNode;
}

vNode = vNode.parent;
}

return null;
};
59 changes: 59 additions & 0 deletions test/core/utils/closest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
describe('utils.closest', function() {
var closest = axe.utils.closest;
var fixture = document.querySelector('#fixture');
var queryFixture = axe.testUtils.queryFixture;
var shadowSupported = axe.testUtils.shadowSupport.v1;

afterEach(function() {
fixture.innerHTML = '';
});

it('should find the current node', function() {
var virtualNode = queryFixture(
'<div id="parent"><div id="target">foo</div></div>'
);
var closestNode = closest(virtualNode, 'div');
assert.equal(closestNode, virtualNode);
});

it('should find a parent node', function() {
var virtualNode = queryFixture(
'<div id="parent"><span id="target">foo</span></div>'
);
var closestNode = closest(virtualNode, 'div');
var parent = fixture.querySelector('#parent');
assert.equal(closestNode, axe.utils.getNodeFromTree(parent));
});

it('should find an ancestor node', function() {
var virtualNode = queryFixture(
'<div id="parent"><span><span><span><span id="target">foo</span></span></span></div>'
);
var closestNode = closest(virtualNode, 'div');
var parent = fixture.querySelector('#parent');
assert.equal(closestNode, axe.utils.getNodeFromTree(parent));
});

it('should return null if no ancestor is found', function() {
var virtualNode = queryFixture(
'<div id="parent"><div id="target">foo</div></div>'
);
var closestNode = closest(virtualNode, 'h1');
assert.isNull(closestNode);
});

(shadowSupported ? it : xit)('should support shadow dom', function() {
fixture.innerHTML = '<div id="parent"></div>';

var root = fixture.firstChild.attachShadow({ mode: 'open' });
var slotted = document.createElement('span');
slotted.innerHTML = '<span id="target">foo</span>';
root.appendChild(slotted);
axe.utils.getFlattenedTree(fixture.firstChild);

var virtualNode = axe.utils.getNodeFromTree(slotted.firstChild);
var parent = fixture.querySelector('#parent');
var closestNode = closest(virtualNode, 'div');
assert.equal(closestNode, axe.utils.getNodeFromTree(parent));
});
});

0 comments on commit 493dd22

Please sign in to comment.