UNPKG

siesta-lite

Version:

Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers

236 lines (179 loc) 8.84 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The source code</title> <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="../resources/prettify/prettify.js"></script> <style type="text/css"> .highlight { display: block; background-color: #ddd; } </style> <script type="text/javascript"> function highlight() { document.getElementById(location.hash.replace(/#/, "")).className = "highlight"; } </script> </head> <body onload="prettyPrint(); highlight();"> <pre class="prettyprint lang-js">/* Siesta 5.6.1 Copyright(c) 2009-2022 Bryntum AB https://bryntum.com/contact https://bryntum.com/products/siesta/license */ Class(&#39;Siesta.Util.Queue&#39;, { has : { // array of Objects, each containing arbitrary data about queue step. Possibly keys: // `processor` - an individual processor function for this step // can also be provided for whole queue // will receive the: (stepData, index, queue) // `isAsync` - when provided, the `next` function will be also embedded, // which should be called manually // `interval` - the delay after step (except for asynchronous) steps : Joose.I.Array, interval : 100, callbackDelay : 0, // setTimeout deferer : { required : true }, // clearTimeout - only required when &quot;abort&quot; is planned / possible deferClearer : null, processor : null, processorScope : null, currentTimeout : null, callback : null, scope : null, isAborted : false, observeTest : null, currentDelayStepId : null, isDestroyed : false }, methods : { // step is an object with // { // processor : func, // processorScope : obj, // next : func (in case of async step, will be populated by queue) // } addStep : function (stepData) { this.addSyncStep(stepData) }, addSyncStep : function (stepData) { this.steps.push(stepData) }, addAsyncStep : function (stepData) { stepData.isAsync = true this.steps.push(stepData) }, addDelayStep : function (delayMs) { var origSetTimeout = this.deferer; var me = this; this.addAsyncStep({ processor : function(data) { me.currentDelayStepId = origSetTimeout(data.next, delayMs || 500); } }); }, run : function (callback, scope) { this.callback = callback this.scope = scope // abort the queue, if the provided test instance has finalized (probably because of exception) this.observeTest &amp;&amp; this.observeTest.on(&#39;teststop&#39;, function () { this.abort(true) }, this, { single : true }) this.doSteps(this.steps.slice(), callback, scope) }, abort : function (ignoreCallback) { if (this.isDestroyed) return this.isAborted = true var deferClearer = this.deferClearer if (!deferClearer) throw &quot;Need `deferClearer` to be able to `abort` the queue&quot; deferClearer(this.currentDelayStepId); deferClearer(this.currentTimeout) if (!ignoreCallback) this.callback.call(this.scope || this) this.destroy() }, doSteps : function (steps, callback, scope) { this.currentTimeout = null var me = this var deferer = this.deferer var step = steps.shift() if (this.isAborted) return if (step) { // Normally, the `doSteps` is called recursively for every step in the chain // but, steps may complete synchronously, which means, stack will grow // since some version, FF has smaller stack size than other browsers // and it starts behaving unstable when stack grows // because of that, we perform a special check if step has completed synchronously // and processing the next step in the same `doStep` context (in the loop), avoiding recursion // if `doOneStep` has returned `true`, then step has completed synchronously // and the flow did not recurse into `doSteps` // in this case we continue processing to the next step while (this.doOneStep(step, steps, callback, scope) &amp;&amp; !this.isAborted) { if (steps.length) step = steps.shift() else { this.doSteps(steps, callback, scope) break; } } } else { if (callback) if (this.callbackDelay) deferer(function () { if (!me.isAborted) { callback.call(scope || this); me.destroy() } }, this.callbackDelay) else { callback.call(scope || this) me.destroy() } } }, doOneStep : function (step, steps, callback, scope) { var me = this var deferer = this.deferer var processor = step.processor || this.processor var processorScope = step.processorScope || this.processorScope var index = this.steps.length - steps.length - 1 if (!processor) throw new Error(&quot;No process function found for step: &quot; + index) if (step.isAsync) { var stepHasCompletedSynchronously = false var processorHasCompleted = false var next = step.next = function () { // if at this point `processorHasCompleted` is still `false`, that means that &quot;next&quot; function // has been called before the `processor` function has returned, and thus, step has completed // synchronously // see the comment in `doSteps` why we treat this case differently if (!processorHasCompleted) stepHasCompletedSynchronously = true else me.doSteps(steps, callback, scope) } // processor should call `next` to continue processor.call(processorScope || me, step, index, this, next) processorHasCompleted = true if (stepHasCompletedSynchronously) return true } else { processor.call(processorScope || me, step, index, this) if (this.isAborted) return var interval = step.hasOwnProperty(&#39;interval&#39;) ? step.interval : me.interval if (interval) this.currentTimeout = deferer(function () { me.doSteps(steps, callback, scope) }, interval) else me.doSteps(steps, callback, scope) } }, // help garbage collector to release the memory destroy : function () { if (this.isDestroyed) return this.callback = this.observeTest = this.deferer = this.deferClearer = null this.processor = this.processorScope = null // cleanup paranoya, this shouldn&#39;t matter in general, since &quot;next&quot; here is from the same context for (var i = 0; i &lt; this.steps.length; i++) this.steps[ i ].next = null this.steps = null this.isDestroyed = true } } }) </pre> </body> </html>