jsunit.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utilities for working with JsUnit. Writes out the JsUnit file
  16. * that needs to be included in every unit test.
  17. *
  18. * Testing code should not have dependencies outside of goog.testing so as to
  19. * reduce the chance of masking missing dependencies.
  20. *
  21. */
  22. goog.setTestOnly('goog.testing.jsunit');
  23. goog.provide('goog.testing.jsunit');
  24. goog.require('goog.dom.TagName');
  25. goog.require('goog.testing.TestCase');
  26. goog.require('goog.testing.TestRunner');
  27. /**
  28. * @define {boolean} If this code is being parsed by JsTestC, we let it disable
  29. * the onload handler to avoid running the test in JsTestC.
  30. */
  31. goog.define('goog.testing.jsunit.AUTO_RUN_ONLOAD', true);
  32. /**
  33. * @define {number} Sets a delay in milliseconds after the window onload event
  34. * and running the tests. Used to prevent interference with Selenium and give
  35. * tests with asynchronous operations time to finish loading.
  36. */
  37. goog.define('goog.testing.jsunit.AUTO_RUN_DELAY_IN_MS', 500);
  38. (function() {
  39. // Only allow one global test runner to be created on a page.
  40. if (goog.global['G_testRunner'] instanceof goog.testing.TestRunner) {
  41. return;
  42. }
  43. // Increases the maximum number of stack frames in Google Chrome from the
  44. // default 10 to 50 to get more useful stack traces.
  45. Error.stackTraceLimit = 50;
  46. // Store a reference to the window's timeout so that it can't be overridden
  47. // by tests.
  48. /** @type {!Function} */
  49. var realTimeout = window.setTimeout;
  50. // Create a test runner.
  51. var tr = new goog.testing.TestRunner();
  52. // Export it so that it can be queried by Selenium and tests that use a
  53. // compiled test runner.
  54. goog.exportSymbol('G_testRunner', tr);
  55. goog.exportSymbol('G_testRunner.initialize', tr.initialize);
  56. goog.exportSymbol('G_testRunner.isInitialized', tr.isInitialized);
  57. goog.exportSymbol('G_testRunner.isFinished', tr.isFinished);
  58. goog.exportSymbol('G_testRunner.getUniqueId', tr.getUniqueId);
  59. goog.exportSymbol('G_testRunner.isSuccess', tr.isSuccess);
  60. goog.exportSymbol('G_testRunner.getReport', tr.getReport);
  61. goog.exportSymbol('G_testRunner.getRunTime', tr.getRunTime);
  62. goog.exportSymbol('G_testRunner.getNumFilesLoaded', tr.getNumFilesLoaded);
  63. goog.exportSymbol('G_testRunner.setStrict', tr.setStrict);
  64. goog.exportSymbol('G_testRunner.logTestFailure', tr.logTestFailure);
  65. goog.exportSymbol('G_testRunner.getTestResults', tr.getTestResults);
  66. goog.exportSymbol(
  67. 'G_testRunner.getTestResultsAsJson', tr.getTestResultsAsJson);
  68. // Export debug as a global function for JSUnit compatibility. This just
  69. // calls log on the current test case.
  70. if (!goog.global['debug']) {
  71. goog.exportSymbol('debug', goog.bind(tr.log, tr));
  72. }
  73. // If the application has defined a global error filter, set it now. This
  74. // allows users who use a base test include to set the error filter before
  75. // the testing code is loaded.
  76. if (goog.global['G_errorFilter']) {
  77. tr.setErrorFilter(goog.global['G_errorFilter']);
  78. }
  79. var maybeGetStack = function(error) {
  80. if (typeof error == 'object') {
  81. var stack = error.stack;
  82. if (stack && typeof stack == 'string') {
  83. // non-empty string
  84. return stack;
  85. }
  86. }
  87. return '';
  88. };
  89. // Add an error handler to report errors that may occur during
  90. // initialization of the page.
  91. var onerror = window.onerror;
  92. window.onerror = function(messageOrEvent, url, line) {
  93. // TODO(johnlenz): fix this function parameters once the "onerror"
  94. // definition has been corrected.
  95. // colno and errObj were added later.
  96. var colno = arguments[3];
  97. var errObj = arguments[4];
  98. // Call any existing onerror handlers, except our boot handler.
  99. if (onerror && onerror != window["__onerror_at_boot"]) {
  100. onerror.apply(window, arguments);
  101. }
  102. var stack = maybeGetStack(errObj || messageOrEvent);
  103. if (stack) {
  104. tr.logError(stack);
  105. } else if (typeof messageOrEvent == 'object') {
  106. var error = messageOrEvent;
  107. // Some older webkit browsers pass an event object as the only argument
  108. // to window.onerror. It doesn't contain an error message, url or line
  109. // number. We therefore log as much info as we can.
  110. if (error.target && error.target.tagName == goog.dom.TagName.SCRIPT) {
  111. tr.logError('UNKNOWN ERROR: Script ' + error.target.src);
  112. } else {
  113. tr.logError('UNKNOWN ERROR: No error information available.');
  114. }
  115. } else {
  116. // Add the column if it is available, older browsers won't have it.
  117. var colstr = colno != null ? '\nColumn: ' + colno : '';
  118. tr.logError(
  119. 'JS ERROR: ' + messageOrEvent + '\nURL: ' + url + '\nLine: ' + line +
  120. colstr);
  121. }
  122. };
  123. /**
  124. * The onerror handler that may have been set by the test runner.
  125. * @type {?function(string, string=, number=, number=, Object=)}
  126. */
  127. window["__onerror_at_boot"] = window["__onerror_at_boot"] || null;
  128. /**
  129. * The arguments for any call to window.onerror occuring before this point.
  130. * @type {Array<!Array<?>>} */
  131. window["__errors_since_boot"] = window["__errors_since_boot"] || null;
  132. if (window["__onerror_at_boot"]) {
  133. if (window['__errors_since_boot']) {
  134. for (var i = 0; i < window['__errors_since_boot'].length; i++) {
  135. var args = window['__errors_since_boot'][i];
  136. window.onerror.apply(window, args);
  137. }
  138. }
  139. // http://perfectionkills.com/understanding-delete/#ie_bugs
  140. window["__onerror_at_boot"] = null;
  141. }
  142. // Create an onload handler, if the test runner hasn't been initialized then
  143. // no test has been registered with the test runner by the test file. We
  144. // then create a new test case and auto discover any tests in the global
  145. // scope. If this code is being parsed by JsTestC, we let it disable the
  146. // onload handler to avoid running the test in JsTestC.
  147. if (goog.testing.jsunit.AUTO_RUN_ONLOAD) {
  148. var onload = window.onload;
  149. window.onload = function(e) {
  150. // Call any existing onload handlers.
  151. if (onload) {
  152. onload(e);
  153. }
  154. // Wait so that we don't interfere with WebDriver.
  155. realTimeout(function() {
  156. if (!tr.initialized) {
  157. var testCase = new goog.testing.TestCase(document.title);
  158. goog.testing.TestCase.initializeTestRunner(testCase);
  159. }
  160. tr.execute();
  161. }, goog.testing.jsunit.AUTO_RUN_DELAY_IN_MS);
  162. window.onload = null;
  163. };
  164. }
  165. })();