Index: chrome/test/data/webui/test_api.js |
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js |
index 03c6721d51d55bf0baf4641caa2e6d9955c31802..fbe5640a5a9f6b80ecf31be64717a2a24480288e 100644 |
--- a/chrome/test/data/webui/test_api.js |
+++ b/chrome/test/data/webui/test_api.js |
@@ -122,6 +122,18 @@ var testing = {}; |
extraLibraries: [], |
/** |
+ * FIXME(aboxhall) |
+ */ |
+ runA11yChecks : true, |
+ |
+ /** |
+ * FIXME(aboxhall) |
+ * Off by default to begin with; as we add the ability to suppress false |
+ * positives, we will transition this to true. |
+ */ |
+ a11yIssuesAreErrors: false, |
+ |
+ /** |
* Create a new class to handle |messageNames|, assign it to |
* |this.mockHandler|, register its messages and return it. |
* @return {Mock} Mock handler class assigned to |this.mockHandler|. |
@@ -234,6 +246,8 @@ var testing = {}; |
function TestCase(name, fixture, body) { |
this.name = name; |
this.fixture = fixture; |
+ this.runA11yChecks = fixture.runA11yChecks; |
+ this.a11yIssuesAreErrors = fixture.a11yIssuesAreErrors; |
this.body = body; |
} |
@@ -263,6 +277,13 @@ var testing = {}; |
*/ |
deferred_: false, |
+ runA11yChecks: true, |
+ |
+ /** |
+ * FIXME(aboxhall) |
+ */ |
+ a11yIssuesAreErrors: true, |
+ |
/** |
* Called at preload time, proxies to the fixture. |
* @type {Function} |
@@ -585,6 +606,13 @@ var testing = {}; |
var errors = []; |
/** |
+ * Hold the accessibility warnings and errors, respectively. |
+ * Like errors, cleared when results are reported. |
+ */ |
+ var a11y_warnings = []; |
+ var a11y_errors = []; |
+ |
+ /** |
* URL to dummy WebUI page for testing framework. |
* @type {string} |
*/ |
@@ -607,6 +635,20 @@ var testing = {}; |
if (!testIsDone) { |
testIsDone = true; |
if (currentTestCase) { |
+ if (currentTestCase.runA11yChecks && |
+ !runAccessibilityAudit_(a11y_errors, a11y_warnings)) { |
+ if (currentTestCase.a11yIssuesAreErrors) { |
+ if (!result) |
+ result = testResult(); |
+ result = [false, accessibilityErrorsToMessage(a11y_errors, |
+ a11y_warnings, |
+ result[1])]; |
+ } else { /* a11yIssuesAreErrors */ |
+ console.warn(accessibilityErrorsToMessage(a11y_errors, |
+ a11y_warnings)); |
+ } |
+ } |
+ |
try { |
currentTestCase.tearDown(); |
} catch (e) { |
@@ -618,7 +660,9 @@ var testing = {}; |
} |
currentTestCase = null; |
} |
- chrome.send('testResult', result ? result : testResult()); |
+ if (!result) |
+ result = testResult(); |
+ chrome.send('testResult', result); |
errors.splice(0, errors.length); |
} else { |
console.warn('testIsDone already'); |
@@ -652,9 +696,9 @@ var testing = {}; |
*/ |
function testResult(errorsOk) { |
var result = [true, '']; |
- if (errors.length) { |
+ if (errors.length) |
result = [!!errorsOk, errorsToMessage(errors)]; |
- } |
+ |
return result; |
} |
@@ -792,6 +836,126 @@ var testing = {}; |
throw new Error(helper.getCallMessage(message)); |
} |
+ function disableA11yChecks() { |
+ if (!currentTestCase) |
+ return; |
+ currentTestCase.runA11yChecks = false; |
+ } |
+ |
+ function enableA11yChecks() { |
+ if (!currentTestCase) |
+ return; |
+ currentTestCase.runA11yChecks = true; |
+ } |
+ |
+ function a11yIssuesAreErrors(flag) { |
+ if (!currentTestCase) |
+ return; |
+ currentTestCase.a11yIssuesAreErrors = flag; |
+ } |
+ |
+ /** |
+ * FIXME(aboxhall) documentation |
+ */ |
+ function accessibilityErrorsToMessage(a11y_errors, a11y_warnings, message) { |
+ if (message) |
+ message += '\n\n'; |
+ else |
+ message = '\n'; |
+ |
+ message += 'An accessibility audit found '; |
+ |
+ if (a11y_errors.length > 0) { |
+ message += a11y_errors.length + |
+ (a11y_errors.length == 1 ? ' error ' : ' errors '); |
+ if (a11y_warnings.length > 0) |
+ message += 'and '; |
+ } |
+ if (a11y_warnings.length > 0) { |
+ message += a11y_warnings.length + |
+ (a11y_warnings.length == 1 ? ' warning ' : ' warnings '); |
+ } |
+ message += 'on this page.\n'; |
+ if (!currentTestCase.a11yIssuesAreErrors) { |
+ message += 'These are currently for information only, but will become ' + |
+ 'errors at a later date.\n' |
+ } |
+ message += 'For more information, please see ' + |
+ 'https://sites.google.com/a/chromium.org/dev/webui-accessibility-audit'; |
+ |
+ for (var i = 0; i < a11y_errors.length; i++) |
+ message += '\n\n' + a11y_errors[i]; |
+ |
+ for (var i = 0; i < a11y_warnings.length; i++) |
+ message += '\n\n' + a11y_warnings[i]; |
+ return message; |
+ } |
+ |
+ /** |
+ * FIXME(aboxhall): documentation |
+ */ |
+ function accessibilityErrorMessage(rule, result) { |
+ if (rule.severity == axs.constants.Severity.Severe) |
+ var message = 'Error: ' |
+ else |
+ var message = 'Warning: ' |
+ message += rule.name + ' failed on the following ' + |
+ (result.elements.length == 1 ? 'element' : 'elements'); |
+ |
+ if (result.elements.length == 1) |
+ message += ':' |
+ else |
+ message += ' (1 - ' + Math.min(5, result.elements.length) + |
+ ' of ' + result.elements.length + '):'; |
+ |
+ for (var i = 0; i < Math.min(result.elements.length, 5); i++) |
+ message += '\n' + axs.utils.getQuerySelectorText(result.elements[i]); |
+ return message; |
+ } |
+ |
+ /** |
+ * FIXME(aboxhall) documentation |
+ */ |
+ function assertAccessibilityOk() { |
+ helper.registerCall(); |
+ var a11y_errors = []; |
+ var a11y_warnings = []; |
+ if (!runAccessibilityAudit_(a11y_errors, a11y_warnings)) |
+ throw new Error(accessibilityErrorsToMessage(a11y_errors, |
+ a11y_warnings)); |
+ } |
+ |
+ /** |
+ * Run an accessibility audit on the current page state. |
+ * FIXME(aboxhall) documentation |
+ * @type {Function} |
+ * @return {boolean} Whether there were any errors or warnings |
+ * @private |
+ */ |
+ function runAccessibilityAudit_(a11yErrors, a11yWarnings) { |
+ for (var auditRuleName in axs.AuditRule.specs) { |
+ var auditRule = axs.AuditRules.getRule(auditRuleName); |
+ if (!auditRule) |
+ continue; // Shouldn't happen, but fail silently if it does. |
+ |
+ if (auditRule.disabled || auditRule.requiresConsoleAPI) |
+ continue; |
+ |
+ var result = auditRule.run(); |
+ if (result.result == axs.constants.AuditResult.FAIL) { |
+ // TODO(aboxhall): more useful error messages (sadly non-trivial) |
+ if (auditRule.severity == axs.constants.Severity.Severe) |
+ a11yErrors.push(accessibilityErrorMessage(auditRule, result)); |
+ else |
+ a11yWarnings.push(accessibilityErrorMessage(auditRule, result)); |
+ } |
+ } |
+ // TODO(aboxhall): have strict (no errors or warnings) vs non-strict |
+ // (warnings ok) |
+ // TODO(aboxhall): some kind of info logging for warnings only?? |
+ return (a11yErrors.length == 0 && a11yWarnings.length == 0); |
+ } |
+ |
/** |
* Creates a function based upon a function that thows an exception on |
* failure. The new function stuffs any errors into the |errors| array for |
@@ -1368,6 +1532,7 @@ var testing = {}; |
// Exports. |
testing.Test = Test; |
exports.testDone = testDone; |
+ exports.a11yIssuesAreErrors = a11yIssuesAreErrors; |
exports.assertTrue = assertTrue; |
exports.assertFalse = assertFalse; |
exports.assertGE = assertGE; |
@@ -1377,9 +1542,12 @@ var testing = {}; |
exports.assertLT = assertLT; |
exports.assertNotEquals = assertNotEquals; |
exports.assertNotReached = assertNotReached; |
+ exports.assertAccessibilityOk = assertAccessibilityOk; |
exports.callFunction = callFunction; |
exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs; |
exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs; |
+ exports.disableA11yChecks = disableA11yChecks; |
+ exports.enableA11yChecks = enableA11yChecks; |
exports.expectTrue = createExpect(assertTrue); |
exports.expectFalse = createExpect(assertFalse); |
exports.expectGE = createExpect(assertGE); |
@@ -1389,11 +1557,13 @@ var testing = {}; |
exports.expectLT = createExpect(assertLT); |
exports.expectNotEquals = createExpect(assertNotEquals); |
exports.expectNotReached = createExpect(assertNotReached); |
+ exports.expectAccessibilityOk = createExpect(assertAccessibilityOk); |
exports.preloadJavascriptLibraries = preloadJavascriptLibraries; |
exports.registerMessageCallback = registerMessageCallback; |
exports.registerMockGlobals = registerMockGlobals; |
exports.registerMockMessageCallbacks = registerMockMessageCallbacks; |
exports.resetTestState = resetTestState; |
+ exports.runAccessibilityAudit_ = runAccessibilityAudit_; |
exports.runAllActions = runAllActions; |
exports.runAllActionsAsync = runAllActionsAsync; |
exports.runTest = runTest; |
@@ -1402,6 +1572,7 @@ var testing = {}; |
exports.DUMMY_URL = DUMMY_URL; |
exports.TEST = TEST; |
exports.TEST_F = TEST_F; |
+ exports.RUNTIME_TEST_F = TEST_F; |
exports.GEN = GEN; |
exports.GEN_INCLUDE = GEN_INCLUDE; |
exports.WhenTestDone = WhenTestDone; |