diff --git a/build/tasks/validate.js b/build/tasks/validate.js index 4e4aaabcc0..bc3c76b4e4 100644 --- a/build/tasks/validate.js +++ b/build/tasks/validate.js @@ -27,6 +27,27 @@ function hasUniqueId() { }; } +function hasMultipleOutcomes(messages) { + const keys = Object.keys(messages); + if (keys.length < 2) { + return false; + } + + return keys.every(key => { + switch (key) { + case 'pass': + case 'fail': + return typeof messages[key] === 'string'; + + case 'incomplete': + return ['string', 'object'].includes(typeof messages[key]); + + default: + return false; + } + }); +} + function createSchemas() { var schemas = {}; @@ -84,15 +105,9 @@ function createSchemas() { messages: { required: true, type: 'object', - properties: { - fail: { - required: true, - type: 'string' - }, - pass: { - required: true, - type: 'string' - } + conform: hasMultipleOutcomes, + messages: { + conform: 'Must have at least two valid messages' } }, impact: { diff --git a/lib/checks/media/caption.js b/lib/checks/media/caption.js index 35863e7531..fc0dafd2e3 100644 --- a/lib/checks/media/caption.js +++ b/lib/checks/media/caption.js @@ -1,11 +1,8 @@ -var tracks = axe.utils.querySelectorAll(virtualNode, 'track'); +const tracks = axe.utils.querySelectorAll(virtualNode, 'track'); +const hasCaptions = tracks.some( + ({ actualNode }) => + (actualNode.getAttribute('kind') || '').toLowerCase() === 'captions' +); -if (tracks.length) { - // return false if any track has kind === 'caption' - return !tracks.some( - ({ actualNode }) => - (actualNode.getAttribute('kind') || '').toLowerCase() === 'captions' - ); -} -// Undefined if there are no tracks - media may be decorative -return undefined; +// Undefined if there are no tracks - media may use another caption method +return hasCaptions ? false : undefined; diff --git a/lib/checks/media/caption.json b/lib/checks/media/caption.json index 0b9a503409..061a0bc397 100644 --- a/lib/checks/media/caption.json +++ b/lib/checks/media/caption.json @@ -5,8 +5,7 @@ "impact": "critical", "messages": { "pass": "The multimedia element has a captions track", - "fail": "The multimedia element does not have a captions track", - "incomplete": "A captions track for this element could not be found" + "incomplete": "Check that captions is available for the element" } } } diff --git a/lib/checks/media/description.js b/lib/checks/media/description.js index 51627acf61..0ea03102da 100644 --- a/lib/checks/media/description.js +++ b/lib/checks/media/description.js @@ -1,12 +1,8 @@ -var tracks = axe.utils.querySelectorAll(virtualNode, 'track'); +const tracks = axe.utils.querySelectorAll(virtualNode, 'track'); +const hasDescriptions = tracks.some( + ({ actualNode }) => + (actualNode.getAttribute('kind') || '').toLowerCase() === 'descriptions' +); -if (tracks.length) { - // return false if any track has kind === 'description' - var out = !tracks.some( - ({ actualNode }) => - (actualNode.getAttribute('kind') || '').toLowerCase() === 'descriptions' - ); - return out; -} -// Undefined if there are no tracks - media may be decorative -return undefined; +// Undefined if there are no tracks - media may have another description method +return hasDescriptions ? false : undefined; diff --git a/lib/checks/media/description.json b/lib/checks/media/description.json index c81782e9bd..18fbd517ec 100644 --- a/lib/checks/media/description.json +++ b/lib/checks/media/description.json @@ -5,8 +5,7 @@ "impact": "critical", "messages": { "pass": "The multimedia element has an audio description track", - "fail": "The multimedia element does not have an audio description track", - "incomplete": "An audio description track for this element could not be found" + "incomplete": "Check that audio description is available for the element" } } } diff --git a/test/checks/media/caption.js b/test/checks/media/caption.js index 8773ef5fcf..b1f067707e 100644 --- a/test/checks/media/caption.js +++ b/test/checks/media/caption.js @@ -14,17 +14,17 @@ describe('caption', function() { assert.isUndefined(checks.caption.evaluate.apply(null, checkArgs)); }); - it('should fail if there is no kind=captions attribute', function() { + it('should return undefined if there is no kind=captions attribute', function() { var checkArgs = checkSetup( '', 'audio' ); - assert.isTrue(checks.caption.evaluate.apply(null, checkArgs)); + assert.isUndefined(checks.caption.evaluate.apply(null, checkArgs)); }); - it('should fail if there is no kind attribute', function() { + it('should return undefined if there is no kind attribute', function() { var checkArgs = checkSetup('', 'video'); - assert.isTrue(checks.description.evaluate.apply(null, checkArgs)); + assert.isUndefined(checks.description.evaluate.apply(null, checkArgs)); }); it('should pass if there is a kind=captions attribute', function() { @@ -36,12 +36,12 @@ describe('caption', function() { 'should get track from composed tree', function() { var node = document.createElement('div'); - node.innerHTML = ''; + node.innerHTML = ''; var shadow = node.attachShadow({ mode: 'open' }); shadow.innerHTML = ''; var checkArgs = checkSetup(node, {}, 'audio'); - assert.isTrue(checks.caption.evaluate.apply(null, checkArgs)); + assert.isFalse(checks.caption.evaluate.apply(null, checkArgs)); } ); }); diff --git a/test/checks/media/description.js b/test/checks/media/description.js index 711e222e17..854ac5eadf 100644 --- a/test/checks/media/description.js +++ b/test/checks/media/description.js @@ -13,14 +13,14 @@ describe('description', function() { assert.isUndefined(checks.description.evaluate.apply(null, checkArgs)); }); - it('should fail if there is no kind=captions attribute', function() { + it('should return undefined if there is no kind=captions attribute', function() { var checkArgs = checkSetup('', 'video'); - assert.isTrue(checks.description.evaluate.apply(null, checkArgs)); + assert.isUndefined(checks.description.evaluate.apply(null, checkArgs)); }); - it('should fail if there is no kind attribute', function() { + it('should return undefined if there is no kind attribute', function() { var checkArgs = checkSetup('', 'video'); - assert.isTrue(checks.description.evaluate.apply(null, checkArgs)); + assert.isUndefined(checks.description.evaluate.apply(null, checkArgs)); }); it('should pass if there is a kind=descriptions attribute', function() { diff --git a/test/integration/rules/video-caption/video-caption.html b/test/integration/rules/video-caption/video-caption.html index e9872a04f4..c9bf69e9fc 100644 --- a/test/integration/rules/video-caption/video-caption.html +++ b/test/integration/rules/video-caption/video-caption.html @@ -1,4 +1,4 @@ - + diff --git a/test/integration/rules/video-caption/video-caption.json b/test/integration/rules/video-caption/video-caption.json index bd169a0875..09c69be6e2 100644 --- a/test/integration/rules/video-caption/video-caption.json +++ b/test/integration/rules/video-caption/video-caption.json @@ -1,7 +1,6 @@ { "description": "video-caption test", "rule": "video-caption", - "incomplete": [["#incomplete1"]], - "violations": [["#fail1"]], + "incomplete": [["#incomplete1"], ["#incomplete2"]], "passes": [["#pass1"], ["#pass2"]] } diff --git a/test/integration/rules/video-description/video-description.html b/test/integration/rules/video-description/video-description.html index 2419ad3c85..d80b527c64 100644 --- a/test/integration/rules/video-description/video-description.html +++ b/test/integration/rules/video-description/video-description.html @@ -1,5 +1,5 @@ - + diff --git a/test/integration/rules/video-description/video-description.json b/test/integration/rules/video-description/video-description.json index f6aa232157..753df677a0 100644 --- a/test/integration/rules/video-description/video-description.json +++ b/test/integration/rules/video-description/video-description.json @@ -1,7 +1,6 @@ { "description": "video-description test", "rule": "video-description", - "incomplete": [["#incomplete1"]], - "violations": [["#fail1"]], + "incomplete": [["#incomplete1"], ["#incomplete2"]], "passes": [["#pass1"], ["#pass2"]] }