diff --git a/.gitignore b/.gitignore index 9d40291..72bfeb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ node_modules .idea .nul +.hgignore +.hgsubstate +.hg +.hgsub test/npm-debug.log \ No newline at end of file diff --git a/lib/vows.js b/lib/vows.js index cfbc91f..cfc789f 100644 --- a/lib/vows.js +++ b/lib/vows.js @@ -64,6 +64,9 @@ function addVow(vow) { // always set a listener on the event this.on(event, function () { + if(vow.caughtError) + return; + var args = Array.prototype.slice.call(arguments); // If the vow is a sub-event then we know it is an // emitted event. So I don't muck with the arguments @@ -80,6 +83,7 @@ function addVow(vow) { if (event !== 'error') { this.on("error", function (err) { + vow.caughtError = true; if (vow.callback.length >= 2 || !batch.suite.options.error) { runTest(arguments, this.ctx); } else { diff --git a/lib/vows/extras.js b/lib/vows/extras.js index a90d7a5..a6345f4 100644 --- a/lib/vows/extras.js +++ b/lib/vows/extras.js @@ -1,6 +1,6 @@ var events = require('events'); // -// Wrap a Node.js style async function into an EventEmmitter +// Wrap a Node.js style async function into an EventEmitter // this.prepare = function (obj, targets) { targets.forEach(function (target) { diff --git a/lib/vows/reporters/xunit.js b/lib/vows/reporters/xunit.js index 411a948..45d9b6c 100644 --- a/lib/vows/reporters/xunit.js +++ b/lib/vows/reporters/xunit.js @@ -4,7 +4,9 @@ // added, see: http://ant.1045680.n5.nabble.com/schema-for-junit-xml-output-td1375274.html // -var puts = require('util').puts; +var options = { tail: '\n', raw: true }; +var console = require('../../vows/console'); +var puts = console.puts(options); var buffer = [], curSubject = null; @@ -47,6 +49,9 @@ function cdata(data) { } this.name = 'xunit'; +this.setStream = function (s) { + options.stream = s; +}; this.report = function (data) { var event = data[1]; diff --git a/lib/vows/suite.js b/lib/vows/suite.js index 014571f..2d4e200 100644 --- a/lib/vows/suite.js +++ b/lib/vows/suite.js @@ -129,13 +129,14 @@ this.Suite.prototype = new(function () { } // Run the topic, passing the previous context topics - // If topic `throw`s an exception, pass it down as a value try { topic = topic.apply(ctx.env, ctx.topics); } + // If an unexpected error occurs in the topic, set the return + // value to 'undefined' and call back with the error catch (ex) { - if(/ReferenceError/.test(ex)) throw ex; - topic = ex; + ctx.env.callback(ex); + topic = undefined; } if (typeof(topic) === 'undefined') { ctx._callback = true } @@ -229,13 +230,17 @@ this.Suite.prototype = new(function () { if (topic && ctx.name !== 'on' && (!topic._vowsEmitedEvents || !topic._vowsEmitedEvents.hasOwnProperty(ctx.event))) { - topic.on(ctx.event, function (ctx) { - return function (val) { - return run(new(Context)(vow, ctx, env), lastTopic); + var runInnerContext = function(ctx){ + return function(val){ + return run(new (Context)(vow, ctx, env), lastTopic); }; - }(ctx)); - } else { - run(new(Context)(vow, ctx, env), lastTopic); + }(ctx); + topic.on(ctx.event, runInnerContext); + // Run an inner context if the outer context fails, too. + topic.on('error', runInnerContext); + } + else { + run(new (Context)(vow, ctx, env), lastTopic); } } }); diff --git a/test/vows-error-test.js b/test/vows-error-test.js index 79afaba..25fe300 100644 --- a/test/vows-error-test.js +++ b/test/vows-error-test.js @@ -2,7 +2,8 @@ var path = require('path'), events = require('events'), assert = require('assert'), fs = require('fs'), - vows = require('../lib/vows'); + vows = require('../lib/vows'), + silent = require('../lib/vows/reporters/silent'); function doSomethingAsync(callback) { var err = null; @@ -48,4 +49,74 @@ vows.describe('vows/error').addBatch({ assert.equal(testValue, 'a'); } } -}).export(module) \ No newline at end of file +}).export(module) + +vows.describe('Error Handling').addBatch({ + "A topic with a function that errors": { + topic: function() { + throw("Something wrong here"); + }, + "should return an error to a vow with two parameters": function(e, data) { + assert.equal(e, "Something wrong here"); + } + }, + "A topic with a built-in error": { + topic: function() { + bad.bad; + }, + "should return an error to a vow with two parameters": function(e, data) { + assert(e instanceof Error, "Return value " + e + " wasn't an Error."); + } + }, + "The previous two topics run in their own suite," : { + "connected to two vows expecting one argument each" : { + topic: function(){ + vows.describe().addBatch({ + "A topic with a function that errors": { + topic: function() { + throw("Something wrong here"); + }, + "should record the error in the test results" : function(data) { + assert.ok(!data); + } + //» An unexpected error was caught: "Something wrong here" + }, + "A topic with a built-in error": { + topic: function() { + bad.bad; + }, + "should record the error in the test results" : function(data) { + assert.ok(!data); + } + //» An unexpected error was caught: ReferenceError: bad is not defined + } + }).run({reporter : silent}, this.callback); + }, + "should have an errored count of two" : function(results, unused) { + assert.equal(results.errored, 2); + }, + "should have a total count of two" : function(results, unused) { + assert.equal(results.total, 2); + }, + "should have an honored count of zero" : function(results, unused){ + assert.equal(results.honored, 0); + } + } + }, + "A topic with an error in it" : { + topic : function(){ + throw('awesome'); + }, + "should error" : function(error, result){ + assert.equal(error, 'awesome'); + }, + "containing a subtopic" : { + topic : function(){ + return 52; + }, + "should reach a vow in the subtopic" : function(){ + } + } + } +}).export(module); + diff --git a/test/vows-test.js b/test/vows-test.js index d539a54..bcb5134 100644 --- a/test/vows-test.js +++ b/test/vows-test.js @@ -168,15 +168,7 @@ vows.describe("Vows").addBatch({ "should work as expected": function (topic) { assert.isFunction(topic); assert.equal(topic(), 42); - }, - } - }, - "A topic with a function that errors": { - topic: function() { - throw("Something wrong here"); - }, - "should error out": function(topic) { - assert.equal(topic, "Something wrong here"); + } } }, "A topic emitting an error": {