| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| 254 console.warn(report); |
| 255 } |
| 256 }, |
| 257 |
| 258 /** |
| 181 * Create a closure function for continuing the test at a later time. May be | 259 * Create a closure function for continuing the test at a later time. May be |
| 182 * used as a listener function. | 260 * used as a listener function. |
| 183 * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate | 261 * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| 184 * time. | 262 * time. |
| 185 * @param {Function} completion The function to call to complete the test. | 263 * @param {Function} completion The function to call to complete the test. |
| 186 * @param {...*} var_args Arguments to pass when calling completionAction. | 264 * @param {...*} var_args Arguments to pass when calling completionAction. |
| 187 * @return {function(): void} Return a function, bound to this test fixture, | 265 * @return {function(): void} Return a function, bound to this test fixture, |
| 188 * which continues the test. | 266 * which continues the test. |
| 189 */ | 267 */ |
| 190 continueTest: function(whenTestDone, completion) { | 268 continueTest: function(whenTestDone, completion) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 | 368 |
| 291 /** | 369 /** |
| 292 * Called to run this test's body. | 370 * Called to run this test's body. |
| 293 */ | 371 */ |
| 294 runTest: function() { | 372 runTest: function() { |
| 295 if (this.body && this.fixture) | 373 if (this.body && this.fixture) |
| 296 this.fixture.runTest(this.body); | 374 this.fixture.runTest(this.body); |
| 297 }, | 375 }, |
| 298 | 376 |
| 299 /** | 377 /** |
| 378 * Called after a test is run (in testDone) to test accessibility. |
| 379 */ |
| 380 runAccessibilityAudit: function() { |
| 381 if (this.fixture) |
| 382 this.fixture.runAccessibilityAudit(); |
| 383 }, |
| 384 |
| 385 /** |
| 300 * Runs this test case with |this| set to the |fixture|. | 386 * Runs this test case with |this| set to the |fixture|. |
| 301 * | 387 * |
| 302 * Note: Tests created with TEST_F may depend upon |this| being set to an | 388 * 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 | 389 * instance of this.fixture. The current implementation of TEST creates a |
| 304 * dummy constructor, but tests created with TEST should not rely on |this| | 390 * dummy constructor, but tests created with TEST should not rely on |this| |
| 305 * being set. | 391 * being set. |
| 306 * @type {Function} | 392 * @type {Function} |
| 307 */ | 393 */ |
| 308 run: function() { | 394 run: function() { |
| 309 try { | 395 try { |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 | 686 |
| 601 /** | 687 /** |
| 602 * Notifies the running browser test of the test results. Clears |errors|. | 688 * Notifies the running browser test of the test results. Clears |errors|. |
| 603 * @param {Array.<boolean, string>=} result When passed, this is used for the | 689 * @param {Array.<boolean, string>=} result When passed, this is used for the |
| 604 * testResult message. | 690 * testResult message. |
| 605 */ | 691 */ |
| 606 function testDone(result) { | 692 function testDone(result) { |
| 607 if (!testIsDone) { | 693 if (!testIsDone) { |
| 608 testIsDone = true; | 694 testIsDone = true; |
| 609 if (currentTestCase) { | 695 if (currentTestCase) { |
| 610 try { | 696 var ok = true; |
| 611 currentTestCase.tearDown(); | 697 ok = createExpect(currentTestCase.runAccessibilityAudit.bind( |
| 612 } catch (e) { | 698 currentTestCase)).call(null) && ok; |
| 613 // Caught an exception in tearDown; Register the error and recreate | 699 ok = createExpect(currentTestCase.tearDown.bind( |
| 614 // the result if it is passed in. | 700 currentTestCase)).call(null) && ok; |
| 615 errors.push(e); | 701 |
| 616 if (result) | 702 if (!ok && result) |
| 617 result = [false, errorsToMessage([e], result[1])]; | 703 result = [false, errorsToMessage(errors, result[1])]; |
| 618 } | 704 |
| 619 currentTestCase = null; | 705 currentTestCase = null; |
| 620 } | 706 } |
| 621 chrome.send('testResult', result ? result : testResult()); | 707 if (!result) |
| 708 result = testResult(); |
| 709 chrome.send('testResult', result); |
| 622 errors.splice(0, errors.length); | 710 errors.splice(0, errors.length); |
| 623 } else { | 711 } else { |
| 624 console.warn('testIsDone already'); | 712 console.warn('testIsDone already'); |
| 625 } | 713 } |
| 626 } | 714 } |
| 627 | 715 |
| 628 /** | 716 /** |
| 629 * Converts each Error in |errors| to a suitable message, adding them to | 717 * Converts each Error in |errors| to a suitable message, adding them to |
| 630 * |message|, and returns the message string. | 718 * |message|, and returns the message string. |
| 631 * @param {Array.<Error>} errors Array of errors to add to |message|. | 719 * @param {Array.<Error>} errors Array of errors to add to |message|. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 645 return message; | 733 return message; |
| 646 } | 734 } |
| 647 | 735 |
| 648 /** | 736 /** |
| 649 * Returns [success, message] & clears |errors|. | 737 * Returns [success, message] & clears |errors|. |
| 650 * @param {boolean} errorsOk When true, errors are ok. | 738 * @param {boolean} errorsOk When true, errors are ok. |
| 651 * @return {Array.<boolean, string>} | 739 * @return {Array.<boolean, string>} |
| 652 */ | 740 */ |
| 653 function testResult(errorsOk) { | 741 function testResult(errorsOk) { |
| 654 var result = [true, '']; | 742 var result = [true, '']; |
| 655 if (errors.length) { | 743 if (errors.length) |
| 656 result = [!!errorsOk, errorsToMessage(errors)]; | 744 result = [!!errorsOk, errorsToMessage(errors)]; |
| 657 } | 745 |
| 658 return result; | 746 return result; |
| 659 } | 747 } |
| 660 | 748 |
| 661 // Asserts. | 749 // Asserts. |
| 662 // Use the following assertions to verify a condition within a test. | 750 // Use the following assertions to verify a condition within a test. |
| 663 // If assertion fails, throw an Error with information pertinent to the test. | 751 // If assertion fails, throw an Error with information pertinent to the test. |
| 664 | 752 |
| 665 /** | 753 /** |
| 666 * When |test| !== true, aborts the current test. | 754 * When |test| !== true, aborts the current test. |
| 667 * @param {boolean} test The predicate to check against |expected|. | 755 * @param {boolean} test The predicate to check against |expected|. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 * Always aborts the current test. | 874 * Always aborts the current test. |
| 787 * @param {string=} message The message to include in the Error thrown. | 875 * @param {string=} message The message to include in the Error thrown. |
| 788 * @throws {Error} always. | 876 * @throws {Error} always. |
| 789 */ | 877 */ |
| 790 function assertNotReached(message) { | 878 function assertNotReached(message) { |
| 791 helper.registerCall(); | 879 helper.registerCall(); |
| 792 throw new Error(helper.getCallMessage(message)); | 880 throw new Error(helper.getCallMessage(message)); |
| 793 } | 881 } |
| 794 | 882 |
| 795 /** | 883 /** |
| 884 * Run an accessibility audit on the current page state. |
| 885 * @type {Function} |
| 886 * @return {boolean} Whether there were any errors or warnings |
| 887 * @private |
| 888 */ |
| 889 function runAccessibilityAudit(a11yErrors, a11yWarnings) { |
| 890 var auditResults = axs.Audit.run(); |
| 891 for (var i = 0; i < auditResults.length; i++) { |
| 892 var auditResult = auditResults[i]; |
| 893 if (auditResult.result == axs.constants.AuditResult.FAIL) { |
| 894 var auditRule = auditResult.rule; |
| 895 // TODO(aboxhall): more useful error messages (sadly non-trivial) |
| 896 if (auditRule.severity == axs.constants.Severity.Severe) |
| 897 a11yErrors.push(accessibilityErrorMessage(auditRule, auditResult)); |
| 898 else |
| 899 a11yWarnings.push(accessibilityErrorMessage(auditRule, auditResult)); |
| 900 } |
| 901 } |
| 902 |
| 903 // TODO(aboxhall): have strict (no errors or warnings) vs non-strict |
| 904 // (warnings ok) |
| 905 // TODO(aboxhall): some kind of info logging for warnings only?? |
| 906 return (a11yErrors.length == 0 && a11yWarnings.length == 0); |
| 907 } |
| 908 |
| 909 /** |
| 910 * Concatenates the accessibility error messages in |a11yErrors| and |
| 911 * |a11yWarnings| in to an accessibility report, appends it to the given |
| 912 * |message| and returns the resulting message string. |
| 913 * @param {Array.<string>} a11yErrors The list of accessibility error messages |
| 914 * @param {Array.<string>} a11yWarnings The list of accessibility warning |
| 915 * messages. |
| 916 * @return {string} |message| + accessibility report. |
| 917 */ |
| 918 function accessibilityAuditReport(a11yErrors, a11yWarnings, message) { |
| 919 message = message ? message + '\n' : ''; |
| 920 message += '\n*** Begin accessibility audit results ***'; |
| 921 message += '\nAn accessibility audit found '; |
| 922 |
| 923 if (a11yErrors.length > 0) { |
| 924 message += a11yErrors.length + |
| 925 (a11yErrors.length == 1 ? ' error ' : ' errors '); |
| 926 if (a11yWarnings.length > 0) |
| 927 message += 'and '; |
| 928 } |
| 929 if (a11yWarnings.length > 0) { |
| 930 message += a11yWarnings.length + |
| 931 (a11yWarnings.length == 1 ? ' warning ' : ' warnings '); |
| 932 } |
| 933 message += 'on this page.\n'; |
| 934 message += 'For more information, please see ' + |
| 935 'http://chromium.org/developers/accessibility/webui-accessibility-audit'; |
| 936 |
| 937 for (var i = 0; i < a11yErrors.length; i++) |
| 938 message += '\n\n' + a11yErrors[i]; |
| 939 |
| 940 for (var i = 0; i < a11yWarnings.length; i++) |
| 941 message += '\n\n' + a11yWarnings[i]; |
| 942 message += '\n*** End accessibility audit results ***'; |
| 943 return message; |
| 944 } |
| 945 |
| 946 /** |
| 947 * Creates an error message for a given accessibility audit rule and |
| 948 * corresponding result. |
| 949 * @param {axs.AuditRule} rule The audit rule which the result is for |
| 950 * @param {Object.<string, (string|Array.<Element>)>} result The result |
| 951 * object returned from the audit. |
| 952 * @return {string} An error message describing the failure and listing |
| 953 * up to five elements which failed the audit rule. |
| 954 */ |
| 955 function accessibilityErrorMessage(rule, result) { |
| 956 if (rule.severity == axs.constants.Severity.Severe) |
| 957 var message = 'Error: ' |
| 958 else |
| 959 var message = 'Warning: ' |
| 960 message += rule.name + ' failed on the following ' + |
| 961 (result.elements.length == 1 ? 'element' : 'elements'); |
| 962 |
| 963 if (result.elements.length == 1) |
| 964 message += ':' |
| 965 else { |
| 966 message += ' (1 - ' + Math.min(5, result.elements.length) + |
| 967 ' of ' + result.elements.length + '):'; |
| 968 } |
| 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 Loading... |
| 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); |
| OLD | NEW |