Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: chrome/test/data/webui/test_api.js

Issue 11363170: Add an accessibility audit test for WebUI pages (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Library providing basic test framework functionality. 6 * @fileoverview Library providing basic test framework functionality.
7 */ 7 */
8 8
9 /** 9 /**
10 * Namespace for |Test|. 10 * Namespace for |Test|.
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 */ 115 */
116 testShouldFail: false, 116 testShouldFail: false,
117 117
118 /** 118 /**
119 * Extra libraries to add before loading this test file. 119 * Extra libraries to add before loading this test file.
120 * @type {Array.<string>} 120 * @type {Array.<string>}
121 */ 121 */
122 extraLibraries: [], 122 extraLibraries: [],
123 123
124 /** 124 /**
125 * Whether to run the accessibility checks.
126 * @type {boolean}
127 */
128 runAccessibilityChecks : true,
129
130 /**
131 * Whether to treat accessibility issues (errors or warnings) as test
132 * failures. If true, any accessibility issues will cause the test to fail.
133 * If false, accessibility issues will cause a console.warn.
134 * Off by default to begin with; as we add the ability to suppress false
135 * positives, we will transition this to true.
136 * @type {boolean}
137 */
138 accessibilityIssuesAreErrors: false,
139
140 /**
141 * Holds any accessibility errors found during the accessibility audit.
142 * @type {Array.<string>}
143 */
144 a11yErrors_: [],
145
146 /**
147 * Holds any accessibility warnings found during the accessibility audit.
148 * @type {Array.<string>}
149 */
150 a11yWarnings_: [],
151
152 /**
153 * Gets the list of accessibility errors found during the accessibility
154 * audit. Only for use in testing.
155 * @return {Array.<string>}
156 */
157 getAccessibilityErrors: function() {
158 return this.a11yErrors_;
159 },
160
161 /**
162 * Gets the list of accessibility warnings found during the accessibility
163 * audit. Only for use in testing.
164 * @return {Array.<string>}
165 */
166 getAccessibilityWarnings: function() {
167 return this.a11yWarnings_;
168 },
169
170 /**
171 * Run accessibility checks after this test completes.
172 */
173 enableAccessibilityChecks: function() {
174 this.runAccessibilityChecks = true;
175 },
176
177 /**
178 * Don't run accessibility checks after this test completes.
179 */
180 disableAccessibilityChecks: function() {
181 this.runAccessibilityChecks = false;
182 },
183
184 /**
125 * Create a new class to handle |messageNames|, assign it to 185 * Create a new class to handle |messageNames|, assign it to
126 * |this.mockHandler|, register its messages and return it. 186 * |this.mockHandler|, register its messages and return it.
127 * @return {Mock} Mock handler class assigned to |this.mockHandler|. 187 * @return {Mock} Mock handler class assigned to |this.mockHandler|.
128 */ 188 */
129 makeAndRegisterMockHandler: function(messageNames) { 189 makeAndRegisterMockHandler: function(messageNames) {
130 var MockClass = makeMockClass(messageNames); 190 var MockClass = makeMockClass(messageNames);
131 this.mockHandler = mock(MockClass); 191 this.mockHandler = mock(MockClass);
132 registerMockMessageCallbacks(this.mockHandler, MockClass); 192 registerMockMessageCallbacks(this.mockHandler, MockClass);
133 return this.mockHandler; 193 return this.mockHandler;
134 }, 194 },
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 231
172 /** 232 /**
173 * Called to run the body from the perspective of this fixture. 233 * Called to run the body from the perspective of this fixture.
174 * @type {Function} 234 * @type {Function}
175 */ 235 */
176 runTest: function(testBody) { 236 runTest: function(testBody) {
177 testBody.call(this); 237 testBody.call(this);
178 }, 238 },
179 239
180 /** 240 /**
241 * Called to run the accessibility audit from the perspective of this
242 * fixture.
243 */
244 runAccessibilityAudit: function() {
245 if (!this.runAccessibilityChecks || typeof document === 'undefined')
246 return;
247
248 if (!runAccessibilityAudit(this.a11yErrors_, this.a11yWarnings_)) {
249 var report = accessibilityAuditReport(this.a11yErrors_,
250 this.a11yWarnings_);
251 if (this.accessibilityIssuesAreErrors) {
252 throw new Error(report);
253 } else {
James Hawkins 2013/01/03 21:23:39 nit: No braces for single-line blocks.
aboxhall 2013/01/04 00:26:50 Done.
254 console.warn(report);
255 }
256 }
257 },
258
259 /**
181 * Create a closure function for continuing the test at a later time. May be 260 * Create a closure function for continuing the test at a later time. May be
182 * used as a listener function. 261 * used as a listener function.
183 * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate 262 * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate
184 * time. 263 * time.
185 * @param {Function} completion The function to call to complete the test. 264 * @param {Function} completion The function to call to complete the test.
186 * @param {...*} var_args Arguments to pass when calling completionAction. 265 * @param {...*} var_args Arguments to pass when calling completionAction.
187 * @return {function(): void} Return a function, bound to this test fixture, 266 * @return {function(): void} Return a function, bound to this test fixture,
188 * which continues the test. 267 * which continues the test.
189 */ 268 */
190 continueTest: function(whenTestDone, completion) { 269 continueTest: function(whenTestDone, completion) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 369
291 /** 370 /**
292 * Called to run this test's body. 371 * Called to run this test's body.
293 */ 372 */
294 runTest: function() { 373 runTest: function() {
295 if (this.body && this.fixture) 374 if (this.body && this.fixture)
296 this.fixture.runTest(this.body); 375 this.fixture.runTest(this.body);
297 }, 376 },
298 377
299 /** 378 /**
379 * Called after a test is run (in testDone) to test accessibility.
380 */
381 runAccessibilityAudit: function() {
382 if (this.fixture)
383 this.fixture.runAccessibilityAudit();
384 },
385
386 /**
300 * Runs this test case with |this| set to the |fixture|. 387 * Runs this test case with |this| set to the |fixture|.
301 * 388 *
302 * Note: Tests created with TEST_F may depend upon |this| being set to an 389 * Note: Tests created with TEST_F may depend upon |this| being set to an
303 * instance of this.fixture. The current implementation of TEST creates a 390 * instance of this.fixture. The current implementation of TEST creates a
304 * dummy constructor, but tests created with TEST should not rely on |this| 391 * dummy constructor, but tests created with TEST should not rely on |this|
305 * being set. 392 * being set.
306 * @type {Function} 393 * @type {Function}
307 */ 394 */
308 run: function() { 395 run: function() {
309 try { 396 try {
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 687
601 /** 688 /**
602 * Notifies the running browser test of the test results. Clears |errors|. 689 * Notifies the running browser test of the test results. Clears |errors|.
603 * @param {Array.<boolean, string>=} result When passed, this is used for the 690 * @param {Array.<boolean, string>=} result When passed, this is used for the
604 * testResult message. 691 * testResult message.
605 */ 692 */
606 function testDone(result) { 693 function testDone(result) {
607 if (!testIsDone) { 694 if (!testIsDone) {
608 testIsDone = true; 695 testIsDone = true;
609 if (currentTestCase) { 696 if (currentTestCase) {
610 try { 697 var ok = true;
611 currentTestCase.tearDown(); 698 ok = createExpect(currentTestCase.runAccessibilityAudit.bind(
612 } catch (e) { 699 currentTestCase)).call(null) && ok;
613 // Caught an exception in tearDown; Register the error and recreate 700 ok = createExpect(currentTestCase.tearDown.bind(
614 // the result if it is passed in. 701 currentTestCase)).call(null) && ok;
615 errors.push(e); 702
616 if (result) 703 if (!ok && result)
617 result = [false, errorsToMessage([e], result[1])]; 704 result = [false, errorsToMessage(errors, result[1])];
618 } 705
619 currentTestCase = null; 706 currentTestCase = null;
620 } 707 }
621 chrome.send('testResult', result ? result : testResult()); 708 if (!result)
709 result = testResult();
710 chrome.send('testResult', result);
622 errors.splice(0, errors.length); 711 errors.splice(0, errors.length);
623 } else { 712 } else {
624 console.warn('testIsDone already'); 713 console.warn('testIsDone already');
625 } 714 }
626 } 715 }
627 716
628 /** 717 /**
629 * Converts each Error in |errors| to a suitable message, adding them to 718 * Converts each Error in |errors| to a suitable message, adding them to
630 * |message|, and returns the message string. 719 * |message|, and returns the message string.
631 * @param {Array.<Error>} errors Array of errors to add to |message|. 720 * @param {Array.<Error>} errors Array of errors to add to |message|.
(...skipping 13 matching lines...) Expand all
645 return message; 734 return message;
646 } 735 }
647 736
648 /** 737 /**
649 * Returns [success, message] & clears |errors|. 738 * Returns [success, message] & clears |errors|.
650 * @param {boolean} errorsOk When true, errors are ok. 739 * @param {boolean} errorsOk When true, errors are ok.
651 * @return {Array.<boolean, string>} 740 * @return {Array.<boolean, string>}
652 */ 741 */
653 function testResult(errorsOk) { 742 function testResult(errorsOk) {
654 var result = [true, '']; 743 var result = [true, ''];
655 if (errors.length) { 744 if (errors.length)
656 result = [!!errorsOk, errorsToMessage(errors)]; 745 result = [!!errorsOk, errorsToMessage(errors)];
657 } 746
658 return result; 747 return result;
659 } 748 }
660 749
661 // Asserts. 750 // Asserts.
662 // Use the following assertions to verify a condition within a test. 751 // Use the following assertions to verify a condition within a test.
663 // If assertion fails, throw an Error with information pertinent to the test. 752 // If assertion fails, throw an Error with information pertinent to the test.
664 753
665 /** 754 /**
666 * When |test| !== true, aborts the current test. 755 * When |test| !== true, aborts the current test.
667 * @param {boolean} test The predicate to check against |expected|. 756 * @param {boolean} test The predicate to check against |expected|.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 * Always aborts the current test. 875 * Always aborts the current test.
787 * @param {string=} message The message to include in the Error thrown. 876 * @param {string=} message The message to include in the Error thrown.
788 * @throws {Error} always. 877 * @throws {Error} always.
789 */ 878 */
790 function assertNotReached(message) { 879 function assertNotReached(message) {
791 helper.registerCall(); 880 helper.registerCall();
792 throw new Error(helper.getCallMessage(message)); 881 throw new Error(helper.getCallMessage(message));
793 } 882 }
794 883
795 /** 884 /**
885 * Run an accessibility audit on the current page state.
886 * @type {Function}
887 * @return {boolean} Whether there were any errors or warnings
888 * @private
889 */
890 function runAccessibilityAudit(a11yErrors, a11yWarnings) {
891 var auditResults = axs.Audit.run();
892 for (var i = 0; i < auditResults.length; i++) {
893 var auditResult = auditResults[i];
894 if (auditResult.result == axs.constants.AuditResult.FAIL) {
895 var auditRule = auditResult.rule;
896 // TODO(aboxhall): more useful error messages (sadly non-trivial)
897 if (auditRule.severity == axs.constants.Severity.Severe)
898 a11yErrors.push(accessibilityErrorMessage(auditRule, auditResult));
899 else
900 a11yWarnings.push(accessibilityErrorMessage(auditRule, auditResult));
901 }
902 }
903
904 // TODO(aboxhall): have strict (no errors or warnings) vs non-strict
905 // (warnings ok)
906 // TODO(aboxhall): some kind of info logging for warnings only??
907 return (a11yErrors.length == 0 && a11yWarnings.length == 0);
908 }
909
910 /**
911 * Concatenates the accessibility error messages in |a11yErrors| and
912 * |a11yWarnings| in to an accessibility report, appends it to the given
913 * |message| and returns the resulting message string.
914 * @param {Array.<string>} a11yErrors The list of accessibility error messages
915 * @param {Array.<string>} a11yWarnings The list of accessibility warning
916 * messages.
917 * @return {string} |message| + accessibility report.
918 */
919 function accessibilityAuditReport(a11yErrors, a11yWarnings, message) {
920 message = message ? message + '\n' : '';
921 message += '\n*** Begin accessibility audit results ***';
922 message += '\nAn accessibility audit found ';
923
924 if (a11yErrors.length > 0) {
925 message += a11yErrors.length +
926 (a11yErrors.length == 1 ? ' error ' : ' errors ');
927 if (a11yWarnings.length > 0)
928 message += 'and ';
929 }
930 if (a11yWarnings.length > 0) {
931 message += a11yWarnings.length +
932 (a11yWarnings.length == 1 ? ' warning ' : ' warnings ');
933 }
934 message += 'on this page.\n';
935 message += 'For more information, please see ' +
936 'http://chromium.org/developers/accessibility/webui-accessibility-audit';
937
938 for (var i = 0; i < a11yErrors.length; i++)
939 message += '\n\n' + a11yErrors[i];
940
941 for (var i = 0; i < a11yWarnings.length; i++)
942 message += '\n\n' + a11yWarnings[i];
943 message += '\n*** End accessibility audit results ***';
944 return message;
945 }
946
947 /**
948 * Creates an error message for a given accessibility audit rule and
949 * corresponding result.
950 * @param {axs.AuditRule} rule The audit rule which the result is for
951 * @param {Object.<string, (string|Array.<Element>)>} result The result
952 * object returned from the audit.
953 * @return {string} An error message describing the failure and listing
954 * up to five elements which failed the audit rule.
955 */
956 function accessibilityErrorMessage(rule, result) {
957 if (rule.severity == axs.constants.Severity.Severe)
958 var message = 'Error: '
959 else
960 var message = 'Warning: '
961 message += rule.name + ' failed on the following ' +
962 (result.elements.length == 1 ? 'element' : 'elements');
963
964 if (result.elements.length == 1)
965 message += ':'
966 else
James Hawkins 2013/01/03 21:23:39 nit: Braces required for multi-line blocks.
aboxhall 2013/01/04 00:26:50 Done.
aboxhall 2013/01/04 00:26:50 Done.
967 message += ' (1 - ' + Math.min(5, result.elements.length) +
968 ' of ' + result.elements.length + '):';
969
970 var maxElements = Math.min(result.elements.length, 5);
971 for (var i = 0; i < maxElements; i++)
972 message += '\n' + axs.utils.getQuerySelectorText(result.elements[i]);
973 return message;
974 }
975
976 /**
977 * Asserts that the current page state passes the accessibility audit.
978 */
979 function assertAccessibilityOk() {
980 helper.registerCall();
981 var a11yErrors = [];
982 var a11yWarnings = [];
983 if (!runAccessibilityAudit(a11yErrors, a11yWarnings))
984 throw new Error(accessibilityAuditReport(a11yErrors, a11yWarnings));
985 }
986
987 /**
796 * Creates a function based upon a function that thows an exception on 988 * Creates a function based upon a function that thows an exception on
797 * failure. The new function stuffs any errors into the |errors| array for 989 * failure. The new function stuffs any errors into the |errors| array for
798 * checking by runTest. This allows tests to continue running other checks, 990 * checking by runTest. This allows tests to continue running other checks,
799 * while failing the overall test if any errors occurrred. 991 * while failing the overall test if any errors occurrred.
800 * @param {Function} assertFunc The function which may throw an Error. 992 * @param {Function} assertFunc The function which may throw an Error.
801 * @return {function(...*):bool} A function that applies its arguments to 993 * @return {function(...*):bool} A function that applies its arguments to
802 * |assertFunc| and returns true if |assertFunc| passes. 994 * |assertFunc| and returns true if |assertFunc| passes.
803 * @see errors 995 * @see errors
804 * @see runTestFunction 996 * @see runTestFunction
805 */ 997 */
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
1370 exports.testDone = testDone; 1562 exports.testDone = testDone;
1371 exports.assertTrue = assertTrue; 1563 exports.assertTrue = assertTrue;
1372 exports.assertFalse = assertFalse; 1564 exports.assertFalse = assertFalse;
1373 exports.assertGE = assertGE; 1565 exports.assertGE = assertGE;
1374 exports.assertGT = assertGT; 1566 exports.assertGT = assertGT;
1375 exports.assertEquals = assertEquals; 1567 exports.assertEquals = assertEquals;
1376 exports.assertLE = assertLE; 1568 exports.assertLE = assertLE;
1377 exports.assertLT = assertLT; 1569 exports.assertLT = assertLT;
1378 exports.assertNotEquals = assertNotEquals; 1570 exports.assertNotEquals = assertNotEquals;
1379 exports.assertNotReached = assertNotReached; 1571 exports.assertNotReached = assertNotReached;
1572 exports.assertAccessibilityOk = assertAccessibilityOk;
1380 exports.callFunction = callFunction; 1573 exports.callFunction = callFunction;
1381 exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs; 1574 exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs;
1382 exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs; 1575 exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs;
1383 exports.expectTrue = createExpect(assertTrue); 1576 exports.expectTrue = createExpect(assertTrue);
1384 exports.expectFalse = createExpect(assertFalse); 1577 exports.expectFalse = createExpect(assertFalse);
1385 exports.expectGE = createExpect(assertGE); 1578 exports.expectGE = createExpect(assertGE);
1386 exports.expectGT = createExpect(assertGT); 1579 exports.expectGT = createExpect(assertGT);
1387 exports.expectEquals = createExpect(assertEquals); 1580 exports.expectEquals = createExpect(assertEquals);
1388 exports.expectLE = createExpect(assertLE); 1581 exports.expectLE = createExpect(assertLE);
1389 exports.expectLT = createExpect(assertLT); 1582 exports.expectLT = createExpect(assertLT);
1390 exports.expectNotEquals = createExpect(assertNotEquals); 1583 exports.expectNotEquals = createExpect(assertNotEquals);
1391 exports.expectNotReached = createExpect(assertNotReached); 1584 exports.expectNotReached = createExpect(assertNotReached);
1585 exports.expectAccessibilityOk = createExpect(assertAccessibilityOk);
1392 exports.preloadJavascriptLibraries = preloadJavascriptLibraries; 1586 exports.preloadJavascriptLibraries = preloadJavascriptLibraries;
1393 exports.registerMessageCallback = registerMessageCallback; 1587 exports.registerMessageCallback = registerMessageCallback;
1394 exports.registerMockGlobals = registerMockGlobals; 1588 exports.registerMockGlobals = registerMockGlobals;
1395 exports.registerMockMessageCallbacks = registerMockMessageCallbacks; 1589 exports.registerMockMessageCallbacks = registerMockMessageCallbacks;
1396 exports.resetTestState = resetTestState; 1590 exports.resetTestState = resetTestState;
1591 exports.runAccessibilityAudit = runAccessibilityAudit;
1397 exports.runAllActions = runAllActions; 1592 exports.runAllActions = runAllActions;
1398 exports.runAllActionsAsync = runAllActionsAsync; 1593 exports.runAllActionsAsync = runAllActionsAsync;
1399 exports.runTest = runTest; 1594 exports.runTest = runTest;
1400 exports.runTestFunction = runTestFunction; 1595 exports.runTestFunction = runTestFunction;
1401 exports.SaveMockArguments = SaveMockArguments; 1596 exports.SaveMockArguments = SaveMockArguments;
1402 exports.DUMMY_URL = DUMMY_URL; 1597 exports.DUMMY_URL = DUMMY_URL;
1403 exports.TEST = TEST; 1598 exports.TEST = TEST;
1404 exports.TEST_F = TEST_F; 1599 exports.TEST_F = TEST_F;
1600 exports.RUNTIME_TEST_F = TEST_F;
1405 exports.GEN = GEN; 1601 exports.GEN = GEN;
1406 exports.GEN_INCLUDE = GEN_INCLUDE; 1602 exports.GEN_INCLUDE = GEN_INCLUDE;
1407 exports.WhenTestDone = WhenTestDone; 1603 exports.WhenTestDone = WhenTestDone;
1408 1604
1409 // Import the Mock4JS helpers. 1605 // Import the Mock4JS helpers.
1410 Mock4JS.addMockSupport(exports); 1606 Mock4JS.addMockSupport(exports);
1411 })(this); 1607 })(this);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698