Skip to content

Commit

Permalink
Deferred output of feature results and very basic reporter engine
Browse files Browse the repository at this point in the history
Will make sure all results are displayed together when running multiple
async features in parallel.
  • Loading branch information
fieldkit-zz committed Feb 22, 2010
1 parent 1326bf5 commit b26104d
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 32 deletions.
58 changes: 29 additions & 29 deletions lib/story/feature.js
@@ -1,9 +1,8 @@
var sys = require('sys');
var Step = require('./step').Step;

function logError(e) {
sys.puts(' ' + (e.message || e));
}
var sys = require('sys');
var Step = require('./step').Step;
var Reporter = require('./reporter').Reporter;
var ReportableString = require('./reportables/reportable_string').ReportableString;
var ReportableError = require('./reportables/reportable_error').ReportableError;

//
// Every Step object created by the step definitions in the Feature
Expand All @@ -13,49 +12,53 @@ function logError(e) {
// the queue by calling queue.next(), which will recursively shift
// and call enqueued items.
//
function StepQueue() {
function StepQueue(reporter) {
this.q = [];
// Expected passed/failed statements before processing the next
// item in the queue.
this._expected = 0;
// The currently processed step.
this.current = null;
this.reporter = reporter;
}

StepQueue.prototype = {
get expected() { return this._expected },
set expected(value) {
// If this is the last expected pass or fail, display the steps'
// output
if (value === 0) this.current.log();
//if (value === 0) this.current.log();
if (value === 0) this.reporter.add(this.current);
this._expected = value;
},
// Adds an item to the queue.
add: function (item) { this.q.push(item) },
// Runs the next job, unless we expect passes.
next: function () {
if (this.expected === 0 && this.q.length !== 0) {
if (this.expected === 0 && this.q.length > 0) {
this.current = this.q.shift();
try {
this.current.fn.call();
// If we expect more passes to be emitted, don't display
// the current steps' output.
if (!this.expected) this.current.log();
if (!this.expected) this.reporter.add(this.current);
} catch (e) {
this.current.passed = false;
this.current.log();
logError(e);
this.reporter.add(this.current);
this.reporter.add(new ReportableError(e));
}
return this.next();
} else if (this.expected == 0) {
this.reporter.show();
}
return this;
}
};

exports.Feature = function (feature, fn) {
sys.puts('\nFeature: ' + feature + '\n');

var queue = new StepQueue();
var reporter = new Reporter();
var queue = new StepQueue(reporter);
reporter.add(new ReportableString('\nFeature: ' + feature + '\n'));

//
// Async DSL:
Expand Down Expand Up @@ -83,17 +86,12 @@ exports.Feature = function (feature, fn) {
//

var asyncHelpers = {
awaited: 0,
await: function (awaited) {
this.awaited = awaited;
return this;
},
get passes() {
queue.expected = this.awaited;
this.awaited = 0;
queue.expected = awaited;
return this;
},
get pass() { return this.passes },
get passes() { return this },
get pass() { return this },
get passed() {
if (queue.expected && queue.current) {
queue.expected--;
Expand All @@ -105,7 +103,7 @@ exports.Feature = function (feature, fn) {
if (queue.expected && queue.current) {
queue.current.passed = false;
queue.expected--;
logError(arguments.callee.caller.arguments[0] || 'Unknown error.');
reporter.add(new ReportableError(arguments.callee.caller.arguments[0] || 'Unknown error.'));
queue.next();
}
return this;
Expand All @@ -115,7 +113,7 @@ exports.Feature = function (feature, fn) {
setTimeout(function () {
queue.current.passed = false;
queue.expected = 0;
logError('Step timed-out after ' + timeout + ' ms.');
reporter.add(new ReportableError('Step timed-out after ' + timeout + ' ms.'));
queue.next();
}, timeout);
}
Expand All @@ -136,11 +134,13 @@ exports.Feature = function (feature, fn) {
};

// Evaluate the Feature block.
try { with (steps) { with (asyncHelpers) { eval(contents) } } }
catch (e) { sys.puts(e); process.exit() }
/*try {*/ with (steps) { with (asyncHelpers) { eval(contents) } } //}
//catch (e) { sys.puts(e); process.exit() }

// Run the queue.
queue.next();
// Run the queue on the next tick, so we return from the constructor first.
process.nextTick(function () {
queue.next();
});
};

// This is totally superficial and just for aesthetic reasons.
Expand Down
11 changes: 11 additions & 0 deletions lib/story/reportables/reportable_error.js
@@ -0,0 +1,11 @@
var ERROR_INDENT = ' ';
var ReportableError = exports.ReportableError = function (error) {
this.error = error;
};

ReportableError.prototype = {
toReport: function () {
return ERROR_INDENT + (this.error.message || this.error);
}
};

9 changes: 9 additions & 0 deletions lib/story/reportables/reportable_string.js
@@ -0,0 +1,9 @@
var ReportableString = exports.ReportableString = function (string) {
this.string = string;
};

ReportableString.prototype = {
toReport: function () {
return this.string;
}
};
13 changes: 13 additions & 0 deletions lib/story/reporter.js
@@ -0,0 +1,13 @@
var sys = require('sys');
var Reporter = exports.Reporter = function () {
this.reports = [];
};

Reporter.prototype = {
add: function (reportable) {
this.reports.push(reportable.toReport());
},
show: function () {
sys.puts(this.reports.join('\n'));
}
};
5 changes: 2 additions & 3 deletions lib/story/step.js
Expand Up @@ -17,14 +17,13 @@ var Step = exports.Step = function (type, description, fn) {
}

Step.prototype = {
log: function () {
toReport: function () {
var ansiPrefix = ANSI_CSI + ANSI_FG,
ansiSuffix = ANSI_CSI + ANSI_RESET + ANSI_TEXT_PROP;

ansiPrefix += this.passed ? ANSI_GREEN : ANSI_RED;

ansiPrefix += ANSI_TEXT_PROP;

sys.puts(ansiPrefix + ' ' + this.type + ' ' + this.description + ansiSuffix);
return ansiPrefix + ' ' + this.type + ' ' + this.description + ansiSuffix;
}
}

0 comments on commit b26104d

Please sign in to comment.