From 1bc8e9e31fae41889bc03946ba333c7efe2708d2 Mon Sep 17 00:00:00 2001 From: Ian Bicking Date: Fri, 12 Apr 2013 15:09:13 -0500 Subject: [PATCH] Added printResolved() to support promises --- doctest.js | 61 ++++++++++++++++++++++++++++++++++++++++++ examples/examples.html | 49 ++++++++++++++++++++++++--------- reference.html | 29 ++++++++++++++++++++ 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/doctest.js b/doctest.js index 43bf9da..7d0036a 100644 --- a/doctest.js +++ b/doctest.js @@ -673,6 +673,7 @@ Runner.prototype = { var globs = { write: this.write.bind(this), writeln: this.writeln.bind(this), + printResolved: this.printResolved.bind(this), wait: this.wait.bind(this), Abort: this.Abort.bind(this), repr: repr, @@ -727,6 +728,65 @@ Runner.prototype = { this.write('\n'); }, + printResolved: function () { + // We used finished to signal that nothing should be printed, even when + // waiting is 0, as there are more arguments still to collect: + var finished = false; + var waiting = 0; + var fullValues = []; + var args = Array.prototype.slice.call(arguments); + + // This function is called as each promise is resolved, to see if it + // was the last promise: + var check = (function (dec) { + waiting -= dec; + if (waiting || ! finished) { + return; + } + var flattened = []; + fullValues.forEach(function (items) { + items.forEach(function (item) { + flattened.push(item); + }); + }); + this.writeln.apply(this, flattened); + }).bind(this); + + args.forEach(function (value, index) { + if (value.then) { + // It's a promise + waiting++; + value.then( + (function () { + var values = Array.prototype.slice.call(arguments); + if (! values.length) { + values.push("(resolved)"); + } + fullValues[index] = values; + check(1); + }).bind(this), + (function () { + var errs = Array.prototype.slice.call(arguments); + if (! errs.length) { + errs.push("(error)"); + } + errs = ["Error:"].concat(errs); + fullValues[index] = errs; + check(1); + }).bind(this)); + } else { + fullValues[index] = [value]; + } + }, this); + finished = true; + if (waiting) { + this.wait(function () { + return ! waiting; + }); + } + check(0); + }, + wait: function (conditionOrTime, hardTimeout) { // FIXME: should support a timeout even with a condition if (conditionOrTime === undefined || @@ -811,6 +871,7 @@ Runner.prototype = { if (typeof window != 'undefined') { window.write = undefined; window.writeln = undefined; + window.printResolved = undefined; window.print = undefined; window.wait = undefined; window.onerror = undefined; diff --git a/examples/examples.html b/examples/examples.html index f088a34..f1fb642 100644 --- a/examples/examples.html +++ b/examples/examples.html @@ -116,27 +116,52 @@

Web Service/XML

What we do for JSON, we can also do for XML; in this case it's just fetching a static XML Atom document. -
-$ $.ajax({
->   url: './.resources/example.xml',
->   dataType: 'xml',
->   success: function (doc) {
->     gdoc = doc;
->     writeln(repr(doc));
->   },
->   error: Spy('error')
-> });
-$ wait(0.5);
+
+$.ajax({
+  url: './.resources/example.xml',
+  dataType: 'xml',
+  success: function (doc) {
+    gdoc = doc;
+    writeln(repr(doc));
+  },
+  error: Spy('error')
+});
+wait(0.5);
+/* =>
 <feed xmlns="http://www.w3.org/2005/Atom">
   <title>Example Feed</title>
   ...
 </feed>
+*/
 
 
- +

Deferred/Promise

+ +
+ + You can also + print jquery.Deferred + (promise) objects once they've resolved, using + the printResolved() function. This also implicitly + calls wait() with the condition that all the promises + be resolved. Both errors and resolved values are printed. + +
+var def1 = $.Deferred();
+var def2 = $.Deferred();
+def1.resolve("Value 1!", "Value2!");
+setTimeout(function () {
+  def2.reject("sucka");
+}, 500);
+printResolved("def1", def1, "def2", def2);
+// => def1 Value 1! Value2! def2 Error: sucka
+  
+
+ + diff --git a/reference.html b/reference.html index 5bcb14f..4b26bf4 100644 --- a/reference.html +++ b/reference.html @@ -218,6 +218,35 @@

console.log()

All the methods on console should work, like console.warn(). The underlying normal console function is called, but in addition on a test-by-test basis these are collected and displayed.

+

printResolved() for Deferred and Promises

+ +

There's special support for the jQuery Deferred object, and generally Promises/A.

+ +

This support is through the printResolved() function, which is basically equivalent to print() except any promise arguments will be waited on to resolve (proper resolution or an error). You can use it like this:

+ +
+var def = $.Deferred();
+setTimeout(function () {
+  def.resolve("Resolved!");
+});
+printResolved(def);
+// => Resolved!
+
+ +

Errors are printed out with Error: before the value, and multiple arguments are printed out with spaces between them, or a placeholder if there's no arguments. For instance:

+ +
+var def = $.Deferred();
+def.reject({code: 1}, "a message");
+printResolved(def);
+// => Error: {code: 1} a message
+// Or you might not have any value at all:
+def = $.Deferred();
+def.resolve();
+printResolved(def);
+// => (resolved)
+
+

Output matching

The expected output is compared with the output you actually got (received).