Attempt at normalizing error stacks across browsers.

Failed expectations now have a `stack` property, remove `trace.stack`
This commit is contained in:
Dan Hansen and Davis W. Frank
2013-02-27 16:37:31 -08:00
parent dc4563d45c
commit d6da13a8dd
12 changed files with 237 additions and 132 deletions

View File

@@ -71,18 +71,21 @@
}
};
var exceptionFormatter = jasmine.exceptionFormatter;
var specConstructor = jasmine.Spec;
var getSpecName = function(spec, currentSuite) {
return currentSuite.getFullName() + ' ' + spec.description + '.';
};
var buildExpectationResult = jasmine.buildExpectationResult;
var expectationResultFactory = function(attrs) {
return buildExpectationResult(attrs);
};
// TODO: we may just be able to pass in the fn instead of wrapping here
var buildExpectationResult = jasmine.buildExpectationResult,
exceptionFormatter = new jasmine.ExceptionFormatter(),
expectationResultFactory = function(attrs) {
attrs.messageFormatter = exceptionFormatter.message;
attrs.stackFormatter = exceptionFormatter.stack;
return buildExpectationResult(attrs);
};
// TODO: fix this naming, and here's where the value comes in
this.catchExceptions = function(value) {

View File

@@ -1,12 +1,21 @@
jasmine.exceptionMessageFor = function(e) {
var message = e.name
+ ': '
+ e.message
+ ' in '
+ (e.fileName || e.sourceURL || '')
+ ' (line '
+ (e.line || e.lineNumber || '')
+ ')';
jasmine.ExceptionFormatter = function() {
this.message = function(error) {
var message = error.name
+ ': '
+ error.message;
return message;
};
if (error.fileName || error.sourceURL) {
message += " in " + (error.fileName || error.sourceURL);
}
if (error.line || error.lineNumber) {
message += " (line " + (error.line || error.lineNumber) + ")"
}
return message;
};
this.stack = function(error) {
return error ? error.stack : null;
}
};

View File

@@ -1,12 +1,41 @@
//TODO: expectation result may make more sense as a presentation of an expectation.
jasmine.buildExpectationResult = function(params) {
jasmine.buildExpectationResult = function(options) {
var messageFormatter = options.messageFormatter || function() {},
stackFormatter = options.stackFormatter || function() {};
return {
type: 'expect',
matcherName: params.matcherName,
expected: params.expected,
actual: params.actual,
message: params.passed ? 'Passed.' : params.message,
trace: params.passed ? '' : (params.trace || new Error(this.message)),
passed: params.passed
matcherName: options.matcherName,
expected: options.expected,
actual: options.actual,
message: message(),
stack: stack(),
passed: options.passed
};
function message() {
if (options.passed) {
return "Passed."
} else if (options.message) {
return options.message
} else if (options.error) {
return messageFormatter(options.error);
}
return ""
}
function stack() {
if (options.passed) {
return "";
}
var error = options.error;
if (!error) {
try {
throw new Error(message());
} catch (e) {
error = e;
}
}
return stackFormatter(error);
}
};

View File

@@ -53,21 +53,19 @@ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
message += ".";
}
}
var expectationResult = jasmine.buildExpectationResult({
this.spec.addExpectationResult(result, {
matcherName: matcherName,
passed: result,
expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
actual: this.actual,
message: message
});
this.spec.addExpectationResult(result, expectationResult);
return jasmine.undefined;
};
};
/**
* toBe: compares the actual to the expected using ===
* @param expected
@@ -147,11 +145,11 @@ jasmine.Matchers.prototype.toBeNull = function() {
* Matcher that compares the actual to NaN.
*/
jasmine.Matchers.prototype.toBeNaN = function() {
this.message = function() {
return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
};
this.message = function() {
return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
};
return (this.actual !== this.actual);
return (this.actual !== this.actual);
};
/**
@@ -366,7 +364,7 @@ jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
jasmine.Matchers.ObjectContaining = function(sample) {
this.sample = sample;
};
@@ -392,6 +390,6 @@ jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mis
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function() {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};

View File

@@ -26,9 +26,10 @@ jasmine.Spec = function(attrs) {
jasmine.Spec.prototype.addExpectationResult = function(passed, data) {
this.encounteredExpectations = true;
if (!passed) {
this.result.failedExpectations.push(data);
if (passed) {
return;
}
this.result.failedExpectations.push(this.expectationResultFactory(data));
};
jasmine.Spec.prototype.expect = function(actual) {
@@ -51,14 +52,13 @@ jasmine.Spec.prototype.execute = function(onComplete) {
this.queueRunner({
fns: allFns,
onException: function(e) {
self.addExpectationResult(false, self.expectationResultFactory({
self.addExpectationResult(false, {
matcherName: "",
passed: false,
expected: "",
actual: "",
message: self.exceptionFormatter(e),
trace: e
}));
error: e
});
},
onComplete: complete
});
@@ -95,4 +95,4 @@ jasmine.Spec.prototype.status = function() {
jasmine.Spec.prototype.getFullName = function() {
return this.getSpecName(this);
}
};

View File

@@ -79,9 +79,8 @@ jasmine.HtmlReporter = function(options) {
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
var stack = (expectation.trace && expectation.trace.stack) || "";
messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
messages.appendChild(createDom("div", {className: "stack-trace"}, stack));
messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack));
}
failures.push(failure);