Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(svg-image-alt): work with serial virtual nodes #2397

Merged
merged 5 commits into from
Jul 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/checks/shared/svg-non-empty-title-evaluate.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import visibleVirtual from '../../commons/text/visible-virtual';

function svgNonEmptyTitleEvaluate(node, options, virtualNode) {
if (!virtualNode.children) {
return undefined;
}

const titleNode = virtualNode.children.find(({ props }) => {
return props.nodeName === 'title';
});
return !!titleNode && titleNode.actualNode.textContent.trim() !== '';
return !!titleNode && visibleVirtual(titleNode) !== '';
}

export default svgNonEmptyTitleEvaluate;
3 changes: 2 additions & 1 deletion lib/checks/shared/svg-non-empty-title.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"impact": "serious",
"messages": {
"pass": "element has a child that is a title",
"fail": "element has no child that is a title"
"fail": "element has no child that is a title",
"incomplete": "Unable to determine element has a child that is a title"
}
}
}
17 changes: 15 additions & 2 deletions lib/rules/svg-namespace-matches.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
function svgNamespaceMatches(node) {
return node.namespaceURI === 'http://www.w3.org/2000/svg';
import { closest } from '../core/utils';

function svgNamespaceMatches(node, virtualNode) {
try {
const nodeName = virtualNode.props.nodeName;

if (nodeName === 'svg') {
return true;
}

// element is svg namespace if its parent is an svg element
return !!closest(virtualNode, 'svg');
} catch (e) {
return false;
}
}

export default svgNamespaceMatches;
54 changes: 46 additions & 8 deletions test/checks/shared/svg-non-empty-title.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ describe('svg-non-empty-title tests', function() {

var fixture = document.getElementById('fixture');
var checkSetup = axe.testUtils.checkSetup;
var check = checks['svg-non-empty-title'];
var checkEvaluate = axe.testUtils.getCheckEvaluate('svg-non-empty-title');

afterEach(function() {
fixture.innerHTML = '';
Expand All @@ -13,44 +13,82 @@ describe('svg-non-empty-title tests', function() {
var checkArgs = checkSetup(
'<svg id="target"><title>Time II: Party</title></svg>'
);
assert.isTrue(check.evaluate.apply(null, checkArgs));
assert.isTrue(checkEvaluate.apply(null, checkArgs));
});

it('returns true if the `title` child has text nested in another element', function() {
var checkArgs = checkSetup(
'<svg id="target"><title><g>Time II: Party</g></title></svg>'
);
assert.isTrue(check.evaluate.apply(null, checkArgs));
assert.isTrue(checkEvaluate.apply(null, checkArgs));
});

it('returns false if the element has no `title` child', function() {
var checkArgs = checkSetup('<svg id="target"></svg>');
assert.isFalse(check.evaluate.apply(null, checkArgs));
assert.isFalse(checkEvaluate.apply(null, checkArgs));
});

it('returns false if the `title` child is empty', function() {
var checkArgs = checkSetup('<svg id="target"><title></title></svg>');
assert.isFalse(check.evaluate.apply(null, checkArgs));
assert.isFalse(checkEvaluate.apply(null, checkArgs));
});

it('returns false if the `title` is a grandchild', function() {
var checkArgs = checkSetup(
'<svg id="target"><circle><title>Time II: Party</title></circle></svg>'
);
assert.isFalse(check.evaluate.apply(null, checkArgs));
assert.isFalse(checkEvaluate.apply(null, checkArgs));
});

it('returns false if the `title` child has only whitespace', function() {
var checkArgs = checkSetup(
'<svg id="target"><title> \t\r\n </title></svg>'
);
assert.isFalse(check.evaluate.apply(null, checkArgs));
assert.isFalse(checkEvaluate.apply(null, checkArgs));
});

it('returns false if there are multiple titles, and the first is empty', function() {
var checkArgs = checkSetup(
'<svg id="target"><title></title><title>Time II: Party</title></svg>'
);
assert.isFalse(check.evaluate.apply(null, checkArgs));
assert.isFalse(checkEvaluate.apply(null, checkArgs));
});

describe('Serial Virtual Node', function() {
it('returns true if the element has a `title` child', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'svg'
});
var child = new axe.SerialVirtualNode({
nodeName: 'title'
});
var text = new axe.SerialVirtualNode({
nodeName: '#text',
nodeType: 3,
nodeValue: 'Time II: Party'
});
child.parent = serialNode;
child.children = [text];
serialNode.children = [child];

assert.isTrue(checkEvaluate(null, {}, serialNode));
});

it('returns false if the element has no `title` child', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'svg'
});
serialNode.children = [];

assert.isFalse(checkEvaluate(null, {}, serialNode));
});

it('returns undefined if the element has empty children', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'svg'
});

assert.isUndefined(checkEvaluate(null, {}, serialNode));
});
});
});
51 changes: 51 additions & 0 deletions test/rule-matches/svg-namespace-matches.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,55 @@ describe('svg-namespace-matches', function() {
var virtualNode = axe.utils.getNodeFromTree(axe._tree[0], node);
assert.isFalse(rule.matches(node, virtualNode));
});

describe('Serial Virtual Node', function() {
it('should return true when passed an SVG element', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'svg'
});
var child = new axe.SerialVirtualNode({
nodeName: 'title',
nodeValue: 'Pretty picture'
});
child.parent = serialNode;
serialNode.children = [child];

assert.isTrue(rule.matches(null, serialNode));
});

it('returns true when passed an SVG circle element', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'svg'
});
var child = new axe.SerialVirtualNode({
nodeName: 'circle'
});
child.parent = serialNode;
serialNode.children = [child];

assert.isTrue(rule.matches(null, child));
});

it('returns false when passed an HTML element', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'h1',
nodeValue: 'Hello world'
});

assert.isFalse(rule.matches(null, serialNode));
});

it('should return false when passed an svg element without a parent', function() {
var serialNode = new axe.SerialVirtualNode({
nodeName: 'circle'
});
var parent = new axe.SerialVirtualNode({
nodeName: 'svg'
});
parent.children = [serialNode];
serialNode.parent = parent;

assert.isTrue(rule.matches(null, serialNode));
});
});
});