Skip to content
Browse files

Working on problems with async execution

  • Loading branch information...
1 parent 5a4762c commit 66abdd7009ea1dbd774fea454ade1509e23ef450 @lukebayes committed
View
23 bin/nodeshould.js
@@ -0,0 +1,23 @@
+
+/**
+ * Run this file with:
+ *
+ * nodeshould -s sources \
+ * -s lib/foo \
+ * -s lib/bar \
+ * -t '/test-*.js/' \
+ * -n '/should make happy/'
+ *
+ * @param s Directories that contain code that can be required. If a directory
+ * is found at ./src or ./test, those directories will be automatically added
+ * to the load path.
+ * @param t Regular Expression that matches the test file or files that you
+ * want to load.
+ * @param n Regular Expression that matches the test label(s) that you want
+ * to execute.
+ */
+
+var Runner = require('node_should').Runner;
+var runner = new Runner();
+runner.runFromTerminal(process.argv);
+
View
4 example/test/unit/some_class_test.js
@@ -38,12 +38,12 @@ context('SomeClass', function() {
// This is an asynchronous test method:
// Node how we send our custom handler to
- // this.async, and send it's response to
+ // async, and send it's response to
// whatever would normally trigger our custom
// handler.
should('do some long task', function() {
var self = this;
- this.instance.doSomeLongAsyncTask(10, this.async(function() {
+ this.instance.doSomeLongAsyncTask(10, async(function() {
assert.ok(self.instance.isDone, 'long async task completed');
}));
});
View
14 package.json
@@ -0,0 +1,14 @@
+{
+ "name" : "nodeshould",
+ "version" : "0.0.1",
+ "description" : "A small implementation of Shoulda for testing JavaScript applications with Node",
+ "keywords" : ["shoulda", "test", "unit", "integration"],
+ "homepage" : "http://github.com/lukebayes/node-should",
+ "author" : {
+ "name" : "Luke Bayes",
+ "email" : "lbayes@patternpark.com",
+ "url" : "http://lukebayes.com",
+ },
+ "main" : "node_should.js",
+ "test" : "runner.js",
+}
View
1 src/node_should.js
@@ -1,4 +1,5 @@
+exports.TestHandler = require('node_should/test_handler').TestHandler;
exports.Context = require('node_should/context').Context;
exports.Printer = require('node_should/printer').Printer;
exports.Runner = require('node_should/runner').Runner;
View
76 src/node_should/context.js
@@ -1,8 +1,7 @@
var ArrayIterator = require('node_should/array_iterator').ArrayIterator;
var Composite = require('node_should/composite').Composite;
-
-var AssertionError = require('assert').AssertionError;
+var TestHandler = require('node_should/test_handler').TestHandler;
var util = require('util');
var Context = function(label) {
@@ -15,6 +14,8 @@ var Context = function(label) {
util.inherits(Context, Composite);
+Context.DEFAULT_ASYNC_TIMEOUT = 50;
+
Context.prototype.addExecutionHandler = function(label, handler) {
this._cleanHandlerArguments(arguments);
this._label = label;
@@ -23,12 +24,12 @@ Context.prototype.addExecutionHandler = function(label, handler) {
Context.prototype.addSetupHandler = function(handler) {
if (handler == null) throw 'The handler provided to Context.addSetupHandler must not be null';
- this._setupHandlers.push({ handler: handler });
+ this._setupHandlers.push(TestHandler.create(this, this.getLabel(), handler));
}
Context.prototype.addTeardownHandler = function(handler) {
if (handler == null) throw 'The handler provided to Context.addTeardownHandler must not be null';
- this._teardownHandlers.push({ handler: handler });
+ this._teardownHandlers.push(TestHandler.create(this, this.getLabel(), handler));
}
/**
@@ -40,12 +41,49 @@ Context.prototype.addTestHandler = function(label, handler) {
if (this.getLabel() != '') {
label = [this.getLabel(), 'should', label].join(' ');
}
- this._testHandlers.push({ handler: handler, label: label });
+ //this._testHandlers.push({ handler: handler, label: label });
+ this._testHandlers.push(TestHandler.create(this, label, handler));
// TODO(lukebayes) Probably shouldn't set label here, it's doing work that
// isn't necessary, and will only be used in cases of failure?
}
/**
+ * Called during test execution and should prevent the call of the next test
+ * setup, test or teardown until the async handler either times out, or
+ * completes.
+ */
+Context.prototype.addAsyncHandler = function(callback, timeout) {
+ timeout = (timeout == null) ? Context.DEFAULT_ASYNC_TIMEOUT : timeout;
+ var timeoutError = new Error('Async timeout (' + timeout + 'ms) exceeded.');
+ var self = this;
+ var options = this.currentOptions;
+ var timeoutId = null;
+ var timeoutExecuted = false;
+
+ options.asyncHandlers++;
+
+ timeoutId = setTimeout(function() {
+ console.log("async timeout exceeded with!: " + timeoutError.stack);
+ timeoutExecuted = true;
+ options.asyncHandlers--;
+
+ self._onError({
+ error : timeoutError
+ });
+
+ self._executeNextSetupOrTestOrTeardown(options);
+ }, timeout);
+
+ return function() {
+ if (!timeoutExecuted) {
+ clearTimeout(timeoutId);
+ options.asyncHandlers--;
+ self._callHandler(callback, options);
+ }
+ }
+}
+
+/**
* Will modify the provided arguments hash that may have a single handler argument,
* or a label, followed by a handler function. Regardless of how the args come in,
* they should be modified so that the zeroth element is a label and the first is
@@ -128,7 +166,7 @@ Context.prototype._createTestHandlerIterator = function(completeHandler) {
// that wraps test methods:
setTimeout(function() {
completeHandler();
- }, 0);
+ });
}
});
@@ -139,23 +177,9 @@ Context.prototype._getTestExecutionOptions = function(iterator) {
var self = this;
var options = {};
- var asyncHandler = function(callback) {
- options.asyncHandlers++;
- return function() {
- options.asyncHandlers--;
- self._callHandler(callback, options);
- if (options.asyncHandlers == 0) {
- self._executeNextSetupOrTestOrTeardown(options);
- }
- }
- }
-
options.asyncHandlers = 0;
options.iterator = iterator;
- options.scope = {
- async : asyncHandler
- }
-
+ options.scope = {};
return options;
}
@@ -189,6 +213,7 @@ Context.prototype._onFailure = function(testHandlerData) {
}
Context.prototype._onError = function(testHandlerData) {
+ //console.log(testHandlerData.error.stack);
if (this.listeners('error').length == 0) {
throw testHandlerData.error;
}
@@ -206,6 +231,7 @@ Context.prototype._callHandler = function(handlerData, options) {
}
try {
+ this.currentOptions = options;
handler.call(options.scope);
} catch (e) {
//console.log("-----------------");
@@ -232,16 +258,14 @@ Context.prototype._callHandler = function(handlerData, options) {
throw 'Caught handler exception with no exception? (' + e +')';
}
}
+
+ this._executeNextSetupOrTestOrTeardown(options);
}
Context.prototype._executeNextSetupOrTestOrTeardown = function(options) {
var itr = options.iterator;
-
- if (itr.hasNext()) {
+ if (options.asyncHandlers == 0 && itr.hasNext()) {
this._callHandler(itr.next(), options);
- if(options.asyncHandlers == 0) {
- this._executeNextSetupOrTestOrTeardown(options);
- }
}
}
View
19 src/node_should/runner.js
@@ -12,6 +12,20 @@ var DEFAULT_PRINTERS = [new Printer()];
var Runner = function() {
}
+Runner.prototype.runFromTerminal = function(argv, printers, completeHandler) {
+ console.log("Running from term with: " + argv);
+ argv.forEach(function(val, index, array) {
+ console.log("val: " + val + " index: " + index);
+ if (val == '-s' || val == '--source-path') {
+ console.log("source path with: " + array[index+1]);
+ } else if (val == '-t' || val == '--test-expression') {
+ console.log("testl expression with: " + array[index+1]);
+ } else if (val == '-n' || val == '--name') {
+ console.log("test name with: " + array[index+1]);
+ }
+ });
+}
+
Runner.prototype.run = function(expr, path, printers, completeHandler) {
printers = (printers) ? printers : DEFAULT_PRINTERS;
// start provided printers:
@@ -73,8 +87,6 @@ Runner.prototype._createScope = function(file, printers, completeHandler) {
scope[k] = global[k];
}
- //scope.exports = this.exports;
- //scope.module = this;
scope.global = scope;
scope.root = root;
@@ -82,6 +94,9 @@ Runner.prototype._createScope = function(file, printers, completeHandler) {
scope.require = require;
scope.console = console;
+ scope.async = function() {
+ return context.addAsyncHandler.apply(context, arguments);
+ };
scope.context = function() {
createContext.apply(this, arguments);
};
View
38 src/node_should/test_handler.js
@@ -0,0 +1,38 @@
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+
+var TestHandler = function() {
+ EventEmitter.call(this);
+ this.asyncHandlers = [];
+ this.context = null;
+ this.error = null;
+ this.failure = null;
+ this.handler = null;
+ this.label = '';
+}
+
+util.inherits(TestHandler, EventEmitter);
+
+TestHandler.create = function(context, label, handler) {
+ var instance = new TestHandler();
+ instance.context = context;
+ instance.handler = handler;
+ instance.label = label;
+ return instance;
+}
+
+TestHandler.prototype.execute = function() {
+}
+
+TestHandler.prototype.onComplete = function() {
+ this.emit('complete', this);
+}
+
+TestHandler.prototype.addAsyncHandler = function(callback, timeout) {
+}
+
+TestHandler.prototype.asyncHandlerCount = function() {
+ return this.asyncHandlers.length;
+}
+
+exports.TestHandler = TestHandler;
View
2 test/common.js
@@ -23,8 +23,6 @@ IN THE SOFTWARE.
var path = require('path');
var assert = require('node_should/assert');
-//require('assert_match');
-//require('assert_same');
exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
View
36 test/unit/context_test.js
@@ -199,7 +199,7 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addSetupHandler(function() {
- var asyncHandler = this.async(function() {
+ var asyncHandler = async(function() {
executed.push('asyncsetup');
});
setTimeout(asyncHandler, 0);
@@ -218,12 +218,12 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addSetupHandler(function() {
- setTimeout(this.async(function() {
+ setTimeout(async(function() {
executed.push('asyncsetup');
}), 0);
});
c.addTestHandler(function() {
- setTimeout(this.async(function() {
+ setTimeout(async(function() {
executed.push('asynctest1');
}), 0);
// TODO(lukebayes) Problem with async tests:
@@ -232,12 +232,12 @@ context('A new Context', function() {
// This fails!!!!!
});
c.addTestHandler(function() {
- setTimeout(this.async(function() {
+ setTimeout(async(function() {
executed.push('asynctest2');
}), 0);
});
c.addTeardownHandler(function() {
- setTimeout(this.async(function() {
+ setTimeout(async(function() {
executed.push('asyncteardown');
}), 0);
});
@@ -283,7 +283,7 @@ context('A new Context', function() {
failure = f;
});
c.addTestHandler(function() {
- setTimeout(this.async(function() {
+ setTimeout(c.addAsyncHandler(function() {
assert.ok(false, 'should be false');
}), 0);
});
@@ -310,15 +310,21 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addTestHandler(function() {
- setTimeout(this.async(function() {
- executed.push('one');
- }), 0);
- setTimeout(this.async(function() {
- executed.push('two');
- }), 0);
- setTimeout(this.async(function() {
- executed.push('three');
- }), 0);
+ setTimeout(async(function() {
+ c.addAsyncHandler(function() {
+ executed.push('one');
+ });
+ }));
+ setTimeout(async(function() {
+ c.addAsyncHandler(function() {
+ executed.push('two');
+ });
+ }));
+ setTimeout(async(function() {
+ c.addAsyncHandler(function() {
+ executed.push('three');
+ });
+ }));
});
c.execute(function() {
View
25 test/unit/runner_test.js
@@ -1,21 +1,30 @@
-
+/*
require('common');
var Runner = require('node_should/runner').Runner;
var FakePrinter = require('fake_printer').FakePrinter;
context('A new Runner', function() {
- should('be instantiable', function() {
- var r = new Runner();
+ setup(function() {
+ this.printer = new FakePrinter();
+ this.runner = new Runner();
});
should('load specified files', function() {
- var printer = new FakePrinter();
- var r = new Runner();
- r.run(/first.js/, 'test/fixtures', [printer], function() {
+ this.runner.run(/first.js/, 'test/fixtures', [this.printer], async(function() {
//console.log(printer.out.message);
- assert.match(/OK: 2/, printer.out.message);
+ assert.match(/OK: 2/, this.printer.out.message);
+ }, 500));
+ });
+
+ context('run from the terminal', function() {
+
+ should('accept source path argument', function() {
+ var argv = [];
+ this.runner.runFromTerminal(argv, [this.printer], async(function() {
+ console.log("async handler called!");
+ }, 20));
});
});
});
-
+*/

0 comments on commit 66abdd7

Please sign in to comment.
Something went wrong with that request. Please try again.