Skip to content

Commit

Permalink
fix(getSelector): improve selectors for namespaced elements
Browse files Browse the repository at this point in the history
- by default, ensure the nodename is escaped
- for XHTML documents, only use the local name

Replaces dequelabs#566
Closes dequelabs#563
  • Loading branch information
WilcoFiers authored and rdeltour committed Dec 15, 2017
1 parent d6dab39 commit 0215713
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
13 changes: 9 additions & 4 deletions lib/core/utils/get-selector.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const escapeSelector = axe.utils.escapeSelector;
let isXHTML;

function isUncommonClassName (className) {
return ![
Expand Down Expand Up @@ -27,7 +28,7 @@ function getDistinctClassList (elm) {
}

const commonNodes = [
'div', 'span', 'p',
'div', 'span', 'p',
'b', 'i', 'u', 'strong', 'em',
'h2', 'h3'
];
Expand Down Expand Up @@ -79,7 +80,6 @@ const createSelector = {
// Get uncommon node names
getUncommonElm (elm, { isCommonElm, isCustomElm, nodeName }) {
if (!isCommonElm && !isCustomElm) {
nodeName = escapeSelector(nodeName);
// Add [type] if nodeName is an input element
if (nodeName === 'input' && elm.hasAttribute('type')) {
nodeName += '[type="' + elm.type + '"]';
Expand Down Expand Up @@ -130,7 +130,12 @@ const createSelector = {
* recognize the element by (IDs, aria roles, custom element names, etc.)
*/
function getElmFeatures (elm, featureCount) {
const nodeName = elm.nodeName.toLowerCase();
if (typeof isXHTML === 'undefined') {
isXHTML = axe.utils.isXHTML(document);
}
const nodeName = escapeSelector(isXHTML?
elm.localName
:elm.nodeName.toLowerCase());
const classList = Array.from(elm.classList) || [];
// Collect some props we need to build the selector
const props = {
Expand Down Expand Up @@ -174,7 +179,7 @@ function generateSelector (elm, options, doc) {
let { isUnique = false } = options;
const idSelector = createSelector.getElmId(elm);
const {
featureCount = 2,
featureCount = 2,
minDepth = 1,
toRoot = false,
childSelectors = []
Expand Down
14 changes: 14 additions & 0 deletions test/core/utils/get-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ describe('axe.utils.getSelector', function () {
assert.equal(result[0], node);
});

it('should work on complex namespaced elements', function () {
fixture.innerHTML = '<m:math xmlns:m="http://www.w3.org/1998/Math/MathML">' +
'<m:mi>x</m:mi>' +
'<m:annotation-xml encoding="MathML-Content">' +
'<m:ci>x</m:ci>' +
'</m:annotation-xml>' +
'</m:math>';
var node = fixture.querySelector('m\\:ci');
var sel = axe.utils.getSelector(node);
var result = document.querySelectorAll(sel);
assert.lengthOf(result, 1);
assert.equal(result[0], node);
});

it('shouldn\'t fail if the node\'s parentNode doesnt have children, somehow (Firefox bug)', function () {
var sel = axe.utils.getSelector({
nodeName: 'a',
Expand Down

0 comments on commit 0215713

Please sign in to comment.