getJasmineRequireObj().QueueRunner = function(j$) { function StopExecutionError() {} StopExecutionError.prototype = new Error(); j$.StopExecutionError = StopExecutionError; function once(fn) { var called = false; return function(arg) { if (!called) { called = true; // Direct call using single parameter, because cleanup/next does not need more fn(arg); } return null; }; } function emptyFn() {} function QueueRunner(attrs) { var queueableFns = attrs.queueableFns || []; this.queueableFns = queueableFns.concat(attrs.cleanupFns || []); this.firstCleanupIx = queueableFns.length; this.onComplete = attrs.onComplete || emptyFn; this.clearStack = attrs.clearStack || function(fn) { fn(); }; this.onException = attrs.onException || emptyFn; this.userContext = attrs.userContext || new j$.UserContext(); this.timeout = attrs.timeout || { setTimeout: setTimeout, clearTimeout: clearTimeout }; this.fail = attrs.fail || emptyFn; this.globalErrors = attrs.globalErrors || { pushListener: emptyFn, popListener: emptyFn }; this.completeOnFirstError = !!attrs.completeOnFirstError; this.errored = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); } this.deprecated = attrs.deprecated; } QueueRunner.prototype.execute = function() { var self = this; this.handleFinalError = function(message, source, lineno, colno, error) { // Older browsers would send the error as the first parameter. HTML5 // specifies the the five parameters above. The error instance should // be preffered, otherwise the call stack would get lost. self.onException(error || message); }; this.globalErrors.pushListener(this.handleFinalError); this.run(0); }; QueueRunner.prototype.skipToCleanup = function(lastRanIndex) { if (lastRanIndex < this.firstCleanupIx) { this.run(this.firstCleanupIx); } else { this.run(lastRanIndex + 1); } }; 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 handleError(error) { onException(error); next(error); }, cleanup = once(function cleanup() { if (timeoutId !== void 0) { self.clearTimeout(timeoutId); } self.globalErrors.popListener(handleError); }), next = once(function next(err) { cleanup(); if (j$.isError_(err)) { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } self.errored = errored = true; } 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 nextFail() { self.fail.apply(null, arguments); self.errored = errored = true; next(); }; self.globalErrors.pushListener(handleError); if (queueableFn.timeout !== undefined) { var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL; timeoutId = self.setTimeout(function() { var error = new Error( 'Timeout - Async function did not complete within ' + timeoutInterval + 'ms ' + (queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') ); onException(error); next(); }, timeoutInterval); } 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) { onException(e); self.errored = errored = true; } cleanup(); return { completedSynchronously: true, errored: errored }; function onException(e) { self.onException(e); self.errored = errored = true; } function onPromiseRejection(e) { onException(e); next(); } }; QueueRunner.prototype.run = function(recursiveIndex) { var length = this.queueableFns.length, self = this, iterativeIndex; for ( iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++ ) { var result = this.attempt(iterativeIndex); if (!result.completedSynchronously) { return; } self.errored = self.errored || result.errored; if (this.completeOnFirstError && result.errored) { this.skipToCleanup(iterativeIndex); return; } } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); self.onComplete(self.errored && new StopExecutionError()); }); }; return QueueRunner; };