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

feat(rule): add color-contrast check for unicode characters, behind flags. #1969

Merged
merged 1 commit into from
Jan 9, 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
20 changes: 16 additions & 4 deletions lib/checks/color/color-contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ if (!dom.isVisible(node, false)) {
return true;
}

const visibleText = text.visibleVirtual(virtualNode, false, true);
const ignoreUnicode = !!(options || {}).ignoreUnicode;
const textContainsOnlyUnicode = !text.removeUnicode(visibleText, {
emoji: false,
nonBmp: true,
punctuations: false
}).length;

if (textContainsOnlyUnicode && ignoreUnicode) {
return true;
}

const noScroll = !!(options || {}).noScroll;
const bgNodes = [];
const bgColor = color.getBackgroundColor(node, bgNodes, noScroll);
Expand All @@ -28,11 +40,11 @@ if (bgColor === null) {
}

const equalRatio = truncatedResult === 1;
const shortTextContent =
text.visibleVirtual(virtualNode, false, true).length === 1;
const shortTextContent = visibleText.length === 1;
const ignoreLength = !!(options || {}).ignoreLength;
if (equalRatio) {
missing = color.incompleteData.set('bgColor', 'equalRatio');
} else if (shortTextContent) {
} else if (shortTextContent && !ignoreLength) {
// Check that the text content is a single character long
missing = 'shortTextContent';
}
Expand All @@ -55,7 +67,7 @@ if (
fgColor === null ||
bgColor === null ||
equalRatio ||
(shortTextContent && !cr.isValid)
(shortTextContent && !ignoreLength && !cr.isValid)
) {
missing = null;
color.incompleteData.clear();
Expand Down
5 changes: 5 additions & 0 deletions lib/checks/color/color-contrast.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"evaluate": "color-contrast.js",
"metadata": {
"impact": "serious",
"options": {
"noScroll": false,
"ignoreUnicode": true,
"ignoreLength": false
},
"messages": {
"pass": "Element has sufficient color contrast of ${data.contrastRatio}",
"fail": "Element has insufficient color contrast of ${data.contrastRatio} (foreground color: ${data.fgColor}, background color: ${data.bgColor}, font size: ${data.fontSize}, font weight: ${data.fontWeight}). Expected contrast ratio of ${data.expectedContrastRatio}",
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/color-contrast-matches.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if (
visibleText === '' ||
axe.commons.text.removeUnicode(visibleText, {
emoji: true,
nonBmp: true,
nonBmp: false,
punctuations: true
}) === ''
) {
Expand Down
4 changes: 3 additions & 1 deletion lib/rules/color-contrast.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"matches": "color-contrast-matches.js",
"excludeHidden": false,
"options": {
"noScroll": false
"noScroll": false,
"ignoreUnicode": true,
"ignoreLength": false
},
"tags": ["cat.color", "wcag2aa", "wcag143"],
"metadata": {
Expand Down
59 changes: 58 additions & 1 deletion test/checks/color/color-contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,14 +327,71 @@ describe('color-contrast', function() {
it('should return true for a single character text with insufficient contrast', function() {
var params = checkSetup(
'<div style="background-color: #FFF;">' +
'<div style="color:#000;" id="target">X</div>' +
'<div style="color:#DDD;" id="target">X</div>' +
'</div>'
);

var actual = contrastEvaluate.apply(checkContext, params);
assert.isUndefined(actual);
assert.equal(checkContext._data.messageKey, 'shortTextContent');
});

it('should return undefined when the text only contains nonBmp unicode by default', function() {
var params = checkSetup(
'<div style="background-color: #FFF;">' +
KyleBastien marked this conversation as resolved.
Show resolved Hide resolved
'<div style="color:#DDD;" id="target">◓</div>' +
'</div>'
);

var actual = contrastEvaluate.apply(checkContext, params);
assert.isUndefined(actual);
assert.equal(checkContext._data.messageKey, 'shortTextContent');
});

it('should return true when the text only contains nonBmp unicode when the ignoreUnicode option is false, and there is sufficient contrast', function() {
var params = checkSetup(
'<div style="background-color: #FFF;">' +
'<div style="color:#000;" id="target">◓</div>' +
'</div>',
{
ignoreUnicode: false
}
);

var actual = contrastEvaluate.apply(checkContext, params);
assert.isTrue(actual);
});

it('should return undefined when the text only contains nonBmp unicode when the ignoreUnicode option is false and the ignoreLength option is default, and there is insufficient contrast', function() {
var params = checkSetup(
'<div style="background-color: #FFF;">' +
'<div style="color:#DDD;" id="target">◓</div>' +
'</div>',
{
ignoreUnicode: false
}
);

var actual = contrastEvaluate.apply(checkContext, params);
assert.isUndefined(actual);
assert.equal(checkContext._data.messageKey, 'shortTextContent');
});

it('should return false when the text only contains nonBmp unicode when the ignoreUnicode option is false and the ignoreLength option is true, and there is insufficient contrast', function() {
var params = checkSetup(
'<div style="background-color: #FFF;">' +
'<div style="color:#DDD;" id="target">◓</div>' +
'</div>',
{
ignoreUnicode: false,
ignoreLength: true
}
);

var actual = contrastEvaluate.apply(checkContext, params);
assert.isFalse(actual);
});

(shadowSupported ? it : xit)(
'returns colors across Shadow DOM boundaries',
function() {
Expand Down
4 changes: 2 additions & 2 deletions test/rule-matches/color-contrast-matches.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ describe('color-contrast-matches', function() {
assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target)));
});

it('should not match when text only contains nonBmp unicode', function() {
it('should match when text only contains nonBmp unicode', function() {
fixture.innerHTML =
'<div style="color: yellow; background-color: white;" id="target">' +
'◓</div>';
var target = fixture.querySelector('#target');
axe.testUtils.flatTreeSetup(fixture);
assert.isFalse(rule.matches(target, axe.utils.getNodeFromTree(target)));
assert.isTrue(rule.matches(target, axe.utils.getNodeFromTree(target)));
});

it('should not match when there is text that is out of the container', function() {
Expand Down