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

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: Working test for a11y audit Created 8 years 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 * FIXME(aboxhall)
126 */
127 runA11yChecks : true,
128
129 /**
130 * FIXME(aboxhall)
131 * Off by default to begin with; as we add the ability to suppress false
132 * positives, we will transition this to true.
133 */
134 a11yIssuesAreErrors: false,
135
136 /**
125 * Create a new class to handle |messageNames|, assign it to 137 * Create a new class to handle |messageNames|, assign it to
126 * |this.mockHandler|, register its messages and return it. 138 * |this.mockHandler|, register its messages and return it.
127 * @return {Mock} Mock handler class assigned to |this.mockHandler|. 139 * @return {Mock} Mock handler class assigned to |this.mockHandler|.
128 */ 140 */
129 makeAndRegisterMockHandler: function(messageNames) { 141 makeAndRegisterMockHandler: function(messageNames) {
130 var MockClass = makeMockClass(messageNames); 142 var MockClass = makeMockClass(messageNames);
131 this.mockHandler = mock(MockClass); 143 this.mockHandler = mock(MockClass);
132 registerMockMessageCallbacks(this.mockHandler, MockClass); 144 registerMockMessageCallbacks(this.mockHandler, MockClass);
133 return this.mockHandler; 145 return this.mockHandler;
134 }, 146 },
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 * This class is not exported and is available to hold the state of the 239 * This class is not exported and is available to hold the state of the
228 * |currentTestCase| throughout preload and test run. 240 * |currentTestCase| throughout preload and test run.
229 * @param {string} name The name of the test case. 241 * @param {string} name The name of the test case.
230 * @param {Test} fixture The fixture object for this test case. 242 * @param {Test} fixture The fixture object for this test case.
231 * @param {Function} body The code to run for the test. 243 * @param {Function} body The code to run for the test.
232 * @constructor 244 * @constructor
233 */ 245 */
234 function TestCase(name, fixture, body) { 246 function TestCase(name, fixture, body) {
235 this.name = name; 247 this.name = name;
236 this.fixture = fixture; 248 this.fixture = fixture;
249 this.runA11yChecks = fixture.runA11yChecks;
250 this.a11yIssuesAreErrors = fixture.a11yIssuesAreErrors;
237 this.body = body; 251 this.body = body;
238 } 252 }
239 253
240 TestCase.prototype = { 254 TestCase.prototype = {
241 /** 255 /**
242 * The name of this test. 256 * The name of this test.
243 * @type {string} 257 * @type {string}
244 */ 258 */
245 name: null, 259 name: null,
246 260
247 /** 261 /**
248 * The test fixture to set |this| to when running the test |body|. 262 * The test fixture to set |this| to when running the test |body|.
249 * @type {testing.Test} 263 * @type {testing.Test}
250 */ 264 */
251 fixture: null, 265 fixture: null,
252 266
253 /** 267 /**
254 * The test body to execute in runTest(). 268 * The test body to execute in runTest().
255 * @type {Function} 269 * @type {Function}
256 */ 270 */
257 body: null, 271 body: null,
258 272
259 /** 273 /**
260 * True when the test fixture will run the test later. 274 * True when the test fixture will run the test later.
261 * @type {boolean} 275 * @type {boolean}
262 * @private 276 * @private
263 */ 277 */
264 deferred_: false, 278 deferred_: false,
265 279
280 runA11yChecks: true,
281
282 /**
283 * FIXME(aboxhall)
284 */
285 a11yIssuesAreErrors: true,
286
266 /** 287 /**
267 * Called at preload time, proxies to the fixture. 288 * Called at preload time, proxies to the fixture.
268 * @type {Function} 289 * @type {Function}
269 */ 290 */
270 preLoad: function(name) { 291 preLoad: function(name) {
271 if (this.fixture) 292 if (this.fixture)
272 this.fixture.preLoad(); 293 this.fixture.preLoad();
273 }, 294 },
274 295
275 /** 296 /**
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 var testIsDone = false; 599 var testIsDone = false;
579 600
580 /** 601 /**
581 * Holds the errors, if any, caught by expects so that the test case can 602 * Holds the errors, if any, caught by expects so that the test case can
582 * fail. Cleared when results are reported from runTest() or testDone(). 603 * fail. Cleared when results are reported from runTest() or testDone().
583 * @type {Array.<Error>} 604 * @type {Array.<Error>}
584 */ 605 */
585 var errors = []; 606 var errors = [];
586 607
587 /** 608 /**
609 * Hold the accessibility warnings and errors, respectively.
610 * Like errors, cleared when results are reported.
611 */
612 var a11y_warnings = [];
dmazzoni 2012/12/14 18:45:41 Use camelCase but make it a private variable with
aboxhall 2012/12/14 23:26:44 Done.
613 var a11y_errors = [];
614
615 function getA11yWarnings() {
dmazzoni 2012/12/14 18:45:41 Should you use js getters? http://stackoverflow.c
aboxhall 2012/12/14 23:26:44 It won't work in this case as it's not a property
616 return a11y_warnings;
617 };
618
619 function getA11yErrors() {
620 return a11y_errors;
621 };
622
623 /**
588 * URL to dummy WebUI page for testing framework. 624 * URL to dummy WebUI page for testing framework.
589 * @type {string} 625 * @type {string}
590 */ 626 */
591 var DUMMY_URL = 'chrome://DummyURL'; 627 var DUMMY_URL = 'chrome://DummyURL';
592 628
593 /** 629 /**
594 * Resets test state by clearing |errors| and |testIsDone| flags. 630 * Resets test state by clearing |errors| and |testIsDone| flags.
595 */ 631 */
596 function resetTestState() { 632 function resetTestState() {
597 errors.splice(0, errors.length); 633 errors.splice(0, errors.length);
598 testIsDone = false; 634 testIsDone = false;
599 } 635 }
600 636
601 /** 637 /**
602 * Notifies the running browser test of the test results. Clears |errors|. 638 * Notifies the running browser test of the test results. Clears |errors|.
603 * @param {Array.<boolean, string>=} result When passed, this is used for the 639 * @param {Array.<boolean, string>=} result When passed, this is used for the
604 * testResult message. 640 * testResult message.
605 */ 641 */
606 function testDone(result) { 642 function testDone(result) {
607 if (!testIsDone) { 643 if (!testIsDone) {
608 testIsDone = true; 644 testIsDone = true;
609 if (currentTestCase) { 645 if (currentTestCase) {
646 if (currentTestCase.runA11yChecks) {
647 var a11yOk = runAccessibilityAudit(a11y_errors, a11y_warnings);
648 if (!a11yOk) {
649 if (currentTestCase.a11yIssuesAreErrors && result) {
650 result = [false, a11yIssuesToMessage(a11y_errors,
651 a11y_warnings,
652 result[1])];
653 } else
654 console.warn(a11yIssuesToMessage(a11y_errors, a11y_warnings));
655 }
656 }
657
610 try { 658 try {
611 currentTestCase.tearDown(); 659 currentTestCase.tearDown();
612 } catch (e) { 660 } catch (e) {
613 // Caught an exception in tearDown; Register the error and recreate 661 // Caught an exception in tearDown; Register the error and recreate
614 // the result if it is passed in. 662 // the result if it is passed in.
615 errors.push(e); 663 errors.push(e);
616 if (result) 664 if (result)
617 result = [false, errorsToMessage([e], result[1])]; 665 result = [false, errorsToMessage([e], result[1])];
618 } 666 }
667 if (!result)
668 result = testResult();
619 currentTestCase = null; 669 currentTestCase = null;
620 } 670 }
621 chrome.send('testResult', result ? result : testResult()); 671 if (!result)
672 result = testResult();
673 chrome.send('testResult', result);
622 errors.splice(0, errors.length); 674 errors.splice(0, errors.length);
675 a11y_errors.splice(0, a11y_errors.length);
623 } else { 676 } else {
624 console.warn('testIsDone already'); 677 console.warn('testIsDone already');
625 } 678 }
626 } 679 }
627 680
628 /** 681 /**
629 * Converts each Error in |errors| to a suitable message, adding them to 682 * Converts each Error in |errors| to a suitable message, adding them to
630 * |message|, and returns the message string. 683 * |message|, and returns the message string.
631 * @param {Array.<Error>} errors Array of errors to add to |message|. 684 * @param {Array.<Error>} errors Array of errors to add to |message|.
632 * @param {string?} message When supplied, error messages are appended to it. 685 * @param {string?} message When supplied, error messages are appended to it.
(...skipping 12 matching lines...) Expand all
645 return message; 698 return message;
646 } 699 }
647 700
648 /** 701 /**
649 * Returns [success, message] & clears |errors|. 702 * Returns [success, message] & clears |errors|.
650 * @param {boolean} errorsOk When true, errors are ok. 703 * @param {boolean} errorsOk When true, errors are ok.
651 * @return {Array.<boolean, string>} 704 * @return {Array.<boolean, string>}
652 */ 705 */
653 function testResult(errorsOk) { 706 function testResult(errorsOk) {
654 var result = [true, '']; 707 var result = [true, ''];
655 if (errors.length) { 708 if (errors.length)
656 result = [!!errorsOk, errorsToMessage(errors)]; 709 result = [!!errorsOk, errorsToMessage(errors)];
710
711 if (currentTestCase &&
712 currentTestCase.a11yIssuesAreErrors &&
713 (a11y_warnings.length || a11y_errors.length)) {
714 result = [!!errorsOk, a11yIssuesToMessage(a11y_errors,
715 a11y_warnings,
716 result[1])];
657 } 717 }
658 return result; 718 return result;
659 } 719 }
660 720
661 // Asserts. 721 // Asserts.
662 // Use the following assertions to verify a condition within a test. 722 // Use the following assertions to verify a condition within a test.
663 // If assertion fails, throw an Error with information pertinent to the test. 723 // If assertion fails, throw an Error with information pertinent to the test.
664 724
665 /** 725 /**
666 * When |test| !== true, aborts the current test. 726 * When |test| !== true, aborts the current test.
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 * Always aborts the current test. 846 * Always aborts the current test.
787 * @param {string=} message The message to include in the Error thrown. 847 * @param {string=} message The message to include in the Error thrown.
788 * @throws {Error} always. 848 * @throws {Error} always.
789 */ 849 */
790 function assertNotReached(message) { 850 function assertNotReached(message) {
791 helper.registerCall(); 851 helper.registerCall();
792 throw new Error(helper.getCallMessage(message)); 852 throw new Error(helper.getCallMessage(message));
793 } 853 }
794 854
795 /** 855 /**
856 * Run an accessibility audit on the current page state.
857 * FIXME(aboxhall) documentation
858 * @type {Function}
859 * @return {boolean} Whether there were any errors or warnings
860 * @private
861 */
862 function runAccessibilityAudit(a11yErrors, a11yWarnings) {
863 var auditResults = axs.Audit.run();
864 for (var i = 0; i < auditResults.length; i++) {
865 var result = auditResults[i];
866 if (result.result == axs.constants.AuditResult.FAIL) {
dmazzoni 2012/12/14 18:45:41 result.result is confusing - i wonder if it should
aboxhall 2012/12/14 23:26:44 Or I could change result to auditResult? Changing
867 var auditRule = result.rule;
868 // TODO(aboxhall): more useful error messages (sadly non-trivial)
869 if (auditRule.severity == axs.constants.Severity.Severe)
870 a11yErrors.push(accessibilityErrorMessage(auditRule, result));
871 else
872 a11yWarnings.push(accessibilityErrorMessage(auditRule, result));
873 }
874 }
875
876 // TODO(aboxhall): have strict (no errors or warnings) vs non-strict
877 // (warnings ok)
878 // TODO(aboxhall): some kind of info logging for warnings only??
879 return (a11yErrors.length == 0 && a11yWarnings.length == 0);
880 }
881
882 function disableA11yChecks() {
883 if (!currentTestCase)
884 return;
885 currentTestCase.runA11yChecks = false;
886 }
887
888 function enableA11yChecks() {
889 if (!currentTestCase)
890 return;
891 currentTestCase.runA11yChecks = true;
892 }
893
894 function a11yIssuesAreErrors(flag) {
895 if (!currentTestCase)
896 return;
897 currentTestCase.a11yIssuesAreErrors = flag;
898 }
899
900 /**
901 * FIXME(aboxhall) documentation
902 */
903 function a11yIssuesToMessage(a11y_errors, a11y_warnings, message) {
dmazzoni 2012/12/14 18:45:41 It might be cleaner here to just have this functio
aboxhall 2012/12/14 23:26:44 I collapsed it into one line; hopefully that's a b
904 if (message)
905 message += '\n\n';
906 else
907 message = '\n';
908
909 message += 'An accessibility audit found ';
910
911 if (a11y_errors.length > 0) {
912 message += a11y_errors.length +
913 (a11y_errors.length == 1 ? ' error ' : ' errors ');
914 if (a11y_warnings.length > 0)
915 message += 'and ';
916 }
917 if (a11y_warnings.length > 0) {
918 message += a11y_warnings.length +
919 (a11y_warnings.length == 1 ? ' warning ' : ' warnings ');
920 }
921 message += 'on this page.\n';
922 message += 'For more information, please see ' +
923 'https://sites.google.com/a/chromium.org/dev/webui-accessibility-audit';
dmazzoni 2012/12/14 18:45:41 This url is shorter and should be the same: http:
aboxhall 2012/12/14 23:26:44 Done.
924
925 for (var i = 0; i < a11y_errors.length; i++)
926 message += '\n\n' + a11y_errors[i];
927
928 for (var i = 0; i < a11y_warnings.length; i++)
929 message += '\n\n' + a11y_warnings[i];
930 return message;
931 }
932
933 /**
934 * FIXME(aboxhall): documentation
935 */
936 function accessibilityErrorMessage(rule, result) {
937 if (rule.severity == axs.constants.Severity.Severe)
938 var message = 'Error: '
939 else
940 var message = 'Warning: '
941 message += rule.name + ' failed on the following ' +
942 (result.elements.length == 1 ? 'element' : 'elements');
943
944 if (result.elements.length == 1)
945 message += ':'
946 else
947 message += ' (1 - ' + Math.min(5, result.elements.length) +
948 ' of ' + result.elements.length + '):';
949
950 for (var i = 0; i < Math.min(result.elements.length, 5); i++)
dmazzoni 2012/12/14 18:45:41 Do the Math.min just once
aboxhall 2012/12/14 23:26:44 Done.
951 message += '\n' + axs.utils.getQuerySelectorText(result.elements[i]);
952 return message;
953 }
954
955 /**
956 * FIXME(aboxhall) documentation
957 */
958 function assertAccessibilityOk() {
959 helper.registerCall();
960 var a11y_errors = [];
dmazzoni 2012/12/14 18:45:41 var a11yErrors (no underscores in js variables nor
aboxhall 2012/12/14 23:26:44 Done.
961 var a11y_warnings = [];
962 if (!runAccessibilityAudit(a11y_errors, a11y_warnings))
963 throw new Error(a11yIssuesToMessage(a11y_errors, a11y_warnings));
964 }
965
966 /**
796 * Creates a function based upon a function that thows an exception on 967 * 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 968 * failure. The new function stuffs any errors into the |errors| array for
798 * checking by runTest. This allows tests to continue running other checks, 969 * checking by runTest. This allows tests to continue running other checks,
799 * while failing the overall test if any errors occurrred. 970 * while failing the overall test if any errors occurrred.
800 * @param {Function} assertFunc The function which may throw an Error. 971 * @param {Function} assertFunc The function which may throw an Error.
801 * @return {function(...*):bool} A function that applies its arguments to 972 * @return {function(...*):bool} A function that applies its arguments to
802 * |assertFunc| and returns true if |assertFunc| passes. 973 * |assertFunc| and returns true if |assertFunc| passes.
803 * @see errors 974 * @see errors
804 * @see runTestFunction 975 * @see runTestFunction
805 */ 976 */
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
1361 * @return {RunAllAction} Action for use in will. 1532 * @return {RunAllAction} Action for use in will.
1362 */ 1533 */
1363 function runAllActionsAsync(whenTestDone) { 1534 function runAllActionsAsync(whenTestDone) {
1364 return new RunAllAction(true, whenTestDone, 1535 return new RunAllAction(true, whenTestDone,
1365 Array.prototype.slice.call(arguments, 1)); 1536 Array.prototype.slice.call(arguments, 1));
1366 } 1537 }
1367 1538
1368 // Exports. 1539 // Exports.
1369 testing.Test = Test; 1540 testing.Test = Test;
1370 exports.testDone = testDone; 1541 exports.testDone = testDone;
1542 exports.a11yIssuesAreErrors = a11yIssuesAreErrors;
1371 exports.assertTrue = assertTrue; 1543 exports.assertTrue = assertTrue;
1372 exports.assertFalse = assertFalse; 1544 exports.assertFalse = assertFalse;
1373 exports.assertGE = assertGE; 1545 exports.assertGE = assertGE;
1374 exports.assertGT = assertGT; 1546 exports.assertGT = assertGT;
1375 exports.assertEquals = assertEquals; 1547 exports.assertEquals = assertEquals;
1376 exports.assertLE = assertLE; 1548 exports.assertLE = assertLE;
1377 exports.assertLT = assertLT; 1549 exports.assertLT = assertLT;
1378 exports.assertNotEquals = assertNotEquals; 1550 exports.assertNotEquals = assertNotEquals;
1379 exports.assertNotReached = assertNotReached; 1551 exports.assertNotReached = assertNotReached;
1552 exports.assertAccessibilityOk = assertAccessibilityOk;
1380 exports.callFunction = callFunction; 1553 exports.callFunction = callFunction;
1381 exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs; 1554 exports.callFunctionWithSavedArgs = callFunctionWithSavedArgs;
1382 exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs; 1555 exports.callGlobalWithSavedArgs = callGlobalWithSavedArgs;
1556 exports.disableA11yChecks = disableA11yChecks;
1557 exports.enableA11yChecks = enableA11yChecks;
1383 exports.expectTrue = createExpect(assertTrue); 1558 exports.expectTrue = createExpect(assertTrue);
1384 exports.expectFalse = createExpect(assertFalse); 1559 exports.expectFalse = createExpect(assertFalse);
1385 exports.expectGE = createExpect(assertGE); 1560 exports.expectGE = createExpect(assertGE);
1386 exports.expectGT = createExpect(assertGT); 1561 exports.expectGT = createExpect(assertGT);
1387 exports.expectEquals = createExpect(assertEquals); 1562 exports.expectEquals = createExpect(assertEquals);
1388 exports.expectLE = createExpect(assertLE); 1563 exports.expectLE = createExpect(assertLE);
1389 exports.expectLT = createExpect(assertLT); 1564 exports.expectLT = createExpect(assertLT);
1390 exports.expectNotEquals = createExpect(assertNotEquals); 1565 exports.expectNotEquals = createExpect(assertNotEquals);
1391 exports.expectNotReached = createExpect(assertNotReached); 1566 exports.expectNotReached = createExpect(assertNotReached);
1567 exports.expectAccessibilityOk = createExpect(assertAccessibilityOk);
1568 exports.getA11yErrors = getA11yErrors;
1569 exports.getA11yWarnings = getA11yWarnings;
1392 exports.preloadJavascriptLibraries = preloadJavascriptLibraries; 1570 exports.preloadJavascriptLibraries = preloadJavascriptLibraries;
1393 exports.registerMessageCallback = registerMessageCallback; 1571 exports.registerMessageCallback = registerMessageCallback;
1394 exports.registerMockGlobals = registerMockGlobals; 1572 exports.registerMockGlobals = registerMockGlobals;
1395 exports.registerMockMessageCallbacks = registerMockMessageCallbacks; 1573 exports.registerMockMessageCallbacks = registerMockMessageCallbacks;
1396 exports.resetTestState = resetTestState; 1574 exports.resetTestState = resetTestState;
1575 exports.runAccessibilityAudit = runAccessibilityAudit;
1397 exports.runAllActions = runAllActions; 1576 exports.runAllActions = runAllActions;
1398 exports.runAllActionsAsync = runAllActionsAsync; 1577 exports.runAllActionsAsync = runAllActionsAsync;
1399 exports.runTest = runTest; 1578 exports.runTest = runTest;
1400 exports.runTestFunction = runTestFunction; 1579 exports.runTestFunction = runTestFunction;
1401 exports.SaveMockArguments = SaveMockArguments; 1580 exports.SaveMockArguments = SaveMockArguments;
1402 exports.DUMMY_URL = DUMMY_URL; 1581 exports.DUMMY_URL = DUMMY_URL;
1403 exports.TEST = TEST; 1582 exports.TEST = TEST;
1404 exports.TEST_F = TEST_F; 1583 exports.TEST_F = TEST_F;
1584 exports.RUNTIME_TEST_F = TEST_F;
1405 exports.GEN = GEN; 1585 exports.GEN = GEN;
1406 exports.GEN_INCLUDE = GEN_INCLUDE; 1586 exports.GEN_INCLUDE = GEN_INCLUDE;
1407 exports.WhenTestDone = WhenTestDone; 1587 exports.WhenTestDone = WhenTestDone;
1408 1588
1409 // Import the Mock4JS helpers. 1589 // Import the Mock4JS helpers.
1410 Mock4JS.addMockSupport(exports); 1590 Mock4JS.addMockSupport(exports);
1411 })(this); 1591 })(this);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698