multitestrunner_test.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright 2015 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. goog.module('goog.testing.MultiTestRunnerTest');
  15. goog.setTestOnly('goog.testing.MultiTestRunnerTest');
  16. var Promise = goog.require('goog.Promise');
  17. var events = goog.require('goog.events');
  18. var testingEvents = goog.require('goog.testing.events');
  19. var MockControl = goog.require('goog.testing.MockControl');
  20. var MultiTestRunner = goog.require('goog.testing.MultiTestRunner');
  21. var PropertyReplacer = goog.require('goog.testing.PropertyReplacer');
  22. var TestCase = goog.require('goog.testing.TestCase');
  23. var jsunit = goog.require('goog.testing.jsunit');
  24. var testSuite = goog.require('goog.testing.testSuite');
  25. var ALL_TESTS = [
  26. 'testdata/fake_passing_test.html', 'testdata/fake_failing_test.html',
  27. 'testdata/fake_failing_test2.html'
  28. ];
  29. var EMPTY_TEST = 'testdata/fake_failing_test3.html';
  30. var SKIPPED_TEST = 'testdata/fake_failing_test4.html';
  31. var testRunner;
  32. var mocks = new MockControl();
  33. var stubs = new PropertyReplacer();
  34. /**
  35. * Asserts string matches exactly one item in the given array. Useful for
  36. * matching elements in an array without guaranteed ordering.
  37. * @param {string} string String to match in the array.
  38. * @param {!Array<string>} array Array of strings find match.
  39. */
  40. function assertArrayContainsString(string, array) {
  41. var matcher = function(item) { return string == item; };
  42. assertArrayContainsMatcher(matcher, array);
  43. }
  44. /**
  45. * Asserts at least one item in array causes matcher to return true. Used by
  46. * more specific assertion methods and not meant to be used directly.
  47. * @param {function(string):boolean} matcher Function called for each item in
  48. * array. Should return true when match is found.
  49. * @param {!Array<string>} array Array of strings find match.
  50. */
  51. function assertArrayContainsMatcher(matcher, array) {
  52. var matching = 0;
  53. for (var i = 0; i < array.length; i++) {
  54. if (matcher(array[i])) {
  55. matching++;
  56. }
  57. }
  58. assertEquals(
  59. 'Matched ' + matching + ' items in array, but should be 1', 1, matching);
  60. }
  61. /**
  62. * Returns promise that resolves when eventType is dispatched from target.
  63. * @param {!EventTarget|!goog.events.Listenable} target Target to listen for
  64. * event on.
  65. * @param {string} eventType Type of event.
  66. * @return {!Promise} Promise that resolves with triggered event.
  67. */
  68. function createEventPromise(target, eventType) {
  69. return new Promise(function(resolve, reject) {
  70. events.listen(target, eventType, resolve);
  71. });
  72. }
  73. /**
  74. * @typedef {{
  75. * failureReports: !Array<TestCase.IResult>,
  76. * testNames: !Array<string>
  77. * }}
  78. */
  79. var TestResults;
  80. /**
  81. * Processes the test results returned from MultiTestRunner and creates a
  82. * consolidated test result object.
  83. * @param {!Array<!Object<string,!Array<TestCase.IResult>>>}
  84. * testResults The list of individual test results from MultiTestRunner.
  85. * @return {!TestResults} Consolidated test results for all individual tests.
  86. */
  87. function processTestResults(testResults) {
  88. var failureReports = [];
  89. var testNames = [];
  90. for (var i = 0; i < testResults.length; i++) {
  91. for (var testName in testResults[i]) {
  92. testNames.push(testName);
  93. failureReports = failureReports.concat(testResults[i][testName]);
  94. }
  95. }
  96. return {failureReports: failureReports, testNames: testNames};
  97. }
  98. testSuite({
  99. setUpPage: function() {
  100. TestCase.getActiveTestCase().promiseTimeout = 20000;
  101. },
  102. setUp: function() {
  103. testRunner = new MultiTestRunner().setPoolSize(3).addTests(ALL_TESTS);
  104. },
  105. tearDown: function() {
  106. testRunner.dispose();
  107. mocks.$tearDown();
  108. stubs.reset();
  109. },
  110. testStartButtonStartsTests: function() {
  111. testRunner.createDom();
  112. testRunner.render(document.getElementById('runner'));
  113. var el = testRunner.getElement();
  114. var startButton = el.querySelectorAll('button')[0];
  115. assertEquals('Start', startButton.innerHTML);
  116. var mockStart = mocks.createMethodMock(MultiTestRunner.prototype, 'start');
  117. mockStart();
  118. mocks.$replayAll();
  119. testingEvents.fireClickSequence(startButton);
  120. mocks.$verifyAll();
  121. },
  122. testStopButtonStopsTests: function() {
  123. var promise = createEventPromise(testRunner, 'testsFinished');
  124. testRunner.createDom();
  125. testRunner.render(document.getElementById('runner'));
  126. var el = testRunner.getElement();
  127. var startButton = el.querySelectorAll('button')[0];
  128. var stopButton = el.querySelectorAll('button')[1];
  129. assertEquals('Stop', stopButton.innerHTML);
  130. stubs.replace(
  131. MultiTestRunner.TestFrame.prototype, 'runTest', function() { return; });
  132. testingEvents.fireClickSequence(startButton);
  133. testingEvents.fireClickSequence(stopButton);
  134. return promise.then(function(results) {
  135. // Tests should be halted and marked as "unfinished".
  136. assertContains(
  137. 'These tests did not finish:\n' +
  138. 'testdata/fake_passing_test.html\n' +
  139. 'testdata/fake_failing_test.html\n' +
  140. 'testdata/fake_failing_test2.html',
  141. el.innerHTML);
  142. });
  143. },
  144. testDisposeInternal: function() {
  145. testRunner.dispose();
  146. assertTrue(testRunner.tableSorter_.isDisposed());
  147. assertTrue(testRunner.eh_.isDisposed());
  148. assertNull(testRunner.startButtonEl_);
  149. assertNull(testRunner.stopButtonEl_);
  150. assertNull(testRunner.logEl_);
  151. assertNull(testRunner.reportEl_);
  152. assertNull(testRunner.progressEl_);
  153. assertNull(testRunner.logTabEl_);
  154. assertNull(testRunner.reportTabEl_);
  155. assertNull(testRunner.statsTabEl_);
  156. assertNull(testRunner.statsEl_);
  157. },
  158. testRunsTestsAndReportsResults: function() {
  159. var promise = createEventPromise(testRunner, 'testsFinished');
  160. testRunner.render(document.getElementById('runner'));
  161. testRunner.start();
  162. return promise.then(function(results) {
  163. var testResults = processTestResults(results['allTestResults']);
  164. var testNames = testResults.testNames;
  165. assertEquals(3, testNames.length);
  166. assertArrayContainsString(
  167. 'testdata/fake_failing_test2:testFail', testNames);
  168. assertArrayContainsString(
  169. 'testdata/fake_failing_test:testFail', testNames);
  170. assertArrayContainsString(
  171. 'testdata/fake_passing_test:testPass', testNames);
  172. var failureReports = testResults.failureReports;
  173. var failedTests = testRunner.getTestsThatFailed();
  174. assertEquals(2, failureReports.length);
  175. assertEquals(2, failedTests.length);
  176. assertArrayContainsString('testdata/fake_failing_test.html', failedTests);
  177. assertArrayContainsString(
  178. 'testdata/fake_failing_test2.html', failedTests);
  179. });
  180. },
  181. testMissingTestResultsIsAFailure: function() {
  182. var promise = createEventPromise(testRunner, 'testsFinished');
  183. testRunner.addTests(EMPTY_TEST);
  184. testRunner.render(document.getElementById('runner'));
  185. testRunner.start();
  186. return promise.then(function(results) {
  187. var testResults = processTestResults(results['allTestResults']);
  188. var testNames = testResults.testNames;
  189. assertEquals(4, testNames.length);
  190. assertArrayContainsString('testdata/fake_failing_test3', testNames);
  191. var failureReports = testResults.failureReports;
  192. var failedTests = testRunner.getTestsThatFailed();
  193. assertEquals(3, failureReports.length);
  194. assertEquals(3, failedTests.length);
  195. assertArrayContainsString(
  196. 'testdata/fake_failing_test3.html', failedTests);
  197. });
  198. },
  199. testShouldRunTestsFalseIsSuccess: function() {
  200. var promise = createEventPromise(testRunner, 'testsFinished');
  201. testRunner.addTests(SKIPPED_TEST);
  202. testRunner.render(document.getElementById('runner'));
  203. testRunner.start();
  204. return promise.then(function(results) {
  205. var testResults = processTestResults(results['allTestResults']);
  206. var testNames = testResults.testNames;
  207. assertEquals(4, testNames.length);
  208. assertArrayContainsString('testdata/fake_failing_test4', testNames);
  209. var failureReports = testResults.failureReports;
  210. var failedTests = testRunner.getTestsThatFailed();
  211. // Test should pass even though its test method is a failure.
  212. assertNotContains('testdata/fake_failing_test4', failedTests);
  213. });
  214. },
  215. testRunTestsWithEmptyTestList: function() {
  216. var testRunner = new MultiTestRunner().setPoolSize(3).addTests([]);
  217. var promise = createEventPromise(testRunner, 'testsFinished');
  218. testRunner.render(document.getElementById('runner'));
  219. testRunner.start();
  220. return promise.then(function(results) {
  221. var allTestResults = results['allTestResults'];
  222. assertEquals(0, allTestResults.length);
  223. var failureReports = processTestResults(allTestResults).failureReports;
  224. assertEquals(0, failureReports.length);
  225. assertEquals(0, testRunner.getTestsThatFailed().length);
  226. testRunner.dispose();
  227. });
  228. },
  229. testFilterFunctionFiltersTest: function() {
  230. var promise = createEventPromise(testRunner, 'testsFinished');
  231. testRunner.render(document.getElementById('runner'));
  232. testRunner.setFilterFunction(function(test) {
  233. return test.indexOf('fake_failing_test2') != -1;
  234. });
  235. testRunner.start();
  236. return promise.then(function(results) {
  237. var allTestResults = results['allTestResults'];
  238. assertEquals(1, allTestResults.length);
  239. var failureReports = processTestResults(allTestResults).failureReports;
  240. var failedTests = testRunner.getTestsThatFailed();
  241. assertEquals(1, failureReports.length);
  242. assertEquals(1, failedTests.length);
  243. assertArrayContainsString(
  244. 'testdata/fake_failing_test2.html', failedTests);
  245. });
  246. },
  247. testTimeoutFailsAfterTimeout: function() {
  248. var promise = createEventPromise(testRunner, 'testsFinished');
  249. testRunner.render(document.getElementById('runner'));
  250. testRunner.setTimeout(0);
  251. testRunner.start();
  252. return promise.then(function(results) {
  253. var testResults = processTestResults(results['allTestResults']);
  254. var testNames = testResults.testNames;
  255. assertEquals(3, testNames.length);
  256. // Only the filename should be the test name for timeouts.
  257. assertArrayContainsString('testdata/fake_failing_test2', testNames);
  258. assertArrayContainsString('testdata/fake_failing_test', testNames);
  259. assertArrayContainsString('testdata/fake_passing_test', testNames);
  260. var failureReports = testResults.failureReports;
  261. var failedTests = testRunner.getTestsThatFailed();
  262. assertEquals(3, failureReports.length);
  263. assertEquals(3, failedTests.length);
  264. assertContains('timed out', failureReports[0]['message']);
  265. assertContains('timed out', failureReports[1]['message']);
  266. assertContains('timed out', failureReports[2]['message']);
  267. assertArrayContainsString('testdata/fake_passing_test.html', failedTests);
  268. assertArrayContainsString('testdata/fake_failing_test.html', failedTests);
  269. assertArrayContainsString(
  270. 'testdata/fake_failing_test2.html', failedTests);
  271. });
  272. },
  273. testRunsAllTestsWhenPoolSizeSmallerThanTotalTests: function() {
  274. var promise = createEventPromise(testRunner, 'testsFinished');
  275. testRunner.render(document.getElementById('runner'));
  276. // There are 3 tests, it should load and run the 3 serially without failing.
  277. testRunner.setPoolSize(1);
  278. testRunner.start();
  279. return promise.then(function(results) {
  280. assertEquals(3, results['allTestResults'].length);
  281. var testResults = processTestResults(results['allTestResults']);
  282. var testNames = testResults.testNames;
  283. assertEquals(3, testNames.length);
  284. assertArrayContainsString(
  285. 'testdata/fake_failing_test2:testFail', testNames);
  286. assertArrayContainsString(
  287. 'testdata/fake_failing_test:testFail', testNames);
  288. assertArrayContainsString(
  289. 'testdata/fake_passing_test:testPass', testNames);
  290. var failureReports = testResults.failureReports;
  291. var failedTests = testRunner.getTestsThatFailed();
  292. assertEquals(2, failureReports.length);
  293. assertEquals(2, failedTests.length);
  294. assertArrayContainsString('testdata/fake_failing_test.html', failedTests);
  295. assertArrayContainsString(
  296. 'testdata/fake_failing_test2.html', failedTests);
  297. });
  298. },
  299. testFrameGetStats: function() {
  300. var frame = new MultiTestRunner.TestFrame('/', 2000, false);
  301. frame.testFile_ = 'foo';
  302. frame.isSuccess_ = true;
  303. frame.runTime_ = 42;
  304. frame.totalTime_ = 9000;
  305. frame.numFilesLoaded_ = 4;
  306. assertObjectEquals(
  307. {
  308. 'testFile': 'foo',
  309. 'success': true,
  310. 'runTime': 42,
  311. 'totalTime': 9000,
  312. 'numFilesLoaded': 4
  313. },
  314. frame.getStats());
  315. },
  316. testFrameDisposeInternal: function() {
  317. var frame = new MultiTestRunner.TestFrame('', 2000, false);
  318. frame.createDom();
  319. frame.render();
  320. stubs.replace(frame, 'checkForCompletion_', function() { return; });
  321. frame.runTest(ALL_TESTS[0]);
  322. assertEquals(
  323. 1, frame.getDomHelper().getElementsByTagNameAndClass('iframe').length);
  324. frame.dispose();
  325. assertTrue(frame.eh_.isDisposed());
  326. assertEquals(
  327. 0, frame.getDomHelper().getElementsByTagNameAndClass('iframe').length);
  328. assertNull(frame.iframeEl_);
  329. }
  330. });