[Pkg-javascript-commits] [node-q] 05/20: Imported Upstream version 1.1.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sun Mar 1 12:36:26 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-q.

commit 772db9778de9411bd2b07d98b7f4fb0c7ce69948
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Feb 28 22:35:32 2015 +0100

    Imported Upstream version 1.1.0
---
 .gitignore                          |   4 ++
 .travis.yml                         |   2 -
 CHANGES.md                          |  15 +++++
 README.md                           |  67 ++++++++++++++++---
 examples/all.js                     |   2 +-
 examples/async-generators/README.md |   6 +-
 package.json                        |   2 +-
 q.js                                |  85 ++++++++++++++++--------
 q.png                               | Bin 0 -> 34119 bytes
 q.svg                               | 114 ++++++++++++++++++++++++++++++++
 spec/q-spec.js                      | 127 +++++++++++++++++++++++++++++++++++-
 11 files changed, 379 insertions(+), 45 deletions(-)

diff --git a/.gitignore b/.gitignore
index db6189f..4c44b4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,7 @@ q.min.js
 .coverage_data/
 .coverage_debug/
 cover_html/
+
+# IntelliJ IDEA project files
+.idea
+*.iml
diff --git a/.travis.yml b/.travis.yml
index 0eeb53f..d68110e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,5 @@
 language: node_js
 node_js:
-  - "0.6"
-  - "0.8"
   - "0.10"
 script:
   npm run lint && npm test
diff --git a/CHANGES.md b/CHANGES.md
index 4b91dfc..14e9c15 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,20 @@
 <!-- vim:ts=4:sts=4:sw=4:et:tw=70 -->
 
+## 1.1.0
+
+ - Adds support for enabling long stack traces in node.js by setting
+   environment variable `Q_DEBUG=1`.
+ - Introduces the `tap` method to promises, which will see a value
+   pass through without alteration.
+ - Use instanceof to recognize own promise instances as opposed to
+   thenables.
+ - Construct timeout errors with `code === ETIMEDOUT` (Kornel Lesiński)
+ - More descriminant CommonJS module environment detection.
+ - Dropped continuous integration for Node.js 0.6 and 0.8 because of
+   changes to npm that preclude the use of new `^` version predicate
+   operator in any transitive dependency.
+ - Users can now override `Q.nextTick`.
+
 ## 1.0.1
 
  - Adds support for `Q.Promise`, which implements common usage of the
diff --git a/README.md b/README.md
index bdd4168..b10ea04 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
 [![Build Status](https://secure.travis-ci.org/kriskowal/q.png?branch=master)](http://travis-ci.org/kriskowal/q)
 
 <a href="http://promises-aplus.github.com/promises-spec">
-    <img src="http://promises-aplus.github.com/promises-spec/assets/logo-small.png"
-         align="right" alt="Promises/A+ logo" />
+    <img src="http://kriskowal.github.io/q/q.png"
+         align="right" alt="Q logo" />
 </a>
 
 *This is Q version 1, from the `v1` branch in Git. This documentation applies to
 the latest of both the version 1 and version 0.9 release trains. These releases
 are stable. There will be no further releases of 0.9 after 0.9.7 which is nearly
 equivalent to version 1.0.0. All further releases of `q@~1.0` will be backward
-compatible. The version 2 release train introduces significant but
+compatible. The version 2 release train introduces significant and
 backward-incompatible changes and is experimental at this time.*
 
 If a function cannot return a value or throw an exception without
@@ -80,7 +80,7 @@ The Q module can be loaded as:
     the [q](https://npmjs.org/package/q) package
 -   An AMD module
 -   A [component](https://github.com/component/component) as ``microjs/q``
--   Using [bower](http://bower.io/) as ``q``
+-   Using [bower](http://bower.io/) as `q#1.0.1`
 -   Using [NuGet](http://nuget.org/) as [Q](https://nuget.org/packages/q)
 
 Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.
@@ -294,7 +294,7 @@ If you have a promise for an array, you can use ``spread`` as a
 replacement for ``then``.  The ``spread`` function “spreads” the
 values over the arguments of the fulfillment handler.  The rejection handler
 will get called at the first sign of failure.  That is, whichever of
-the recived promises fails first gets handled by the rejection handler.
+the received promises fails first gets handled by the rejection handler.
 
 ```javascript
 function eventualAdd(a, b) {
@@ -366,16 +366,16 @@ return funcs.reduce(function (soFar, f) {
 }, Q(initialVal));
 ```
 
-Or, you could use th ultra-compact version:
+Or, you could use the ultra-compact version:
 
 ```javascript
-return funcs.reduce(Q.when, Q());
+return funcs.reduce(Q.when, Q(initialVal));
 ```
 
 ### Handling Errors
 
 One sometimes-unintuive aspect of promises is that if you throw an
-exception in the fulfillment handler, it will not be be caught by the error
+exception in the fulfillment handler, it will not be caught by the error
 handler.
 
 ```javascript
@@ -610,6 +610,46 @@ requestOkText("http://localhost:3000")
 });
 ```
 
+#### Using `Q.Promise`
+
+This is an alternative promise-creation API that has the same power as
+the deferred concept, but without introducing another conceptual entity.
+
+Rewriting the `requestOkText` example above using `Q.Promise`:
+
+```javascript
+function requestOkText(url) {
+    return Q.Promise(function(resolve, reject, notify) {
+        var request = new XMLHttpRequest();
+
+        request.open("GET", url, true);
+        request.onload = onload;
+        request.onerror = onerror;
+        request.onprogress = onprogress;
+        request.send();
+
+        function onload() {
+            if (request.status === 200) {
+                resolve(request.responseText);
+            } else {
+                reject(new Error("Status code was " + request.status));
+            }
+        }
+
+        function onerror() {
+            reject(new Error("Can't XHR " + JSON.stringify(url)));
+        }
+
+        function onprogress(event) {
+            notify(event.loaded / event.total);
+        }
+    });
+}
+```
+
+If `requestOkText` were to throw an exception, the returned promise would be
+rejected with that thrown exception as the rejection reason.
+
 ### The Middle
 
 If you are using a function that may return a promise, but just might
@@ -798,11 +838,20 @@ From previous event:
     at Object.<anonymous> (/path/to/test.js:7:1)
 ```
 
-Note how you can see the the function that triggered the async operation in the
+Note how you can see the function that triggered the async operation in the
 stack trace! This is very helpful for debugging, as otherwise you end up getting
 only the first line, plus a bunch of Q internals, with no sign of where the
 operation started.
 
+In node.js, this feature can also be enabled through the Q_DEBUG environment
+variable:
+
+```
+Q_DEBUG=1 node server.js
+```
+
+This will enable long stack support in every instance of Q.
+
 This feature does come with somewhat-serious performance and memory overhead,
 however. If you're working with lots of promises, or trying to scale a server
 to many users, you should probably keep it off. But in development, go for it!
diff --git a/examples/all.js b/examples/all.js
index 4794c5a..8e01c67 100644
--- a/examples/all.js
+++ b/examples/all.js
@@ -8,7 +8,7 @@ function eventually(value) {
 
 Q.all([1, 2, 3].map(eventually))
 .done(function (result) {
-    console.log(x);
+    console.log(result);
 });
 
 Q.all([
diff --git a/examples/async-generators/README.md b/examples/async-generators/README.md
index 46dc310..c409f0b 100644
--- a/examples/async-generators/README.md
+++ b/examples/async-generators/README.md
@@ -24,9 +24,9 @@ function* count() {
 }
 
 var counter = count();
-count.next().value === 0;
-count.next().value === 1;
-count.next().value === 2;
+counter.next().value === 0;
+counter.next().value === 1;
+counter.next().value === 2;
 ```
 
 `yield` can also return a value, if the `next` method of the generator is
diff --git a/package.json b/package.json
index 1e66b76..6af7d53 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "q",
-  "version": "1.0.1",
+  "version": "1.1.0",
   "description": "A library for promises (CommonJS/Promises/A,B,D)",
   "homepage": "https://github.com/kriskowal/q",
   "author": "Kris Kowal <kris at cixar.com> (https://github.com/kriskowal)",
diff --git a/q.js b/q.js
index df36027..22f1328 100644
--- a/q.js
+++ b/q.js
@@ -27,8 +27,7 @@
  */
 
 (function (definition) {
-    // Turn off strict mode for this function so we can assign to global.Q
-    /* jshint strict: false */
+    "use strict";
 
     // This file will function properly as a <script> tag, or a module
     // using CommonJS and NodeJS or RequireJS module formats.  In
@@ -40,7 +39,7 @@
         bootstrap("promise", definition);
 
     // CommonJS
-    } else if (typeof exports === "object") {
+    } else if (typeof exports === "object" && typeof module === "object") {
         module.exports = definition();
 
     // RequireJS
@@ -56,8 +55,11 @@
         }
 
     // <script>
+    } else if (typeof window !== "undefined") {
+        window.Q = Q = definition();
+
     } else {
-        Q = definition();
+        throw new Error("This environment was not anticiapted by Q. Please file a bug.");
     }
 
 })(function () {
@@ -450,7 +452,7 @@ function Q(value) {
     // If the object is already a Promise, return it directly.  This enables
     // the resolve function to both be used to created references from objects,
     // but to tolerably coerce non-promises to promises.
-    if (isPromise(value)) {
+    if (value instanceof Promise) {
         return value;
     }
 
@@ -474,6 +476,11 @@ Q.nextTick = nextTick;
  */
 Q.longStackSupport = false;
 
+// enable long stacks if Q_DEBUG is set
+if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) {
+    Q.longStackSupport = true;
+}
+
 /**
  * Constructs a {promise, resolve, reject} object.
  *
@@ -505,7 +512,7 @@ function defer() {
                 progressListeners.push(operands[1]);
             }
         } else {
-            nextTick(function () {
+            Q.nextTick(function () {
                 resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
             });
         }
@@ -553,7 +560,7 @@ function defer() {
         promise.source = newPromise;
 
         array_reduce(messages, function (undefined, message) {
-            nextTick(function () {
+            Q.nextTick(function () {
                 newPromise.promiseDispatch.apply(newPromise, message);
             });
         }, void 0);
@@ -591,7 +598,7 @@ function defer() {
         }
 
         array_reduce(progressListeners, function (undefined, progressListener) {
-            nextTick(function () {
+            Q.nextTick(function () {
                 progressListener(progress);
             });
         }, void 0);
@@ -684,9 +691,9 @@ Promise.prototype.join = function (that) {
 };
 
 /**
- * Returns a promise for the first of an array of promises to become fulfilled.
+ * Returns a promise for the first of an array of promises to become settled.
  * @param answers {Array[Any*]} promises to race
- * @returns {Any*} the first promise to be fulfilled
+ * @returns {Any*} the first promise to be settled
  */
 Q.race = race;
 function race(answerPs) {
@@ -806,7 +813,7 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
         return typeof progressed === "function" ? progressed(value) : value;
     }
 
-    nextTick(function () {
+    Q.nextTick(function () {
         self.promiseDispatch(function (value) {
             if (done) {
                 return;
@@ -847,6 +854,30 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
     return deferred.promise;
 };
 
+Q.tap = function (promise, callback) {
+    return Q(promise).tap(callback);
+};
+
+/**
+ * Works almost like "finally", but not called for rejections.
+ * Original resolution value is passed through callback unaffected.
+ * Callback may return a promise that will be awaited for.
+ * @param {Function} callback
+ * @returns {Q.Promise}
+ * @example
+ * doSomething()
+ *   .then(...)
+ *   .tap(console.log)
+ *   .then(...);
+ */
+Promise.prototype.tap = function (callback) {
+    callback = Q(callback);
+
+    return this.then(function (value) {
+        return callback.fcall(value).thenResolve(value);
+    });
+};
+
 /**
  * Registers an observer on a promise.
  *
@@ -912,9 +943,7 @@ function nearer(value) {
  */
 Q.isPromise = isPromise;
 function isPromise(object) {
-    return isObject(object) &&
-        typeof object.promiseDispatch === "function" &&
-        typeof object.inspect === "function";
+    return object instanceof Promise;
 }
 
 Q.isPromiseAlike = isPromiseAlike;
@@ -1092,7 +1121,7 @@ function fulfill(value) {
  */
 function coerce(promise) {
     var deferred = defer();
-    nextTick(function () {
+    Q.nextTick(function () {
         try {
             promise.then(deferred.resolve, deferred.reject, deferred.notify);
         } catch (exception) {
@@ -1193,7 +1222,7 @@ function async(makeGenerator) {
                     return reject(exception);
                 }
                 if (result.done) {
-                    return result.value;
+                    return Q(result.value);
                 } else {
                     return when(result.value, callback, errback);
                 }
@@ -1204,7 +1233,7 @@ function async(makeGenerator) {
                     result = generator[verb](arg);
                 } catch (exception) {
                     if (isStopIteration(exception)) {
-                        return exception.value;
+                        return Q(exception.value);
                     } else {
                         return reject(exception);
                     }
@@ -1300,7 +1329,7 @@ function dispatch(object, op, args) {
 Promise.prototype.dispatch = function (op, args) {
     var self = this;
     var deferred = defer();
-    nextTick(function () {
+    Q.nextTick(function () {
         self.promiseDispatch(deferred.resolve, op, args);
     });
     return deferred.promise;
@@ -1643,7 +1672,7 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
     var onUnhandledError = function (error) {
         // forward to a future turn so that ``when``
         // does not catch it and turn it into a rejection.
-        nextTick(function () {
+        Q.nextTick(function () {
             makeStackTraceLong(error, promise);
             if (Q.onerror) {
                 Q.onerror(error);
@@ -1670,18 +1699,22 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
  * some milliseconds time out.
  * @param {Any*} promise
  * @param {Number} milliseconds timeout
- * @param {String} custom error message (optional)
+ * @param {Any*} custom error message or Error object (optional)
  * @returns a promise for the resolution of the given promise if it is
  * fulfilled before the timeout, otherwise rejected.
  */
-Q.timeout = function (object, ms, message) {
-    return Q(object).timeout(ms, message);
+Q.timeout = function (object, ms, error) {
+    return Q(object).timeout(ms, error);
 };
 
-Promise.prototype.timeout = function (ms, message) {
+Promise.prototype.timeout = function (ms, error) {
     var deferred = defer();
     var timeoutId = setTimeout(function () {
-        deferred.reject(new Error(message || "Timed out after " + ms + " ms"));
+        if (!error || "string" === typeof error) {
+            error = new Error(error || "Timed out after " + ms + " ms");
+            error.code = "ETIMEDOUT";
+        }
+        deferred.reject(error);
     }, ms);
 
     this.then(function (value) {
@@ -1883,11 +1916,11 @@ function nodeify(object, nodeback) {
 Promise.prototype.nodeify = function (nodeback) {
     if (nodeback) {
         this.then(function (value) {
-            nextTick(function () {
+            Q.nextTick(function () {
                 nodeback(null, value);
             });
         }, function (error) {
-            nextTick(function () {
+            Q.nextTick(function () {
                 nodeback(error);
             });
         });
diff --git a/q.png b/q.png
new file mode 100644
index 0000000..fb1b336
Binary files /dev/null and b/q.png differ
diff --git a/q.svg b/q.svg
new file mode 100644
index 0000000..e8cab2e
--- /dev/null
+++ b/q.svg
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="157.5"
+   height="180"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="q.svg"
+   inkscape:export-filename="/home/kris/art/q.png"
+   inkscape:export-xdpi="51.200001"
+   inkscape:export-ydpi="51.200001">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2"
+     inkscape:cx="62.864072"
+     inkscape:cy="167.31214"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     units="in"
+     inkscape:window-width="1680"
+     inkscape:window-height="973"
+     inkscape:window-x="0"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-872.3622)">
+    <path
+       sodipodi:type="star"
+       style="fill:#f9df34;fill-opacity:1;stroke:none;opacity:1"
+       id="path3833"
+       sodipodi:sides="6"
+       sodipodi:cx="1118"
+       sodipodi:cy="456.36218"
+       sodipodi:r1="277.59683"
+       sodipodi:r2="240.40591"
+       sodipodi:arg1="0.52359878"
+       sodipodi:arg2="1.0471976"
+       inkscape:flatsided="true"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 1358.4059,595.1606 1118,733.95901 877.59409,595.1606 l 0,-277.59683 L 1118,178.76535 1358.4059,317.56377 z"
+       transform="matrix(0.28609737,0,0,0.28609737,-241.10686,831.79819)" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path3840"
+       d="m 23.150536,930.17141 c 0.02584,21.44054 0.05616,42.88112 0.0266,64.32167 18.544384,10.71192 37.074475,21.44862 55.599461,32.19412 18.524303,-10.7114 37.048573,-21.4227 55.572863,-32.13419 -0.0259,-21.44055 -0.0561,-42.88112 -0.0266,-64.32168 C 115.77802,919.52027 97.24878,908.78212 78.723431,898.0372 60.199152,908.74861 41.674869,919.46002 23.150565,930.17141 z m 55.792247,-8.92728 c 11.80936,6.85273 23.635797,13.68573 35.470907,20.49746 -0.004,13.75374 -0.009,27.50747 -0.0132 [...]
+       style="fill:#b7a634;fill-opacity:1;stroke:#524839;stroke-width:5.37970828999999995;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:0.96" />
+    <path
+       style="fill:#f9df34;fill-opacity:1;stroke:#524839;stroke-width:5.54999999999999982;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 3.9712996,919.13021 c 0.034761,28.79449 0.07553,57.58902 0.035762,86.38349 24.9413394,14.3861 49.8634534,28.8054 74.7787004,43.2365 24.914328,-14.3853 49.828638,-28.7707 74.742938,-43.156 -0.0347,-28.79449 -0.0755,-57.58901 -0.0358,-86.38352 -24.942,-14.38487 -49.86297,-28.80613 -74.778703,-43.23647 -24.914303,14.38534 -49.828606,28.77067 -74.7429375,43.156 z M 79.00929,907.14095 c 15.883039,9.20316 31.78905,18.37981 47.70674,27.52793 -0.006,18.47116 -0.0123,36.94232 -0.0177, [...]
+       id="path2993"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g4862"
+       transform="matrix(0.11775097,-0.06798356,0.06798356,0.11775097,5.1642661,919.0661)">
+	<path
+   style="fill:#524739"
+   inkscape:connector-curvature="0"
+   d="m 217.503,388.691 v 14.757 h -16.155 v 39.766 c 0,3.729 0.621,6.214 1.864,7.457 1.243,1.242 3.728,1.863 7.456,1.863 1.243,0 2.432,-0.051 3.573,-0.155 1.138,-0.102 2.226,-0.257 3.262,-0.466 V 469 c -1.864,0.311 -3.937,0.517 -6.213,0.621 -2.279,0.103 -4.505,0.155 -6.68,0.155 -3.417,0 -6.655,-0.232 -9.708,-0.698 -3.056,-0.467 -5.747,-1.372 -8.077,-2.719 -2.33,-1.345 -4.17,-3.262 -5.515,-5.747 -1.347,-2.485 -2.019,-5.748 -2.019,-9.786 v -47.378 h -13.359 v -14.757 h 13.359 v -24.077 h  [...]
+   id="path4864" />
+
+	<path
+   style="fill:#524739"
+   inkscape:connector-curvature="0"
+   d="m 248.569,358.091 v 41.785 h 0.466 c 2.796,-4.66 6.369,-8.051 10.718,-10.175 4.349,-2.121 8.594,-3.185 12.737,-3.185 5.903,0 10.742,0.804 14.524,2.408 3.778,1.606 6.757,3.832 8.932,6.68 2.175,2.849 3.701,6.317 4.582,10.407 0.879,4.092 1.32,8.621 1.32,13.592 V 469 H 279.79 v -45.357 c 0,-6.627 -1.036,-11.573 -3.106,-14.835 -2.073,-3.262 -5.747,-4.894 -11.029,-4.894 -6.007,0 -10.356,1.787 -13.048,5.359 -2.694,3.573 -4.039,9.451 -4.039,17.631 V 469 H 226.51 V 358.091 h 22.059 z"
+   id="path4866" />
+
+	<path
+   style="fill:#524739"
+   inkscape:connector-curvature="0"
+   d="m 334.467,449.738 c 3.313,3.211 8.077,4.815 14.291,4.815 4.451,0 8.283,-1.111 11.495,-3.34 3.208,-2.226 5.177,-4.582 5.902,-7.067 h 19.417 c -3.106,9.631 -7.871,16.519 -14.291,20.659 -6.422,4.144 -14.188,6.214 -23.3,6.214 -6.318,0 -12.015,-1.01 -17.087,-3.029 -5.075,-2.02 -9.374,-4.893 -12.894,-8.621 -3.521,-3.728 -6.24,-8.18 -8.154,-13.358 -1.918,-5.178 -2.874,-10.874 -2.874,-17.087 0,-6.005 0.982,-11.597 2.951,-16.776 1.966,-5.177 4.762,-9.655 8.388,-13.437 3.624,-3.779 7.947,-6. [...]
+   id="path4868" />
+
+	<path
+   style="fill:#524739"
+   inkscape:connector-curvature="0"
+   d="m 413.221,388.691 v 11.185 h 0.466 c 2.796,-4.66 6.42,-8.051 10.874,-10.175 4.451,-2.121 9.009,-3.185 13.669,-3.185 5.903,0 10.742,0.804 14.524,2.408 3.778,1.606 6.757,3.832 8.932,6.68 2.175,2.849 3.701,6.317 4.582,10.407 0.879,4.092 1.32,8.621 1.32,13.592 V 469 H 445.53 v -45.357 c 0,-6.627 -1.036,-11.573 -3.106,-14.835 -2.073,-3.262 -5.747,-4.894 -11.029,-4.894 -6.007,0 -10.356,1.787 -13.048,5.359 -2.694,3.573 -4.039,9.451 -4.039,17.631 V 469 H 392.25 v -80.309 h 20.971 z"
+   id="path4870" />
+
+</g>
+  </g>
+</svg>
diff --git a/spec/q-spec.js b/spec/q-spec.js
index 450685c..005e3cb 100644
--- a/spec/q-spec.js
+++ b/spec/q-spec.js
@@ -191,6 +191,17 @@ describe("always next tick", function () {
         return promise;
     });
 
+	it("allows overriding global nextTick", function () {
+		var spy = jasmine.createSpy();
+		spyOn(Q, 'nextTick').andCallFake(function immediateTick(task){
+			task();
+		});
+		
+		Q.when(Q(), spy);
+		
+		expect(spy).toHaveBeenCalled();
+		expect(Q.nextTick).toHaveBeenCalled();
+	});
 });
 
 describe("progress", function () {
@@ -1445,6 +1456,100 @@ describe("fin", function () {
 
 });
 
+// Almost like "fin"
+describe("tap", function () {
+    var exception1 = new Error("boo!");
+
+    describe("when the promise is fulfilled", function () {
+        it("should call the callback", function () {
+            var called = false;
+            return Q("foo")
+                .tap(function () {
+                    called = true;
+                })
+                .then(function () {
+                    expect(called).toBe(true);
+                });
+        });
+
+        it("should fulfill with the original value", function () {
+            return Q("foo")
+                .tap(function () {
+                    return "bar";
+                })
+                .then(function (result) {
+                    expect(result).toBe("foo");
+                });
+        });
+
+        describe("when the callback returns a promise", function () {
+            describe("that is fulfilled", function () {
+                it("should fulfill with the original reason after that promise resolves", function () {
+                    var promise = Q.delay(250);
+
+                    return Q("foo")
+                        .tap(function () {
+                            return promise;
+                        })
+                        .then(function (result) {
+                            expect(Q.isPending(promise)).toBe(false);
+                            expect(result).toBe("foo");
+                        });
+                });
+            });
+
+            describe("that is rejected", function () {
+                it("should reject with this new rejection reason", function () {
+                    return Q("foo")
+                        .tap(function () {
+                            return Q.reject(exception1);
+                        })
+                        .then(function () {
+                            expect(false).toBe(true);
+                        },
+                        function (exception) {
+                            expect(exception).toBe(exception1);
+                        });
+                });
+            });
+
+        });
+
+        describe("when the callback throws an exception", function () {
+            it("should reject with this new exception", function () {
+                return Q("foo")
+                    .tap(function () {
+                        throw exception1;
+                    })
+                    .then(function () {
+                        expect(false).toBe(true);
+                    },
+                    function (exception) {
+                        expect(exception).toBe(exception1);
+                    });
+            });
+        });
+
+    });
+
+    describe("when the promise is rejected", function () {
+        it("should not call the callback", function () {
+            var called = false;
+
+            return Q.reject(exception1)
+                .tap(function () {
+                    called = true;
+                })
+                .then(function () {
+                    expect(called).toBe(false);
+                }, function () {
+                    expect(called).toBe(false);
+                });
+        });
+    });
+});
+
+
 describe("done", function () {
     describe("when the promise is fulfilled", function () {
         describe("and the callback does not throw", function () {
@@ -1634,10 +1739,26 @@ describe("timeout", function () {
             },
             function (error) {
                 expect(/custom/i.test(error.message)).toBe(true);
+                expect(error.code).toBe("ETIMEDOUT");
             }
         );
     });
 
+    it("should reject with a custom timeout error if the promise is too slow and Error object was provided", function () {
+        var customError = new Error("custom");
+        customError.isCustom = true;
+        return Q.delay(100)
+        .timeout(10, customError)
+        .then(
+            function () {
+                expect(true).toBe(false);
+            },
+            function (error) {
+                expect(/custom/i.test(error.message)).toBe(true);
+                expect(error.isCustom).toBe(true);
+            }
+        );
+    });
 
 });
 
@@ -1800,7 +1921,6 @@ describe("thenReject", function () {
     });
 });
 
-
 describe("thenables", function () {
 
     it("assimilates a thenable with fulfillment with resolve", function () {
@@ -1997,7 +2117,8 @@ describe("node support", function () {
         });
 
     });
-    describe("npost", function () {
+    
+	describe("npost", function () {
 
         it("fulfills with callback result", function () {
             return Q.npost(obj, "method", [1, 2, 3])
@@ -2148,7 +2269,7 @@ describe("node support", function () {
                 expect(ten).toBe(10);
             });
         });
-
+		
     });
 
 });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-q.git



More information about the Pkg-javascript-commits mailing list