From 6504e10eba890a2a255244b75f0717f48cc33b6a Mon Sep 17 00:00:00 2001 From: Xavi Date: Mon, 21 Jan 2013 16:47:20 -0800 Subject: [PATCH] - Made `jumpTo` async in all cases. - Fixed bug that caused unwanted infinite loops. - Added error reporting when user tries to jump to unknown function name. - Added jumpTo unit test. --- README.markdown | 2 +- index.js | 19 ++++++++++++------- test/basic-checks.js | 16 ++++++++++------ test/error.js | 17 +++++++++++++++++ test/jumpTo.js | 39 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/README.markdown b/README.markdown index 2717e91..d394f24 100644 --- a/README.markdown +++ b/README.markdown @@ -81,7 +81,7 @@ An optional string parameter can passed in to `this.val` as well. This string c ); ``` - **this.jumpTo(string, [argsArray])** -- allows you to jump to any named function in the current step chain -- **this.jumpTo(function, [argsArray])** -- used to call an outside function and to exit the current step chain +- **this.jumpTo(function, [argsArray])** -- exits the current step chain and asynchronously call an outside function ```javascript function badNews(err) { diff --git a/index.js b/index.js index 14d800f..dcb69b3 100644 --- a/index.js +++ b/index.js @@ -104,19 +104,24 @@ function TwoStep() { var data = {}; function jumpTo(func, args) { + this._params._used = true; + if (typeof func === 'function') { curIdx = Number.MAX_VALUE; func.apply(this, args); - } else { - for(var i = 0; i < steps.length; i++) { - if(steps[i].name !== func) { continue; } + return; + } - curIdx = i; + for(var i = 0; i < steps.length; i++) { + if(steps[i].name !== func) { continue; } - break; - } + curIdx = i; + + break; } - nextStep.apply(null, args); + if(i === steps.length) { throw Error("Unknown jumpTo location: " + func); } + + process.nextTick(function() { nextStep.apply(null, args); }); } function nextStep(err) { diff --git a/test/basic-checks.js b/test/basic-checks.js index 08410cb..1d8d242 100644 --- a/test/basic-checks.js +++ b/test/basic-checks.js @@ -2,6 +2,8 @@ var assert = require("assert"); module.exports = { save: function(stepObj, args) { + stepObj.data.callSeq = stepObj.data.callSeq || []; + stepObj.data.callSeq.push(stepObj._params.name); stepObj.data[stepObj._params.name] = { when: Date.now(), args: Array.prototype.slice.call(args) }; }, coverage: function(names) { @@ -11,12 +13,14 @@ module.exports = { }, order: function(names) { return function(data) { - for(var i = 1; i < names.length; i++) { - var nameA = names[i - 1], nameB = names[i]; - assert.ok(data[nameA] != null, "Unknown function name: '" + nameA + "'"); - assert.ok(data[nameB] != null, "Unknown function name: '" + nameB + "'"); - assert.ok(data[nameA].when <= data[nameB].when, nameA + " was not called before " + nameB); - } + names.forEach(function(name) { + assert.ok(data[name] != null, "Unknown function name: '" + name + "'"); + }); + assert.deepEqual( + data.callSeq, + names, + "Functions were not called in order:\n\t\texpected: " + names + "\n\t\tactual: " + data.callSeq + ); }; }, emptyArgs: function(name) { diff --git a/test/error.js b/test/error.js index a36b10d..c1391af 100644 --- a/test/error.js +++ b/test/error.js @@ -54,6 +54,23 @@ vows.describe("Test error handling").addBatch({ function lastErr() { throw "Last Error Thrown"; } ); }, "Last Error Thrown"); + }, + "error thrown when jumpTo non-existant location": function(TwoStep) { + assert.throws(function() { + TwoStep( + function first() { this.jumpTo("no-where"); } + ); + }, "Error thrown when trying to jumpTo unknow function name."); + assert.throws(function() { + TwoStep( + function first() { this.jumpTo(5); } + ); + }, "Error thrown when trying to jumpTo unknow function index."); + assert.throws(function() { + TwoStep( + function first() { this.jumpTo(null); } + ); + }, "Error thrown when trying to jumpTo unknow function."); } } }).export(module); \ No newline at end of file diff --git a/test/jumpTo.js b/test/jumpTo.js index d818ca1..927792d 100644 --- a/test/jumpTo.js +++ b/test/jumpTo.js @@ -4,7 +4,7 @@ var TwoStep = require("../"); var check = require("./basic-checks"); vows.describe("Test `this.val`").addBatch({ - "basic test passing one param": { + "basic test passing function name and one param": { topic: function() { TwoStep( function start(err) { @@ -32,6 +32,43 @@ vows.describe("Test `this.val`").addBatch({ assert.equal(data["last"].args[1], "hello", "The incorrect arguments were sent"); } }, + "test that step chain continues once a jumpTo is executed": { + topic: function() { + TwoStep( + function first(err) { + check.save(this, arguments); + this.jumpTo("fourth", [ err, "go to fourth" ]); + }, + function second(err) { + check.save(this, arguments); + this.syncVal("foo") + }, + function third(err) { + check.save(this, arguments); + this.jumpTo("fifth", [ err, "go to fifth" ]); + }, + function fourth(err) { + check.save(this, arguments); + this.jumpTo("second", [ err, "go to second" ]); + }, + function fifth(err) { + check.save(this, arguments); + this.syncVal(this.data); + }, + this.callback + ); + }, + "no args to first callback": check.emptyArgs("first"), + "correct callbacks were called": check.coverage([ "first", "second", "third", "fourth", "fifth" ]), + "callbacks executed in order": check.order([ "first", "fourth", "second", "third", "fifth" ]), + "check arguments of recieving function": function(data) { + assert.ok(!data["second"].args[0], "The error argument was incorrectly set"); + assert.equal(data["second"].args[1], "go to second", "The incorrect arguments were sent"); + assert.equal(data["third"].args[1], "foo", "The incorrect arguments were sent"); + assert.equal(data["fourth"].args[1], "go to fourth", "The incorrect arguments were sent"); + assert.equal(data["fifth"].args[1], "go to fifth", "The incorrect arguments were sent"); + } + }, "bail out if a function was specified": { topic: function() { var callback = this.callback;