Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Commit

Permalink
Add support for reporting Mozilla stack traces to exception reporting.
Browse files Browse the repository at this point in the history
Handle opening trace window when popup blocking is enabled.

Implemented new jsUnitSetOnLoad() function to support catching window
onload events in Opera and Konqueror

Fixed problem in Opera where Error/Failure select box was not updated.

Reduce Mozilla strict warnings through safe access to jsUnitParmHash
via new jsUnitGetParm(propertyName) function.

Modified Files:
  testRunner.html app/jsUnitCore.js app/jsUnitTestManager.js
  app/jsUnitTestSuite.js app/jsUnitTracer.js app/main-data.html
  app/testContainerController.html
  • Loading branch information
bclary committed Feb 3, 2004
1 parent 4d5afa2 commit 1c2ecb2
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 72 deletions.
109 changes: 95 additions & 14 deletions app/jsUnitCore.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function fail(failureMessage) {
function error(errorMessage) {
var errorObject = new Object();
errorObject.description = errorMessage;
errorObject.stackTrace = getStackTrace();
throw errorObject;
}

Expand Down Expand Up @@ -211,15 +212,67 @@ function getFunctionName(aFunction) {
function getStackTrace() {
var result = '';

for (var a = arguments.caller; a != null; a = a.caller) {
result += '> ' + getFunctionName(a.callee) + '\n';
if (a.caller == a) {
result += '*';
break;
if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
for (var a = arguments.caller; a != null; a = a.caller) {
result += '> ' + getFunctionName(a.callee) + '\n';
if (a.caller == a) {
result += '*';
break;
}
}
}
else { // Mozilla, not ECMA
// fake an exception so we can get Mozilla's error stack
var testExcp;
try
{
foo.bar;
}
catch(testExcp)
{
var stack = parseErrorStack(testExcp);
for (var i = 1; i < stack.length; i++)
{
result += '> ' + stack[i] + '\n';
// result = stack.join('\n');
}
}
}

return result;

}

function parseErrorStack(excp)
{
var stack = [];
var name;

if (!excp || !excp.stack)
{
return stack;
}

var stacklist = excp.stack.split('\n');

for (var i = 0; i < stacklist.length - 1; i++)
{
var framedata = stacklist[i];

name = framedata.match(/^(\w*)/)[1];
if (!name) {
name = 'anonymous';
}

stack[stack.length] = name;
}
// remove top level anonymous functions to match IE

while (stack.length && stack[stack.length - 1] == 'anonymous')
{
stack.length = stack.length - 1;
}
return stack;
}

function JsUnitException(comment, message) {
Expand Down Expand Up @@ -289,7 +342,17 @@ function pop(anArray) {
}
}

if (top.xbDEBUG && top.xbDEBUG.on && top.testManager)
// safe, strict access to jsUnitParmHash
function jsUnitGetParm(name)
{
if (typeof(top.jsUnitParmHash[name]) != 'undefined')
{
return top.jsUnitParmHash[name];
}
return null;
}

if (top && typeof(top.xbDEBUG) != 'undefined' && top.xbDEBUG.on && top.testManager)
{
top.xbDebugTraceObject('top.testManager.containerTestFrame', 'JSUnitException');
// asserts
Expand Down Expand Up @@ -330,11 +393,29 @@ function newOnLoadEvent() {
isTestPageLoaded = true;
}

if (window.attachEvent) {
window.attachEvent("onload", newOnLoadEvent);
} else if (window.addEventListener) {
window.addEventListener("load", newOnLoadEvent, false);
} else {
// browsers that do not support window.attachEvent or window.addEventListener will not override a page's own onload event
window.onload=newOnLoadEvent;
}
function jsUnitSetOnLoad(windowRef, onloadHandler)
{
var isKonqueror = navigator.userAgent.indexOf('Konqueror/') != -1;

if (typeof(windowRef.attachEvent) != 'undefined') {
// Internet Explorer, Opera
windowRef.attachEvent("onload", onloadHandler);
} else if (typeof(windowRef.addEventListener) != 'undefined' && !isKonqueror){
// Mozilla, Konqueror
// exclude Konqueror due to load issues
windowRef.addEventListener("load", onloadHandler, false);
} else if (typeof(windowRef.document.addEventListener) != 'undefined' && !isKonqueror) {
// DOM 2 Events
// exclude Mozilla, Konqueror due to load issues
windowRef.document.addEventListener("load", onloadHandler, false);
} else if (typeof(windowRef.onload) != 'undefined' && windowRef.onload) {
windowRef.jsunit_original_onload = windowRef.onload;
windowRef.onload = function() { windowRef.jsunit_original_onload(); onloadHandler(); };
} else {
// browsers that do not support windowRef.attachEvent or
// windowRef.addEventListener will override a page's own onload event
windowRef.onload=onloadHandler;
}
}

jsUnitSetOnLoad(window, newOnLoadEvent);
64 changes: 46 additions & 18 deletions app/jsUnitTestManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ jsUnitTestManager.prototype.start = function ()
{
this._timeRunStarted = new Date();
this.initialize();
top.tracer.initialize();
setTimeout('top.testManager._nextPage();', jsUnitTestManager.TIMEOUT_LENGTH);
}

Expand Down Expand Up @@ -156,7 +155,7 @@ jsUnitTestManager.prototype._runTest = function ()
this.containerTestFrame.startTime = new Date();
this.containerTestFrame.setUpPage();
// try test again later
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPAGE_INTERVAL);
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL);
return;
}

Expand All @@ -174,7 +173,7 @@ jsUnitTestManager.prototype._runTest = function ()
this.containerTestFrame.startTime = (new Date());
}
// try test again later
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPAGE_INTERVAL);
setTimeout('top.testManager._runTest()', jsUnitTestManager.SETUPPAGE_INTERVAL);
return;
}
}
Expand Down Expand Up @@ -276,12 +275,10 @@ jsUnitTestManager.prototype.getsetUpPageTimeout = function ()

jsUnitTestManager.prototype.isTestPageSuite = function ()
{
var result = true;
try {
this.containerTestFrame.suite();
}
catch (e) {
result = false;
var result = false;
if (typeof(this.containerTestFrame.suite) == 'function')
{
result = true;
}
return result;
}
Expand All @@ -292,13 +289,15 @@ jsUnitTestManager.prototype.getTestFunctionNames = function ()
var testFunctionNames = new Array();
var i;

if (testFrame && testFrame.exposeTestFunctionNames)
if (testFrame && typeof(testFrame.exposeTestFunctionNames) == 'function')
return testFrame.exposeTestFunctionNames();

if (testFrame && testFrame.document && testFrame.document.scripts) { // IE5 and up
if (testFrame &&
testFrame.document &&
typeof(testFrame.document.scripts) != 'undefined') { // IE5 and up
var scriptsInTestFrame = testFrame.document.scripts;

for (var i = 0; i < scriptsInTestFrame.length; i++) {
for (i = 0; i < scriptsInTestFrame.length; i++) {
var someNames = this._extractTestFunctionNamesFromScript(scriptsInTestFrame[i]);
if (someNames)
testFunctionNames=testFunctionNames.concat(someNames);
Expand Down Expand Up @@ -394,7 +393,7 @@ jsUnitTestManager.prototype.executeTestFunction = function (functionName)
if (excep==null)
serializedTestCaseString+="S||";
else {
if (excep.isJsUnitException)
if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException)
serializedTestCaseString+="F|";
else {
serializedTestCaseString+="E|";
Expand All @@ -412,7 +411,8 @@ jsUnitTestManager.prototype._fullyQualifiedCurrentTestFunctionName = function()
jsUnitTestManager.prototype._handleTestException = function (excep)
{
var problemMessage = this._fullyQualifiedCurrentTestFunctionName() + ' ';
if (!excep.isJsUnitException) {
var errOption;
if (typeof(excep.isJsUnitException) == 'undefined' || !excep.isJsUnitException) {
problemMessage += 'had an error';
this.errorCount++;
}
Expand All @@ -421,13 +421,39 @@ jsUnitTestManager.prototype._handleTestException = function (excep)
this.failureCount++;
}
var listField = this.problemsListField;
listField.options[listField.length]=new Option(problemMessage, this._problemDetailMessageFor(excep));
var problemDocument = this.mainFrame.frames.mainErrors.document;
if (typeof(problemDocument.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
errOption = problemDocument.createElement('option');
errOption.setAttribute('value', this._problemDetailMessageFor(excep));
errOption.appendChild(problemDocument.createTextNode(problemMessage));
listField.appendChild(errOption);
}
else {
// new Option() is DOM 0
errOption = new Option(problemMessage, this._problemDetailMessageFor(excep));
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._problemDetailMessageFor = function (excep)
{
var result=null;
if (excep.isJsUnitException) {
if (typeof(excep.isJsUnitException) != 'undefined' && excep.isJsUnitException) {
result = '';
if (excep.comment != null)
result+=('"'+excep.comment+'"\n');
Expand All @@ -440,10 +466,12 @@ jsUnitTestManager.prototype._problemDetailMessageFor = function (excep)
else {
result = 'Error message is:\n"';
result +=
(excep.description == top.JSUNIT_UNDEFINED_VALUE) ?
(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;
}
Expand Down Expand Up @@ -623,7 +651,7 @@ function isBeingRunOverHTTP() {

function getWebserver() {
if (isBeingRunOverHTTP()) {
var myUrl = loc = location.href;
var myUrl = location.href;
var myUrlWithProtocolStripped = myUrl.substring(myUrl.indexOf("/") + 2);
return myUrlWithProtocolStripped.substring(0, myUrlWithProtocolStripped.indexOf("/"));
}
Expand Down
6 changes: 2 additions & 4 deletions app/jsUnitTestSuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,13 @@ function jsUnitTestSuite() {

jsUnitTestSuite.prototype.addTestPage = function (pageName)
{
with (this)
testPages[testPages.length] = pageName;
this.testPages[this.testPages.length] = pageName;
}

jsUnitTestSuite.prototype.addTestSuite = function (suite)
{
with (this)
for (var i = 0; i < suite.testPages.length; i++)
addTestPage(suite.testPages[i]);
this.addTestPage(suite.testPages[i]);
}

jsUnitTestSuite.prototype.containsTestPages = function ()
Expand Down
14 changes: 10 additions & 4 deletions app/jsUnitTracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function jsUnitTracer() {
this.TRACE_LEVEL_WARNING = 1;
this.TRACE_LEVEL_INFO = 2;
this.TRACE_LEVEL_DEBUG = 3;
this.popupWindowsBlocked = false;
}

jsUnitTracer.prototype.initialize = function ()
Expand Down Expand Up @@ -98,11 +99,16 @@ jsUnitTracer.prototype._writeToTraceWindow = function (traceString, traceLevel)

jsUnitTracer.prototype._getTraceWindow = function ()
{
if (this._traceWindow == null) {
if (this._traceWindow == null && !this.popupWindowsBlocked) {
this._traceWindow = window.open('','','width=600, height=350,status=no,resizable=yes,scrollbars=yes');
var resDoc = this._traceWindow.document;
resDoc.write('<html>\n<head>\n<link rel="stylesheet" href="css/jsUnitStyle.css">\n<title>Tracing - JsUnit<\/title>\n<head>\n<body>');
resDoc.write('<h2>Tracing - JsUnit<\/h2>\n');
if (!this._traceWindow) {
this.popupWindowsBlocked = true;
}
else {
var resDoc = this._traceWindow.document;
resDoc.write('<html>\n<head>\n<link rel="stylesheet" href="css/jsUnitStyle.css">\n<title>Tracing - JsUnit<\/title>\n<head>\n<body>');
resDoc.write('<h2>Tracing - JsUnit<\/h2>\n');
}
}
return this._traceWindow;
}
Expand Down
23 changes: 18 additions & 5 deletions app/main-data.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,22 @@
top.testManager.setup();

top.testManager._currentSuite().addTestPage(top.testManager.resolveUserEnteredTestFileName());
top.tracer.initialize();

var traceLevel = document.forms.testRunnerForm.traceLevel;
if (traceLevel.value != '0')
{
var traceWindow = top.tracer._getTraceWindow();
if (traceWindow) {
traceWindow.focus();
}
else {
alert('Tracing requires popup windows which are blocked in your browser.\n\nPlease enable popups if you wish to use tracing.');
}
}

top.testManager.start();
}

</script>
</head>

Expand Down Expand Up @@ -90,23 +103,23 @@
<td nowrap align="center" valign="bottom">
&nbsp;
<script language="JavaScript" type="text/javascript">
if (top.getDocumentProtocol() == 'file:///' && !top.jsUnitParmHash.testpage)
if (top.getDocumentProtocol() == 'file:///' && !jsUnitGetParm('testpage'))
{
document.write('<input type="file" name="testFileName" size="60">');
}
else
{
var inputStr = '<input type="text" name="testFileName" size="60" ';
if (top.jsUnitParmHash.testpage)
if (jsUnitGetParm('testpage'))
{
inputStr += 'value="';
if (
(top.getDocumentProtocol() == 'http://' || top.getDocumentProtocol() == 'https://') &&
top.jsUnitParmHash.testpage.indexOf('/') == 0)
jsUnitGetParm('testpage').indexOf('/') == 0)
{
inputStr += top.location.host;
}
inputStr += top.jsUnitParmHash.testpage;
inputStr += jsUnitGetParm('testpage');
var testParms = top.jsUnitConstructTestParms();
if (testParms!='') {
inputStr += '?';
Expand Down
5 changes: 4 additions & 1 deletion app/testContainerController.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@
try
{
// attempt to access the var isTestPageLoaded in the testFrame
isTestPageLoaded=top.testManager.containerTestFrame.isTestPageLoaded;
if (typeof(top.testManager.containerTestFrame.isTestPageLoaded) != 'undefined')
{
isTestPageLoaded=top.testManager.containerTestFrame.isTestPageLoaded;
}

// ok, if the above did not throw an exception, then the
// variable is defined. If the onload has not fired in the
Expand Down
Loading

0 comments on commit 1c2ecb2

Please sign in to comment.