diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/testing/multitestrunner.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/testing/multitestrunner.js | 1440 |
1 files changed, 0 insertions, 1440 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/testing/multitestrunner.js b/contexts/data/lib/closure-library/closure/goog/testing/multitestrunner.js deleted file mode 100644 index c6040a1..0000000 --- a/contexts/data/lib/closure-library/closure/goog/testing/multitestrunner.js +++ /dev/null @@ -1,1440 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utility for running multiple test files that utilize the same - * interface as goog.testing.TestRunner. Each test is run in series and their - * results aggregated. The main usecase for the MultiTestRunner is to allow - * the testing of all tests in a project locally. - * - */ - -goog.provide('goog.testing.MultiTestRunner'); -goog.provide('goog.testing.MultiTestRunner.TestFrame'); - -goog.require('goog.Timer'); -goog.require('goog.array'); -goog.require('goog.dom'); -goog.require('goog.dom.classes'); -goog.require('goog.events.EventHandler'); -goog.require('goog.functions'); -goog.require('goog.string'); -goog.require('goog.ui.Component'); -goog.require('goog.ui.ServerChart'); -goog.require('goog.ui.ServerChart.ChartType'); -goog.require('goog.ui.TableSorter'); - - - -/** - * A component for running multiple tests within the browser. - * @param {goog.dom.DomHelper=} opt_domHelper A DOM helper. - * @extends {goog.ui.Component} - * @constructor - */ -goog.testing.MultiTestRunner = function(opt_domHelper) { - goog.ui.Component.call(this, opt_domHelper); - - /** - * Array of tests to execute, when combined with the base path this should be - * a relative path to the test from the page containing the multi testrunner. - * @type {Array.<string>} - * @private - */ - this.allTests_ = []; - - /** - * Tests that match the filter function. - * @type {Array.<string>} - * @private - */ - this.activeTests_ = []; - - /** - * An event handler for handling events. - * @type {goog.events.EventHandler} - * @private - */ - this.eh_ = new goog.events.EventHandler(this); - - /** - * A table sorter for the stats. - * @type {goog.ui.TableSorter} - * @private - */ - this.tableSorter_ = new goog.ui.TableSorter(this.dom_); -}; -goog.inherits(goog.testing.MultiTestRunner, goog.ui.Component); - - -/** - * Default maximimum amount of time to spend at each stage of the test. - * @type {number} - */ -goog.testing.MultiTestRunner.DEFAULT_TIMEOUT_MS = 45 * 1000; - - -/** - * Messages corresponding to the numeric states. - * @type {Array.<string>} - */ -goog.testing.MultiTestRunner.STATES = [ - 'waiting for test runner', - 'initializing tests', - 'waiting for tests to finish' -]; - - -/** - * The test suite's name. - * @type {string} name - * @private - */ -goog.testing.MultiTestRunner.prototype.name_ = ''; - - -/** - * The base path used to resolve files within the allTests_ array. - * @type {string} - * @private - */ -goog.testing.MultiTestRunner.prototype.basePath_ = ''; - - -/** - * A set of tests that have finished. All extant keys map to true. - * @type {Object.<boolean>} - * @private - */ -goog.testing.MultiTestRunner.prototype.finished_ = null; - - -/** - * Whether the report should contain verbose information about the passes. - * @type {boolean} - * @private - */ -goog.testing.MultiTestRunner.prototype.verbosePasses_ = false; - - -/** - * Whether to hide passing tests completely in the report, makes verbosePasses_ - * obsolete. - * @type {boolean} - * @private - */ -goog.testing.MultiTestRunner.prototype.hidePasses_ = false; - - -/** - * Flag used to tell the test runner to stop after the current test. - * @type {boolean} - * @private - */ -goog.testing.MultiTestRunner.prototype.stopped_ = false; - - -/** - * Flag indicating whether the test runner is active. - * @type {boolean} - * @private - */ -goog.testing.MultiTestRunner.prototype.active_ = false; - - -/** - * Index of the next test to run. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.startedCount_ = 0; - - -/** - * Count of the results received so far. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.resultCount_ = 0; - - -/** - * Number of passes so far. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.passes_ = 0; - - -/** - * Timestamp for the current start time. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.startTime_ = 0; - - -/** - * Only tests whose paths patch this filter function will be - * executed. - * @type {function(string): boolean} - * @private - */ -goog.testing.MultiTestRunner.prototype.filterFn_ = goog.functions.TRUE; - - -/** - * Number of milliseconds to wait for loading and initialization steps. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.timeoutMs_ = - goog.testing.MultiTestRunner.DEFAULT_TIMEOUT_MS; - - -/** - * An array of objects containing stats about the tests. - * @type {Array.<Object>?} - * @private - */ -goog.testing.MultiTestRunner.prototype.stats_ = null; - - -/** - * Reference to the start button element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.startButtonEl_ = null; - - -/** - * Reference to the stop button element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.stopButtonEl_ = null; - - -/** - * Reference to the log element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.logEl_ = null; - - -/** - * Reference to the report element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.reportEl_ = null; - - -/** - * Reference to the stats element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.statsEl_ = null; - - -/** - * Reference to the progress bar's element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.progressEl_ = null; - - -/** - * Reference to the progress bar's inner row element. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.progressRow_ = null; - - -/** - * Reference to the log tab. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.logTabEl_ = null; - - -/** - * Reference to the report tab. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.reportTabEl_ = null; - - -/** - * Reference to the stats tab. - * @type {Element} - * @private - */ -goog.testing.MultiTestRunner.prototype.statsTabEl_ = null; - - -/** - * The number of tests to run at a time. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.poolSize_ = 1; - - -/** - * The size of the stats bucket for the number of files loaded histogram. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.numFilesStatsBucketSize_ = 20; - - -/** - * The size of the stats bucket in ms for the run time histogram. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.prototype.runTimeStatsBucketSize_ = 500; - - -/** - * Sets the name for the test suite. - * @param {string} name The suite's name. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setName = function(name) { - this.name_ = name; - return this; -}; - - -/** - * Returns the name for the test suite. - * @return {string} The name for the test suite. - */ -goog.testing.MultiTestRunner.prototype.getName = function() { - return this.name_; -}; - - -/** - * Sets the basepath that tests added using addTests are resolved with. - * @param {string} path The relative basepath. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setBasePath = function(path) { - this.basePath_ = path; - return this; -}; - - -/** - * Returns the basepath that tests added using addTests are resolved with. - * @return {string} The basepath that tests added using addTests are resolved - * with. - */ -goog.testing.MultiTestRunner.prototype.getBasePath = function() { - return this.basePath_; -}; - - -/** - * Sets whether the report should contain verbose information for tests that - * pass. - * @param {boolean} verbose Whether report should be verbose. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setVerbosePasses = function(verbose) { - this.verbosePasses_ = verbose; - return this; -}; - - -/** - * Returns whether the report should contain verbose information for tests that - * pass. - * @return {boolean} Whether the report should contain verbose information for - * tests that pass. - */ -goog.testing.MultiTestRunner.prototype.getVerbosePasses = function() { - return this.verbosePasses_; -}; - - -/** - * Sets whether the report should contain passing tests at all, makes - * setVerbosePasses obsolete. - * @param {boolean} hide Whether report should not contain passing tests. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setHidePasses = function(hide) { - this.hidePasses_ = hide; - return this; -}; - - -/** - * Returns whether the report should contain passing tests at all, makes - * setVerbosePasses obsolete. - * @return {boolean} Whether the report should contain passing tests at all, - * makes setVerbosePasses obsolete. - */ -goog.testing.MultiTestRunner.prototype.getHidePasses = function() { - return this.hidePasses_; -}; - - -/** - * Sets the bucket sizes for the histograms. - * @param {number} f Bucket size for num files loaded histogram. - * @param {number} t Bucket size for run time histogram. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setStatsBucketSizes = function(f, t) { - this.numFilesStatsBucketSize_ = f; - this.runTimeStatsBucketSize_ = t; - return this; -}; - - -/** - * Sets the number of milliseconds to wait for the page to load, initialize and - * run the tests. - * @param {number} timeout Time in milliseconds. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setTimeout = function(timeout) { - this.timeoutMs_ = timeout; - return this; -}; - - -/** - * Returns the number of milliseconds to wait for the page to load, initialize - * and run the tests. - * @return {number} The number of milliseconds to wait for the page to load, - * initialize and run the tests. - */ -goog.testing.MultiTestRunner.prototype.getTimeout = function() { - return this.timeoutMs_; -}; - - -/** - * Sets the number of tests that can be run at the same time. This only improves - * performance due to the amount of time spent loading the tests. - * @param {number} size The number of tests to run at a time. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setPoolSize = function(size) { - this.poolSize_ = size; - return this; -}; - - -/** - * Returns the number of tests that can be run at the same time. This only - * improves performance due to the amount of time spent loading the tests. - * @return {number} The number of tests that can be run at the same time. This - * only improves performance due to the amount of time spent loading the - * tests. - */ -goog.testing.MultiTestRunner.prototype.getPoolSize = function() { - return this.poolSize_; -}; - - -/** - * Sets a filter function. Only test paths that match the filter function - * will be executed. - * @param {function(string): boolean} filterFn Filters test paths. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.setFilterFunction = function(filterFn) { - this.filterFn_ = filterFn; - return this; -}; - - -/** - * Returns a filter function. Only test paths that match the filter function - * will be executed. - * @return {function(string): boolean} A filter function. Only test paths that - * match the filter function will be executed. - - */ -goog.testing.MultiTestRunner.prototype.getFilterFunction = function() { - return this.filterFn_; -}; - - -/** - * Adds an array of tests to the tests that the test runner should execute. - * @param {Array.<string>} tests Adds tests to the test runner. - * @return {goog.testing.MultiTestRunner} Instance for chaining. - */ -goog.testing.MultiTestRunner.prototype.addTests = function(tests) { - goog.array.extend(this.allTests_, tests); - return this; -}; - - -/** - * Returns the list of all tests added to the runner. - * @return {Array.<string>} The list of all tests added to the runner. - */ -goog.testing.MultiTestRunner.prototype.getAllTests = function() { - return this.allTests_; -}; - - -/** - * Returns the list of tests that will be run when start() is called. - * @return {Array.<string>} The list of tests that will be run when start() is - * called. - */ -goog.testing.MultiTestRunner.prototype.getTestsToRun = function() { - return goog.array.filter(this.allTests_, this.filterFn_); -}; - - -/** - * Returns a list of tests from runner that have been marked as failed. - * @return {Array.<string>} A list of tests from runner that have been marked as - * failed. - */ -goog.testing.MultiTestRunner.prototype.getTestsThatFailed = function() { - var stats = this.stats_; - var failedTests = []; - if (stats) { - for (var i = 0, stat; stat = stats[i]; i++) { - if (!stat.success) { - failedTests.push(stat.testFile); - } - } - } - return failedTests; -}; - - -/** - * Deletes and re-creates the progress table inside the progess element. - * @private - */ -goog.testing.MultiTestRunner.prototype.resetProgressDom_ = function() { - goog.dom.removeChildren(this.progressEl_); - var progressTable = this.dom_.createDom('table'); - var progressTBody = this.dom_.createDom('tbody'); - this.progressRow_ = this.dom_.createDom('tr'); - for (var i = 0; i < this.activeTests_.length; i++) { - var progressCell = this.dom_.createDom('td'); - this.progressRow_.appendChild(progressCell); - } - progressTBody.appendChild(this.progressRow_); - progressTable.appendChild(progressTBody); - this.progressEl_.appendChild(progressTable); -}; - - -/** @override */ -goog.testing.MultiTestRunner.prototype.createDom = function() { - goog.testing.MultiTestRunner.superClass_.createDom.call(this); - var el = this.getElement(); - el.className = goog.getCssName('goog-testrunner'); - - this.progressEl_ = this.dom_.createDom('div'); - this.progressEl_.className = goog.getCssName('goog-testrunner-progress'); - el.appendChild(this.progressEl_); - - var buttons = this.dom_.createDom('div'); - buttons.className = goog.getCssName('goog-testrunner-buttons'); - this.startButtonEl_ = this.dom_.createDom('button', null, 'Start'); - this.stopButtonEl_ = - this.dom_.createDom('button', {'disabled': true}, 'Stop'); - buttons.appendChild(this.startButtonEl_); - buttons.appendChild(this.stopButtonEl_); - el.appendChild(buttons); - - this.eh_.listen(this.startButtonEl_, 'click', - this.onStartClicked_); - this.eh_.listen(this.stopButtonEl_, 'click', - this.onStopClicked_); - - this.logEl_ = this.dom_.createElement('div'); - this.logEl_.className = goog.getCssName('goog-testrunner-log'); - el.appendChild(this.logEl_); - - this.reportEl_ = this.dom_.createElement('div'); - this.reportEl_.className = goog.getCssName('goog-testrunner-report'); - this.reportEl_.style.display = 'none'; - el.appendChild(this.reportEl_); - - this.statsEl_ = this.dom_.createElement('div'); - this.statsEl_.className = goog.getCssName('goog-testrunner-stats'); - this.statsEl_.style.display = 'none'; - el.appendChild(this.statsEl_); - - this.logTabEl_ = this.dom_.createDom('div', null, 'Log'); - this.logTabEl_.className = goog.getCssName('goog-testrunner-logtab') + ' ' + - goog.getCssName('goog-testrunner-activetab'); - el.appendChild(this.logTabEl_); - - this.reportTabEl_ = this.dom_.createDom('div', null, 'Report'); - this.reportTabEl_.className = goog.getCssName('goog-testrunner-reporttab'); - el.appendChild(this.reportTabEl_); - - this.statsTabEl_ = this.dom_.createDom('div', null, 'Stats'); - this.statsTabEl_.className = goog.getCssName('goog-testrunner-statstab'); - el.appendChild(this.statsTabEl_); - - this.eh_.listen(this.logTabEl_, 'click', this.onLogTabClicked_); - this.eh_.listen(this.reportTabEl_, 'click', this.onReportTabClicked_); - this.eh_.listen(this.statsTabEl_, 'click', this.onStatsTabClicked_); - -}; - - -/** @override */ -goog.testing.MultiTestRunner.prototype.disposeInternal = function() { - goog.testing.MultiTestRunner.superClass_.disposeInternal.call(this); - this.tableSorter_.dispose(); - this.eh_.dispose(); - this.startButtonEl_ = null; - this.stopButtonEl_ = null; - this.logEl_ = null; - this.reportEl_ = null; - this.progressEl_ = null; - this.logTabEl_ = null; - this.reportTabEl_ = null; - this.statsTabEl_ = null; - this.statsEl_ = null; -}; - - -/** - * Starts executing the tests. - */ -goog.testing.MultiTestRunner.prototype.start = function() { - this.startButtonEl_.disabled = true; - this.stopButtonEl_.disabled = false; - this.stopped_ = false; - this.active_ = true; - this.finished_ = {}; - this.activeTests_ = this.getTestsToRun(); - this.startedCount_ = 0; - this.resultCount_ = 0; - this.passes_ = 0; - this.stats_ = []; - this.startTime_ = goog.now(); - - this.resetProgressDom_(); - goog.dom.removeChildren(this.logEl_); - - this.resetReport_(); - this.clearStats_(); - this.showTab_(0); - - // Ensure the pool isn't too big. - while (this.getChildCount() > this.poolSize_) { - this.removeChildAt(0, true).dispose(); - } - - // Start a test in each runner. - for (var i = 0; i < this.poolSize_; i++) { - if (i >= this.getChildCount()) { - var testFrame = new goog.testing.MultiTestRunner.TestFrame( - this.basePath_, this.timeoutMs_, this.verbosePasses_, this.dom_); - this.addChild(testFrame, true); - } - this.runNextTest_( - /** @type {goog.testing.MultiTestRunner.TestFrame} */ - (this.getChildAt(i))); - } -}; - - -/** - * Logs a message to the log window. - * @param {string} msg A message to log. - */ -goog.testing.MultiTestRunner.prototype.log = function(msg) { - if (msg != '.') { - msg = this.getTimeStamp_() + ' : ' + msg; - } - - this.logEl_.appendChild(this.dom_.createDom('div', null, msg)); - - // Autoscroll if we're near the bottom. - var top = this.logEl_.scrollTop; - var height = this.logEl_.scrollHeight - this.logEl_.offsetHeight; - if (top == 0 || top > height - 50) { - this.logEl_.scrollTop = height; - } -}; - - -/** - * Processes a result returned from a TestFrame. If there are tests remaining - * it will trigger the next one to be run, otherwise if there are no tests and - * all results have been recieved then it will call finish. - * @param {goog.testing.MultiTestRunner.TestFrame} frame The frame that just - * finished. - */ -goog.testing.MultiTestRunner.prototype.processResult = function(frame) { - var success = frame.isSuccess(); - var report = frame.getReport(); - var test = frame.getTestFile(); - - this.stats_.push(frame.getStats()); - this.finished_[test] = true; - - var prefix = success ? '' : '*** FAILURE *** '; - this.log(prefix + - this.trimFileName_(test) + ' : ' + (success ? 'Passed' : 'Failed')); - - this.resultCount_++; - - if (success) { - this.passes_++; - } - - this.drawProgressSegment_(test, success); - this.writeCurrentSummary_(); - if (!(success && this.hidePasses_)) { - this.drawTestResult_(test, success, report); - } - - if (!this.stopped_ && this.startedCount_ < this.activeTests_.length) { - this.runNextTest_(frame); - } else if (this.resultCount_ == this.activeTests_.length) { - this.finish_(); - } -}; - - -/** - * Runs the next available test, if there are any left. - * @param {goog.testing.MultiTestRunner.TestFrame} frame Where to run the test. - * @private - */ -goog.testing.MultiTestRunner.prototype.runNextTest_ = function(frame) { - if (this.startedCount_ < this.activeTests_.length) { - var nextTest = this.activeTests_[this.startedCount_++]; - this.log(this.trimFileName_(nextTest) + ' : Loading'); - frame.runTest(nextTest); - } -}; - - -/** - * Handles the test finishing, processing the results and rendering the report. - * @private - */ -goog.testing.MultiTestRunner.prototype.finish_ = function() { - if (this.stopped_) { - this.log('Stopped'); - } else { - this.log('Finished'); - } - - this.startButtonEl_.disabled = false; - this.stopButtonEl_.disabled = true; - this.active_ = false; - - this.showTab_(1); - this.drawStats_(); - - // Remove all the test frames - while (this.getChildCount() > 0) { - this.removeChildAt(0, true).dispose(); - } - - // Compute tests that did not finish before the stop button was hit. - var unfinished = []; - for (var i = 0; i < this.activeTests_.length; i++) { - var test = this.activeTests_[i]; - if (!this.finished_[test]) { - unfinished.push(test); - } - } - - if (unfinished.length) { - this.reportEl_.appendChild(goog.dom.createDom('pre', undefined, - 'Theses tests did not finish:\n' + unfinished.join('\n'))); - } -}; - - -/** - * Resets the report, clearing out all children and drawing the initial summary. - * @private - */ -goog.testing.MultiTestRunner.prototype.resetReport_ = function() { - goog.dom.removeChildren(this.reportEl_); - var summary = this.dom_.createDom('div'); - summary.className = goog.getCssName('goog-testrunner-progress-summary'); - this.reportEl_.appendChild(summary); - this.writeCurrentSummary_(); -}; - - -/** - * Draws the stats for the test run. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawStats_ = function() { - this.drawFilesHistogram_(); - - // Only show time stats if pool size is 1, otherwise times are wrong. - if (this.poolSize_ == 1) { - this.drawRunTimePie_(); - this.drawTimeHistogram_(); - } - - this.drawWorstTestsTable_(); -}; - - -/** - * Draws the histogram showing number of files loaded. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawFilesHistogram_ = function() { - this.drawStatsHistogram_( - 'numFilesLoaded', - this.numFilesStatsBucketSize_, - goog.functions.identity, - 500, - 'Histogram showing distribution of\nnumber of files loaded per test'); -}; - - -/** - * Draws the histogram showing how long each test took to complete. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawTimeHistogram_ = function() { - this.drawStatsHistogram_( - 'totalTime', - this.runTimeStatsBucketSize_, - function(x) { return x / 1000; }, - 500, - 'Histogram showing distribution of\ntime spent running tests in s'); -}; - - -/** - * Draws a stats histogram. - * @param {string} statsField Field of the stats object to graph. - * @param {number} bucketSize The size for the histogram's buckets. - * @param {function(number, ...[*]): *} valueTransformFn Function for - * transforming the x-labels value for display. - * @param {number} width The width in pixels of the graph. - * @param {string} title The graph's title. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawStatsHistogram_ = function( - statsField, bucketSize, valueTransformFn, width, title) { - - var hist = {}, data = [], xlabels = [], ylabels = []; - var max = 0; - for (var i = 0; i < this.stats_.length; i++) { - var num = this.stats_[i][statsField]; - var bucket = Math.floor(num / bucketSize) * bucketSize; - if (bucket > max) { - max = bucket; - } - if (!hist[bucket]) { - hist[bucket] = 1; - } else { - hist[bucket]++; - } - } - var maxBucketSize = 0; - for (var i = 0; i <= max; i += bucketSize) { - xlabels.push(valueTransformFn(i)); - var count = hist[i] || 0; - if (count > maxBucketSize) { - maxBucketSize = count; - } - data.push(count); - } - var diff = Math.max(1, Math.ceil(maxBucketSize / 10)); - for (var i = 0; i <= maxBucketSize; i += diff) { - ylabels.push(i); - } - var chart = new goog.ui.ServerChart( - goog.ui.ServerChart.ChartType.VERTICAL_STACKED_BAR, width, 250); - chart.setTitle(title); - chart.addDataSet(data, 'ff9900'); - chart.setLeftLabels(ylabels); - chart.setGridY(ylabels.length - 1); - chart.setXLabels(xlabels); - chart.render(this.statsEl_); -}; - - -/** - * Draws a pie chart showing the percentage of time spent running the tests - * compared to loading them etc. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawRunTimePie_ = function() { - var totalTime = 0, runTime = 0; - for (var i = 0; i < this.stats_.length; i++) { - var stat = this.stats_[i]; - totalTime += stat.totalTime; - runTime += stat.runTime; - } - var loadTime = totalTime - runTime; - var pie = new goog.ui.ServerChart( - goog.ui.ServerChart.ChartType.PIE, 500, 250); - pie.setMinValue(0); - pie.setMaxValue(totalTime); - pie.addDataSet([runTime, loadTime], 'ff9900'); - pie.setXLabels([ - 'Test execution (' + runTime + 'ms)', - 'Loading (' + loadTime + 'ms)']); - pie.render(this.statsEl_); -}; - - -/** - * Draws a pie chart showing the percentage of time spent running the tests - * compared to loading them etc. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawWorstTestsTable_ = function() { - this.stats_.sort(function(a, b) { - return b['numFilesLoaded'] - a['numFilesLoaded']; - }); - - var tbody = goog.bind(this.dom_.createDom, this.dom_, 'tbody'); - var thead = goog.bind(this.dom_.createDom, this.dom_, 'thead'); - var tr = goog.bind(this.dom_.createDom, this.dom_, 'tr'); - var th = goog.bind(this.dom_.createDom, this.dom_, 'th'); - var td = goog.bind(this.dom_.createDom, this.dom_, 'td'); - var a = goog.bind(this.dom_.createDom, this.dom_, 'a'); - - var head = thead({'style': 'cursor: pointer'}, - tr(null, - th(null, ' '), - th(null, 'Test file'), - th('center', 'Num files loaded'), - th('center', 'Run time (ms)'), - th('center', 'Total time (ms)'))); - var body = tbody(); - var table = this.dom_.createDom('table', null, head, body); - - for (var i = 0; i < this.stats_.length; i++) { - var stat = this.stats_[i]; - body.appendChild(tr(null, - td('center', String(i + 1)), - td(null, a( - {'href': this.basePath_ + stat['testFile'], 'target': '_blank'}, - stat['testFile'])), - td('center', String(stat['numFilesLoaded'])), - td('center', String(stat['runTime'])), - td('center', String(stat['totalTime'])))); - } - - this.statsEl_.appendChild(table); - - this.tableSorter_.setDefaultSortFunction(goog.ui.TableSorter.numericSort); - this.tableSorter_.setSortFunction( - 1 /* test file name */, goog.ui.TableSorter.alphaSort); - this.tableSorter_.decorate(table); -}; - - -/** - * Clears the stats page. - * @private - */ -goog.testing.MultiTestRunner.prototype.clearStats_ = function() { - goog.dom.removeChildren(this.statsEl_); -}; - - -/** - * Updates the report's summary. - * @private - */ -goog.testing.MultiTestRunner.prototype.writeCurrentSummary_ = function() { - var total = this.activeTests_.length; - var executed = this.resultCount_; - var passes = this.passes_; - var duration = Math.round((goog.now() - this.startTime_) / 1000); - var text = executed + ' of ' + total + ' tests executed.<br>' + - passes + ' passed, ' + (executed - passes) + ' failed.<br>' + - 'Duration: ' + duration + 's.'; - this.reportEl_.firstChild.innerHTML = text; -}; - - -/** - * Adds a segment to the progress bar. - * @param {string} title Title for the segment. - * @param {*} success Whether the segment should indicate a success. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawProgressSegment_ = - function(title, success) { - var part = this.progressRow_.cells[this.resultCount_ - 1]; - part.title = title + ' : ' + (success ? 'SUCCESS' : 'FAILURE'); - part.style.backgroundColor = success ? '#090' : '#900'; -}; - - -/** - * Draws a test result in the report pane. - * @param {string} test Test name. - * @param {*} success Whether the test succeeded. - * @param {string} report The report. - * @private - */ -goog.testing.MultiTestRunner.prototype.drawTestResult_ = function( - test, success, report) { - var text = goog.string.isEmpty(report) ? - 'No report for ' + test + '\n' : report; - var el = this.dom_.createDom('div'); - text = goog.string.htmlEscape(text).replace(/\n/g, '<br>'); - if (success) { - el.className = goog.getCssName('goog-testrunner-report-success'); - } else { - text += '<a href="' + this.basePath_ + test + - '">Run individually »</a><br> '; - el.className = goog.getCssName('goog-testrunner-report-failure'); - } - el.innerHTML = text; - this.reportEl_.appendChild(el); -}; - - -/** - * Returns the current timestamp. - * @return {string} HH:MM:SS. - * @private - */ -goog.testing.MultiTestRunner.prototype.getTimeStamp_ = function() { - var d = new Date; - return goog.string.padNumber(d.getHours(), 2) + ':' + - goog.string.padNumber(d.getMinutes(), 2) + ':' + - goog.string.padNumber(d.getSeconds(), 2); -}; - - -/** - * Trims a filename to be less than 35-characters, ensuring that we do not break - * a path part. - * @param {string} name The file name. - * @return {string} The shortened name. - * @private - */ -goog.testing.MultiTestRunner.prototype.trimFileName_ = function(name) { - if (name.length < 35) { - return name; - } - var parts = name.split('/'); - var result = ''; - while (result.length < 35 && parts.length > 0) { - result = '/' + parts.pop() + result; - } - return '...' + result; -}; - - -/** - * Shows the report and hides the log if the argument is true. - * @param {number} tab Which tab to show. - * @private - */ -goog.testing.MultiTestRunner.prototype.showTab_ = function(tab) { - var activeTabCssClass = goog.getCssName('goog-testrunner-activetab'); - if (tab == 0) { - this.logEl_.style.display = ''; - goog.dom.classes.add(this.logTabEl_, activeTabCssClass); - } else { - this.logEl_.style.display = 'none'; - goog.dom.classes.remove(this.logTabEl_, activeTabCssClass); - } - - if (tab == 1) { - this.reportEl_.style.display = ''; - goog.dom.classes.add(this.reportTabEl_, activeTabCssClass); - } else { - this.reportEl_.style.display = 'none'; - goog.dom.classes.remove(this.reportTabEl_, activeTabCssClass); - } - - if (tab == 2) { - this.statsEl_.style.display = ''; - goog.dom.classes.add(this.statsTabEl_, activeTabCssClass); - } else { - this.statsEl_.style.display = 'none'; - goog.dom.classes.remove(this.statsTabEl_, activeTabCssClass); - } -}; - - -/** - * Handles the start button being clicked. - * @param {goog.events.BrowserEvent} e The click event. - * @private - */ -goog.testing.MultiTestRunner.prototype.onStartClicked_ = function(e) { - this.start(); -}; - - -/** - * Handles the stop button being clicked. - * @param {goog.events.BrowserEvent} e The click event. - * @private - */ -goog.testing.MultiTestRunner.prototype.onStopClicked_ = function(e) { - this.stopped_ = true; - this.finish_(); -}; - - -/** - * Handles the log tab being clicked. - * @param {goog.events.BrowserEvent} e The click event. - * @private - */ -goog.testing.MultiTestRunner.prototype.onLogTabClicked_ = function(e) { - this.showTab_(0); -}; - - -/** - * Handles the log tab being clicked. - * @param {goog.events.BrowserEvent} e The click event. - * @private - */ -goog.testing.MultiTestRunner.prototype.onReportTabClicked_ = function(e) { - this.showTab_(1); -}; - - -/** - * Handles the stats tab being clicked. - * @param {goog.events.BrowserEvent} e The click event. - * @private - */ -goog.testing.MultiTestRunner.prototype.onStatsTabClicked_ = function(e) { - this.showTab_(2); -}; - - - -/** - * Class used to manage the interaction with a single iframe. - * @param {string} basePath The base path for tests. - * @param {number} timeoutMs The time to wait for the test to load and run. - * @param {boolean} verbosePasses Whether to show results for passes. - * @param {goog.dom.DomHelper=} opt_domHelper Optional dom helper. - * @constructor - * @extends {goog.ui.Component} - */ -goog.testing.MultiTestRunner.TestFrame = function( - basePath, timeoutMs, verbosePasses, opt_domHelper) { - goog.ui.Component.call(this, opt_domHelper); - - /** - * Base path where tests should be resolved from. - * @type {string} - * @private - */ - this.basePath_ = basePath; - - /** - * The timeout for the test. - * @type {number} - * @private - */ - this.timeoutMs_ = timeoutMs; - - /** - * Whether to show a summary for passing tests. - * @type {boolean} - * @private - */ - this.verbosePasses_ = verbosePasses; - - /** - * An event handler for handling events. - * @type {goog.events.EventHandler} - * @private - */ - this.eh_ = new goog.events.EventHandler(this); - -}; -goog.inherits(goog.testing.MultiTestRunner.TestFrame, goog.ui.Component); - - -/** - * Reference to the iframe. - * @type {HTMLIFrameElement} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.iframeEl_ = null; - - -/** - * Whether the iframe for the current test has loaded. - * @type {boolean} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.iframeLoaded_ = false; - - -/** - * The test file being run. - * @type {string} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.testFile_ = ''; - - -/** - * The report returned from the test. - * @type {string} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.report_ = ''; - - -/** - * The total time loading and running the test in milliseconds. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.totalTime_ = 0; - - -/** - * The actual runtime of the test in milliseconds. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.runTime_ = 0; - - -/** - * The number of files loaded by the test. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.numFilesLoaded_ = 0; - - -/** - * Whether the test was successful, null if no result has been returned yet. - * @type {?boolean} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.isSuccess_ = null; - - -/** - * Timestamp for the when the test was started. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.startTime_ = 0; - - -/** - * Timestamp for the last state, used to determine timeouts. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.lastStateTime_ = 0; - - -/** - * The state of the active test. - * @type {number} - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.currentState_ = 0; - - -/** @override */ -goog.testing.MultiTestRunner.TestFrame.prototype.disposeInternal = function() { - goog.testing.MultiTestRunner.TestFrame.superClass_.disposeInternal.call(this); - this.dom_.removeNode(this.iframeEl_); - this.eh_.dispose(); - this.iframeEl_ = null; -}; - - -/** - * Runs a test file in this test frame. - * @param {string} testFile The test to run. - */ -goog.testing.MultiTestRunner.TestFrame.prototype.runTest = function(testFile) { - this.lastStateTime_ = this.startTime_ = goog.now(); - - if (!this.iframeEl_) { - this.createIframe_(); - } - - this.iframeLoaded_ = false; - this.currentState_ = 0; - this.isSuccess_ = null; - this.report_ = ''; - this.testFile_ = testFile; - - try { - this.iframeEl_.src = this.basePath_ + testFile; - } catch (e) { - // Failures will trigger a JS exception on the local file system. - this.report_ = this.testFile_ + ' failed to load : ' + e.message; - this.isSuccess_ = false; - this.finish_(); - return; - } - - this.checkForCompletion_(); -}; - - -/** - * @return {string} The test file the TestFrame is running. - */ -goog.testing.MultiTestRunner.TestFrame.prototype.getTestFile = function() { - return this.testFile_; -}; - - -/** - * @return {Object} Stats about the test run. - */ -goog.testing.MultiTestRunner.TestFrame.prototype.getStats = function() { - return { - 'testFile': this.testFile_, - 'success': this.isSuccess_, - 'runTime': this.runTime_, - 'totalTime': this.totalTime_, - 'numFilesLoaded': this.numFilesLoaded_ - }; -}; - - -/** - * @return {string} The report for the test run. - */ -goog.testing.MultiTestRunner.TestFrame.prototype.getReport = function() { - return this.report_; -}; - - -/** - * @return {?boolean} Whether the test frame had a success. - */ -goog.testing.MultiTestRunner.TestFrame.prototype.isSuccess = function() { - return this.isSuccess_; -}; - - -/** - * Handles the TestFrame finishing a single test. - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.finish_ = function() { - this.totalTime_ = goog.now() - this.startTime_; - // TODO(user): Fire an event instead? - if (this.getParent() && this.getParent().processResult) { - this.getParent().processResult(this); - } -}; - - -/** - * Creates an iframe to run the tests in. For overriding in unit tests. - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.createIframe_ = function() { - this.iframeEl_ = - (/** @type {HTMLIFrameElement} */ this.dom_.createDom('iframe')); - this.getElement().appendChild(this.iframeEl_); - this.eh_.listen(this.iframeEl_, 'load', this.onIframeLoaded_); -}; - - -/** - * Handles the iframe loading. - * @param {goog.events.BrowserEvent} e The load event. - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.onIframeLoaded_ = function(e) { - this.iframeLoaded_ = true; -}; - - -/** - * Checks the active test for completion, keeping track of the tests' various - * execution stages. - * @private - */ -goog.testing.MultiTestRunner.TestFrame.prototype.checkForCompletion_ = - function() { - var js = goog.dom.getFrameContentWindow(this.iframeEl_); - switch (this.currentState_) { - case 0: - if (this.iframeLoaded_ && js['G_testRunner']) { - this.lastStateTime_ = goog.now(); - this.currentState_++; - } - break; - case 1: - if (js['G_testRunner']['isInitialized']()) { - this.lastStateTime_ = goog.now(); - this.currentState_++; - } - break; - case 2: - if (js['G_testRunner']['isFinished']()) { - var tr = js['G_testRunner']; - this.isSuccess_ = tr['isSuccess'](); - this.report_ = tr['getReport'](this.verbosePasses_); - this.runTime_ = tr['getRunTime'](); - this.numFilesLoaded_ = tr['getNumFilesLoaded'](); - this.finish_(); - return; - } - } - - // Check to see if the test has timed out. - if (goog.now() - this.lastStateTime_ > this.timeoutMs_) { - this.report_ = this.testFile_ + ' timed out ' + - goog.testing.MultiTestRunner.STATES[this.currentState_]; - this.isSuccess_ = false; - this.finish_(); - return; - } - - // Check again in 100ms. - goog.Timer.callOnce(this.checkForCompletion_, 100, this); -}; |