Skip to content

Commit

Permalink
fix(commons): handle node(s) contained by SVG document when de… (#2054)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeeyyy authored and straker committed Mar 6, 2020
1 parent e216322 commit bf4c9bf
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 7 deletions.
21 changes: 15 additions & 6 deletions lib/commons/dom/url-props-from-attribute.js
Expand Up @@ -8,8 +8,7 @@
* @returns {Object}
*/
dom.urlPropsFromAttribute = function urlPropsFromAttribute(node, attribute) {
const value = node[attribute];
if (!value) {
if (!node.hasAttribute(attribute)) {
return undefined;
}

Expand All @@ -18,11 +17,14 @@ dom.urlPropsFromAttribute = function urlPropsFromAttribute(node, attribute) {

/**
* Note:
* The need to create a parser, is to keep this function generic, to be able to parse resource from element like `iframe` with `src` attribute
* The need to create a parser, is to keep this function generic, to be able to parse resource from element(s) like `iframe` with `src` attribute,
*
* Also, when `a` or `area` is nested inside an svg document,
* they do not have url properties as a HTML Node, hence the check for `ownerSVGElement`
*/
if (!['A', 'AREA'].includes(nodeName)) {
if (!['A', 'AREA'].includes(nodeName) || node.ownerSVGElement) {
parser = document.createElement('a');
parser.href = value;
parser.href = node.getAttribute(attribute);
}

/**
Expand All @@ -32,7 +34,14 @@ dom.urlPropsFromAttribute = function urlPropsFromAttribute(node, attribute) {
? parser.protocol.replace(/s:$/, ':')
: parser.protocol;

const { pathname, filename } = getPathnameOrFilename(parser.pathname);
/**
* certain browser (in this case IE10 & 11)
* does not resolve pathname with a beginning slash, thence prepending with a beginning slash
*/
const parserPathname = /^\//.test(parser.pathname)
? parser.pathname
: `/${parser.pathname}`;
const { pathname, filename } = getPathnameOrFilename(parserPathname);

return {
protocol,
Expand Down
43 changes: 43 additions & 0 deletions test/commons/dom/url-props-from-attribute.js
Expand Up @@ -49,6 +49,27 @@ describe('dom.urlPropsFromAttribute', function() {
assert.deepEqual(actual, expected);
});

it('returns URL properties when `A` with empty `HREF`', function() {
var vNode = queryFixture('<a id="target" href="">See commons tests</a>');
var actual = axe.commons.dom.urlPropsFromAttribute(
vNode.actualNode,
'href'
);
/**
* Note:
* Given `a` has empty `href`, the url props will depend on the context in which the page is loaded
* eg:
* - http://localhost:9876/test/commons
* - http://localhost:9876/test/commons/?grep=url...
*
* Hence only asserting the what we know to be static values
*/
assert.equal(actual.protocol, 'http:');
assert.equal(actual.hostname, 'localhost');
assert.equal(actual.port, '9876');
assert.equal(actual.pathname, '/test/commons/');
});

it('returns URL properties for `A` with `HREF` (having HTTPS protocol)', function() {
var vNode = queryFixture(
'<a id="target" href="https://facebook.com">follow us on Facebook</a>'
Expand Down Expand Up @@ -220,4 +241,26 @@ describe('dom.urlPropsFromAttribute', function() {
);
assert.deepEqual(actual, expected);
});

it('returns URL properties for `A` with `HREF` that is contained in SVG document', function() {
var vNode = queryFixture(
'<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
'<a id="target" href="http://mysite.com/directory/widgets/calendar.html" aria-label="Book tour"><circle cx="50" cy="40" r="35" /></a>' +
'</svg>'
);
var expected = {
filename: 'calendar.html',
hash: '',
hostname: 'mysite.com',
pathname: '/directory/widgets/',
port: '',
protocol: 'http:',
search: {}
};
var actual = axe.commons.dom.urlPropsFromAttribute(
vNode.actualNode,
'href'
);
assert.deepEqual(actual, expected);
});
});
Expand Up @@ -99,6 +99,38 @@
<a id="pass15" href="/home">Pass 15</a>
<a id="pass15-identical1" href="http://localhost:9876/home">Pass 15</a>

<!-- ARIA links, with same resource, where one inside svg document -->
<a id="pass16" href="http://deque.com">Pass 16</a>
<svg
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<a id="pass16-identical1" href="http://deque.com" aria-label="Pass 16">
<circle cx="50" cy="40" r="35" />
</a>
</svg>

<!-- ARIA links, with same resource, both are inside svg document -->
<svg
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<a href="http://deque.com" aria-label="Pass 17" id="pass17">
<circle cx="50" cy="40" r="35" />
</a>
<a href="http://deque.com" id="pass17-identical1">
<text x="50" y="90" text-anchor="middle">
Pass 17
</text>
</a>
</svg>

<!-- native links with identical name and empty resource (href) -->
<a id="pass18" href="">Pass 18</a>
<a id="pass18-identical1" href="">Pass 18</a>

<!-- incomplete -->
<!-- Note:identical incomplete nodes are appended as relatedNodes -->
<!-- native links with different purpose -->
Expand Down
Expand Up @@ -19,7 +19,10 @@
["#pass13"],
["#pass13-identical-resource-but-different-name"],
["#pass14"],
["#pass15"]
["#pass15"],
["#pass16"],
["#pass17"],
["#pass18"]
],
"incomplete": [
["#incomplete1"],
Expand Down

0 comments on commit bf4c9bf

Please sign in to comment.