From 021571370fde877bd4be29cb7b1c0e5a42c246da Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Tue, 10 Oct 2017 13:03:03 +0200 Subject: [PATCH] fix(getSelector): improve selectors for namespaced elements - by default, ensure the nodename is escaped - for XHTML documents, only use the local name Replaces #566 Closes #563 --- lib/core/utils/get-selector.js | 13 +++++++++---- test/core/utils/get-selector.js | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/core/utils/get-selector.js b/lib/core/utils/get-selector.js index d94531910a..03b247690a 100644 --- a/lib/core/utils/get-selector.js +++ b/lib/core/utils/get-selector.js @@ -1,4 +1,5 @@ const escapeSelector = axe.utils.escapeSelector; +let isXHTML; function isUncommonClassName (className) { return ![ @@ -27,7 +28,7 @@ function getDistinctClassList (elm) { } const commonNodes = [ - 'div', 'span', 'p', + 'div', 'span', 'p', 'b', 'i', 'u', 'strong', 'em', 'h2', 'h3' ]; @@ -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 + '"]'; @@ -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 = { @@ -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 = [] diff --git a/test/core/utils/get-selector.js b/test/core/utils/get-selector.js index d7eb4b89c4..540b77f2c0 100644 --- a/test/core/utils/get-selector.js +++ b/test/core/utils/get-selector.js @@ -194,6 +194,20 @@ describe('axe.utils.getSelector', function () { assert.equal(result[0], node); }); + it('should work on complex namespaced elements', function () { + fixture.innerHTML = '' + + 'x' + + '' + + 'x' + + '' + + ''; + 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',