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 = '