witten
/
luminotes
Archived
1
0
Fork 0
This repository has been archived on 2023-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
luminotes/static/jsunit/app/jsUnitTestManager.js

706 lines
24 KiB
JavaScript

function jsUnitTestManager() {
this._windowForAllProblemMessages = null;
this.container = top.frames.testContainer
this.documentLoader = top.frames.documentLoader;
this.mainFrame = top.frames.mainFrame;
this.containerController = this.container.frames.testContainerController;
this.containerTestFrame = this.container.frames.testFrame;
var mainData = this.mainFrame.frames.mainData;
// form elements on mainData frame
this.testFileName = mainData.document.testRunnerForm.testFileName;
this.runButton = mainData.document.testRunnerForm.runButton;
this.traceLevel = mainData.document.testRunnerForm.traceLevel;
this.closeTraceWindowOnNewRun = mainData.document.testRunnerForm.closeTraceWindowOnNewRun;
this.timeout = mainData.document.testRunnerForm.timeout;
this.setUpPageTimeout = mainData.document.testRunnerForm.setUpPageTimeout;
// image output
this.progressBar = this.mainFrame.frames.mainProgress.document.progress;
this.problemsListField = this.mainFrame.frames.mainErrors.document.testRunnerForm.problemsList;
this.testCaseResultsField = this.mainFrame.frames.mainResults.document.resultsForm.testCases;
this.resultsTimeField = this.mainFrame.frames.mainResults.document.resultsForm.time;
// 'layer' output frames
this.uiFrames = new Object();
this.uiFrames.mainStatus = this.mainFrame.frames.mainStatus;
var mainCounts = this.mainFrame.frames.mainCounts;
this.uiFrames.mainCountsErrors = mainCounts.frames.mainCountsErrors;
this.uiFrames.mainCountsFailures = mainCounts.frames.mainCountsFailures;
this.uiFrames.mainCountsRuns = mainCounts.frames.mainCountsRuns;
this._baseURL = "";
this.setup();
}
// seconds to wait for each test page to load
jsUnitTestManager.TESTPAGE_WAIT_SEC = 120;
jsUnitTestManager.TIMEOUT_LENGTH = 20;
// seconds to wait for setUpPage to complete
jsUnitTestManager.SETUPPAGE_TIMEOUT = 120;
// milliseconds to wait between polls on setUpPages
jsUnitTestManager.SETUPPAGE_INTERVAL = 100;
jsUnitTestManager.RESTORED_HTML_DIV_ID = "jsUnitRestoredHTML";
jsUnitTestManager.prototype.setup = function () {
this.totalCount = 0;
this.errorCount = 0;
this.failureCount = 0;
this._suiteStack = Array();
var initialSuite = new top.jsUnitTestSuite();
push(this._suiteStack, initialSuite);
}
jsUnitTestManager.prototype.start = function () {
this._baseURL = this.resolveUserEnteredTestFileName();
var firstQuery = this._baseURL.indexOf("?");
if (firstQuery >= 0) {
this._baseURL = this._baseURL.substring(0, firstQuery);
}
var lastSlash = this._baseURL.lastIndexOf("/");
var lastRevSlash = this._baseURL.lastIndexOf("\\");
if (lastRevSlash > lastSlash) {
lastSlash = lastRevSlash;
}
if (lastSlash > 0) {
this._baseURL = this._baseURL.substring(0, lastSlash + 1);
}
this._timeRunStarted = new Date();
this.initialize();
setTimeout('top.testManager._nextPage();', jsUnitTestManager.TIMEOUT_LENGTH);
}
jsUnitTestManager.prototype.getBaseURL = function () {
return this._baseURL;
}
jsUnitTestManager.prototype.doneLoadingPage = function (pageName) {
//this.containerTestFrame.setTracer(top.tracer);
this._testFileName = pageName;
if (this.isTestPageSuite())
this._handleNewSuite();
else
{
this._testIndex = 0;
this._testsInPage = this.getTestFunctionNames();
this._numberOfTestsInPage = this._testsInPage.length;
this._runTest();
}
}
jsUnitTestManager.prototype._handleNewSuite = function () {
var allegedSuite = this.containerTestFrame.suite();
if (allegedSuite.isjsUnitTestSuite) {
var newSuite = allegedSuite.clone();
if (newSuite.containsTestPages())
push(this._suiteStack, newSuite);
this._nextPage();
}
else {
this.fatalError('Invalid test suite in file ' + this._testFileName);
this.abort();
}
}
jsUnitTestManager.prototype._runTest = function () {
if (this._testIndex + 1 > this._numberOfTestsInPage)
{
// execute tearDownPage *synchronously*
// (unlike setUpPage which is asynchronous)
if (typeof this.containerTestFrame.tearDownPage == 'function') {
this.containerTestFrame.tearDownPage();
}
this._nextPage();
return;
}
if (this._testIndex == 0) {
this.storeRestoredHTML();
if (typeof(this.containerTestFrame.setUpPage) == 'function') {
// first test for this page and a setUpPage is defined
if (typeof(this.containerTestFrame.setUpPageStatus) == 'undefined') {
// setUpPage() not called yet, so call it
this.containerTestFrame.setUpPageStatus = false;
this.containerTestFrame.startTime = new Date();
this.containerTestFrame.setUpPage();
// try test again later
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL);
return;
}
if (this.containerTestFrame.setUpPageStatus != 'complete') {
top.status = 'setUpPage not completed... ' + this.containerTestFrame.setUpPageStatus + ' ' + (new Date());
if ((new Date() - this.containerTestFrame.startTime) / 1000 > this.getsetUpPageTimeout()) {
this.fatalError('setUpPage timed out without completing.');
if (!this.userConfirm('Retry Test Run?')) {
this.abort();
return;
}
this.containerTestFrame.startTime = (new Date());
}
// try test again later
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL);
return;
}
}
}
top.status = '';
// either not first test, or no setUpPage defined, or setUpPage completed
this.executeTestFunction(this._testsInPage[this._testIndex]);
this.totalCount++;
this.updateProgressIndicators();
this._testIndex++;
setTimeout('top.testManager._runTest()', jsUnitTestManager.TIMEOUT_LENGTH);
}
jsUnitTestManager.prototype._done = function () {
var secondsSinceRunBegan = (new Date() - this._timeRunStarted) / 1000;
this.setStatus('Done (' + secondsSinceRunBegan + ' seconds)');
this._cleanUp();
if (top.shouldSubmitResults()) {
this.resultsTimeField.value = secondsSinceRunBegan;
top.submitResults();
}
}
jsUnitTestManager.prototype._nextPage = function () {
this._restoredHTML = null;
if (this._currentSuite().hasMorePages()) {
this.loadPage(this._currentSuite().nextPage());
}
else {
pop(this._suiteStack);
if (this._currentSuite() == null)
this._done();
else
this._nextPage();
}
}
jsUnitTestManager.prototype._currentSuite = function () {
var suite = null;
if (this._suiteStack && this._suiteStack.length > 0)
suite = this._suiteStack[this._suiteStack.length - 1];
return suite;
}
jsUnitTestManager.prototype.calculateProgressBarProportion = function () {
if (this.totalCount == 0)
return 0;
var currentDivisor = 1;
var result = 0;
for (var i = 0; i < this._suiteStack.length; i++) {
var aSuite = this._suiteStack[i];
currentDivisor *= aSuite.testPages.length;
result += (aSuite.pageIndex - 1) / currentDivisor;
}
result += (this._testIndex + 1) / (this._numberOfTestsInPage * currentDivisor);
return result;
}
jsUnitTestManager.prototype._cleanUp = function () {
this.containerController.setTestPage('./app/emptyPage.html');
this.finalize();
top.tracer.finalize();
}
jsUnitTestManager.prototype.abort = function () {
this.setStatus('Aborted');
this._cleanUp();
}
jsUnitTestManager.prototype.getTimeout = function () {
var result = jsUnitTestManager.TESTPAGE_WAIT_SEC;
try {
result = eval(this.timeout.value);
}
catch (e) {
}
return result;
}
jsUnitTestManager.prototype.getsetUpPageTimeout = function () {
var result = jsUnitTestManager.SETUPPAGE_TIMEOUT;
try {
result = eval(this.setUpPageTimeout.value);
}
catch (e) {
}
return result;
}
jsUnitTestManager.prototype.isTestPageSuite = function () {
var result = false;
if (typeof(this.containerTestFrame.suite) == 'function')
{
result = true;
}
return result;
}
jsUnitTestManager.prototype.getTestFunctionNames = function () {
var testFrame = this.containerTestFrame;
var testFunctionNames = new Array();
var i;
if (testFrame && typeof(testFrame.exposeTestFunctionNames) == 'function')
return testFrame.exposeTestFunctionNames();
if (testFrame &&
testFrame.document &&
typeof(testFrame.document.scripts) != 'undefined' &&
testFrame.document.scripts.length > 0) { // IE5 and up
var scriptsInTestFrame = testFrame.document.scripts;
for (i = 0; i < scriptsInTestFrame.length; i++) {
var someNames = this._extractTestFunctionNamesFromScript(scriptsInTestFrame[i]);
if (someNames)
testFunctionNames = testFunctionNames.concat(someNames);
}
}
else {
for (i in testFrame) {
if (i.substring(0, 4) == 'test' && typeof(testFrame[i]) == 'function')
push(testFunctionNames, i);
}
}
return testFunctionNames;
}
jsUnitTestManager.prototype._extractTestFunctionNamesFromScript = function (aScript) {
var result;
var remainingScriptToInspect = aScript.text;
var currentIndex = this._indexOfTestFunctionIn(remainingScriptToInspect);
while (currentIndex != -1) {
if (!result)
result = new Array();
var fragment = remainingScriptToInspect.substring(currentIndex, remainingScriptToInspect.length);
result = result.concat(fragment.substring('function '.length, fragment.indexOf('(')));
remainingScriptToInspect = remainingScriptToInspect.substring(currentIndex + 12, remainingScriptToInspect.length);
currentIndex = this._indexOfTestFunctionIn(remainingScriptToInspect);
}
return result;
}
jsUnitTestManager.prototype._indexOfTestFunctionIn = function (string) {
return string.indexOf('function test');
}
jsUnitTestManager.prototype.loadPage = function (testFileName) {
this._testFileName = testFileName;
this._loadAttemptStartTime = new Date();
this.setStatus('Opening Test Page "' + this._testFileName + '"');
this.containerController.setTestPage(this._testFileName);
this._callBackWhenPageIsLoaded();
}
jsUnitTestManager.prototype._callBackWhenPageIsLoaded = function () {
if ((new Date() - this._loadAttemptStartTime) / 1000 > this.getTimeout()) {
this.fatalError('Reading Test Page ' + this._testFileName + ' timed out.\nMake sure that the file exists and is a Test Page.');
if (this.userConfirm('Retry Test Run?')) {
this.loadPage(this._testFileName);
return;
} else {
this.abort();
return;
}
}
if (!this._isTestFrameLoaded()) {
setTimeout('top.testManager._callBackWhenPageIsLoaded();', jsUnitTestManager.TIMEOUT_LENGTH);
return;
}
this.doneLoadingPage(this._testFileName);
}
jsUnitTestManager.prototype._isTestFrameLoaded = function () {
try {
return this.containerController.isPageLoaded();
}
catch (e) {
}
return false;
}
jsUnitTestManager.prototype.executeTestFunction = function (functionName) {
this._testFunctionName = functionName;
this.setStatus('Running test "' + this._testFunctionName + '"');
var excep = null;
var timeBefore = new Date();
try {
if (this._restoredHTML)
top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID).innerHTML = this._restoredHTML;
if (this.containerTestFrame.setUp !== JSUNIT_UNDEFINED_VALUE)
this.containerTestFrame.setUp();
this.containerTestFrame[this._testFunctionName]();
}
catch (e1) {
excep = e1;
}
finally {
try {
if (this.containerTestFrame.tearDown !== JSUNIT_UNDEFINED_VALUE)
this.containerTestFrame.tearDown();
}
catch (e2) {
//Unlike JUnit, only assign a tearDown exception to excep if there is not already an exception from the test body
if (excep == null)
excep = e2;
}
}
var timeTaken = (new Date() - timeBefore) / 1000;
if (excep != null)
this._handleTestException(excep);
var serializedTestCaseString = this._currentTestFunctionNameWithTestPageName(true) + "|" + timeTaken + "|";
if (excep == null)
serializedTestCaseString += "S||";
else {
if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException)
serializedTestCaseString += "F|";
else {
serializedTestCaseString += "E|";
}
serializedTestCaseString += this._problemDetailMessageFor(excep);
}
this._addOption(this.testCaseResultsField,
serializedTestCaseString,
serializedTestCaseString);
}
jsUnitTestManager.prototype._currentTestFunctionNameWithTestPageName = function(useFullyQualifiedTestPageName) {
var testURL = this.containerTestFrame.location.href;
var testQuery = testURL.indexOf("?");
if (testQuery >= 0) {
testURL = testURL.substring(0, testQuery);
}
if (!useFullyQualifiedTestPageName) {
if (testURL.substring(0, this._baseURL.length) == this._baseURL)
testURL = testURL.substring(this._baseURL.length);
}
return testURL + ':' + this._testFunctionName;
}
jsUnitTestManager.prototype._addOption = function(listField, problemValue, problemMessage) {
if (typeof(listField.ownerDocument) != 'undefined'
&& typeof(listField.ownerDocument.createElement) != 'undefined') {
// DOM Level 2 HTML method.
// this is required for Opera 7 since appending to the end of the
// options array does not work, and adding an Option created by new Option()
// and appended by listField.options.add() fails due to WRONG_DOCUMENT_ERR
var problemDocument = listField.ownerDocument;
var errOption = problemDocument.createElement('option');
errOption.setAttribute('value', problemValue);
errOption.appendChild(problemDocument.createTextNode(problemMessage));
listField.appendChild(errOption);
}
else {
// new Option() is DOM 0
errOption = new Option(problemMessage, problemValue);
if (typeof(listField.add) != 'undefined') {
// DOM 2 HTML
listField.add(errOption, null);
}
else if (typeof(listField.options.add) != 'undefined') {
// DOM 0
listField.options.add(errOption, null);
}
else {
// DOM 0
listField.options[listField.length] = errOption;
}
}
}
jsUnitTestManager.prototype._handleTestException = function (excep) {
var problemMessage = this._currentTestFunctionNameWithTestPageName(false) + ' ';
var errOption;
if (typeof(excep.isJsUnitException) == 'undefined' || !excep.isJsUnitException) {
problemMessage += 'had an error';
this.errorCount++;
}
else {
problemMessage += 'failed';
this.failureCount++;
}
var listField = this.problemsListField;
this._addOption(listField,
this._problemDetailMessageFor(excep),
problemMessage);
}
jsUnitTestManager.prototype._problemDetailMessageFor = function (excep) {
var result = null;
if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException) {
result = '';
if (excep.comment != null)
result += ('"' + excep.comment + '"\n');
result += excep.jsUnitMessage;
if (excep.stackTrace)
result += '\n\nStack trace follows:\n' + excep.stackTrace;
}
else {
result = 'Error message is:\n"';
result +=
(typeof(excep.description) == 'undefined') ?
excep :
excep.description;
result += '"';
if (typeof(excep.stack) != 'undefined') // Mozilla only
result += '\n\nStack trace follows:\n' + excep.stack;
}
return result;
}
jsUnitTestManager.prototype._setTextOnLayer = function (layerName, str) {
try {
var content;
if (content = this.uiFrames[layerName].document.getElementById('content'))
content.innerHTML = str;
else
throw 'No content div found.';
}
catch (e) {
var html = '';
html += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
html += '<html><head><link rel="stylesheet" type="text/css" href="css/jsUnitStyle.css"><\/head>';
html += '<body><div id="content">';
html += str;
html += '<\/div><\/body>';
html += '<\/html>';
this.uiFrames[layerName].document.write(html);
this.uiFrames[layerName].document.close();
}
}
jsUnitTestManager.prototype.setStatus = function (str) {
this._setTextOnLayer('mainStatus', '<b>Status:<\/b> ' + str);
}
jsUnitTestManager.prototype._setErrors = function (n) {
this._setTextOnLayer('mainCountsErrors', '<b>Errors: <\/b>' + n);
}
jsUnitTestManager.prototype._setFailures = function (n) {
this._setTextOnLayer('mainCountsFailures', '<b>Failures:<\/b> ' + n);
}
jsUnitTestManager.prototype._setTotal = function (n) {
this._setTextOnLayer('mainCountsRuns', '<b>Runs:<\/b> ' + n);
}
jsUnitTestManager.prototype._setProgressBarImage = function (imgName) {
this.progressBar.src = imgName;
}
jsUnitTestManager.prototype._setProgressBarWidth = function (w) {
this.progressBar.width = w;
}
jsUnitTestManager.prototype.updateProgressIndicators = function () {
this._setTotal(this.totalCount);
this._setErrors(this.errorCount);
this._setFailures(this.failureCount);
this._setProgressBarWidth(300 * this.calculateProgressBarProportion());
if (this.errorCount > 0 || this.failureCount > 0)
this._setProgressBarImage('../images/red.gif');
else
this._setProgressBarImage('../images/green.gif');
}
jsUnitTestManager.prototype.showMessageForSelectedProblemTest = function () {
var problemTestIndex = this.problemsListField.selectedIndex;
if (problemTestIndex != -1)
this.fatalError(this.problemsListField[problemTestIndex].value);
}
jsUnitTestManager.prototype.showMessagesForAllProblemTests = function () {
if (this.problemsListField.length == 0)
return;
try {
if (this._windowForAllProblemMessages && !this._windowForAllProblemMessages.closed)
this._windowForAllProblemMessages.close();
}
catch(e) {
}
this._windowForAllProblemMessages = window.open('', '', 'width=600, height=350,status=no,resizable=yes,scrollbars=yes');
var resDoc = this._windowForAllProblemMessages.document;
resDoc.write('<html><head><link rel="stylesheet" href="../css/jsUnitStyle.css"><title>Tests with problems - JsUnit<\/title><head><body>');
resDoc.write('<p class="jsUnitSubHeading">Tests with problems (' + this.problemsListField.length + ' total) - JsUnit<\/p>');
resDoc.write('<p class="jsUnitSubSubHeading"><i>Running on ' + navigator.userAgent + '</i></p>');
for (var i = 0; i < this.problemsListField.length; i++)
{
resDoc.write('<p class="jsUnitDefault">');
resDoc.write('<b>' + (i + 1) + '. ');
resDoc.write(this.problemsListField[i].text);
resDoc.write('<\/b><\/p><p><pre>');
resDoc.write(this._makeHTMLSafe(this.problemsListField[i].value));
resDoc.write('<\/pre><\/p>');
}
resDoc.write('<\/body><\/html>');
resDoc.close();
}
jsUnitTestManager.prototype._makeHTMLSafe = function (string) {
string = string.replace(/&/g, '&amp;');
string = string.replace(/</g, '&lt;');
string = string.replace(/>/g, '&gt;');
return string;
}
jsUnitTestManager.prototype._clearProblemsList = function () {
var listField = this.problemsListField;
var initialLength = listField.options.length;
for (var i = 0; i < initialLength; i++)
listField.remove(0);
}
jsUnitTestManager.prototype.initialize = function () {
this.setStatus('Initializing...');
this._setRunButtonEnabled(false);
this._clearProblemsList();
this.updateProgressIndicators();
this.setStatus('Done initializing');
}
jsUnitTestManager.prototype.finalize = function () {
this._setRunButtonEnabled(true);
}
jsUnitTestManager.prototype._setRunButtonEnabled = function (b) {
this.runButton.disabled = !b;
}
jsUnitTestManager.prototype.getTestFileName = function () {
var rawEnteredFileName = this.testFileName.value;
var result = rawEnteredFileName;
while (result.indexOf('\\') != -1)
result = result.replace('\\', '/');
return result;
}
jsUnitTestManager.prototype.getTestFunctionName = function () {
return this._testFunctionName;
}
jsUnitTestManager.prototype.resolveUserEnteredTestFileName = function (rawText) {
var userEnteredTestFileName = top.testManager.getTestFileName();
// only test for file:// since Opera uses a different format
if (userEnteredTestFileName.indexOf('http://') == 0 || userEnteredTestFileName.indexOf('https://') == 0 || userEnteredTestFileName.indexOf('file://') == 0)
return userEnteredTestFileName;
return getTestFileProtocol() + this.getTestFileName();
}
jsUnitTestManager.prototype.storeRestoredHTML = function () {
if (document.getElementById && top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID))
this._restoredHTML = top.testContainer.testFrame.document.getElementById(jsUnitTestManager.RESTORED_HTML_DIV_ID).innerHTML;
}
jsUnitTestManager.prototype.fatalError = function(aMessage) {
if (top.shouldSubmitResults())
this.setStatus(aMessage);
else
alert(aMessage);
}
jsUnitTestManager.prototype.userConfirm = function(aMessage) {
if (top.shouldSubmitResults())
return false;
else
return confirm(aMessage);
}
function getTestFileProtocol() {
return getDocumentProtocol();
}
function getDocumentProtocol() {
var protocol = top.document.location.protocol;
if (protocol == "file:")
return "file:///";
if (protocol == "http:")
return "http://";
if (protocol == 'https:')
return 'https://';
if (protocol == "chrome:")
return "chrome://";
return null;
}
function browserSupportsReadingFullPathFromFileField() {
return !isOpera() && !isIE7();
}
function isOpera() {
return navigator.userAgent.toLowerCase().indexOf("opera") != -1;
}
function isIE7() {
return navigator.userAgent.toLowerCase().indexOf("msie 7") != -1;
}
function isBeingRunOverHTTP() {
return getDocumentProtocol() == "http://";
}
function getWebserver() {
if (isBeingRunOverHTTP()) {
var myUrl = location.href;
var myUrlWithProtocolStripped = myUrl.substring(myUrl.indexOf("/") + 2);
return myUrlWithProtocolStripped.substring(0, myUrlWithProtocolStripped.indexOf("/"));
}
return null;
}
// the functions push(anArray, anObject) and pop(anArray)
// exist because the JavaScript Array.push(anObject) and Array.pop()
// functions are not available in IE 5.0
function push(anArray, anObject) {
anArray[anArray.length] = anObject;
}
function pop(anArray) {
if (anArray.length >= 1) {
delete anArray[anArray.length - 1];
anArray.length--;
}
}
if (xbDEBUG.on) {
xbDebugTraceObject('window', 'jsUnitTestManager');
xbDebugTraceFunction('window', 'getTestFileProtocol');
xbDebugTraceFunction('window', 'getDocumentProtocol');
}