1 QUnit
.module( "deferred", {
2 afterEach
: moduleTeardown
7 if ( !includesModule( "deferred" ) ) {
11 jQuery
.each( [ "", " - new operator" ], function( _
, withNew
) {
13 function createDeferred( fn
) {
14 return withNew
? new jQuery
.Deferred( fn
) : jQuery
.Deferred( fn
);
17 QUnit
.test( "jQuery.Deferred" + withNew
, function( assert
) {
21 var defer
= createDeferred();
23 assert
.ok( typeof defer
.pipe
=== "function", "defer.pipe is a function" );
25 defer
.resolve().done( function() {
26 assert
.ok( true, "Success on resolve" );
27 assert
.strictEqual( defer
.state(), "resolved", "Deferred is resolved (state)" );
28 } ).fail( function() {
29 assert
.ok( false, "Error on resolve" );
30 } ).always( function() {
31 assert
.ok( true, "Always callback on resolve" );
34 defer
= createDeferred();
35 defer
.reject().done( function() {
36 assert
.ok( false, "Success on reject" );
37 } ).fail( function() {
38 assert
.ok( true, "Error on reject" );
39 assert
.strictEqual( defer
.state(), "rejected", "Deferred is rejected (state)" );
40 } ).always( function() {
41 assert
.ok( true, "Always callback on reject" );
44 createDeferred( function( defer
) {
45 assert
.ok( this === defer
, "Defer passed as this & first argument" );
46 this.resolve( "done" );
47 } ).done( function( value
) {
48 assert
.strictEqual( value
, "done", "Passed function executed" );
51 createDeferred( function( defer
) {
52 var promise
= defer
.promise(),
54 funcPromise
= defer
.promise( func
);
55 assert
.strictEqual( defer
.promise(), promise
, "promise is always the same" );
56 assert
.strictEqual( funcPromise
, func
, "non objects get extended" );
57 jQuery
.each( promise
, function( key
) {
58 if ( typeof promise
[ key
] !== "function" ) {
59 assert
.ok( false, key
+ " is a function (" + typeof( promise
[ key
] ) + ")" );
61 if ( promise
[ key
] !== func
[ key
] ) {
62 assert
.strictEqual( func
[ key
], promise
[ key
], key
+ " is the same" );
67 jQuery
.expandedEach
= jQuery
.each
;
68 jQuery
.expandedEach( "resolve reject".split( " " ), function( _
, change
) {
69 createDeferred( function( defer
) {
70 assert
.strictEqual( defer
.state(), "pending", "pending after creation" );
72 defer
.progress( function( value
) {
73 assert
.strictEqual( value
, checked
, "Progress: right value (" + value
+ ") received" );
75 for ( checked
= 0; checked
< 3; checked
++ ) {
76 defer
.notify( checked
);
78 assert
.strictEqual( defer
.state(), "pending", "pending after notification" );
80 assert
.notStrictEqual( defer
.state(), "pending", "not pending after " + change
);
87 QUnit
.test( "jQuery.Deferred - chainability", function( assert
) {
89 var defer
= jQuery
.Deferred();
93 jQuery
.expandedEach
= jQuery
.each
;
94 jQuery
.expandedEach( "resolve reject notify resolveWith rejectWith notifyWith done fail progress always".split( " " ), function( _
, method
) {
98 assert
.strictEqual( object
.m(), object
, method
+ " is chainable" );
102 QUnit
.test( "jQuery.Deferred.then - filtering (done)", function( assert
) {
106 var value1
, value2
, value3
,
107 defer
= jQuery
.Deferred(),
108 piped
= defer
.then( function( a
, b
) {
111 done
= jQuery
.map( new Array( 3 ), function() { return assert
.async(); } );
113 piped
.done( function( result
) {
117 defer
.done( function( a
, b
) {
122 defer
.resolve( 2, 3 ).then( function() {
123 assert
.strictEqual( value1
, 2, "first resolve value ok" );
124 assert
.strictEqual( value2
, 3, "second resolve value ok" );
125 assert
.strictEqual( value3
, 6, "result of filter ok" );
129 jQuery
.Deferred().reject().then( function() {
130 assert
.ok( false, "then should not be called on reject" );
131 } ).then( null, done
.pop() );
133 jQuery
.Deferred().resolve().then( jQuery
.noop
).done( function( value
) {
134 assert
.strictEqual( value
, undefined, "then done callback can return undefined/null" );
139 QUnit
.test( "jQuery.Deferred.then - filtering (fail)", function( assert
) {
143 var value1
, value2
, value3
,
144 defer
= jQuery
.Deferred(),
145 piped
= defer
.then( null, function( a
, b
) {
148 done
= jQuery
.map( new Array( 3 ), function() { return assert
.async(); } );
150 piped
.done( function( result
) {
154 defer
.fail( function( a
, b
) {
159 defer
.reject( 2, 3 ).then( null, function() {
160 assert
.strictEqual( value1
, 2, "first reject value ok" );
161 assert
.strictEqual( value2
, 3, "second reject value ok" );
162 assert
.strictEqual( value3
, 6, "result of filter ok" );
166 jQuery
.Deferred().resolve().then( null, function() {
167 assert
.ok( false, "then should not be called on resolve" );
168 } ).then( done
.pop() );
170 jQuery
.Deferred().reject().then( null, jQuery
.noop
).done( function( value
) {
171 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
176 QUnit
.test( "jQuery.Deferred.catch", function( assert
) {
179 var value1
, value2
, value3
,
180 defer
= jQuery
.Deferred(),
181 piped
= defer
.catch( function( a
, b
) {
184 done
= jQuery
.map( new Array( 3 ), function() { return assert
.async(); } );
186 piped
.done( function( result
) {
190 defer
.fail( function( a
, b
) {
195 defer
.reject( 2, 3 ).catch( function() {
196 assert
.strictEqual( value1
, 2, "first reject value ok" );
197 assert
.strictEqual( value2
, 3, "second reject value ok" );
198 assert
.strictEqual( value3
, 6, "result of filter ok" );
202 jQuery
.Deferred().resolve().catch( function() {
203 assert
.ok( false, "then should not be called on resolve" );
204 } ).then( done
.pop() );
206 jQuery
.Deferred().reject().catch( jQuery
.noop
).done( function( value
) {
207 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
212 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( assert
) {
216 var value1
, value2
, value3
,
217 defer
= jQuery
.Deferred(),
218 piped
= defer
.pipe( null, function( a
, b
) {
221 done
= jQuery
.map( new Array( 3 ), function() { return assert
.async(); } );
223 piped
.fail( function( result
) {
227 defer
.fail( function( a
, b
) {
232 defer
.reject( 2, 3 ).pipe( null, function() {
233 assert
.strictEqual( value1
, 2, "first reject value ok" );
234 assert
.strictEqual( value2
, 3, "second reject value ok" );
235 assert
.strictEqual( value3
, 6, "result of filter ok" );
239 jQuery
.Deferred().resolve().pipe( null, function() {
240 assert
.ok( false, "then should not be called on resolve" );
241 } ).then( done
.pop() );
243 jQuery
.Deferred().reject().pipe( null, jQuery
.noop
).fail( function( value
) {
244 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
249 QUnit
.test( "jQuery.Deferred.then - filtering (progress)", function( assert
) {
253 var value1
, value2
, value3
,
254 defer
= jQuery
.Deferred(),
255 piped
= defer
.then( null, null, function( a
, b
) {
258 done
= assert
.async();
260 piped
.progress( function( result
) {
264 defer
.progress( function( a
, b
) {
269 defer
.notify( 2, 3 ).then( null, null, function() {
270 assert
.strictEqual( value1
, 2, "first progress value ok" );
271 assert
.strictEqual( value2
, 3, "second progress value ok" );
272 assert
.strictEqual( value3
, 6, "result of filter ok" );
277 QUnit
.test( "jQuery.Deferred.then - deferred (done)", function( assert
) {
281 var value1
, value2
, value3
,
282 defer
= jQuery
.Deferred(),
283 piped
= defer
.then( function( a
, b
) {
284 return jQuery
.Deferred( function( defer
) {
285 defer
.reject( a
* b
);
288 done
= assert
.async();
290 piped
.fail( function( result
) {
294 defer
.done( function( a
, b
) {
299 defer
.resolve( 2, 3 );
301 piped
.fail( function() {
302 assert
.strictEqual( value1
, 2, "first resolve value ok" );
303 assert
.strictEqual( value2
, 3, "second resolve value ok" );
304 assert
.strictEqual( value3
, 6, "result of filter ok" );
309 QUnit
.test( "jQuery.Deferred.then - deferred (fail)", function( assert
) {
313 var value1
, value2
, value3
,
314 defer
= jQuery
.Deferred(),
315 piped
= defer
.then( null, function( a
, b
) {
316 return jQuery
.Deferred( function( defer
) {
317 defer
.resolve( a
* b
);
320 done
= assert
.async();
322 piped
.done( function( result
) {
326 defer
.fail( function( a
, b
) {
331 defer
.reject( 2, 3 );
333 piped
.done( function() {
334 assert
.strictEqual( value1
, 2, "first reject value ok" );
335 assert
.strictEqual( value2
, 3, "second reject value ok" );
336 assert
.strictEqual( value3
, 6, "result of filter ok" );
341 QUnit
.test( "jQuery.Deferred.then - deferred (progress)", function( assert
) {
345 var value1
, value2
, value3
,
346 defer
= jQuery
.Deferred(),
347 piped
= defer
.then( null, null, function( a
, b
) {
348 return jQuery
.Deferred( function( defer
) {
349 defer
.resolve( a
* b
);
352 done
= assert
.async();
354 piped
.progress( function( result
) {
355 return jQuery
.Deferred().resolve().then( function() {
357 } ).then( function( result
) {
362 defer
.progress( function( a
, b
) {
367 defer
.notify( 2, 3 );
369 piped
.then( null, null, function( result
) {
370 return jQuery
.Deferred().resolve().then( function() {
372 } ).then( function() {
373 assert
.strictEqual( value1
, 2, "first progress value ok" );
374 assert
.strictEqual( value2
, 3, "second progress value ok" );
375 assert
.strictEqual( value3
, 6, "result of filter ok" );
381 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - deferred (progress)", function( assert
) {
385 var value1
, value2
, value3
,
386 defer
= jQuery
.Deferred(),
387 piped
= defer
.pipe( null, null, function( a
, b
) {
388 return jQuery
.Deferred( function( defer
) {
389 defer
.resolve( a
* b
);
392 done
= assert
.async();
394 piped
.done( function( result
) {
398 defer
.progress( function( a
, b
) {
403 defer
.notify( 2, 3 );
405 piped
.done( function() {
406 assert
.strictEqual( value1
, 2, "first progress value ok" );
407 assert
.strictEqual( value2
, 3, "second progress value ok" );
408 assert
.strictEqual( value3
, 6, "result of filter ok" );
413 QUnit
.test( "jQuery.Deferred.then - context", function( assert
) {
417 var defer
, piped
, defer2
, piped2
,
418 context
= { custom
: true },
419 done
= jQuery
.map( new Array( 5 ), function() { return assert
.async(); } );
421 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).then( function( value
) {
422 assert
.strictEqual( this, context
, "custom context received by .then handler" );
424 } ).done( function( value
) {
425 assert
.notStrictEqual( this, context
,
426 "custom context not propagated through .then handler" );
427 assert
.strictEqual( value
, 6, "proper value received" );
431 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).then().done( function( value
) {
432 assert
.strictEqual( this, context
,
433 "custom context propagated through .then without handler" );
434 assert
.strictEqual( value
, 2, "proper value received" );
438 jQuery
.Deferred().resolve().then( function() {
439 assert
.strictEqual( this, window
, "default context in .then handler" );
440 return jQuery
.Deferred().resolveWith( context
);
441 } ).done( function() {
442 assert
.strictEqual( this, context
,
443 "custom context of returned deferred correctly propagated" );
447 defer
= jQuery
.Deferred();
448 piped
= defer
.then( function( value
) {
454 piped
.done( function( value
) {
455 assert
.strictEqual( this, window
, ".then handler does not introduce context" );
456 assert
.strictEqual( value
, 6, "proper value received" );
460 defer2
= jQuery
.Deferred();
461 piped2
= defer2
.then();
465 piped2
.done( function( value
) {
466 assert
.strictEqual( this, window
, ".then without handler does not introduce context" );
467 assert
.strictEqual( value
, 2, "proper value received (without passing function)" );
472 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - context", function( assert
) {
476 var defer
, piped
, defer2
, piped2
,
477 context
= { custom
: true },
478 done
= jQuery
.map( new Array( 5 ), function() { return assert
.async(); } );
480 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).pipe( function( value
) {
481 assert
.strictEqual( this, context
, "custom context received by .pipe handler" );
483 } ).done( function( value
) {
484 assert
.strictEqual( this, context
,
485 "[PIPE ONLY] custom context propagated through .pipe handler" );
486 assert
.strictEqual( value
, 6, "proper value received" );
490 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).pipe().done( function( value
) {
491 assert
.strictEqual( this, context
,
492 "[PIPE ONLY] custom context propagated through .pipe without handler" );
493 assert
.strictEqual( value
, 2, "proper value received" );
497 jQuery
.Deferred().resolve().pipe( function() {
498 assert
.strictEqual( this, window
, "default context in .pipe handler" );
499 return jQuery
.Deferred().resolveWith( context
);
500 } ).done( function() {
501 assert
.strictEqual( this, context
,
502 "custom context of returned deferred correctly propagated" );
506 defer
= jQuery
.Deferred();
507 piped
= defer
.pipe( function( value
) {
513 piped
.done( function( value
) {
514 assert
.strictEqual( this, window
, ".pipe handler does not introduce context" );
515 assert
.strictEqual( value
, 6, "proper value received" );
519 defer2
= jQuery
.Deferred();
520 piped2
= defer2
.pipe();
524 piped2
.done( function( value
) {
525 assert
.strictEqual( this, window
, ".pipe without handler does not introduce context" );
526 assert
.strictEqual( value
, 2, "proper value received (without passing function)" );
531 QUnit
.test( "jQuery.Deferred.then - spec compatibility", function( assert
) {
535 var done
= assert
.async(),
536 defer
= jQuery
.Deferred();
538 defer
.done( function() {
543 defer
.then( function() {
544 assert
.ok( true, "errors in .done callbacks don't stop .then handlers" );
552 QUnit
.testUnlessIE( "jQuery.Deferred.then - IsCallable determination (gh-3596)",
557 var done
= assert
.async(),
558 defer
= jQuery
.Deferred();
561 assert
.ok( true, "handler with non-'Function' @@toStringTag gets invoked" );
563 faker
[ Symbol
.toStringTag
] = "String";
565 defer
.then( faker
).then( done
);
570 QUnit
.test( "jQuery.Deferred.exceptionHook", function( assert
) {
574 var done
= assert
.async(),
575 defer
= jQuery
.Deferred(),
576 oldWarn
= window
.console
.warn
;
578 window
.console
.warn = function( _intro
, error
) {
579 assert
.ok( /barf/.test( error
.message
+ "\n" + error
.stack
),
580 "Error mentions the method: " + error
.message
+ "\n" + error
.stack
);
584 defer
.then( function() {
586 // Should get an error
588 } ).then( null, jQuery
.noop
),
590 defer
.then( function() {
592 // Should NOT get an error
593 throw new Error( "Make me a sandwich" );
594 } ).then( null, jQuery
.noop
)
595 ).then( function barf( ) {
596 jQuery
.thisDiesToo();
597 } ).then( null, function( ) {
598 window
.console
.warn
= oldWarn
;
605 QUnit
.test( "jQuery.Deferred.exceptionHook with error hooks", function( assert
) {
609 var done
= assert
.async(),
610 defer
= jQuery
.Deferred(),
611 oldWarn
= window
.console
.warn
;
613 jQuery
.Deferred
.getErrorHook = function() {
615 // Default exceptionHook assumes the stack is in a form console.warn can log,
616 // but a custom getErrorHook+exceptionHook pair could save a raw form and
617 // format it to a string only when an exception actually occurs.
618 // For the unit test we just ensure the plumbing works.
619 return "NO ERROR FOR YOU";
622 window
.console
.warn = function() {
623 var msg
= Array
.prototype.join
.call( arguments
, " " );
624 assert
.ok( /cough_up_hairball/.test( msg
), "Function mentioned: " + msg
);
625 assert
.ok( /NO ERROR FOR YOU/.test( msg
), "Error included: " + msg
);
628 defer
.then( function() {
629 jQuery
.cough_up_hairball();
630 } ).then( null, function( ) {
631 window
.console
.warn
= oldWarn
;
632 delete jQuery
.Deferred
.getErrorHook
;
639 QUnit
.test( "jQuery.Deferred - 1.x/2.x compatibility", function( assert
) {
643 var context
= { id
: "callback context" },
644 thenable
= jQuery
.Deferred().resolve( "thenable fulfillment" ).promise(),
645 done
= jQuery
.map( new Array( 8 ), function() { return assert
.async(); } );
647 thenable
.unwrapped
= false;
649 jQuery
.Deferred().resolve( 1, 2 ).then( function() {
650 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
651 ".then fulfillment callbacks receive all resolution values" );
654 jQuery
.Deferred().reject( 1, 2 ).then( null, function() {
655 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
656 ".then rejection callbacks receive all rejection values" );
659 jQuery
.Deferred().notify( 1, 2 ).then( null, null, function() {
660 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
661 ".then progress callbacks receive all progress values" );
665 jQuery
.Deferred().resolveWith( context
).then( function() {
666 assert
.deepEqual( this, context
, ".then fulfillment callbacks receive context" );
669 jQuery
.Deferred().rejectWith( context
).then( null, function() {
670 assert
.deepEqual( this, context
, ".then rejection callbacks receive context" );
673 jQuery
.Deferred().notifyWith( context
).then( null, null, function() {
674 assert
.deepEqual( this, context
, ".then progress callbacks receive context" );
678 jQuery
.Deferred().resolve( thenable
).done( function( value
) {
679 assert
.strictEqual( value
, thenable
, ".done doesn't unwrap thenables" );
683 jQuery
.Deferred().notify( thenable
).then().then( null, null, function( value
) {
684 assert
.strictEqual( value
, "thenable fulfillment",
685 ".then implicit progress callbacks unwrap thenables" );
690 QUnit
.test( "jQuery.Deferred.then - progress and thenables", function( assert
) {
694 var trigger
= jQuery
.Deferred().notify(),
695 expectedProgress
= [ "baz", "baz" ],
696 done
= jQuery
.map( new Array( 2 ), function() { return assert
.async(); } ),
697 failer = function( evt
) {
699 assert
.ok( false, "no unexpected " + evt
);
703 trigger
.then( null, null, function() {
704 var notifier
= jQuery
.Deferred().notify( "foo" );
705 setTimeout( function() {
706 notifier
.notify( "bar" ).resolve( "baz" );
709 } ).then( failer( "fulfill" ), failer( "reject" ), function( v
) {
710 assert
.strictEqual( v
, expectedProgress
.shift(), "expected progress value" );
716 QUnit
.test( "jQuery.Deferred - notify and resolve", function( assert
) {
720 var notifiedResolved
= jQuery
.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/,
721 done
= jQuery
.map( new Array( 3 ), function() { return assert
.async(); } );
723 notifiedResolved
.progress( function( v
) {
724 assert
.strictEqual( v
, "foo", "progress value" );
727 notifiedResolved
.pipe().progress( function( v
) {
728 assert
.strictEqual( v
, "foo", "piped progress value" );
731 notifiedResolved
.pipe( null, null, function() {
733 } ).progress( function( v
) {
734 assert
.strictEqual( v
, "baz", "replaced piped progress value" );
737 notifiedResolved
.pipe( null, null, function() {
738 return jQuery
.Deferred().notify( "baz" ).resolve( "quux" );
739 } ).progress( function( v
) {
740 assert
.strictEqual( v
, "baz", "deferred replaced piped progress value" );
743 notifiedResolved
.then().progress( function( v
) {
744 assert
.strictEqual( v
, "foo", "then'd progress value" );
748 notifiedResolved
.then( null, null, function() {
750 } ).progress( function( v
) {
751 assert
.strictEqual( v
, "baz", "replaced then'd progress value" );
755 notifiedResolved
.then( null, null, function() {
756 return jQuery
.Deferred().notify( "baz" ).resolve( "quux" );
757 } ).progress( function( v
) {
759 // Progress from the surrogate deferred is ignored
760 assert
.strictEqual( v
, "quux", "deferred replaced then'd progress value" );
765 QUnit
.test( "jQuery.Deferred - resolved to a notifying deferred", function( assert
) {
769 var deferred
= jQuery
.Deferred(),
770 done
= assert
.async( 2 );
772 deferred
.resolve( jQuery
.Deferred( function( notifyingDeferred
) {
773 notifyingDeferred
.notify( "foo", "bar" );
774 notifyingDeferred
.resolve( "baz", "quux" );
777 // Apply an empty then to force thenable unwrapping.
778 // See https://github.com/jquery/jquery/issues/3000 for more info.
779 deferred
.then().then( function() {
781 [].slice
.call( arguments
),
783 "The fulfilled handler receives proper params"
786 }, null, function() {
788 [].slice
.call( arguments
),
790 "The progress handler receives proper params"
796 QUnit
.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert
) {
801 var defaultContext
= ( function getDefaultContext() { return this; } )(),
803 done
= assert
.async( 20 );
806 .done( function( resolveValue
) {
807 assert
.strictEqual( arguments
.length
, 0, "Resolved .done with no arguments" );
808 assert
.strictEqual( this, defaultContext
, "Default .done context with no arguments" );
810 .then( function( resolveValue
) {
811 assert
.strictEqual( arguments
.length
, 0, "Resolved .then with no arguments" );
812 assert
.strictEqual( this, defaultContext
, "Default .then context with no arguments" );
816 "an empty string": "",
817 "a non-empty string": "some string",
819 "a number other than zero": 1,
823 "undefined": undefined,
824 "a plain object": {},
825 "an array": [ 1, 2, 3 ]
826 }, function( message
, value
) {
827 var code
= "jQuery.when( " + message
+ " )",
828 onFulfilled = function( method
) {
829 var call
= code
+ "." + method
;
830 return function( resolveValue
) {
831 assert
.strictEqual( resolveValue
, value
, call
+ " resolve" );
832 assert
.strictEqual( this, defaultContext
, call
+ " context" );
836 onRejected = function( method
) {
837 var call
= code
+ "." + method
;
839 assert
.ok( false, call
+ " reject" );
845 .done( onFulfilled( "done" ) )
846 .fail( onRejected( "done" ) )
847 .then( onFulfilled( "then" ), onRejected( "then" ) );
851 QUnit
.test( "jQuery.when(thenable) - like Promise.resolve", function( assert
) {
854 var customToStringThen
= {
855 then: function( onFulfilled
) {
859 if ( typeof Symbol
=== "function" ) {
860 customToStringThen
.then
[ Symbol
.toStringTag
] = "String";
863 var slice
= [].slice
,
864 sentinel
= { context
: "explicit" },
865 eventuallyFulfilled
= jQuery
.Deferred().notify( true ),
866 eventuallyRejected
= jQuery
.Deferred().notify( true ),
867 secondaryFulfilled
= jQuery
.Deferred().resolve( eventuallyFulfilled
),
868 secondaryRejected
= jQuery
.Deferred().resolve( eventuallyRejected
),
870 promise
: Promise
.resolve( true ),
871 customToStringThen
: customToStringThen
,
872 rejectedPromise
: Promise
.reject( false ),
873 deferred
: jQuery
.Deferred().resolve( true ),
874 eventuallyFulfilled
: eventuallyFulfilled
,
875 secondaryFulfilled
: secondaryFulfilled
,
876 eventuallySecondaryFulfilled
: jQuery
.Deferred().notify( true ),
877 multiDeferred
: jQuery
.Deferred().resolve( "foo", "bar" ),
878 deferredWith
: jQuery
.Deferred().resolveWith( sentinel
, [ true ] ),
879 multiDeferredWith
: jQuery
.Deferred().resolveWith( sentinel
, [ "foo", "bar" ] ),
880 rejectedDeferred
: jQuery
.Deferred().reject( false ),
881 eventuallyRejected
: eventuallyRejected
,
882 secondaryRejected
: secondaryRejected
,
883 eventuallySecondaryRejected
: jQuery
.Deferred().notify( true ),
884 multiRejectedDeferred
: jQuery
.Deferred().reject( "baz", "quux" ),
885 rejectedDeferredWith
: jQuery
.Deferred().rejectWith( sentinel
, [ false ] ),
886 multiRejectedDeferredWith
: jQuery
.Deferred().rejectWith( sentinel
, [ "baz", "quux" ] )
889 deferredWith
: sentinel
,
890 multiDeferredWith
: sentinel
,
891 rejectedDeferredWith
: sentinel
,
892 multiRejectedDeferredWith
: sentinel
896 customToStringThen
: [],
898 eventuallyFulfilled
: [ true ],
899 secondaryFulfilled
: [ true ],
900 eventuallySecondaryFulfilled
: [ true ],
901 multiDeferred
: [ "foo", "bar" ],
902 deferredWith
: [ true ],
903 multiDeferredWith
: [ "foo", "bar" ]
906 rejectedPromise
: [ false ],
907 rejectedDeferred
: [ false ],
908 eventuallyRejected
: [ false ],
909 secondaryRejected
: [ false ],
910 eventuallySecondaryRejected
: [ false ],
911 multiRejectedDeferred
: [ "baz", "quux" ],
912 rejectedDeferredWith
: [ false ],
913 multiRejectedDeferredWith
: [ "baz", "quux" ]
915 numCases
= Object
.keys( willSucceed
).length
+ Object
.keys( willError
).length
,
917 defaultContext
= ( function getDefaultContext() { return this; } )(),
919 done
= assert
.async( numCases
* 2 );
921 assert
.expect( numCases
* 4 );
923 jQuery
.each( inputs
, function( message
, value
) {
924 var code
= "jQuery.when( " + message
+ " )",
925 shouldResolve
= willSucceed
[ message
],
926 shouldError
= willError
[ message
],
927 context
= contexts
[ message
] || defaultContext
,
928 onFulfilled = function( method
) {
929 var call
= code
+ "." + method
;
931 if ( shouldResolve
) {
932 assert
.deepEqual( slice
.call( arguments
), shouldResolve
,
934 assert
.strictEqual( this, context
, call
+ " context" );
936 assert
.ok( false, call
+ " resolve" );
941 onRejected = function( method
) {
942 var call
= code
+ "." + method
;
945 assert
.deepEqual( slice
.call( arguments
), shouldError
, call
+ " reject" );
946 assert
.strictEqual( this, context
, call
+ " context" );
948 assert
.ok( false, call
+ " reject" );
955 .done( onFulfilled( "done" ) )
956 .fail( onRejected( "done" ) )
957 .then( onFulfilled( "then" ), onRejected( "then" ) );
960 setTimeout( function() {
961 eventuallyFulfilled
.resolve( true );
962 eventuallyRejected
.reject( false );
963 inputs
.eventuallySecondaryFulfilled
.resolve( secondaryFulfilled
);
964 inputs
.eventuallySecondaryRejected
.resolve( secondaryRejected
);
968 QUnit
.test( "jQuery.when(a, b) - like Promise.all", function( assert
) {
971 assert
.expect( 196 );
973 var slice
= [].slice
,
976 fulfilled
: jQuery
.Deferred().resolve( 1 ),
977 rejected
: jQuery
.Deferred().reject( 0 ),
978 eventuallyFulfilled
: jQuery
.Deferred().notify( true ),
979 eventuallyRejected
: jQuery
.Deferred().notify( true ),
980 fulfilledStandardPromise
: Promise
.resolve( 1 ),
981 rejectedStandardPromise
: Promise
.reject( 0 )
986 eventuallyFulfilled
: true,
987 fulfilledStandardPromise
: true
991 eventuallyRejected
: true,
992 rejectedStandardPromise
: true
995 defaultContext
= ( function getDefaultContext() { return this; } )(),
997 done
= assert
.async( 98 );
999 jQuery
.each( deferreds
, function( id1
, v1
) {
1000 jQuery
.each( deferreds
, function( id2
, v2
) {
1001 var code
= "jQuery.when( " + id1
+ ", " + id2
+ " )",
1002 shouldResolve
= willSucceed
[ id1
] && willSucceed
[ id2
],
1003 shouldError
= willError
[ id1
] || willError
[ id2
],
1004 expected
= shouldResolve
? [ 1, 1 ] : [ 0 ],
1005 context
= shouldResolve
? [ defaultContext
, defaultContext
] : defaultContext
,
1006 onFulfilled = function( method
) {
1007 var call
= code
+ "." + method
;
1009 if ( shouldResolve
) {
1010 assert
.deepEqual( slice
.call( arguments
), expected
,
1011 call
+ " resolve" );
1012 assert
.deepEqual( this, context
, code
+ " context" );
1014 assert
.ok( false, call
+ " resolve" );
1019 onRejected = function( method
) {
1020 var call
= code
+ "." + method
;
1022 if ( shouldError
) {
1023 assert
.deepEqual( slice
.call( arguments
), expected
, call
+ " reject" );
1024 assert
.deepEqual( this, context
, code
+ " context" );
1026 assert
.ok( false, call
+ " reject" );
1032 jQuery
.when( v1
, v2
)
1033 .done( onFulfilled( "done" ) )
1034 .fail( onRejected( "done" ) )
1035 .then( onFulfilled( "then" ), onRejected( "then" ) );
1039 setTimeout( function() {
1040 deferreds
.eventuallyFulfilled
.resolve( 1 );
1041 deferreds
.eventuallyRejected
.reject( 0 );
1045 QUnit
.test( "jQuery.when - always returns a new promise", function( assert
) {
1047 assert
.expect( 42 );
1051 "non-thenable": [ "foo" ],
1052 "promise": [ Promise
.resolve( "bar" ) ],
1053 "rejected promise": [ Promise
.reject( "bar" ) ],
1054 "deferred": [ jQuery
.Deferred().resolve( "baz" ) ],
1055 "rejected deferred": [ jQuery
.Deferred().reject( "baz" ) ],
1056 "multi-resolved deferred": [ jQuery
.Deferred().resolve( "qux", "quux" ) ],
1057 "multiple non-thenables": [ "corge", "grault" ],
1058 "multiple deferreds": [
1059 jQuery
.Deferred().resolve( "garply" ),
1060 jQuery
.Deferred().resolve( "waldo" )
1062 }, function( label
, args
) {
1063 var result
= jQuery
.when
.apply( jQuery
, args
);
1065 assert
.ok( typeof result
.then
=== "function", "Thenable returned from " + label
);
1066 assert
.strictEqual( result
.resolve
, undefined, "Non-deferred returned from " + label
);
1067 assert
.strictEqual( result
.promise(), result
, "Promise returned from " + label
);
1069 jQuery
.each( args
, function( i
, arg
) {
1070 assert
.notStrictEqual( result
, arg
, "Returns distinct from arg " + i
+ " of " + label
);
1071 if ( arg
.promise
) {
1072 assert
.notStrictEqual( result
, arg
.promise(),
1073 "Returns distinct from promise of arg " + i
+ " of " + label
);
1079 QUnit
.test( "jQuery.when - notify does not affect resolved", function( assert
) {
1083 var a
= jQuery
.Deferred().notify( 1 ).resolve( 4 ),
1084 b
= jQuery
.Deferred().notify( 2 ).resolve( 5 ),
1085 c
= jQuery
.Deferred().notify( 3 ).resolve( 6 );
1087 jQuery
.when( a
, b
, c
).done( function( a
, b
, c
) {
1088 assert
.strictEqual( a
, 4, "first resolve value ok" );
1089 assert
.strictEqual( b
, 5, "second resolve value ok" );
1090 assert
.strictEqual( c
, 6, "third resolve value ok" );
1091 } ).fail( function() {
1092 assert
.ok( false, "Error on resolve" );
1096 QUnit
.test( "jQuery.when(...) - opportunistically synchronous", function( assert
) {
1100 var when
= "before",
1101 resolved
= jQuery
.Deferred().resolve( true ),
1102 rejected
= jQuery
.Deferred().reject( false ),
1103 validate = function( label
) {
1105 assert
.equal( when
, "before", label
);
1108 done
= assert
.async( 5 );
1110 jQuery
.when().done( validate( "jQuery.when()" ) ).always( done
);
1111 jQuery
.when( when
).done( validate( "jQuery.when(nonThenable)" ) ).always( done
);
1112 jQuery
.when( resolved
).done( validate( "jQuery.when(alreadyFulfilled)" ) ).always( done
);
1113 jQuery
.when( rejected
).fail( validate( "jQuery.when(alreadyRejected)" ) ).always( done
);
1114 jQuery
.when( resolved
, rejected
)
1115 .always( validate( "jQuery.when(alreadyFulfilled, alreadyRejected)" ) )