diff --git a/lib/checks/color/link-in-text-block-style-evaluate.js b/lib/checks/color/link-in-text-block-style-evaluate.js index aaf6fec010..e07929ea41 100644 --- a/lib/checks/color/link-in-text-block-style-evaluate.js +++ b/lib/checks/color/link-in-text-block-style-evaluate.js @@ -9,12 +9,8 @@ const blockLike = [ 'grid', 'inline-block' ]; -function isBlock(elm) { - var display = window.getComputedStyle(elm).getPropertyValue('display'); - return blockLike.indexOf(display) !== -1 || display.substr(0, 6) === 'table-'; -} -function linkInTextBlockStyleEvaluate(node) { +export default function linkInTextBlockStyleEvaluate(node) { if (isBlock(node)) { return false; } @@ -30,7 +26,28 @@ function linkInTextBlockStyleEvaluate(node) { this.relatedNodes([parentBlock]); - return elementIsDistinct(node, parentBlock); + if (elementIsDistinct(node, parentBlock)) { + return true; + } + if (hasPseudoContent(node)) { + this.data({ messageKey: 'pseudoContent' }); + return undefined; + } + return false; +} + +function isBlock(elm) { + var display = window.getComputedStyle(elm).getPropertyValue('display'); + return blockLike.indexOf(display) !== -1 || display.substr(0, 6) === 'table-'; } -export default linkInTextBlockStyleEvaluate; +function hasPseudoContent(node) { + for (const pseudo of ['before', 'after']) { + const style = window.getComputedStyle(node, `:${pseudo}`); + const content = style.getPropertyValue('content'); + if (content !== 'none') { + return true; + } + } + return false; +} diff --git a/lib/checks/color/link-in-text-block-style.json b/lib/checks/color/link-in-text-block-style.json index 566f1cd715..bb909baf12 100644 --- a/lib/checks/color/link-in-text-block-style.json +++ b/lib/checks/color/link-in-text-block-style.json @@ -5,6 +5,10 @@ "impact": "serious", "messages": { "pass": "Links can be distinguished from surrounding text by visual styling", + "incomplete": { + "default": "Check if the link needs styling to distinguish it from nearby text", + "pseudoContent": "Check if the link's pseudo style is sufficient to distinguish it from the surrounding text" + }, "fail": "The link has no styling (such as underline) to distinguish it from the surrounding text" } } diff --git a/locales/_template.json b/locales/_template.json index 20d4246ba6..3cb970b002 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -623,6 +623,10 @@ }, "link-in-text-block-style": { "pass": "Links can be distinguished from surrounding text by visual styling", + "incomplete": { + "default": "Check if the link needs styling to distinguish it from nearby text", + "pseudoContent": "Check if the link's pseudo style is sufficient to distinguish it from the surrounding text" + }, "fail": "The link has no styling (such as underline) to distinguish it from the surrounding text" }, "link-in-text-block": { diff --git a/test/checks/color/link-in-text-block-style.js b/test/checks/color/link-in-text-block-style.js index 2f79c958e5..2fdb94fc4a 100644 --- a/test/checks/color/link-in-text-block-style.js +++ b/test/checks/color/link-in-text-block-style.js @@ -7,6 +7,11 @@ describe('link-in-text-block-style', function () { var checkContext = axe.testUtils.MockCheckContext(); + const { queryFixture } = axe.testUtils; + const linkInBlockStyleCheck = axe.testUtils.getCheckEvaluate( + 'link-in-text-block-style' + ); + before(function () { styleElm = document.createElement('style'); document.head.appendChild(styleElm); @@ -107,11 +112,7 @@ describe('link-in-text-block-style', function () { axe.testUtils.flatTreeSetup(fixture); var linkElm = document.getElementById('link'); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('link-in-text-block-style') - .call(checkContext, linkElm) - ); + assert.isFalse(linkInBlockStyleCheck.call(checkContext, linkElm)); }); (shadowSupport.v1 ? it : xit)( @@ -126,11 +127,7 @@ describe('link-in-text-block-style', function () { axe.testUtils.flatTreeSetup(fixture); - assert.isTrue( - axe.testUtils - .getCheckEvaluate('link-in-text-block-style') - .call(checkContext, linkElm) - ); + assert.isTrue(linkInBlockStyleCheck.call(checkContext, linkElm)); } ); @@ -148,11 +145,7 @@ describe('link-in-text-block-style', function () { axe.testUtils.flatTreeSetup(fixture); var linkElm = div.querySelector('a'); - assert.isTrue( - axe.testUtils - .getCheckEvaluate('link-in-text-block-style') - .call(checkContext, linkElm) - ); + assert.isTrue(linkInBlockStyleCheck.call(checkContext, linkElm)); } ); }); @@ -160,24 +153,58 @@ describe('link-in-text-block-style', function () { describe('links distinguished through style', function () { it('returns false if link style matches parent', function () { var linkElm = getLinkElm({}); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('link-in-text-block-style') - .call(checkContext, linkElm) - ); + assert.isFalse(linkInBlockStyleCheck.call(checkContext, linkElm)); assert.equal(checkContext._relatedNodes[0], linkElm.parentNode); + assert.isNull(checkContext._data); }); it('returns true if link has underline', function () { var linkElm = getLinkElm({ textDecoration: 'underline' }); - assert.isTrue( - axe.testUtils - .getCheckEvaluate('link-in-text-block-style') - .call(checkContext, linkElm) - ); + assert.isTrue(linkInBlockStyleCheck.call(checkContext, linkElm)); assert.equal(checkContext._relatedNodes[0], linkElm.parentNode); + assert.isNull(checkContext._data); + }); + + it('returns undefined when the link has a :before pseudo element', function () { + const link = queryFixture(` + +

A link inside a block of text

+ `).actualNode; + const result = linkInBlockStyleCheck.call(checkContext, link); + assert.isUndefined(result); + assert.deepEqual(checkContext._data, { messageKey: 'pseudoContent' }); + assert.equal(checkContext._relatedNodes[0], link.parentNode); + }); + + it('returns undefined when the link has a :after pseudo element', function () { + const link = queryFixture(` + +

A link inside a block of text

+ `).actualNode; + const result = linkInBlockStyleCheck.call(checkContext, link); + assert.isUndefined(result); + assert.deepEqual(checkContext._data, { messageKey: 'pseudoContent' }); + assert.equal(checkContext._relatedNodes[0], link.parentNode); + }); + + it('does not return undefined when the pseudo element content is none', function () { + const link = queryFixture(` + +

A link inside a block of text

+ `).actualNode; + const result = linkInBlockStyleCheck.call(checkContext, link); + assert.isFalse(result); }); }); }); diff --git a/test/integration/rules/link-in-text-block/link-in-text-block.html b/test/integration/rules/link-in-text-block/link-in-text-block.html index 260a259e4f..9d69d819d0 100644 --- a/test/integration/rules/link-in-text-block/link-in-text-block.html +++ b/test/integration/rules/link-in-text-block/link-in-text-block.html @@ -149,3 +149,21 @@

Incomplete tests

Link test

+ + +

+ Lorem ipsum dolor sit. +

diff --git a/test/integration/rules/link-in-text-block/link-in-text-block.json b/test/integration/rules/link-in-text-block/link-in-text-block.json index 366b5f07dd..e4e2c7dfaa 100644 --- a/test/integration/rules/link-in-text-block/link-in-text-block.json +++ b/test/integration/rules/link-in-text-block/link-in-text-block.json @@ -14,5 +14,8 @@ ["#pass-text-color"], ["#pass-same-colors"] ], - "incomplete": [["#incomplete-low-contrast-parent-has-gradient"]] + "incomplete": [ + ["#incomplete-low-contrast-parent-has-gradient"], + ["#incomplete-pseudo-before"] + ] }