Skip to content

Commit

Permalink
fix(get-ancestry): add nth-child selector for multiple siblings of sh…
Browse files Browse the repository at this point in the history
…adow root (#4606)

Closes: #4563
  • Loading branch information
straker authored Oct 15, 2024
1 parent a9710d7 commit 1cdd6c3
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
16 changes: 9 additions & 7 deletions lib/core/utils/get-ancestry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ import getShadowSelector from './get-shadow-selector';

function generateAncestry(node) {
const nodeName = node.nodeName.toLowerCase();
const parent = node.parentElement;
if (!parent) {
return nodeName;
}
const parentElement = node.parentElement;
const parentNode = node.parentNode;

let nthChild = '';
if (
nodeName !== 'head' &&
nodeName !== 'body' &&
parent.children.length > 1
parentNode.children.length > 1
) {
const index = Array.prototype.indexOf.call(parent.children, node) + 1;
const index = Array.prototype.indexOf.call(parentNode.children, node) + 1;
nthChild = `:nth-child(${index})`;
}

return generateAncestry(parent) + ' > ' + nodeName + nthChild;
if (!parentElement) {
return nodeName + nthChild;
}

return generateAncestry(parentElement) + ' > ' + nodeName + nthChild;
}

/**
Expand Down
49 changes: 34 additions & 15 deletions test/core/utils/get-ancestry.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,69 @@
describe('axe.utils.getAncestry', function () {
describe('axe.utils.getAncestry', () => {
'use strict';
var fixture = document.getElementById('fixture');
var shadowTest = axe.testUtils.shadowSupport.v1 ? it : xit;
const fixture = document.getElementById('fixture');

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

it('should be a function', function () {
it('should be a function', () => {
assert.isFunction(axe.utils.getAncestry);
});

it('should generate an ancestry selector', function () {
it('should generate an ancestry selector', () => {
fixture.innerHTML = '<div>1</div> <p>2</p> <p>3</p>';

var sel1 = axe.utils.getAncestry(fixture.children[0]);
const sel1 = axe.utils.getAncestry(fixture.children[0]);
assert.equal(sel1, 'html > body > div:nth-child(1) > div:nth-child(1)');
assert.isNotNull(document.querySelector(sel1));

var sel2 = axe.utils.getAncestry(fixture.children[1]);
const sel2 = axe.utils.getAncestry(fixture.children[1]);
assert.equal(sel2, 'html > body > div:nth-child(1) > p:nth-child(2)');
assert.isNotNull(document.querySelector(sel1));

var sel3 = axe.utils.getAncestry(fixture.children[2]);
const sel3 = axe.utils.getAncestry(fixture.children[2]);
assert.equal(sel3, 'html > body > div:nth-child(1) > p:nth-child(3)');
assert.isNotNull(document.querySelector(sel1));
});

shadowTest('generates selectors of nested shadow trees', function () {
var node = document.createElement('section');
it('generates selectors of nested shadow trees', () => {
const node = document.createElement('section');
fixture.appendChild(node);

var shadowRoot1 = node.attachShadow({ mode: 'open' });
const shadowRoot1 = node.attachShadow({ mode: 'open' });
shadowRoot1.innerHTML = '<div><article><slot /></article</div>';

var shadowRoot2 = shadowRoot1
const shadowRoot2 = shadowRoot1
.querySelector('article')
.attachShadow({ mode: 'open' });
shadowRoot2.innerHTML = '<h1>Hello world</h1>';

var target = shadowRoot2.querySelector('h1');
var sel = axe.utils.getAncestry(target);
const target = shadowRoot2.querySelector('h1');
const sel = axe.utils.getAncestry(target);
assert.deepEqual(sel, [
'html > body > div:nth-child(1) > section',
'div > article',
'h1'
]);
});

it('generates selectors of siblings in shadow tree', () => {
const node = document.createElement('section');
fixture.appendChild(node);

const shadowRoot = node.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = '<div>1</div> <div>2</div>';

const sel1 = axe.utils.getAncestry(shadowRoot.children[0]);
assert.deepEqual(sel1, [
'html > body > div:nth-child(1) > section',
'div:nth-child(1)'
]);

const sel2 = axe.utils.getAncestry(shadowRoot.children[1]);
assert.deepEqual(sel2, [
'html > body > div:nth-child(1) > section',
'div:nth-child(2)'
]);
});
});

0 comments on commit 1cdd6c3

Please sign in to comment.