[ Index ] |
|
Code source de PRADO 3.0.6 |
1 /* 2 * Copyright 2004 ThoughtWorks, Inc 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 // An object representing the current test, used external 19 var currentTest = null; // TODO: get rid of this global, which mirrors the htmlTestRunner.currentTest 20 var selenium = null; 21 22 var htmlTestRunner; 23 var HtmlTestRunner = Class.create(); 24 Object.extend(HtmlTestRunner.prototype, { 25 initialize: function() { 26 this.metrics = new Metrics(); 27 this.controlPanel = new HtmlTestRunnerControlPanel(); 28 this.htmlTestSuite = null; 29 this.testFailed = false; 30 this.currentTest = null; 31 this.runAllTests = false; 32 this.appWindow = null; 33 // we use a timeout here to make sure the LOG has loaded first, so we can see _every_ error 34 setTimeout(function() { 35 this.loadSuiteFrame(); 36 }.bind(this), 500); 37 }, 38 39 markFailed: function() { 40 this.testFailed = true; 41 this.htmlTestSuite.markFailed(); 42 }, 43 44 loadSuiteFrame: function() { 45 if (selenium == null) { 46 selenium = Selenium.createForWindow(this._getApplicationWindow()); 47 this._registerCommandHandlers(); 48 } 49 this.controlPanel.setHighlightOption(); 50 var testSuiteName = this.controlPanel.getTestSuiteName(); 51 if (testSuiteName) { 52 suiteFrame.load(testSuiteName, this._onloadTestSuite.bind(this)); 53 } 54 }, 55 56 _getApplicationWindow: function () { 57 if (this.controlPanel.isMultiWindowMode()) { 58 return this._getSeparateApplicationWindow(); 59 } 60 return $('myiframe').contentWindow; 61 }, 62 63 _getSeparateApplicationWindow: function () { 64 if (this.appWindow == null) { 65 this.appWindow = openSeparateApplicationWindow('TestRunner-splash.html'); 66 } 67 return this.appWindow; 68 }, 69 70 _onloadTestSuite:function () { 71 this.htmlTestSuite = new HtmlTestSuite(suiteFrame.getDocument()); 72 if (! this.htmlTestSuite.isAvailable()) { 73 return; 74 } 75 if (this.controlPanel.isAutomatedRun()) { 76 htmlTestRunner.startTestSuite(); 77 } else if (this.controlPanel.getAutoUrl()) { 78 //todo what is the autourl doing, left to check it out 79 addLoadListener(this._getApplicationWindow(), this._startSingleTest.bind(this)); 80 this._getApplicationWindow().src = this.controlPanel.getAutoUrl(); 81 } else { 82 this.htmlTestSuite.getSuiteRows()[0].loadTestCase(); 83 } 84 }, 85 86 _startSingleTest:function () { 87 removeLoadListener(getApplicationWindow(), this._startSingleTest.bind(this)); 88 var singleTestName = this.controlPanel.getSingleTestName(); 89 testFrame.load(singleTestName, this.startTest.bind(this)); 90 }, 91 92 _registerCommandHandlers: function () { 93 this.commandFactory = new CommandHandlerFactory(); 94 this.commandFactory.registerAll(selenium); 95 }, 96 97 startTestSuite: function() { 98 this.controlPanel.reset(); 99 this.metrics.resetMetrics(); 100 this.htmlTestSuite.reset(); 101 this.runAllTests = true; 102 this.runNextTest(); 103 }, 104 105 runNextTest: function () { 106 if (!this.runAllTests) { 107 return; 108 } 109 this.htmlTestSuite.runNextTestInSuite(); 110 }, 111 112 startTest: function () { 113 this.controlPanel.reset(); 114 testFrame.scrollToTop(); 115 //todo: move testFailed and storedVars to TestCase 116 this.testFailed = false; 117 storedVars = new Object(); 118 this.currentTest = new HtmlRunnerTestLoop(testFrame.getCurrentTestCase(), this.metrics, this.commandFactory); 119 currentTest = this.currentTest; 120 this.currentTest.start(); 121 }, 122 123 runSingleTest:function() { 124 this.runAllTests = false; 125 this.metrics.resetMetrics(); 126 this.startTest(); 127 } 128 }); 129 130 var FeedbackColors = Class.create(); 131 Object.extend(FeedbackColors, { 132 passColor : "#ccffcc", 133 doneColor : "#eeffee", 134 failColor : "#ffcccc", 135 workingColor : "#ffffcc", 136 breakpointColor : "#cccccc" 137 }); 138 139 140 var runInterval = 0; 141 142 143 /** SeleniumFrame encapsulates an iframe element */ 144 var SeleniumFrame = Class.create(); 145 Object.extend(SeleniumFrame.prototype, { 146 147 initialize : function(frame) { 148 this.frame = frame; 149 addLoadListener(this.frame, this._handleLoad.bind(this)); 150 }, 151 152 getDocument : function() { 153 return this.frame.contentWindow.document; 154 }, 155 156 _handleLoad: function() { 157 this._onLoad(); 158 if (this.loadCallback) { 159 this.loadCallback(); 160 this.loadCallback = null; 161 } 162 }, 163 164 _onLoad: function() { 165 }, 166 167 scrollToTop : function() { 168 this.frame.contentWindow.scrollTo(0, 0); 169 }, 170 171 _setLocation: function(location) { 172 if (browserVersion.isSafari) { 173 // safari doesn't reload the page when the location equals to current location. 174 // hence, set the location to blank so that the page will reload automatically. 175 this.frame.src = "about:blank"; 176 this.frame.src = location; 177 } else { 178 this.frame.contentWindow.location.replace(location); 179 } 180 }, 181 182 load: function(/* url, [callback] */) { 183 if (arguments.length > 1) { 184 this.loadCallback = arguments[1]; 185 186 } 187 this._setLocation(arguments[0]); 188 } 189 190 }); 191 192 /** HtmlTestFrame - encapsulates the test-case iframe element */ 193 var HtmlTestFrame = Class.create(); 194 Object.extend(HtmlTestFrame.prototype, SeleniumFrame.prototype); 195 Object.extend(HtmlTestFrame.prototype, { 196 197 _onLoad: function() { 198 this.setCurrentTestCase(); 199 }, 200 201 setCurrentTestCase: function() { 202 //todo: this is not good looking 203 this.currentTestCase = new HtmlTestCase(this.getDocument(), htmlTestRunner.htmlTestSuite.getCurrentRow()); 204 }, 205 206 getCurrentTestCase: function() { 207 return this.currentTestCase; 208 } 209 210 }); 211 212 function onSeleniumLoad() { 213 suiteFrame = new SeleniumFrame(getSuiteFrame()); 214 testFrame = new HtmlTestFrame(getTestFrame()); 215 htmlTestRunner = new HtmlTestRunner(); 216 } 217 218 219 var suiteFrame; 220 var testFrame; 221 function getSuiteFrame() { 222 var f = $('testSuiteFrame'); 223 if (f == null) { 224 f = top; 225 // proxyInjection mode does not set myiframe 226 } 227 return f; 228 } 229 230 function getTestFrame() { 231 var f = $('testFrame'); 232 if (f == null) { 233 f = top; 234 // proxyInjection mode does not set myiframe 235 } 236 return f; 237 } 238 239 var HtmlTestRunnerControlPanel = Class.create(); 240 Object.extend(HtmlTestRunnerControlPanel.prototype, URLConfiguration.prototype); 241 Object.extend(HtmlTestRunnerControlPanel.prototype, { 242 initialize: function() { 243 this._acquireQueryString(); 244 245 this.runInterval = 0; 246 247 this.highlightOption = $('highlightOption'); 248 this.pauseButton = $('pauseTest'); 249 this.stepButton = $('stepTest'); 250 251 this.highlightOption.onclick = (function() { 252 this.setHighlightOption(); 253 }).bindAsEventListener(this); 254 this.pauseButton.onclick = this.pauseCurrentTest.bindAsEventListener(this); 255 this.stepButton.onclick = this.stepCurrentTest.bindAsEventListener(this); 256 257 this.speedController = new Control.Slider('speedHandle', 'speedTrack', { 258 range: $R(0, 1000), 259 onSlide: this.setRunInterval.bindAsEventListener(this), 260 onChange: this.setRunInterval.bindAsEventListener(this) 261 }); 262 263 this._parseQueryParameter(); 264 }, 265 266 setHighlightOption: function () { 267 var isHighlight = this.highlightOption.checked; 268 selenium.browserbot.getCurrentPage().setHighlightElement(isHighlight); 269 }, 270 271 _parseQueryParameter: function() { 272 var tempRunInterval = this._getQueryParameter("runInterval"); 273 if (tempRunInterval) { 274 this.setRunInterval(tempRunInterval); 275 } 276 this.highlightOption.checked = this._getQueryParameter("highlight"); 277 }, 278 279 setRunInterval: function(runInterval) { 280 this.runInterval = runInterval; 281 }, 282 283 setToPauseAtNextCommand: function() { 284 this.runInterval = -1; 285 }, 286 287 pauseCurrentTest: function () { 288 this.setToPauseAtNextCommand(); 289 this._switchPauseButtonToContinue(); 290 }, 291 292 continueCurrentTest: function () { 293 this.reset(); 294 currentTest.resume(); 295 }, 296 297 reset: function() { 298 this.runInterval = this.speedController.value; 299 this._switchContinueButtonToPause(); 300 }, 301 302 _switchContinueButtonToPause: function() { 303 this.pauseButton.innerHTML = "Pause"; 304 this.pauseButton.onclick = this.pauseCurrentTest.bindAsEventListener(this); 305 }, 306 307 _switchPauseButtonToContinue: function() { 308 $('stepTest').disabled = false; 309 this.pauseButton.innerHTML = "Continue"; 310 this.pauseButton.onclick = this.continueCurrentTest.bindAsEventListener(this); 311 }, 312 313 stepCurrentTest: function () { 314 this.setToPauseAtNextCommand(); 315 currentTest.resume(); 316 }, 317 318 isAutomatedRun: function() { 319 return this._isQueryParameterTrue("auto"); 320 }, 321 322 shouldSaveResultsToFile: function() { 323 return this._isQueryParameterTrue("save"); 324 }, 325 326 closeAfterTests: function() { 327 return this._isQueryParameterTrue("close"); 328 }, 329 330 getTestSuiteName: function() { 331 return this._getQueryParameter("test"); 332 }, 333 334 getSingleTestName: function() { 335 return this._getQueryParameter("singletest"); 336 }, 337 338 getAutoUrl: function() { 339 return this._getQueryParameter("autoURL"); 340 }, 341 342 getResultsUrl: function() { 343 return this._getQueryParameter("resultsUrl"); 344 }, 345 346 _acquireQueryString: function() { 347 if (this.queryString) return; 348 if (browserVersion.isHTA) { 349 var args = this._extractArgs(); 350 if (args.length < 2) return null; 351 this.queryString = args[1]; 352 } else { 353 this.queryString = location.search.substr(1); 354 } 355 } 356 357 }); 358 359 360 var AbstractResultAwareRow = Class.create(); 361 Object.extend(AbstractResultAwareRow.prototype, { 362 363 initialize: function(trElement) { 364 this.trElement = trElement; 365 }, 366 367 markWorking: function() { 368 this.trElement.bgColor = FeedbackColors.workingColor; 369 safeScrollIntoView(this.trElement); 370 }, 371 372 markPassed: function() { 373 this.trElement.bgColor = FeedbackColors.passColor; 374 }, 375 376 markDone: function() { 377 this.trElement.bgColor = FeedbackColors.doneColor; 378 }, 379 380 markFailed: function() { 381 this.trElement.bgColor = FeedbackColors.failColor; 382 } 383 384 }); 385 386 var HtmlTestCaseRow = Class.create(); 387 Object.extend(HtmlTestCaseRow.prototype, AbstractResultAwareRow.prototype); 388 Object.extend(HtmlTestCaseRow.prototype, { 389 390 getCommand: function () { 391 return new SeleniumCommand(getText(this.trElement.cells[0]), 392 getText(this.trElement.cells[1]), 393 getText(this.trElement.cells[2]), 394 this.isBreakpoint()); 395 }, 396 397 markFailed: function(errorMsg) { 398 this.trElement.bgColor = FeedbackColors.failColor; 399 this.setMessage(errorMsg); 400 }, 401 402 setMessage: function(message) { 403 this.trElement.cells[2].innerHTML = message; 404 }, 405 406 reset: function() { 407 this.trElement.bgColor = ''; 408 var thirdCell = this.trElement.cells[2]; 409 if (thirdCell) { 410 if (thirdCell.originalHTML) { 411 thirdCell.innerHTML = thirdCell.originalHTML; 412 } else { 413 thirdCell.originalHTML = thirdCell.innerHTML; 414 } 415 } 416 }, 417 418 onClick: function() { 419 if (this.trElement.isBreakpoint == undefined) { 420 this.trElement.isBreakpoint = true; 421 this.trElement.beforeBackgroundColor = Element.getStyle(this.trElement, "backgroundColor"); 422 Element.setStyle(this.trElement, {"background-color" : FeedbackColors.breakpointColor}); 423 } else { 424 this.trElement.isBreakpoint = undefined; 425 Element.setStyle(this.trElement, {"background-color" : this.trElement.beforeBackgroundColor}); 426 } 427 }, 428 429 addBreakpointSupport: function() { 430 Element.setStyle(this.trElement, {"cursor" : "pointer"}); 431 this.trElement.onclick = function() { 432 this.onClick(); 433 }.bindAsEventListener(this); 434 }, 435 436 isBreakpoint: function() { 437 if (this.trElement.isBreakpoint == undefined || this.trElement.isBreakpoint == null) { 438 return false 439 } 440 return this.trElement.isBreakpoint; 441 } 442 }); 443 444 var HtmlTestSuiteRow = Class.create(); 445 Object.extend(HtmlTestSuiteRow.prototype, AbstractResultAwareRow.prototype); 446 Object.extend(HtmlTestSuiteRow.prototype, { 447 448 initialize: function(trElement, testFrame, htmlTestSuite) { 449 this.trElement = trElement; 450 this.testFrame = testFrame; 451 this.htmlTestSuite = htmlTestSuite; 452 this.link = trElement.getElementsByTagName("a")[0]; 453 this.link.onclick = this._onClick.bindAsEventListener(this); 454 }, 455 456 reset: function() { 457 this.trElement.bgColor = ''; 458 }, 459 460 _onClick: function() { 461 // todo: just send a message to the testSuite 462 this.loadTestCase(null); 463 return false; 464 }, 465 466 loadTestCase: function(onloadFunction) { 467 this.htmlTestSuite.currentRowInSuite = this.trElement.rowIndex - 1; 468 // If the row has a stored results table, use that 469 var resultsFromPreviousRun = this.trElement.cells[1]; 470 if (resultsFromPreviousRun) { 471 // this.testFrame.restoreTestCase(resultsFromPreviousRun.innerHTML); 472 var testBody = this.testFrame.getDocument().body; 473 testBody.innerHTML = resultsFromPreviousRun.innerHTML; 474 testFrame.setCurrentTestCase(); 475 if (onloadFunction) { 476 onloadFunction(); 477 } 478 } else { 479 this.testFrame.load(this.link.href, onloadFunction); 480 } 481 }, 482 483 saveTestResults: function() { 484 // todo: GLOBAL ACCESS! 485 var resultHTML = this.testFrame.getDocument().body.innerHTML; 486 if (!resultHTML) return; 487 488 // todo: why create this div? 489 var divElement = this.trElement.ownerDocument.createElement("div"); 490 divElement.innerHTML = resultHTML; 491 492 var hiddenCell = this.trElement.ownerDocument.createElement("td"); 493 hiddenCell.appendChild(divElement); 494 hiddenCell.style.display = "none"; 495 496 this.trElement.appendChild(hiddenCell); 497 } 498 499 }); 500 501 var HtmlTestSuite = Class.create(); 502 Object.extend(HtmlTestSuite.prototype, { 503 504 initialize: function(suiteDocument) { 505 this.suiteDocument = suiteDocument; 506 this.suiteRows = this._collectSuiteRows(); 507 this.titleRow = this.getTestTable().rows[0]; 508 this.title = this.titleRow.cells[0].innerHTML; 509 this.reset(); 510 }, 511 512 reset: function() { 513 this.failed = false; 514 this.currentRowInSuite = -1; 515 this.titleRow.bgColor = ''; 516 this.suiteRows.each(function(row) { 517 row.reset(); 518 }); 519 }, 520 521 getTitle: function() { 522 return this.title; 523 }, 524 525 getSuiteRows: function() { 526 return this.suiteRows; 527 }, 528 529 getTestTable: function() { 530 var tables = $A(this.suiteDocument.getElementsByTagName("table")); 531 return tables[0]; 532 }, 533 534 isAvailable: function() { 535 return this.getTestTable() != null; 536 }, 537 538 _collectSuiteRows: function () { 539 var result = []; 540 for (rowNum = 1; rowNum < this.getTestTable().rows.length; rowNum++) { 541 var rowElement = this.getTestTable().rows[rowNum]; 542 result.push(new HtmlTestSuiteRow(rowElement, testFrame, this)); 543 } 544 return result; 545 }, 546 547 getCurrentRow: function() { 548 return this.suiteRows[this.currentRowInSuite]; 549 }, 550 551 markFailed: function() { 552 this.failed = true; 553 this.titleRow.bgColor = FeedbackColors.failColor; 554 }, 555 556 markDone: function() { 557 if (!this.failed) { 558 this.titleRow.bgColor = FeedbackColors.passColor; 559 } 560 }, 561 562 _startCurrentTestCase: function() { 563 this.getCurrentRow().markWorking(); 564 this.getCurrentRow().loadTestCase(htmlTestRunner.startTest.bind(htmlTestRunner)); 565 }, 566 567 _onTestSuiteComplete: function() { 568 this.markDone(); 569 new TestResult(this.failed, this.getTestTable()).post(); 570 }, 571 572 _updateSuiteWithResultOfPreviousTest: function() { 573 if (this.currentRowInSuite >= 0) { 574 this.getCurrentRow().saveTestResults(); 575 } 576 }, 577 578 runNextTestInSuite: function() { 579 this._updateSuiteWithResultOfPreviousTest(); 580 this.currentRowInSuite++; 581 582 // If we are done with all of the tests, set the title bar as pass or fail 583 if (this.currentRowInSuite >= this.suiteRows.length) { 584 this._onTestSuiteComplete(); 585 } else { 586 this._startCurrentTestCase(); 587 } 588 } 589 590 591 592 }); 593 594 var TestResult = Class.create(); 595 Object.extend(TestResult.prototype, { 596 597 // Post the results to a servlet, CGI-script, etc. The URL of the 598 // results-handler defaults to "/postResults", but an alternative location 599 // can be specified by providing a "resultsUrl" query parameter. 600 // 601 // Parameters passed to the results-handler are: 602 // result: passed/failed depending on whether the suite passed or failed 603 // totalTime: the total running time in seconds for the suite. 604 // 605 // numTestPasses: the total number of tests which passed. 606 // numTestFailures: the total number of tests which failed. 607 // 608 // numCommandPasses: the total number of commands which passed. 609 // numCommandFailures: the total number of commands which failed. 610 // numCommandErrors: the total number of commands which errored. 611 // 612 // suite: the suite table, including the hidden column of test results 613 // testTable.1 to testTable.N: the individual test tables 614 // 615 initialize: function (suiteFailed, suiteTable) { 616 this.controlPanel = htmlTestRunner.controlPanel; 617 this.metrics = htmlTestRunner.metrics; 618 this.suiteFailed = suiteFailed; 619 this.suiteTable = suiteTable; 620 }, 621 622 post: function () { 623 if (!this.controlPanel.isAutomatedRun()) { 624 return; 625 } 626 var form = document.createElement("form"); 627 document.body.appendChild(form); 628 629 form.id = "resultsForm"; 630 form.method = "post"; 631 form.target = "myiframe"; 632 633 var resultsUrl = this.controlPanel.getResultsUrl(); 634 if (!resultsUrl) { 635 resultsUrl = "./postResults"; 636 } 637 638 var actionAndParameters = resultsUrl.split('?', 2); 639 form.action = actionAndParameters[0]; 640 var resultsUrlQueryString = actionAndParameters[1]; 641 642 form.createHiddenField = function(name, value) { 643 input = document.createElement("input"); 644 input.type = "hidden"; 645 input.name = name; 646 input.value = value; 647 this.appendChild(input); 648 }; 649 650 if (resultsUrlQueryString) { 651 var clauses = resultsUrlQueryString.split('&'); 652 for (var i = 0; i < clauses.length; i++) { 653 var keyValuePair = clauses[i].split('=', 2); 654 var key = unescape(keyValuePair[0]); 655 var value = unescape(keyValuePair[1]); 656 form.createHiddenField(key, value); 657 } 658 } 659 660 form.createHiddenField("selenium.version", Selenium.version); 661 form.createHiddenField("selenium.revision", Selenium.revision); 662 663 form.createHiddenField("result", this.suiteFailed ? "failed" : "passed"); 664 665 form.createHiddenField("totalTime", Math.floor((this.metrics.currentTime - this.metrics.startTime) / 1000)); 666 form.createHiddenField("numTestPasses", this.metrics.numTestPasses); 667 form.createHiddenField("numTestFailures", this.metrics.numTestFailures); 668 form.createHiddenField("numCommandPasses", this.metrics.numCommandPasses); 669 form.createHiddenField("numCommandFailures", this.metrics.numCommandFailures); 670 form.createHiddenField("numCommandErrors", this.metrics.numCommandErrors); 671 672 // Create an input for each test table. The inputs are named 673 // testTable.1, testTable.2, etc. 674 for (rowNum = 1; rowNum < this.suiteTable.rows.length; rowNum++) { 675 // If there is a second column, then add a new input 676 if (this.suiteTable.rows[rowNum].cells.length > 1) { 677 var resultCell = this.suiteTable.rows[rowNum].cells[1]; 678 form.createHiddenField("testTable." + rowNum, resultCell.innerHTML); 679 // remove the resultCell, so it's not included in the suite HTML 680 resultCell.parentNode.removeChild(resultCell); 681 } 682 } 683 684 form.createHiddenField("numTestTotal", rowNum); 685 686 // Add HTML for the suite itself 687 form.createHiddenField("suite", this.suiteTable.parentNode.innerHTML); 688 689 if (this.controlPanel.shouldSaveResultsToFile()) { 690 this._saveToFile(resultsUrl, form); 691 } else { 692 form.submit(); 693 } 694 document.body.removeChild(form); 695 if (this.controlPanel.closeAfterTests()) { 696 window.top.close(); 697 } 698 }, 699 700 _saveToFile: function (fileName, form) { 701 // This only works when run as an IE HTA 702 var inputs = new Object(); 703 for (var i = 0; i < form.elements.length; i++) { 704 inputs[form.elements[i].name] = form.elements[i].value; 705 } 706 var objFSO = new ActiveXObject("Scripting.FileSystemObject") 707 var scriptFile = objFSO.CreateTextFile(fileName); 708 scriptFile.WriteLine("<html><body>\n<h1>Test suite results </h1>" + 709 "\n\n<table>\n<tr>\n<td>result:</td>\n<td>" + inputs["result"] + "</td>\n" + 710 "</tr>\n<tr>\n<td>totalTime:</td>\n<td>" + inputs["totalTime"] + "</td>\n</tr>\n" + 711 "<tr>\n<td>numTestPasses:</td>\n<td>" + inputs["numTestPasses"] + "</td>\n</tr>\n" + 712 "<tr>\n<td>numTestFailures:</td>\n<td>" + inputs["numTestFailures"] + "</td>\n</tr>\n" + 713 "<tr>\n<td>numCommandPasses:</td>\n<td>" + inputs["numCommandPasses"] + "</td>\n</tr>\n" + 714 "<tr>\n<td>numCommandFailures:</td>\n<td>" + inputs["numCommandFailures"] + "</td>\n</tr>\n" + 715 "<tr>\n<td>numCommandErrors:</td>\n<td>" + inputs["numCommandErrors"] + "</td>\n</tr>\n" + 716 "<tr>\n<td>" + inputs["suite"] + "</td>\n<td> </td>\n</tr>"); 717 var testNum = inputs["numTestTotal"]; 718 for (var rowNum = 1; rowNum < testNum; rowNum++) { 719 scriptFile.WriteLine("<tr>\n<td>" + inputs["testTable." + rowNum] + "</td>\n<td> </td>\n</tr>"); 720 } 721 scriptFile.WriteLine("</table></body></html>"); 722 scriptFile.Close(); 723 } 724 }); 725 726 /** HtmlTestCase encapsulates an HTML test document */ 727 var HtmlTestCase = Class.create(); 728 Object.extend(HtmlTestCase.prototype, { 729 730 initialize: function(testDocument, htmlTestSuiteRow) { 731 if (testDocument == null) { 732 throw "testDocument should not be null"; 733 } 734 if (htmlTestSuiteRow == null) { 735 throw "htmlTestSuiteRow should not be null"; 736 } 737 this.testDocument = testDocument; 738 this.htmlTestSuiteRow = htmlTestSuiteRow; 739 this.commandRows = this._collectCommandRows(); 740 this.nextCommandRowIndex = 0; 741 this._addBreakpointSupport(); 742 }, 743 744 _collectCommandRows: function () { 745 var commandRows = []; 746 var tables = $A(this.testDocument.getElementsByTagName("table")); 747 var self = this; 748 tables.each(function (table) { 749 $A(table.rows).each(function(candidateRow) { 750 if (self.isCommandRow(candidateRow)) { 751 commandRows.push(new HtmlTestCaseRow(candidateRow)); 752 } 753 }.bind(this)); 754 }); 755 return commandRows; 756 }, 757 758 isCommandRow: function (row) { 759 return row.cells.length >= 3; 760 }, 761 762 reset: function() { 763 /** 764 * reset the test to runnable state 765 */ 766 this.nextCommandRowIndex = 0; 767 768 this._setTitleColor(''); 769 this.commandRows.each(function(row) { 770 row.reset(); 771 }); 772 773 // remove any additional fake "error" row added to the end of the document 774 var errorElement = this.testDocument.getElementById('error'); 775 if (errorElement) { 776 Element.remove(errorElement); 777 } 778 }, 779 780 getCommandRows: function () { 781 return this.commandRows; 782 }, 783 784 _setTitleColor: function(color) { 785 var headerRow = this.testDocument.getElementsByTagName("tr")[0]; 786 if (headerRow) { 787 headerRow.bgColor = color; 788 } 789 }, 790 791 markFailed: function() { 792 this._setTitleColor(FeedbackColors.failColor); 793 this.htmlTestSuiteRow.markFailed(); 794 }, 795 796 markPassed: function() { 797 this._setTitleColor(FeedbackColors.passColor); 798 this.htmlTestSuiteRow.markPassed(); 799 }, 800 801 addErrorMessage: function(errorMsg, currentRow) { 802 if (currentRow) { 803 currentRow.markFailed(errorMsg); 804 } else { 805 var errorElement = this.testDocument.createElement("p"); 806 errorElement.id = "error"; 807 errorElement.innerHTML = errorMsg; 808 this.testDocument.body.appendChild(errorElement); 809 Element.setStyle(errorElement, {'backgroundColor': FeedbackColors.failColor}); 810 } 811 }, 812 813 _addBreakpointSupport: function() { 814 this.commandRows.each(function(row) { 815 row.addBreakpointSupport(); 816 }); 817 }, 818 819 hasMoreCommandRows: function() { 820 return this.nextCommandRowIndex < this.commandRows.length; 821 }, 822 823 getNextCommandRow: function() { 824 if (this.hasMoreCommandRows()) { 825 return this.commandRows[this.nextCommandRowIndex++]; 826 } 827 return null; 828 } 829 830 }); 831 832 833 // TODO: split out an JavascriptTestCase class to handle the "sejs" stuff 834 835 var get_new_rows = function() { 836 var row_array = new Array(); 837 for (var i = 0; i < new_block.length; i++) { 838 839 var new_source = (new_block[i][0].tokenizer.source.slice(new_block[i][0].start, 840 new_block[i][0].end)); 841 842 var row = '<td style="display:none;" class="js">getEval</td>' + 843 '<td style="display:none;">currentTest.doNextCommand()</td>' + 844 '<td style="white-space: pre;">' + new_source + '</td>' + 845 '<td></td>' 846 847 row_array.push(row); 848 } 849 return row_array; 850 }; 851 852 853 var Metrics = Class.create(); 854 Object.extend(Metrics.prototype, { 855 initialize: function() { 856 // The number of tests run 857 this.numTestPasses = 0; 858 // The number of tests that have failed 859 this.numTestFailures = 0; 860 // The number of commands which have passed 861 this.numCommandPasses = 0; 862 // The number of commands which have failed 863 this.numCommandFailures = 0; 864 // The number of commands which have caused errors (element not found) 865 this.numCommandErrors = 0; 866 // The time that the test was started. 867 this.startTime = null; 868 // The current time. 869 this.currentTime = null; 870 }, 871 872 printMetrics: function() { 873 setText($('commandPasses'), this.numCommandPasses); 874 setText($('commandFailures'), this.numCommandFailures); 875 setText($('commandErrors'), this.numCommandErrors); 876 setText($('testRuns'), this.numTestPasses + this.numTestFailures); 877 setText($('testFailures'), this.numTestFailures); 878 879 this.currentTime = new Date().getTime(); 880 881 var timeDiff = this.currentTime - this.startTime; 882 var totalSecs = Math.floor(timeDiff / 1000); 883 884 var minutes = Math.floor(totalSecs / 60); 885 var seconds = totalSecs % 60; 886 887 setText($('elapsedTime'), this._pad(minutes) + ":" + this._pad(seconds)); 888 }, 889 890 // Puts a leading 0 on num if it is less than 10 891 _pad: function(num) { 892 return (num > 9) ? num : "0" + num; 893 }, 894 895 resetMetrics: function() { 896 this.numTestPasses = 0; 897 this.numTestFailures = 0; 898 this.numCommandPasses = 0; 899 this.numCommandFailures = 0; 900 this.numCommandErrors = 0; 901 this.startTime = new Date().getTime(); 902 } 903 904 }); 905 906 var HtmlRunnerCommandFactory = Class.create(); 907 Object.extend(HtmlRunnerCommandFactory.prototype, { 908 909 initialize: function(seleniumCommandFactory, testLoop) { 910 this.seleniumCommandFactory = seleniumCommandFactory; 911 this.testLoop = testLoop; 912 this.handlers = { 913 pause: { 914 execute: function(selenium, command) { 915 testLoop.pauseInterval = command.target; 916 return {}; 917 } 918 } 919 }; 920 //todo: register commands 921 }, 922 923 getCommandHandler: function(command) { 924 if (this.handlers[command]) { 925 return this.handlers[command]; 926 } 927 return this.seleniumCommandFactory.getCommandHandler(command); 928 } 929 930 }); 931 932 var HtmlRunnerTestLoop = Class.create(); 933 Object.extend(HtmlRunnerTestLoop.prototype, new TestLoop()); 934 Object.extend(HtmlRunnerTestLoop.prototype, { 935 initialize: function(htmlTestCase, metrics, seleniumCommandFactory) { 936 937 this.commandFactory = new HtmlRunnerCommandFactory(seleniumCommandFactory, this); 938 this.metrics = metrics; 939 940 this.htmlTestCase = htmlTestCase; 941 942 se = selenium; 943 global.se = selenium; 944 945 this.currentRow = null; 946 this.currentRowIndex = 0; 947 948 // used for selenium tests in javascript 949 this.currentItem = null; 950 this.commandAgenda = new Array(); 951 952 this.htmlTestCase.reset(); 953 954 this.sejsElement = this.htmlTestCase.testDocument.getElementById('sejs'); 955 if (this.sejsElement) { 956 var fname = 'Selenium JavaScript'; 957 parse_result = parse(this.sejsElement.innerHTML, fname, 0); 958 959 var x2 = new ExecutionContext(GLOBAL_CODE); 960 ExecutionContext.current = x2; 961 962 execute(parse_result, x2) 963 } 964 }, 965 966 _advanceToNextRow: function() { 967 if (this.htmlTestCase.hasMoreCommandRows()) { 968 this.currentRow = this.htmlTestCase.getNextCommandRow(); 969 if (this.sejsElement) { 970 this.currentItem = agenda.pop(); 971 this.currentRowIndex++; 972 } 973 } else { 974 this.currentRow = null; 975 this.currentItem = null; 976 } 977 }, 978 979 nextCommand : function() { 980 this._advanceToNextRow(); 981 if (this.currentRow == null) { 982 return null; 983 } 984 return this.currentRow.getCommand(); 985 }, 986 987 commandStarted : function() { 988 $('pauseTest').disabled = false; 989 this.currentRow.markWorking(); 990 this.metrics.printMetrics(); 991 }, 992 993 commandComplete : function(result) { 994 if (result.failed) { 995 this.metrics.numCommandFailures += 1; 996 this._recordFailure(result.failureMessage); 997 } else if (result.passed) { 998 this.metrics.numCommandPasses += 1; 999 this.currentRow.markPassed(); 1000 } else { 1001 this.currentRow.markDone(); 1002 } 1003 }, 1004 1005 commandError : function(errorMessage) { 1006 this.metrics.numCommandErrors += 1; 1007 this._recordFailure(errorMessage); 1008 }, 1009 1010 _recordFailure : function(errorMsg) { 1011 LOG.warn("currentTest.recordFailure: " + errorMsg); 1012 htmlTestRunner.markFailed(); 1013 this.htmlTestCase.addErrorMessage(errorMsg, this.currentRow); 1014 }, 1015 1016 testComplete : function() { 1017 $('pauseTest').disabled = true; 1018 $('stepTest').disabled = true; 1019 if (htmlTestRunner.testFailed) { 1020 this.htmlTestCase.markFailed(); 1021 this.metrics.numTestFailures += 1; 1022 } else { 1023 this.htmlTestCase.markPassed(); 1024 this.metrics.numTestPasses += 1; 1025 } 1026 1027 this.metrics.printMetrics(); 1028 1029 window.setTimeout(function() { 1030 htmlTestRunner.runNextTest(); 1031 }, 1); 1032 }, 1033 1034 getCommandInterval : function() { 1035 return htmlTestRunner.controlPanel.runInterval; 1036 }, 1037 1038 pause : function() { 1039 htmlTestRunner.controlPanel.pauseCurrentTest(); 1040 }, 1041 1042 doNextCommand: function() { 1043 var _n = this.currentItem[0]; 1044 var _x = this.currentItem[1]; 1045 1046 new_block = new Array() 1047 execute(_n, _x); 1048 if (new_block.length > 0) { 1049 var the_table = this.htmlTestCase.testDocument.getElementById("se-js-table") 1050 var loc = this.currentRowIndex 1051 var new_rows = get_new_rows() 1052 1053 // make the new statements visible on screen... 1054 for (var i = 0; i < new_rows.length; i++) { 1055 the_table.insertRow(loc + 1); 1056 the_table.rows[loc + 1].innerHTML = new_rows[i]; 1057 this.commandRows.unshift(the_table.rows[loc + 1]) 1058 } 1059 1060 } 1061 } 1062 1063 }); 1064 1065 1066 Selenium.prototype.doBreak = function() { 1067 /** Halt the currently running test, and wait for the user to press the Continue button. 1068 * This command is useful for debugging, but be careful when using it, because it will 1069 * force automated tests to hang until a user intervenes manually. 1070 */ 1071 // todo: should not refer to controlPanel directly 1072 htmlTestRunner.controlPanel.setToPauseAtNextCommand(); 1073 }; 1074 1075 Selenium.prototype.doStore = function(expression, variableName) { 1076 /** This command is a synonym for storeExpression. 1077 * @param expression the value to store 1078 * @param variableName the name of a <a href="#storedVars">variable</a> in which the result is to be stored. 1079 */ 1080 storedVars[variableName] = expression; 1081 } 1082 1083 /* 1084 * Click on the located element, and attach a callback to notify 1085 * when the page is reloaded. 1086 */ 1087 // DGF TODO this code has been broken for some time... what is it trying to accomplish? 1088 Selenium.prototype.XXXdoModalDialogTest = function(returnValue) { 1089 this.browserbot.doModalDialogTest(returnValue); 1090 }; 1091 1092 Selenium.prototype.doEcho = function(message) { 1093 /** Prints the specified message into the third table cell in your Selenese tables. 1094 * Useful for debugging. 1095 * @param message the message to print 1096 */ 1097 currentTest.currentRow.setMessage(message); 1098 } 1099 1100 Selenium.prototype.assertSelected = function(selectLocator, optionLocator) { 1101 /** 1102 * 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> 1103 * 1104 * <p>See the select command for more information about option locators.</p> 1105 * 1106 * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu 1107 * @param optionLocator an option locator, typically just an option label (e.g. "John Smith") 1108 */ 1109 var element = this.page().findElement(selectLocator); 1110 var locator = this.optionLocatorFactory.fromLocatorString(optionLocator); 1111 if (element.selectedIndex == -1) 1112 { 1113 Assert.fail("No option selected"); 1114 } 1115 locator.assertSelected(element); 1116 }; 1117 1118 /** 1119 * Tell Selenium to expect a failure on the next command execution. This 1120 * command temporarily installs a CommandFactory that generates 1121 * CommandHandlers that expect a failure. 1122 */ 1123 Selenium.prototype.assertFailureOnNext = function(message) { 1124 if (!message) { 1125 throw new Error("Message must be provided"); 1126 } 1127 1128 var expectFailureCommandFactory = 1129 new ExpectFailureCommandFactory(currentTest.commandFactory, message, "failure", executeCommandAndReturnFailureMessage); 1130 currentTest.commandFactory = expectFailureCommandFactory; 1131 }; 1132 1133 /** 1134 * Tell Selenium to expect an error on the next command execution. This 1135 * command temporarily installs a CommandFactory that generates 1136 * CommandHandlers that expect a failure. 1137 */ 1138 Selenium.prototype.assertErrorOnNext = function(message) { 1139 if (!message) { 1140 throw new Error("Message must be provided"); 1141 } 1142 1143 var expectFailureCommandFactory = 1144 new ExpectFailureCommandFactory(currentTest.commandFactory, message, "error", executeCommandAndReturnErrorMessage); 1145 currentTest.commandFactory = expectFailureCommandFactory; 1146 }; 1147 1148 function executeCommandAndReturnFailureMessage(baseHandler, originalArguments) { 1149 var baseResult = baseHandler.execute.apply(baseHandler, originalArguments); 1150 if (baseResult.passed) { 1151 return null; 1152 } 1153 return baseResult.failureMessage; 1154 }; 1155 1156 function executeCommandAndReturnErrorMessage(baseHandler, originalArguments) { 1157 try { 1158 baseHandler.execute.apply(baseHandler, originalArguments); 1159 return null; 1160 } 1161 catch (expected) { 1162 return expected.message; 1163 } 1164 }; 1165 1166 function ExpectFailureCommandHandler(baseHandler, originalCommandFactory, expectedErrorMessage, errorType, decoratedExecutor) { 1167 this.execute = function() { 1168 var baseFailureMessage = decoratedExecutor(baseHandler, arguments); 1169 var result = {}; 1170 if (!baseFailureMessage) { 1171 result.failed = true; 1172 result.failureMessage = "Expected " + errorType + " did not occur."; 1173 } 1174 else { 1175 if (! PatternMatcher.matches(expectedErrorMessage, baseFailureMessage)) { 1176 result.failed = true; 1177 result.failureMessage = "Expected " + errorType + " message '" + expectedErrorMessage 1178 + "' but was '" + baseFailureMessage + "'"; 1179 } 1180 else { 1181 result.passed = true; 1182 result.result = baseFailureMessage; 1183 } 1184 } 1185 currentTest.commandFactory = originalCommandFactory; 1186 return result; 1187 }; 1188 } 1189 1190 function ExpectFailureCommandFactory(originalCommandFactory, expectedErrorMessage, errorType, decoratedExecutor) { 1191 this.getCommandHandler = function(name) { 1192 var baseHandler = originalCommandFactory.getCommandHandler(name); 1193 return new ExpectFailureCommandHandler(baseHandler, originalCommandFactory, expectedErrorMessage, errorType, decoratedExecutor); 1194 }; 1195 };
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 21:07:04 2007 | par Balluche grâce à PHPXref 0.7 |