diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2a270915..4a04699f 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -603,6 +603,7 @@ getJasmineRequireObj().Spec = function(j$) { this.queueRunnerFactory(runnerConfig); function complete(enabledAgain) { + self.queueableFn.fn = null; self.result.status = self.status(enabledAgain); self.resultCallback(self.result); @@ -4513,6 +4514,103 @@ getJasmineRequireObj().QueueRunner = function(j$) { } }; + QueueRunner.prototype.clearTimeout = function(timeoutId) { + Function.prototype.apply.apply(this.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]); + }; + + QueueRunner.prototype.setTimeout = function(fn, timeout) { + return Function.prototype.apply.apply(this.timeout.setTimeout, [j$.getGlobal(), [fn, timeout]]); + }; + + QueueRunner.prototype.attempt = function attempt(iterativeIndex) { + var self = this, completedSynchronously = true, + handleError = function(error) { + onException(error); + next(); + }, + cleanup = once(function() { + self.clearTimeout(timeoutId); + self.globalErrors.popListener(handleError); + }), + next = once(function () { + cleanup(); + + function runNext() { + if (self.completeOnFirstError && errored) { + self.skipToCleanup(iterativeIndex); + } else { + self.run(iterativeIndex + 1); + } + } + + if (completedSynchronously) { + self.setTimeout(runNext); + } else { + runNext(); + } + }), + errored = false, + queueableFn = self.queueableFns[iterativeIndex], + timeoutId; + + next.fail = function() { + self.fail.apply(null, arguments); + errored = true; + next(); + }; + + self.globalErrors.pushListener(handleError); + + if (queueableFn.timeout) { + timeoutId = self.setTimeout(function() { + var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); + onException(error); + next(); + }, queueableFn.timeout()); + } + + try { + if (queueableFn.fn.length === 0) { + var maybeThenable = queueableFn.fn.call(self.userContext); + + if (maybeThenable && j$.isFunction_(maybeThenable.then)) { + maybeThenable.then(next, onPromiseRejection); + completedSynchronously = false; + return { completedSynchronously: false }; + } + } else { + queueableFn.fn.call(self.userContext, next); + completedSynchronously = false; + return { completedSynchronously: false }; + } + } catch (e) { + handleException(e, queueableFn); + errored = true; + } + + cleanup(); + return { completedSynchronously: true, errored: errored }; + + function onException(e) { + self.onException(e); + errored = true; + } + + function onPromiseRejection(e) { + onException(e); + next(); + } + + function handleException(e, queueableFn) { + onException(e); + if (!self.catchException(e)) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. + throw e; + } + } + }; + QueueRunner.prototype.run = function(recursiveIndex) { var length = this.queueableFns.length, self = this, @@ -4520,7 +4618,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { - var result = attempt(iterativeIndex); + var result = this.attempt(iterativeIndex); if (!result.completedSynchronously) { return; @@ -4537,100 +4635,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { self.onComplete(); }); - function attempt() { - var clearTimeout = function () { - Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]); - }, - setTimeout = function(delayedFn, delay) { - return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]); - }, - completedSynchronously = true, - handleError = function(error) { - onException(error); - next(); - }, - cleanup = once(function() { - clearTimeout(timeoutId); - self.globalErrors.popListener(handleError); - }), - next = once(function () { - cleanup(); - - function runNext() { - if (self.completeOnFirstError && errored) { - self.skipToCleanup(iterativeIndex); - } else { - self.run(iterativeIndex + 1); - } - } - - if (completedSynchronously) { - setTimeout(runNext); - } else { - runNext(); - } - }), - errored = false, - queueableFn = self.queueableFns[iterativeIndex], - timeoutId; - - next.fail = function() { - self.fail.apply(null, arguments); - errored = true; - next(); - }; - - self.globalErrors.pushListener(handleError); - - if (queueableFn.timeout) { - timeoutId = setTimeout(function() { - var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); - onException(error); - next(); - }, queueableFn.timeout()); - } - - try { - if (queueableFn.fn.length === 0) { - var maybeThenable = queueableFn.fn.call(self.userContext); - - if (maybeThenable && j$.isFunction_(maybeThenable.then)) { - maybeThenable.then(next, onPromiseRejection); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } else { - queueableFn.fn.call(self.userContext, next); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } catch (e) { - handleException(e, queueableFn); - errored = true; - } - - cleanup(); - return { completedSynchronously: true, errored: errored }; - - function onException(e) { - self.onException(e); - errored = true; - } - - function onPromiseRejection(e) { - onException(e); - next(); - } - - function handleException(e, queueableFn) { - onException(e); - if (!self.catchException(e)) { - //TODO: set a var when we catch an exception and - //use a finally block to close the loop in a nice way.. - throw e; - } - } - } }; return QueueRunner; @@ -5500,6 +5504,19 @@ getJasmineRequireObj().Suite = function(j$) { this.afterAllFns.unshift(fn); }; + function removeFns(queueableFns) { + for(var i = 0; i < queueableFns.length; i++) { + queueableFns[i].fn = null; + } + } + + Suite.prototype.cleanupBeforeAfter = function() { + removeFns(this.beforeAllFns); + removeFns(this.afterAllFns); + removeFns(this.beforeFns); + removeFns(this.afterFns); + }; + Suite.prototype.addChild = function(child) { this.children.push(child); }; @@ -5796,6 +5813,7 @@ getJasmineRequireObj().TreeProcessor = function() { queueRunnerFactory({ onComplete: function() { + node.cleanupBeforeAfter(); nodeComplete(node, node.getResult()); done(); }, diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index d1f2cd9b..c702d0cc 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -17,6 +17,7 @@ describe("TreeProcessor", function() { this.getResult = jasmine.createSpy(this.id + '#execute'); this.beforeAllFns = attrs.beforeAllFns || []; this.afterAllFns = attrs.afterAllFns || []; + this.cleanupBeforeAfter = function() { }; } function Leaf(attrs) { diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index f422b49d..c9b15a28 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -43,6 +43,103 @@ getJasmineRequireObj().QueueRunner = function(j$) { } }; + QueueRunner.prototype.clearTimeout = function(timeoutId) { + Function.prototype.apply.apply(this.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]); + }; + + QueueRunner.prototype.setTimeout = function(fn, timeout) { + return Function.prototype.apply.apply(this.timeout.setTimeout, [j$.getGlobal(), [fn, timeout]]); + }; + + QueueRunner.prototype.attempt = function attempt(iterativeIndex) { + var self = this, completedSynchronously = true, + handleError = function(error) { + onException(error); + next(); + }, + cleanup = once(function() { + self.clearTimeout(timeoutId); + self.globalErrors.popListener(handleError); + }), + next = once(function () { + cleanup(); + + function runNext() { + if (self.completeOnFirstError && errored) { + self.skipToCleanup(iterativeIndex); + } else { + self.run(iterativeIndex + 1); + } + } + + if (completedSynchronously) { + self.setTimeout(runNext); + } else { + runNext(); + } + }), + errored = false, + queueableFn = self.queueableFns[iterativeIndex], + timeoutId; + + next.fail = function() { + self.fail.apply(null, arguments); + errored = true; + next(); + }; + + self.globalErrors.pushListener(handleError); + + if (queueableFn.timeout) { + timeoutId = self.setTimeout(function() { + var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); + onException(error); + next(); + }, queueableFn.timeout()); + } + + try { + if (queueableFn.fn.length === 0) { + var maybeThenable = queueableFn.fn.call(self.userContext); + + if (maybeThenable && j$.isFunction_(maybeThenable.then)) { + maybeThenable.then(next, onPromiseRejection); + completedSynchronously = false; + return { completedSynchronously: false }; + } + } else { + queueableFn.fn.call(self.userContext, next); + completedSynchronously = false; + return { completedSynchronously: false }; + } + } catch (e) { + handleException(e, queueableFn); + errored = true; + } + + cleanup(); + return { completedSynchronously: true, errored: errored }; + + function onException(e) { + self.onException(e); + errored = true; + } + + function onPromiseRejection(e) { + onException(e); + next(); + } + + function handleException(e, queueableFn) { + onException(e); + if (!self.catchException(e)) { + //TODO: set a var when we catch an exception and + //use a finally block to close the loop in a nice way.. + throw e; + } + } + }; + QueueRunner.prototype.run = function(recursiveIndex) { var length = this.queueableFns.length, self = this, @@ -50,7 +147,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { - var result = attempt(iterativeIndex); + var result = this.attempt(iterativeIndex); if (!result.completedSynchronously) { return; @@ -67,100 +164,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { self.onComplete(); }); - function attempt() { - var clearTimeout = function () { - Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]); - }, - setTimeout = function(delayedFn, delay) { - return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]); - }, - completedSynchronously = true, - handleError = function(error) { - onException(error); - next(); - }, - cleanup = once(function() { - clearTimeout(timeoutId); - self.globalErrors.popListener(handleError); - }), - next = once(function () { - cleanup(); - - function runNext() { - if (self.completeOnFirstError && errored) { - self.skipToCleanup(iterativeIndex); - } else { - self.run(iterativeIndex + 1); - } - } - - if (completedSynchronously) { - setTimeout(runNext); - } else { - runNext(); - } - }), - errored = false, - queueableFn = self.queueableFns[iterativeIndex], - timeoutId; - - next.fail = function() { - self.fail.apply(null, arguments); - errored = true; - next(); - }; - - self.globalErrors.pushListener(handleError); - - if (queueableFn.timeout) { - timeoutId = setTimeout(function() { - var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); - onException(error); - next(); - }, queueableFn.timeout()); - } - - try { - if (queueableFn.fn.length === 0) { - var maybeThenable = queueableFn.fn.call(self.userContext); - - if (maybeThenable && j$.isFunction_(maybeThenable.then)) { - maybeThenable.then(next, onPromiseRejection); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } else { - queueableFn.fn.call(self.userContext, next); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } catch (e) { - handleException(e, queueableFn); - errored = true; - } - - cleanup(); - return { completedSynchronously: true, errored: errored }; - - function onException(e) { - self.onException(e); - errored = true; - } - - function onPromiseRejection(e) { - onException(e); - next(); - } - - function handleException(e, queueableFn) { - onException(e); - if (!self.catchException(e)) { - //TODO: set a var when we catch an exception and - //use a finally block to close the loop in a nice way.. - throw e; - } - } - } }; return QueueRunner; diff --git a/src/core/Spec.js b/src/core/Spec.js index c2ee8a58..7f2c1513 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -81,6 +81,7 @@ getJasmineRequireObj().Spec = function(j$) { this.queueRunnerFactory(runnerConfig); function complete(enabledAgain) { + self.queueableFn.fn = null; self.result.status = self.status(enabledAgain); self.resultCallback(self.result); diff --git a/src/core/Suite.js b/src/core/Suite.js index ed7ed3fb..c7783d59 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -65,6 +65,19 @@ getJasmineRequireObj().Suite = function(j$) { this.afterAllFns.unshift(fn); }; + function removeFns(queueableFns) { + for(var i = 0; i < queueableFns.length; i++) { + queueableFns[i].fn = null; + } + } + + Suite.prototype.cleanupBeforeAfter = function() { + removeFns(this.beforeAllFns); + removeFns(this.afterAllFns); + removeFns(this.beforeFns); + removeFns(this.afterFns); + }; + Suite.prototype.addChild = function(child) { this.children.push(child); }; diff --git a/src/core/TreeProcessor.js b/src/core/TreeProcessor.js index a1f5f4cb..137f23b4 100644 --- a/src/core/TreeProcessor.js +++ b/src/core/TreeProcessor.js @@ -168,6 +168,7 @@ getJasmineRequireObj().TreeProcessor = function() { queueRunnerFactory({ onComplete: function() { + node.cleanupBeforeAfter(); nodeComplete(node, node.getResult()); done(); },