Blame | Letzte Änderung | Log anzeigen | RSS feed
/** Copyright 2004 ThoughtWorks, Inc** 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.**/// An object representing the current test, used externalvar currentTest = null; // TODO: get rid of this global, which mirrors the htmlTestRunner.currentTestvar selenium = null;var htmlTestRunner;var HtmlTestRunner = classCreate();objectExtend(HtmlTestRunner.prototype, {initialize: function() {this.metrics = new Metrics();this.controlPanel = new HtmlTestRunnerControlPanel();this.testFailed = false;this.currentTest = null;this.runAllTests = false;this.appWindow = null;// we use a timeout here to make sure the LOG has loaded first, so we can see _every_ errorsetTimeout(fnBind(function() {this.loadSuiteFrame();}, this), 500);},getTestSuite: function() {return suiteFrame.getCurrentTestSuite();},markFailed: function() {this.testFailed = true;this.getTestSuite().markFailed();},loadSuiteFrame: function() {if (selenium == null) {var appWindow = this._getApplicationWindow();try { appWindow.location; }catch (e) {// when reloading, we may be pointing at an old window (Perm Denied)setTimeout(fnBind(function() {this.loadSuiteFrame();}, this), 50);return;}selenium = Selenium.createForWindow(appWindow);this._registerCommandHandlers();}this.controlPanel.setHighlightOption();var testSuiteName = this.controlPanel.getTestSuiteName();var self = this;if (testSuiteName) {suiteFrame.load(testSuiteName, function() {setTimeout(fnBind(self._onloadTestSuite, self), 50)} );selenium.browserbot.baseUrl = absolutify(testSuiteName, window.location.href);}// DGF or should we use the old default?// selenium.browserbot.baseUrl = window.location.href;if (this.controlPanel.getBaseUrl()) {selenium.browserbot.baseUrl = this.controlPanel.getBaseUrl();}},_getApplicationWindow: function () {if (this.controlPanel.isMultiWindowMode()) {return this._getSeparateApplicationWindow();}return $('myiframe').contentWindow;},_getSeparateApplicationWindow: function () {if (this.appWindow == null) {this.appWindow = openSeparateApplicationWindow('TestRunner-splash.html', this.controlPanel.isAutomatedRun());}return this.appWindow;},_onloadTestSuite:function () {if (! this.getTestSuite().isAvailable()) {return;}if (this.controlPanel.isAutomatedRun()) {this.startTestSuite();} else if (this.controlPanel.getAutoUrl()) {//todo what is the autourl doing, left to check it outaddLoadListener(this._getApplicationWindow(), fnBind(this._startSingleTest, this));this._getApplicationWindow().src = this.controlPanel.getAutoUrl();} else {this.getTestSuite().getSuiteRows()[0].loadTestCase();}},_startSingleTest:function () {removeLoadListener(getApplicationWindow(), fnBind(this._startSingleTest, this));var singleTestName = this.controlPanel.getSingleTestName();testFrame.load(singleTestName, fnBind(this.startTest, this));},_registerCommandHandlers: function () {this.commandFactory = new CommandHandlerFactory();this.commandFactory.registerAll(selenium);},startTestSuite: function() {this.controlPanel.reset();this.metrics.resetMetrics();this.getTestSuite().reset();this.runAllTests = true;this.runNextTest();},runNextTest: function () {this.getTestSuite().updateSuiteWithResultOfPreviousTest();if (!this.runAllTests) {return;}this.getTestSuite().runNextTestInSuite();},startTest: function () {this.controlPanel.reset();testFrame.scrollToTop();//todo: move testFailed and storedVars to TestCasethis.testFailed = false;storedVars = new Object();this.currentTest = new HtmlRunnerTestLoop(testFrame.getCurrentTestCase(), this.metrics, this.commandFactory);currentTest = this.currentTest;this.currentTest.start();},runSingleTest:function() {this.runAllTests = false;this.metrics.resetMetrics();this.startTest();}});var runInterval = 0;/** SeleniumFrame encapsulates an iframe element */var SeleniumFrame = classCreate();objectExtend(SeleniumFrame.prototype, {initialize : function(frame) {this.frame = frame;addLoadListener(this.frame, fnBind(this._handleLoad, this));},getDocument : function() {return this.frame.contentWindow.document;},_handleLoad: function() {this._attachStylesheet();this._onLoad();if (this.loadCallback) {this.loadCallback();this.loadCallback = null;}},_attachStylesheet: function() {var d = this.getDocument();var head = d.getElementsByTagName('head').item(0);var styleLink = d.createElement("link");styleLink.rel = "stylesheet";styleLink.type = "text/css";if (browserVersion && browserVersion.isChrome) {// DGF We have to play a clever trick to get the right absolute path.// This trick works on most browsers, (not IE), but is only needed in// chromevar tempLink = window.document.createElement("link");tempLink.href = "selenium-test.css"; // this will become an absolute hrefstyleLink.href = tempLink.href;} else {// this works in every browser (except Firefox in chrome mode)var styleSheetPath = window.location.pathname.replace(/[^\/\\]+$/, "selenium-test.css");if (browserVersion.isIE && window.location.protocol == "file:") {styleSheetPath = "file://" + styleSheetPath;}styleLink.href = styleSheetPath;}head.appendChild(styleLink);},_onLoad: function() {},scrollToTop : function() {this.frame.contentWindow.scrollTo(0, 0);},_setLocation: function(location) {var isChrome = browserVersion.isChrome || false;var isHTA = browserVersion.isHTA || false;// DGF TODO multiWindowlocation += "?thisIsChrome=" + isChrome + "&thisIsHTA=" + isHTA;if (browserVersion.isSafari) {// safari doesn't reload the page when the location equals to current location.// hence, set the location to blank so that the page will reload automatically.this.frame.src = "about:blank";this.frame.src = location;} else {this.frame.contentWindow.location.replace(location);}},load: function(/* url, [callback] */) {if (arguments.length > 1) {this.loadCallback = arguments[1];}this._setLocation(arguments[0]);}});/** HtmlTestSuiteFrame - encapsulates the suite iframe element */var HtmlTestSuiteFrame = classCreate();objectExtend(HtmlTestSuiteFrame.prototype, SeleniumFrame.prototype);objectExtend(HtmlTestSuiteFrame.prototype, {getCurrentTestSuite: function() {if (!this.currentTestSuite) {this.currentTestSuite = new HtmlTestSuite(this.getDocument());}return this.currentTestSuite;}});/** HtmlTestFrame - encapsulates the test-case iframe element */var HtmlTestFrame = classCreate();objectExtend(HtmlTestFrame.prototype, SeleniumFrame.prototype);objectExtend(HtmlTestFrame.prototype, {_onLoad: function() {this.currentTestCase = new HtmlTestCase(this.getDocument(), htmlTestRunner.getTestSuite().getCurrentRow());},getCurrentTestCase: function() {return this.currentTestCase;}});function onSeleniumLoad() {suiteFrame = new HtmlTestSuiteFrame(getSuiteFrame());testFrame = new HtmlTestFrame(getTestFrame());htmlTestRunner = new HtmlTestRunner();}var suiteFrame;var testFrame;function getSuiteFrame() {var f = $('testSuiteFrame');if (f == null) {f = top;// proxyInjection mode does not set myiframe}return f;}function getTestFrame() {var f = $('testFrame');if (f == null) {f = top;// proxyInjection mode does not set myiframe}return f;}var HtmlTestRunnerControlPanel = classCreate();objectExtend(HtmlTestRunnerControlPanel.prototype, URLConfiguration.prototype);objectExtend(HtmlTestRunnerControlPanel.prototype, {initialize: function() {this._acquireQueryString();this.runInterval = 0;this.highlightOption = $('highlightOption');this.pauseButton = $('pauseTest');this.stepButton = $('stepTest');this.highlightOption.onclick = fnBindAsEventListener((function() {this.setHighlightOption();}), this);this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);this.stepButton.onclick = fnBindAsEventListener(this.stepCurrentTest, this);this.speedController = new Control.Slider('speedHandle', 'speedTrack', {range: $R(0, 1000),onSlide: fnBindAsEventListener(this.setRunInterval, this),onChange: fnBindAsEventListener(this.setRunInterval, this)});this._parseQueryParameter();},setHighlightOption: function () {var isHighlight = this.highlightOption.checked;selenium.browserbot.setShouldHighlightElement(isHighlight);},_parseQueryParameter: function() {var tempRunInterval = this._getQueryParameter("runInterval");if (tempRunInterval) {this.setRunInterval(tempRunInterval);}this.highlightOption.checked = this._getQueryParameter("highlight");},setRunInterval: function(runInterval) {this.runInterval = runInterval;},setToPauseAtNextCommand: function() {this.runInterval = -1;},pauseCurrentTest: function () {this.setToPauseAtNextCommand();this._switchPauseButtonToContinue();},continueCurrentTest: function () {this.reset();currentTest.resume();},reset: function() {// this.runInterval = this.speedController.value;this._switchContinueButtonToPause();},_switchContinueButtonToPause: function() {this.pauseButton.className = "cssPauseTest";this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);},_switchPauseButtonToContinue: function() {$('stepTest').disabled = false;this.pauseButton.className = "cssContinueTest";this.pauseButton.onclick = fnBindAsEventListener(this.continueCurrentTest, this);},stepCurrentTest: function () {this.setToPauseAtNextCommand();currentTest.resume();},isAutomatedRun: function() {return this._isQueryParameterTrue("auto");},shouldSaveResultsToFile: function() {return this._isQueryParameterTrue("save");},closeAfterTests: function() {return this._isQueryParameterTrue("close");},getTestSuiteName: function() {return this._getQueryParameter("test");},getSingleTestName: function() {return this._getQueryParameter("singletest");},getAutoUrl: function() {return this._getQueryParameter("autoURL");},getResultsUrl: function() {return this._getQueryParameter("resultsUrl");},_acquireQueryString: function() {if (this.queryString) return;if (browserVersion.isHTA) {var args = this._extractArgs();if (args.length < 2) return null;this.queryString = args[1];} else {this.queryString = location.search.substr(1);}}});var AbstractResultAwareRow = classCreate();objectExtend(AbstractResultAwareRow.prototype, {initialize: function(trElement) {this.trElement = trElement;},setStatus: function(status) {this.unselect();this.trElement.className = this.trElement.className.replace(/status_[a-z]+/, "");if (status) {addClassName(this.trElement, "status_" + status);}},select: function() {addClassName(this.trElement, "selected");safeScrollIntoView(this.trElement);},unselect: function() {removeClassName(this.trElement, "selected");},markPassed: function() {this.setStatus("passed");},markDone: function() {this.setStatus("done");},markFailed: function() {this.setStatus("failed");}});var TitleRow = classCreate();objectExtend(TitleRow.prototype, AbstractResultAwareRow.prototype);objectExtend(TitleRow.prototype, {initialize: function(trElement) {this.trElement = trElement;trElement.className = "title";}});var HtmlTestCaseRow = classCreate();objectExtend(HtmlTestCaseRow.prototype, AbstractResultAwareRow.prototype);objectExtend(HtmlTestCaseRow.prototype, {getCommand: function () {return new SeleniumCommand(getText(this.trElement.cells[0]),getText(this.trElement.cells[1]),getText(this.trElement.cells[2]),this.isBreakpoint());},markFailed: function(errorMsg) {AbstractResultAwareRow.prototype.markFailed.call(this, errorMsg);this.setMessage(errorMsg);},setMessage: function(message) {setText(this.trElement.cells[2], message);},reset: function() {this.setStatus(null);var thirdCell = this.trElement.cells[2];if (thirdCell) {if (thirdCell.originalHTML) {thirdCell.innerHTML = thirdCell.originalHTML;} else {thirdCell.originalHTML = thirdCell.innerHTML;}}},onClick: function() {if (this.trElement.isBreakpoint == undefined) {this.trElement.isBreakpoint = true;addClassName(this.trElement, "breakpoint");} else {this.trElement.isBreakpoint = undefined;removeClassName(this.trElement, "breakpoint");}},addBreakpointSupport: function() {elementSetStyle(this.trElement, {"cursor" : "pointer"});this.trElement.onclick = fnBindAsEventListener(function() {this.onClick();}, this);},isBreakpoint: function() {if (this.trElement.isBreakpoint == undefined || this.trElement.isBreakpoint == null) {return false}return this.trElement.isBreakpoint;}});var HtmlTestSuiteRow = classCreate();objectExtend(HtmlTestSuiteRow.prototype, AbstractResultAwareRow.prototype);objectExtend(HtmlTestSuiteRow.prototype, {initialize: function(trElement, testFrame, htmlTestSuite) {this.trElement = trElement;this.testFrame = testFrame;this.htmlTestSuite = htmlTestSuite;this.link = trElement.getElementsByTagName("a")[0];this.link.onclick = fnBindAsEventListener(this._onClick, this);},reset: function() {this.setStatus(null);},_onClick: function() {this.loadTestCase(null);return false;},loadTestCase: function(onloadFunction) {this.htmlTestSuite.unselectCurrentRow();this.select();this.htmlTestSuite.currentRowInSuite = this.trElement.rowIndex - 1;// If the row has a stored results table, use thatvar resultsFromPreviousRun = this.trElement.cells[1];if (resultsFromPreviousRun) {// todo: delegate to TestFrame, e.g.// this.testFrame.restoreTestCase(resultsFromPreviousRun.innerHTML);var testBody = this.testFrame.getDocument().body;testBody.innerHTML = resultsFromPreviousRun.innerHTML;this.testFrame._onLoad();if (onloadFunction) {onloadFunction();}} else {this.testFrame.load(this.link.href, onloadFunction);}},saveTestResults: function() {// todo: GLOBAL ACCESS!var resultHTML = this.testFrame.getDocument().body.innerHTML;if (!resultHTML) return;// todo: why create this div?var divElement = this.trElement.ownerDocument.createElement("div");divElement.innerHTML = resultHTML;var hiddenCell = this.trElement.ownerDocument.createElement("td");hiddenCell.appendChild(divElement);hiddenCell.style.display = "none";this.trElement.appendChild(hiddenCell);}});var HtmlTestSuite = classCreate();objectExtend(HtmlTestSuite.prototype, {initialize: function(suiteDocument) {this.suiteDocument = suiteDocument;this.suiteRows = this._collectSuiteRows();this.titleRow = new TitleRow(this.getTestTable().rows[0]);this.reset();},reset: function() {this.failed = false;this.currentRowInSuite = -1;this.titleRow.setStatus(null);for (var i = 0; i < this.suiteRows.length; i++) {var row = this.suiteRows[i];row.reset();}},getSuiteRows: function() {return this.suiteRows;},getTestTable: function() {var tables = $A(this.suiteDocument.getElementsByTagName("table"));return tables[0];},isAvailable: function() {return this.getTestTable() != null;},_collectSuiteRows: function () {var result = [];var tables = $A(this.suiteDocument.getElementsByTagName("table"));var testTable = tables[0];for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {var rowElement = testTable.rows[rowNum];result.push(new HtmlTestSuiteRow(rowElement, testFrame, this));}// process the unsuited rows as wellfor (var tableNum = 1; tableNum < $A(this.suiteDocument.getElementsByTagName("table")).length; tableNum++) {testTable = tables[tableNum];for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {var rowElement = testTable.rows[rowNum];new HtmlTestSuiteRow(rowElement, testFrame, this);}}return result;},getCurrentRow: function() {if (this.currentRowInSuite == -1) {return null;}return this.suiteRows[this.currentRowInSuite];},unselectCurrentRow: function() {var currentRow = this.getCurrentRow()if (currentRow) {currentRow.unselect();}},markFailed: function() {this.failed = true;this.titleRow.markFailed();},markDone: function() {if (!this.failed) {this.titleRow.markPassed();}},_startCurrentTestCase: function() {this.getCurrentRow().loadTestCase(fnBind(htmlTestRunner.startTest, htmlTestRunner));},_onTestSuiteComplete: function() {this.markDone();new TestResult(this.failed, this.getTestTable()).post();},updateSuiteWithResultOfPreviousTest: function() {if (this.currentRowInSuite >= 0) {this.getCurrentRow().saveTestResults();}},runNextTestInSuite: function() {this.currentRowInSuite++;// If we are done with all of the tests, set the title bar as pass or failif (this.currentRowInSuite >= this.suiteRows.length) {this._onTestSuiteComplete();} else {this._startCurrentTestCase();}}});var TestResult = classCreate();objectExtend(TestResult.prototype, {// Post the results to a servlet, CGI-script, etc. The URL of the// results-handler defaults to "/postResults", but an alternative location// can be specified by providing a "resultsUrl" query parameter.//// Parameters passed to the results-handler are:// result: passed/failed depending on whether the suite passed or failed// totalTime: the total running time in seconds for the suite.//// numTestPasses: the total number of tests which passed.// numTestFailures: the total number of tests which failed.//// numCommandPasses: the total number of commands which passed.// numCommandFailures: the total number of commands which failed.// numCommandErrors: the total number of commands which errored.//// suite: the suite table, including the hidden column of test results// testTable.1 to testTable.N: the individual test tables//initialize: function (suiteFailed, suiteTable) {this.controlPanel = htmlTestRunner.controlPanel;this.metrics = htmlTestRunner.metrics;this.suiteFailed = suiteFailed;this.suiteTable = suiteTable;},post: function () {if (!this.controlPanel.isAutomatedRun()) {return;}var form = document.createElement("form");document.body.appendChild(form);form.id = "resultsForm";form.method = "post";form.target = "myiframe";var resultsUrl = this.controlPanel.getResultsUrl();if (!resultsUrl) {resultsUrl = "./postResults";}var actionAndParameters = resultsUrl.split('?', 2);form.action = actionAndParameters[0];var resultsUrlQueryString = actionAndParameters[1];form.createHiddenField = function(name, value) {input = document.createElement("input");input.type = "hidden";input.name = name;input.value = value;this.appendChild(input);};if (resultsUrlQueryString) {var clauses = resultsUrlQueryString.split('&');for (var i = 0; i < clauses.length; i++) {var keyValuePair = clauses[i].split('=', 2);var key = unescape(keyValuePair[0]);var value = unescape(keyValuePair[1]);form.createHiddenField(key, value);}}form.createHiddenField("selenium.version", Selenium.version);form.createHiddenField("selenium.revision", Selenium.revision);form.createHiddenField("result", this.suiteFailed ? "failed" : "passed");form.createHiddenField("totalTime", Math.floor((this.metrics.currentTime - this.metrics.startTime) / 1000));form.createHiddenField("numTestPasses", this.metrics.numTestPasses);form.createHiddenField("numTestFailures", this.metrics.numTestFailures);form.createHiddenField("numCommandPasses", this.metrics.numCommandPasses);form.createHiddenField("numCommandFailures", this.metrics.numCommandFailures);form.createHiddenField("numCommandErrors", this.metrics.numCommandErrors);// Create an input for each test table. The inputs are named// testTable.1, testTable.2, etc.for (rowNum = 1; rowNum < this.suiteTable.rows.length; rowNum++) {// If there is a second column, then add a new inputif (this.suiteTable.rows[rowNum].cells.length > 1) {var resultCell = this.suiteTable.rows[rowNum].cells[1];form.createHiddenField("testTable." + rowNum, resultCell.innerHTML);// remove the resultCell, so it's not included in the suite HTMLresultCell.parentNode.removeChild(resultCell);}}form.createHiddenField("numTestTotal", rowNum);// Add HTML for the suite itselfform.createHiddenField("suite", this.suiteTable.parentNode.innerHTML);if (this.controlPanel.shouldSaveResultsToFile()) {this._saveToFile(resultsUrl, form);} else {form.submit();}document.body.removeChild(form);if (this.controlPanel.closeAfterTests()) {window.top.close();}},_saveToFile: function (fileName, form) {// This only works when run as an IE HTAvar inputs = new Object();for (var i = 0; i < form.elements.length; i++) {inputs[form.elements[i].name] = form.elements[i].value;}var objFSO = new ActiveXObject("Scripting.FileSystemObject")var scriptFile = objFSO.CreateTextFile(fileName);scriptFile.WriteLine("<html><body>\n<h1>Test suite results </h1>" +"\n\n<table>\n<tr>\n<td>result:</td>\n<td>" + inputs["result"] + "</td>\n" +"</tr>\n<tr>\n<td>totalTime:</td>\n<td>" + inputs["totalTime"] + "</td>\n</tr>\n" +"<tr>\n<td>numTestPasses:</td>\n<td>" + inputs["numTestPasses"] + "</td>\n</tr>\n" +"<tr>\n<td>numTestFailures:</td>\n<td>" + inputs["numTestFailures"] + "</td>\n</tr>\n" +"<tr>\n<td>numCommandPasses:</td>\n<td>" + inputs["numCommandPasses"] + "</td>\n</tr>\n" +"<tr>\n<td>numCommandFailures:</td>\n<td>" + inputs["numCommandFailures"] + "</td>\n</tr>\n" +"<tr>\n<td>numCommandErrors:</td>\n<td>" + inputs["numCommandErrors"] + "</td>\n</tr>\n" +"<tr>\n<td>" + inputs["suite"] + "</td>\n<td> </td>\n</tr>");var testNum = inputs["numTestTotal"];for (var rowNum = 1; rowNum < testNum; rowNum++) {scriptFile.WriteLine("<tr>\n<td>" + inputs["testTable." + rowNum] + "</td>\n<td> </td>\n</tr>");}scriptFile.WriteLine("</table></body></html>");scriptFile.Close();}});/** HtmlTestCase encapsulates an HTML test document */var HtmlTestCase = classCreate();objectExtend(HtmlTestCase.prototype, {initialize: function(testDocument, htmlTestSuiteRow) {if (testDocument == null) {throw "testDocument should not be null";}if (htmlTestSuiteRow == null) {throw "htmlTestSuiteRow should not be null";}this.testDocument = testDocument;this.htmlTestSuiteRow = htmlTestSuiteRow;this.headerRow = new TitleRow(this.testDocument.getElementsByTagName("tr")[0]);this.commandRows = this._collectCommandRows();this.nextCommandRowIndex = 0;this._addBreakpointSupport();},_collectCommandRows: function () {var commandRows = [];var tables = $A(this.testDocument.getElementsByTagName("table"));var self = this;for (var i = 0; i < tables.length; i++) {var table = tables[i];var tableRows = $A(table.rows);for (var j = 0; j < tableRows.length; j++) {var candidateRow = tableRows[j];if (self.isCommandRow(candidateRow)) {commandRows.push(new HtmlTestCaseRow(candidateRow));}}}return commandRows;},isCommandRow: function (row) {return row.cells.length >= 3;},reset: function() {/*** reset the test to runnable state*/this.nextCommandRowIndex = 0;this.setStatus('');for (var i = 0; i < this.commandRows.length; i++) {var row = this.commandRows[i];row.reset();}// remove any additional fake "error" row added to the end of the documentvar errorElement = this.testDocument.getElementById('error');if (errorElement) {errorElement.parentNode.removeChild(errorElement);}},getCommandRows: function () {return this.commandRows;},setStatus: function(status) {this.headerRow.setStatus(status);},markFailed: function() {this.setStatus("failed");this.htmlTestSuiteRow.markFailed();},markPassed: function() {this.setStatus("passed");this.htmlTestSuiteRow.markPassed();},addErrorMessage: function(errorMsg, currentRow) {errorMsg = errorMsg.replace(/ /g, String.fromCharCode(160)).replace("\n", '\\n');if (currentRow) {currentRow.markFailed(errorMsg);} else {var errorElement = this.testDocument.createElement("p");errorElement.id = "error";setText(errorElement, errorMsg);this.testDocument.body.appendChild(errorElement);errorElement.className = "status_failed";}},_addBreakpointSupport: function() {for (var i = 0; i < this.commandRows.length; i++) {var row = this.commandRows[i];row.addBreakpointSupport();}},hasMoreCommandRows: function() {return this.nextCommandRowIndex < this.commandRows.length;},getNextCommandRow: function() {if (this.hasMoreCommandRows()) {return this.commandRows[this.nextCommandRowIndex++];}return null;}});// TODO: split out an JavascriptTestCase class to handle the "sejs" stuffvar get_new_rows = function() {var row_array = new Array();for (var i = 0; i < new_block.length; i++) {var new_source = (new_block[i][0].tokenizer.source.slice(new_block[i][0].start,new_block[i][0].end));var row = '<td style="display:none;" class="js">getEval</td>' +'<td style="display:none;">currentTest.doNextCommand()</td>' +'<td style="white-space: pre;">' + new_source + '</td>' +'<td></td>'row_array.push(row);}return row_array;};var Metrics = classCreate();objectExtend(Metrics.prototype, {initialize: function() {// The number of tests runthis.numTestPasses = 0;// The number of tests that have failedthis.numTestFailures = 0;// The number of commands which have passedthis.numCommandPasses = 0;// The number of commands which have failedthis.numCommandFailures = 0;// The number of commands which have caused errors (element not found)this.numCommandErrors = 0;// The time that the test was started.this.startTime = null;// The current time.this.currentTime = null;},printMetrics: function() {setText($('commandPasses'), this.numCommandPasses);setText($('commandFailures'), this.numCommandFailures);setText($('commandErrors'), this.numCommandErrors);setText($('testRuns'), this.numTestPasses + this.numTestFailures);setText($('testFailures'), this.numTestFailures);this.currentTime = new Date().getTime();var timeDiff = this.currentTime - this.startTime;var totalSecs = Math.floor(timeDiff / 1000);var minutes = Math.floor(totalSecs / 60);var seconds = totalSecs % 60;setText($('elapsedTime'), this._pad(minutes) + ":" + this._pad(seconds));},// Puts a leading 0 on num if it is less than 10_pad: function(num) {return (num > 9) ? num : "0" + num;},resetMetrics: function() {this.numTestPasses = 0;this.numTestFailures = 0;this.numCommandPasses = 0;this.numCommandFailures = 0;this.numCommandErrors = 0;this.startTime = new Date().getTime();}});var HtmlRunnerCommandFactory = classCreate();objectExtend(HtmlRunnerCommandFactory.prototype, {initialize: function(seleniumCommandFactory, testLoop) {this.seleniumCommandFactory = seleniumCommandFactory;this.testLoop = testLoop;this.handlers = {};//todo: register commands},getCommandHandler: function(command) {if (this.handlers[command]) {return this.handlers[command];}return this.seleniumCommandFactory.getCommandHandler(command);}});var HtmlRunnerTestLoop = classCreate();objectExtend(HtmlRunnerTestLoop.prototype, new TestLoop());objectExtend(HtmlRunnerTestLoop.prototype, {initialize: function(htmlTestCase, metrics, seleniumCommandFactory) {this.commandFactory = new HtmlRunnerCommandFactory(seleniumCommandFactory, this);this.metrics = metrics;this.htmlTestCase = htmlTestCase;se = selenium;global.se = selenium;this.currentRow = null;this.currentRowIndex = 0;// used for selenium tests in javascriptthis.currentItem = null;this.commandAgenda = new Array();this.expectedFailure = null;this.expectedFailureType = null;this.htmlTestCase.reset();this.sejsElement = this.htmlTestCase.testDocument.getElementById('sejs');if (this.sejsElement) {var fname = 'Selenium JavaScript';parse_result = parse(this.sejsElement.innerHTML, fname, 0);var x2 = new ExecutionContext(GLOBAL_CODE);ExecutionContext.current = x2;execute(parse_result, x2)}},_advanceToNextRow: function() {if (this.htmlTestCase.hasMoreCommandRows()) {this.currentRow = this.htmlTestCase.getNextCommandRow();if (this.sejsElement) {this.currentItem = agenda.pop();this.currentRowIndex++;}} else {this.currentRow = null;this.currentItem = null;}},nextCommand : function() {this._advanceToNextRow();if (this.currentRow == null) {return null;}return this.currentRow.getCommand();},commandStarted : function() {$('pauseTest').disabled = false;this.currentRow.select();this.metrics.printMetrics();},commandComplete : function(result) {this._checkExpectedFailure(result);if (result.failed) {this.metrics.numCommandFailures += 1;this._recordFailure(result.failureMessage);} else if (result.passed) {this.metrics.numCommandPasses += 1;this.currentRow.markPassed();} else {this.currentRow.markDone();}},_checkExpectedFailure : function(result) {if (this.expectedFailure != null) {if (this.expectedFailureJustSet) {this.expectedFailureJustSet = false;return;}if (!result.failed) {result.passed = false;result.failed = true;result.failureMessage = "Expected " + this.expectedFailureType + " did not occur.";} else {if (PatternMatcher.matches(this.expectedFailure, result.failureMessage)) {var failureType = result.error ? "error" : "failure";if (failureType == this.expectedFailureType) {result.failed = false;result.passed = true;} else {result.failed = true;result.failureMessage = "Expected "+this.expectedFailureType+", but "+failureType+" occurred instead";}} else {result.failed = true;result.failureMessage = "Expected " + this.expectedFailureType + " message '" + this.expectedFailure+ "' but was '" + result.failureMessage + "'";}}this.expectedFailure = null;this.expectedFailureType = null;}},commandError : function(errorMessage) {var tempResult = {};tempResult.passed = false;tempResult.failed = true;tempResult.error = true;tempResult.failureMessage = errorMessage;this._checkExpectedFailure(tempResult);if (tempResult.passed) {this.currentRow.markDone();return true;}errorMessage = tempResult.failureMessage;this.metrics.numCommandErrors += 1;this._recordFailure(errorMessage);},_recordFailure : function(errorMsg) {LOG.warn("currentTest.recordFailure: " + errorMsg);htmlTestRunner.markFailed();this.htmlTestCase.addErrorMessage(errorMsg, this.currentRow);},testComplete : function() {$('pauseTest').disabled = true;$('stepTest').disabled = true;if (htmlTestRunner.testFailed) {this.htmlTestCase.markFailed();this.metrics.numTestFailures += 1;} else {this.htmlTestCase.markPassed();this.metrics.numTestPasses += 1;}this.metrics.printMetrics();window.setTimeout(function() {htmlTestRunner.runNextTest();}, 1);},getCommandInterval : function() {return htmlTestRunner.controlPanel.runInterval;},pause : function() {htmlTestRunner.controlPanel.pauseCurrentTest();},doNextCommand: function() {var _n = this.currentItem[0];var _x = this.currentItem[1];new_block = new Array()execute(_n, _x);if (new_block.length > 0) {var the_table = this.htmlTestCase.testDocument.getElementById("se-js-table")var loc = this.currentRowIndexvar new_rows = get_new_rows()// make the new statements visible on screen...for (var i = 0; i < new_rows.length; i++) {the_table.insertRow(loc + 1);the_table.rows[loc + 1].innerHTML = new_rows[i];this.commandRows.unshift(the_table.rows[loc + 1])}}}});Selenium.prototype.doPause = function(waitTime) {/** Wait for the specified amount of time (in milliseconds)* @param waitTime the amount of time to sleep (in milliseconds)*/// todo: should not refer to currentTest directlycurrentTest.pauseInterval = waitTime;};Selenium.prototype.doBreak = function() {/** Halt the currently running test, and wait for the user to press the Continue button.* This command is useful for debugging, but be careful when using it, because it will* force automated tests to hang until a user intervenes manually.*/// todo: should not refer to controlPanel directlyhtmlTestRunner.controlPanel.setToPauseAtNextCommand();};Selenium.prototype.doStore = function(expression, variableName) {/** This command is a synonym for storeExpression.* @param expression the value to store* @param variableName the name of a <a href="#storedVars">variable</a> in which the result is to be stored.*/storedVars[variableName] = expression;}/** Click on the located element, and attach a callback to notify* when the page is reloaded.*/// DGF TODO this code has been broken for some time... what is it trying to accomplish?Selenium.prototype.XXXdoModalDialogTest = function(returnValue) {this.browserbot.doModalDialogTest(returnValue);};Selenium.prototype.doEcho = function(message) {/** Prints the specified message into the third table cell in your Selenese tables.* Useful for debugging.* @param message the message to print*/currentTest.currentRow.setMessage(message);}Selenium.prototype.assertSelected = function(selectLocator, optionLocator) {/*** Verifies that the selected option of a drop-down satisfies the optionSpecifier. <i>Note that this command is deprecated; you should use assertSelectedLabel, assertSelectedValue, assertSelectedIndex, or assertSelectedId instead.</i>** <p>See the select command for more information about option locators.</p>** @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu* @param optionLocator an option locator, typically just an option label (e.g. "John Smith")*/var element = this.page().findElement(selectLocator);var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);if (element.selectedIndex == -1){Assert.fail("No option selected");}locator.assertSelected(element);};Selenium.prototype.assertFailureOnNext = function(message) {/*** Tell Selenium to expect a failure on the next command execution.* @param message The failure message we should expect. This command will fail if the wrong failure message appears.*/if (!message) {throw new SeleniumError("Message must be provided");}currentTest.expectedFailure = message;currentTest.expectedFailureType = "failure";currentTest.expectedFailureJustSet = true;};Selenium.prototype.assertErrorOnNext = function(message) {/*** Tell Selenium to expect an error on the next command execution.* @param message The error message we should expect. This command will fail if the wrong error message appears.*/// This command temporarily installs a CommandFactory that generates// CommandHandlers that expect an error.if (!message) {throw new SeleniumError("Message must be provided");}currentTest.expectedFailure = message;currentTest.expectedFailureType = "error";currentTest.expectedFailureJustSet = true;};