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() {
112 return assert
.async();
115 piped
.done( function( result
) {
119 defer
.done( function( a
, b
) {
124 defer
.resolve( 2, 3 ).then( function() {
125 assert
.strictEqual( value1
, 2, "first resolve value ok" );
126 assert
.strictEqual( value2
, 3, "second resolve value ok" );
127 assert
.strictEqual( value3
, 6, "result of filter ok" );
131 jQuery
.Deferred().reject().then( function() {
132 assert
.ok( false, "then should not be called on reject" );
133 } ).then( null, done
.pop() );
135 jQuery
.Deferred().resolve().then( jQuery
.noop
).done( function( value
) {
136 assert
.strictEqual( value
, undefined, "then done callback can return undefined/null" );
141 QUnit
.test( "jQuery.Deferred.then - filtering (fail)", function( assert
) {
145 var value1
, value2
, value3
,
146 defer
= jQuery
.Deferred(),
147 piped
= defer
.then( null, function( a
, b
) {
150 done
= jQuery
.map( new Array( 3 ), function() {
151 return assert
.async();
154 piped
.done( function( result
) {
158 defer
.fail( function( a
, b
) {
163 defer
.reject( 2, 3 ).then( null, function() {
164 assert
.strictEqual( value1
, 2, "first reject value ok" );
165 assert
.strictEqual( value2
, 3, "second reject value ok" );
166 assert
.strictEqual( value3
, 6, "result of filter ok" );
170 jQuery
.Deferred().resolve().then( null, function() {
171 assert
.ok( false, "then should not be called on resolve" );
172 } ).then( done
.pop() );
174 jQuery
.Deferred().reject().then( null, jQuery
.noop
).done( function( value
) {
175 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
180 QUnit
.test( "jQuery.Deferred.catch", function( assert
) {
183 var value1
, value2
, value3
,
184 defer
= jQuery
.Deferred(),
185 piped
= defer
.catch( function( a
, b
) {
188 done
= jQuery
.map( new Array( 3 ), function() {
189 return assert
.async();
192 piped
.done( function( result
) {
196 defer
.fail( function( a
, b
) {
201 defer
.reject( 2, 3 ).catch( function() {
202 assert
.strictEqual( value1
, 2, "first reject value ok" );
203 assert
.strictEqual( value2
, 3, "second reject value ok" );
204 assert
.strictEqual( value3
, 6, "result of filter ok" );
208 jQuery
.Deferred().resolve().catch( function() {
209 assert
.ok( false, "then should not be called on resolve" );
210 } ).then( done
.pop() );
212 jQuery
.Deferred().reject().catch( jQuery
.noop
).done( function( value
) {
213 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
218 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( assert
) {
222 var value1
, value2
, value3
,
223 defer
= jQuery
.Deferred(),
224 piped
= defer
.pipe( null, function( a
, b
) {
227 done
= jQuery
.map( new Array( 3 ), function() {
228 return assert
.async();
231 piped
.fail( function( result
) {
235 defer
.fail( function( a
, b
) {
240 defer
.reject( 2, 3 ).pipe( null, function() {
241 assert
.strictEqual( value1
, 2, "first reject value ok" );
242 assert
.strictEqual( value2
, 3, "second reject value ok" );
243 assert
.strictEqual( value3
, 6, "result of filter ok" );
247 jQuery
.Deferred().resolve().pipe( null, function() {
248 assert
.ok( false, "then should not be called on resolve" );
249 } ).then( done
.pop() );
251 jQuery
.Deferred().reject().pipe( null, jQuery
.noop
).fail( function( value
) {
252 assert
.strictEqual( value
, undefined, "then fail callback can return undefined/null" );
257 QUnit
.test( "jQuery.Deferred.then - filtering (progress)", function( assert
) {
261 var value1
, value2
, value3
,
262 defer
= jQuery
.Deferred(),
263 piped
= defer
.then( null, null, function( a
, b
) {
266 done
= assert
.async();
268 piped
.progress( function( result
) {
272 defer
.progress( function( a
, b
) {
277 defer
.notify( 2, 3 ).then( null, null, function() {
278 assert
.strictEqual( value1
, 2, "first progress value ok" );
279 assert
.strictEqual( value2
, 3, "second progress value ok" );
280 assert
.strictEqual( value3
, 6, "result of filter ok" );
285 QUnit
.test( "jQuery.Deferred.then - deferred (done)", function( assert
) {
289 var value1
, value2
, value3
,
290 defer
= jQuery
.Deferred(),
291 piped
= defer
.then( function( a
, b
) {
292 return jQuery
.Deferred( function( defer
) {
293 defer
.reject( a
* b
);
296 done
= assert
.async();
298 piped
.fail( function( result
) {
302 defer
.done( function( a
, b
) {
307 defer
.resolve( 2, 3 );
309 piped
.fail( function() {
310 assert
.strictEqual( value1
, 2, "first resolve value ok" );
311 assert
.strictEqual( value2
, 3, "second resolve value ok" );
312 assert
.strictEqual( value3
, 6, "result of filter ok" );
317 QUnit
.test( "jQuery.Deferred.then - deferred (fail)", function( assert
) {
321 var value1
, value2
, value3
,
322 defer
= jQuery
.Deferred(),
323 piped
= defer
.then( null, function( a
, b
) {
324 return jQuery
.Deferred( function( defer
) {
325 defer
.resolve( a
* b
);
328 done
= assert
.async();
330 piped
.done( function( result
) {
334 defer
.fail( function( a
, b
) {
339 defer
.reject( 2, 3 );
341 piped
.done( function() {
342 assert
.strictEqual( value1
, 2, "first reject value ok" );
343 assert
.strictEqual( value2
, 3, "second reject value ok" );
344 assert
.strictEqual( value3
, 6, "result of filter ok" );
349 QUnit
.test( "jQuery.Deferred.then - deferred (progress)", function( assert
) {
353 var value1
, value2
, value3
,
354 defer
= jQuery
.Deferred(),
355 piped
= defer
.then( null, null, function( a
, b
) {
356 return jQuery
.Deferred( function( defer
) {
357 defer
.resolve( a
* b
);
360 done
= assert
.async();
362 piped
.progress( function( result
) {
363 return jQuery
.Deferred().resolve().then( function() {
365 } ).then( function( result
) {
370 defer
.progress( function( a
, b
) {
375 defer
.notify( 2, 3 );
377 piped
.then( null, null, function( result
) {
378 return jQuery
.Deferred().resolve().then( function() {
380 } ).then( function() {
381 assert
.strictEqual( value1
, 2, "first progress value ok" );
382 assert
.strictEqual( value2
, 3, "second progress value ok" );
383 assert
.strictEqual( value3
, 6, "result of filter ok" );
389 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - deferred (progress)", function( assert
) {
393 var value1
, value2
, value3
,
394 defer
= jQuery
.Deferred(),
395 piped
= defer
.pipe( null, null, function( a
, b
) {
396 return jQuery
.Deferred( function( defer
) {
397 defer
.resolve( a
* b
);
400 done
= assert
.async();
402 piped
.done( function( result
) {
406 defer
.progress( function( a
, b
) {
411 defer
.notify( 2, 3 );
413 piped
.done( function() {
414 assert
.strictEqual( value1
, 2, "first progress value ok" );
415 assert
.strictEqual( value2
, 3, "second progress value ok" );
416 assert
.strictEqual( value3
, 6, "result of filter ok" );
421 QUnit
.test( "jQuery.Deferred.then - context", function( assert
) {
425 var defer
, piped
, defer2
, piped2
,
426 context
= { custom
: true },
427 done
= jQuery
.map( new Array( 5 ), function() {
428 return assert
.async();
431 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).then( function( value
) {
432 assert
.strictEqual( this, context
, "custom context received by .then handler" );
434 } ).done( function( value
) {
435 assert
.notStrictEqual( this, context
,
436 "custom context not propagated through .then handler" );
437 assert
.strictEqual( value
, 6, "proper value received" );
441 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).then().done( function( value
) {
442 assert
.strictEqual( this, context
,
443 "custom context propagated through .then without handler" );
444 assert
.strictEqual( value
, 2, "proper value received" );
448 jQuery
.Deferred().resolve().then( function() {
449 assert
.strictEqual( this, window
, "default context in .then handler" );
450 return jQuery
.Deferred().resolveWith( context
);
451 } ).done( function() {
452 assert
.strictEqual( this, context
,
453 "custom context of returned deferred correctly propagated" );
457 defer
= jQuery
.Deferred();
458 piped
= defer
.then( function( value
) {
464 piped
.done( function( value
) {
465 assert
.strictEqual( this, window
, ".then handler does not introduce context" );
466 assert
.strictEqual( value
, 6, "proper value received" );
470 defer2
= jQuery
.Deferred();
471 piped2
= defer2
.then();
475 piped2
.done( function( value
) {
476 assert
.strictEqual( this, window
, ".then without handler does not introduce context" );
477 assert
.strictEqual( value
, 2, "proper value received (without passing function)" );
482 QUnit
.test( "[PIPE ONLY] jQuery.Deferred.pipe - context", function( assert
) {
486 var defer
, piped
, defer2
, piped2
,
487 context
= { custom
: true },
488 done
= jQuery
.map( new Array( 5 ), function() {
489 return assert
.async();
492 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).pipe( function( value
) {
493 assert
.strictEqual( this, context
, "custom context received by .pipe handler" );
495 } ).done( function( value
) {
496 assert
.strictEqual( this, context
,
497 "[PIPE ONLY] custom context propagated through .pipe handler" );
498 assert
.strictEqual( value
, 6, "proper value received" );
502 jQuery
.Deferred().resolveWith( context
, [ 2 ] ).pipe().done( function( value
) {
503 assert
.strictEqual( this, context
,
504 "[PIPE ONLY] custom context propagated through .pipe without handler" );
505 assert
.strictEqual( value
, 2, "proper value received" );
509 jQuery
.Deferred().resolve().pipe( function() {
510 assert
.strictEqual( this, window
, "default context in .pipe handler" );
511 return jQuery
.Deferred().resolveWith( context
);
512 } ).done( function() {
513 assert
.strictEqual( this, context
,
514 "custom context of returned deferred correctly propagated" );
518 defer
= jQuery
.Deferred();
519 piped
= defer
.pipe( function( value
) {
525 piped
.done( function( value
) {
526 assert
.strictEqual( this, window
, ".pipe handler does not introduce context" );
527 assert
.strictEqual( value
, 6, "proper value received" );
531 defer2
= jQuery
.Deferred();
532 piped2
= defer2
.pipe();
536 piped2
.done( function( value
) {
537 assert
.strictEqual( this, window
, ".pipe without handler does not introduce context" );
538 assert
.strictEqual( value
, 2, "proper value received (without passing function)" );
543 QUnit
.test( "jQuery.Deferred.then - spec compatibility", function( assert
) {
547 var done
= assert
.async(),
548 defer
= jQuery
.Deferred();
550 defer
.done( function() {
555 defer
.then( function() {
556 assert
.ok( true, "errors in .done callbacks don't stop .then handlers" );
564 QUnit
.testUnlessIE( "jQuery.Deferred.then - IsCallable determination (gh-3596)",
569 var done
= assert
.async(),
570 defer
= jQuery
.Deferred();
573 assert
.ok( true, "handler with non-'Function' @@toStringTag gets invoked" );
575 faker
[ Symbol
.toStringTag
] = "String";
577 defer
.then( faker
).then( done
);
582 QUnit
.test( "jQuery.Deferred.exceptionHook", function( assert
) {
586 var done
= assert
.async(),
587 defer
= jQuery
.Deferred(),
588 oldWarn
= window
.console
.warn
;
590 window
.console
.warn = function( _intro
, error
) {
591 assert
.ok( /barf/.test( error
.message
+ "\n" + error
.stack
),
592 "Error mentions the method: " + error
.message
+ "\n" + error
.stack
);
596 defer
.then( function() {
598 // Should get an error
600 } ).then( null, jQuery
.noop
),
602 defer
.then( function() {
604 // Should NOT get an error
605 throw new Error( "Make me a sandwich" );
606 } ).then( null, jQuery
.noop
)
607 ).then( function barf( ) {
608 jQuery
.thisDiesToo();
609 } ).then( null, function( ) {
610 window
.console
.warn
= oldWarn
;
617 QUnit
.test( "jQuery.Deferred.exceptionHook with error hooks", function( assert
) {
621 var done
= assert
.async(),
622 defer
= jQuery
.Deferred(),
623 oldWarn
= window
.console
.warn
;
625 jQuery
.Deferred
.getErrorHook = function() {
627 // Default exceptionHook assumes the stack is in a form console.warn can log,
628 // but a custom getErrorHook+exceptionHook pair could save a raw form and
629 // format it to a string only when an exception actually occurs.
630 // For the unit test we just ensure the plumbing works.
631 return "NO ERROR FOR YOU";
634 window
.console
.warn = function() {
635 var msg
= Array
.prototype.join
.call( arguments
, " " );
636 assert
.ok( /cough_up_hairball/.test( msg
), "Function mentioned: " + msg
);
637 assert
.ok( /NO ERROR FOR YOU/.test( msg
), "Error included: " + msg
);
640 defer
.then( function() {
641 jQuery
.cough_up_hairball();
642 } ).then( null, function( ) {
643 window
.console
.warn
= oldWarn
;
644 delete jQuery
.Deferred
.getErrorHook
;
651 QUnit
.test( "jQuery.Deferred - 1.x/2.x compatibility", function( assert
) {
655 var context
= { id
: "callback context" },
656 thenable
= jQuery
.Deferred().resolve( "thenable fulfillment" ).promise(),
657 done
= jQuery
.map( new Array( 8 ), function() {
658 return assert
.async();
661 thenable
.unwrapped
= false;
663 jQuery
.Deferred().resolve( 1, 2 ).then( function() {
664 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
665 ".then fulfillment callbacks receive all resolution values" );
668 jQuery
.Deferred().reject( 1, 2 ).then( null, function() {
669 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
670 ".then rejection callbacks receive all rejection values" );
673 jQuery
.Deferred().notify( 1, 2 ).then( null, null, function() {
674 assert
.deepEqual( [].slice
.call( arguments
), [ 1, 2 ],
675 ".then progress callbacks receive all progress values" );
679 jQuery
.Deferred().resolveWith( context
).then( function() {
680 assert
.deepEqual( this, context
, ".then fulfillment callbacks receive context" );
683 jQuery
.Deferred().rejectWith( context
).then( null, function() {
684 assert
.deepEqual( this, context
, ".then rejection callbacks receive context" );
687 jQuery
.Deferred().notifyWith( context
).then( null, null, function() {
688 assert
.deepEqual( this, context
, ".then progress callbacks receive context" );
692 jQuery
.Deferred().resolve( thenable
).done( function( value
) {
693 assert
.strictEqual( value
, thenable
, ".done doesn't unwrap thenables" );
697 jQuery
.Deferred().notify( thenable
).then().then( null, null, function( value
) {
698 assert
.strictEqual( value
, "thenable fulfillment",
699 ".then implicit progress callbacks unwrap thenables" );
704 QUnit
.test( "jQuery.Deferred.then - progress and thenables", function( assert
) {
708 var trigger
= jQuery
.Deferred().notify(),
709 expectedProgress
= [ "baz", "baz" ],
710 done
= jQuery
.map( new Array( 2 ), function() {
711 return assert
.async();
713 failer = function( evt
) {
715 assert
.ok( false, "no unexpected " + evt
);
719 trigger
.then( null, null, function() {
720 var notifier
= jQuery
.Deferred().notify( "foo" );
721 setTimeout( function() {
722 notifier
.notify( "bar" ).resolve( "baz" );
725 } ).then( failer( "fulfill" ), failer( "reject" ), function( v
) {
726 assert
.strictEqual( v
, expectedProgress
.shift(), "expected progress value" );
732 QUnit
.test( "jQuery.Deferred - notify and resolve", function( assert
) {
736 var notifiedResolved
= jQuery
.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/,
737 done
= jQuery
.map( new Array( 3 ), function() {
738 return assert
.async();
741 notifiedResolved
.progress( function( v
) {
742 assert
.strictEqual( v
, "foo", "progress value" );
745 notifiedResolved
.pipe().progress( function( v
) {
746 assert
.strictEqual( v
, "foo", "piped progress value" );
749 notifiedResolved
.pipe( null, null, function() {
751 } ).progress( function( v
) {
752 assert
.strictEqual( v
, "baz", "replaced piped progress value" );
755 notifiedResolved
.pipe( null, null, function() {
756 return jQuery
.Deferred().notify( "baz" ).resolve( "quux" );
757 } ).progress( function( v
) {
758 assert
.strictEqual( v
, "baz", "deferred replaced piped progress value" );
761 notifiedResolved
.then().progress( function( v
) {
762 assert
.strictEqual( v
, "foo", "then'd progress value" );
766 notifiedResolved
.then( null, null, function() {
768 } ).progress( function( v
) {
769 assert
.strictEqual( v
, "baz", "replaced then'd progress value" );
773 notifiedResolved
.then( null, null, function() {
774 return jQuery
.Deferred().notify( "baz" ).resolve( "quux" );
775 } ).progress( function( v
) {
777 // Progress from the surrogate deferred is ignored
778 assert
.strictEqual( v
, "quux", "deferred replaced then'd progress value" );
783 QUnit
.test( "jQuery.Deferred - resolved to a notifying deferred", function( assert
) {
787 var deferred
= jQuery
.Deferred(),
788 done
= assert
.async( 2 );
790 deferred
.resolve( jQuery
.Deferred( function( notifyingDeferred
) {
791 notifyingDeferred
.notify( "foo", "bar" );
792 notifyingDeferred
.resolve( "baz", "quux" );
795 // Apply an empty then to force thenable unwrapping.
796 // See https://github.com/jquery/jquery/issues/3000 for more info.
797 deferred
.then().then( function() {
799 [].slice
.call( arguments
),
801 "The fulfilled handler receives proper params"
804 }, null, function() {
806 [].slice
.call( arguments
),
808 "The progress handler receives proper params"
814 QUnit
.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert
) {
819 var defaultContext
= ( function getDefaultContext() {
823 done
= assert
.async( 20 );
827 assert
.strictEqual( arguments
.length
, 0, "Resolved .done with no arguments" );
828 assert
.strictEqual( this, defaultContext
, "Default .done context with no arguments" );
831 assert
.strictEqual( arguments
.length
, 0, "Resolved .then with no arguments" );
832 assert
.strictEqual( this, defaultContext
, "Default .then context with no arguments" );
836 "an empty string": "",
837 "a non-empty string": "some string",
839 "a number other than zero": 1,
843 "undefined": undefined,
844 "a plain object": {},
845 "an array": [ 1, 2, 3 ]
846 }, function( message
, value
) {
847 var code
= "jQuery.when( " + message
+ " )",
848 onFulfilled = function( method
) {
849 var call
= code
+ "." + method
;
850 return function( resolveValue
) {
851 assert
.strictEqual( resolveValue
, value
, call
+ " resolve" );
852 assert
.strictEqual( this, defaultContext
, call
+ " context" );
856 onRejected = function( method
) {
857 var call
= code
+ "." + method
;
859 assert
.ok( false, call
+ " reject" );
865 .done( onFulfilled( "done" ) )
866 .fail( onRejected( "done" ) )
867 .then( onFulfilled( "then" ), onRejected( "then" ) );
871 QUnit
.test( "jQuery.when(thenable) - like Promise.resolve", function( assert
) {
874 var customToStringThen
= {
875 then: function( onFulfilled
) {
879 if ( typeof Symbol
=== "function" ) {
880 customToStringThen
.then
[ Symbol
.toStringTag
] = "String";
883 var slice
= [].slice
,
884 sentinel
= { context
: "explicit" },
885 eventuallyFulfilled
= jQuery
.Deferred().notify( true ),
886 eventuallyRejected
= jQuery
.Deferred().notify( true ),
887 secondaryFulfilled
= jQuery
.Deferred().resolve( eventuallyFulfilled
),
888 secondaryRejected
= jQuery
.Deferred().resolve( eventuallyRejected
),
890 promise
: Promise
.resolve( true ),
891 customToStringThen
: customToStringThen
,
892 rejectedPromise
: Promise
.reject( false ),
893 deferred
: jQuery
.Deferred().resolve( true ),
894 eventuallyFulfilled
: eventuallyFulfilled
,
895 secondaryFulfilled
: secondaryFulfilled
,
896 eventuallySecondaryFulfilled
: jQuery
.Deferred().notify( true ),
897 multiDeferred
: jQuery
.Deferred().resolve( "foo", "bar" ),
898 deferredWith
: jQuery
.Deferred().resolveWith( sentinel
, [ true ] ),
899 multiDeferredWith
: jQuery
.Deferred().resolveWith( sentinel
, [ "foo", "bar" ] ),
900 rejectedDeferred
: jQuery
.Deferred().reject( false ),
901 eventuallyRejected
: eventuallyRejected
,
902 secondaryRejected
: secondaryRejected
,
903 eventuallySecondaryRejected
: jQuery
.Deferred().notify( true ),
904 multiRejectedDeferred
: jQuery
.Deferred().reject( "baz", "quux" ),
905 rejectedDeferredWith
: jQuery
.Deferred().rejectWith( sentinel
, [ false ] ),
906 multiRejectedDeferredWith
: jQuery
.Deferred().rejectWith( sentinel
, [ "baz", "quux" ] )
909 deferredWith
: sentinel
,
910 multiDeferredWith
: sentinel
,
911 rejectedDeferredWith
: sentinel
,
912 multiRejectedDeferredWith
: sentinel
916 customToStringThen
: [],
918 eventuallyFulfilled
: [ true ],
919 secondaryFulfilled
: [ true ],
920 eventuallySecondaryFulfilled
: [ true ],
921 multiDeferred
: [ "foo", "bar" ],
922 deferredWith
: [ true ],
923 multiDeferredWith
: [ "foo", "bar" ]
926 rejectedPromise
: [ false ],
927 rejectedDeferred
: [ false ],
928 eventuallyRejected
: [ false ],
929 secondaryRejected
: [ false ],
930 eventuallySecondaryRejected
: [ false ],
931 multiRejectedDeferred
: [ "baz", "quux" ],
932 rejectedDeferredWith
: [ false ],
933 multiRejectedDeferredWith
: [ "baz", "quux" ]
935 numCases
= Object
.keys( willSucceed
).length
+ Object
.keys( willError
).length
,
937 defaultContext
= ( function getDefaultContext() {
941 done
= assert
.async( numCases
* 2 );
943 assert
.expect( numCases
* 4 );
945 jQuery
.each( inputs
, function( message
, value
) {
946 var code
= "jQuery.when( " + message
+ " )",
947 shouldResolve
= willSucceed
[ message
],
948 shouldError
= willError
[ message
],
949 context
= contexts
[ message
] || defaultContext
,
950 onFulfilled = function( method
) {
951 var call
= code
+ "." + method
;
953 if ( shouldResolve
) {
954 assert
.deepEqual( slice
.call( arguments
), shouldResolve
,
956 assert
.strictEqual( this, context
, call
+ " context" );
958 assert
.ok( false, call
+ " resolve" );
963 onRejected = function( method
) {
964 var call
= code
+ "." + method
;
967 assert
.deepEqual( slice
.call( arguments
), shouldError
, call
+ " reject" );
968 assert
.strictEqual( this, context
, call
+ " context" );
970 assert
.ok( false, call
+ " reject" );
977 .done( onFulfilled( "done" ) )
978 .fail( onRejected( "done" ) )
979 .then( onFulfilled( "then" ), onRejected( "then" ) );
982 setTimeout( function() {
983 eventuallyFulfilled
.resolve( true );
984 eventuallyRejected
.reject( false );
985 inputs
.eventuallySecondaryFulfilled
.resolve( secondaryFulfilled
);
986 inputs
.eventuallySecondaryRejected
.resolve( secondaryRejected
);
990 QUnit
.test( "jQuery.when(a, b) - like Promise.all", function( assert
) {
993 assert
.expect( 196 );
995 var slice
= [].slice
,
998 fulfilled
: jQuery
.Deferred().resolve( 1 ),
999 rejected
: jQuery
.Deferred().reject( 0 ),
1000 eventuallyFulfilled
: jQuery
.Deferred().notify( true ),
1001 eventuallyRejected
: jQuery
.Deferred().notify( true ),
1002 fulfilledStandardPromise
: Promise
.resolve( 1 ),
1003 rejectedStandardPromise
: Promise
.reject( 0 )
1008 eventuallyFulfilled
: true,
1009 fulfilledStandardPromise
: true
1013 eventuallyRejected
: true,
1014 rejectedStandardPromise
: true
1017 defaultContext
= ( function getDefaultContext() {
1021 done
= assert
.async( 98 );
1023 jQuery
.each( deferreds
, function( id1
, v1
) {
1024 jQuery
.each( deferreds
, function( id2
, v2
) {
1025 var code
= "jQuery.when( " + id1
+ ", " + id2
+ " )",
1026 shouldResolve
= willSucceed
[ id1
] && willSucceed
[ id2
],
1027 shouldError
= willError
[ id1
] || willError
[ id2
],
1028 expected
= shouldResolve
? [ 1, 1 ] : [ 0 ],
1029 context
= shouldResolve
? [ defaultContext
, defaultContext
] : defaultContext
,
1030 onFulfilled = function( method
) {
1031 var call
= code
+ "." + method
;
1033 if ( shouldResolve
) {
1034 assert
.deepEqual( slice
.call( arguments
), expected
,
1035 call
+ " resolve" );
1036 assert
.deepEqual( this, context
, code
+ " context" );
1038 assert
.ok( false, call
+ " resolve" );
1043 onRejected = function( method
) {
1044 var call
= code
+ "." + method
;
1046 if ( shouldError
) {
1047 assert
.deepEqual( slice
.call( arguments
), expected
, call
+ " reject" );
1048 assert
.deepEqual( this, context
, code
+ " context" );
1050 assert
.ok( false, call
+ " reject" );
1056 jQuery
.when( v1
, v2
)
1057 .done( onFulfilled( "done" ) )
1058 .fail( onRejected( "done" ) )
1059 .then( onFulfilled( "then" ), onRejected( "then" ) );
1063 setTimeout( function() {
1064 deferreds
.eventuallyFulfilled
.resolve( 1 );
1065 deferreds
.eventuallyRejected
.reject( 0 );
1069 QUnit
.test( "jQuery.when - always returns a new promise", function( assert
) {
1071 assert
.expect( 42 );
1075 "non-thenable": [ "foo" ],
1076 "promise": [ Promise
.resolve( "bar" ) ],
1077 "rejected promise": [ Promise
.reject( "bar" ) ],
1078 "deferred": [ jQuery
.Deferred().resolve( "baz" ) ],
1079 "rejected deferred": [ jQuery
.Deferred().reject( "baz" ) ],
1080 "multi-resolved deferred": [ jQuery
.Deferred().resolve( "qux", "quux" ) ],
1081 "multiple non-thenables": [ "corge", "grault" ],
1082 "multiple deferreds": [
1083 jQuery
.Deferred().resolve( "garply" ),
1084 jQuery
.Deferred().resolve( "waldo" )
1086 }, function( label
, args
) {
1087 var result
= jQuery
.when
.apply( jQuery
, args
);
1089 assert
.ok( typeof result
.then
=== "function", "Thenable returned from " + label
);
1090 assert
.strictEqual( result
.resolve
, undefined, "Non-deferred returned from " + label
);
1091 assert
.strictEqual( result
.promise(), result
, "Promise returned from " + label
);
1093 jQuery
.each( args
, function( i
, arg
) {
1094 assert
.notStrictEqual( result
, arg
, "Returns distinct from arg " + i
+ " of " + label
);
1095 if ( arg
.promise
) {
1096 assert
.notStrictEqual( result
, arg
.promise(),
1097 "Returns distinct from promise of arg " + i
+ " of " + label
);
1103 QUnit
.test( "jQuery.when - notify does not affect resolved", function( assert
) {
1107 var a
= jQuery
.Deferred().notify( 1 ).resolve( 4 ),
1108 b
= jQuery
.Deferred().notify( 2 ).resolve( 5 ),
1109 c
= jQuery
.Deferred().notify( 3 ).resolve( 6 );
1111 jQuery
.when( a
, b
, c
).done( function( a
, b
, c
) {
1112 assert
.strictEqual( a
, 4, "first resolve value ok" );
1113 assert
.strictEqual( b
, 5, "second resolve value ok" );
1114 assert
.strictEqual( c
, 6, "third resolve value ok" );
1115 } ).fail( function() {
1116 assert
.ok( false, "Error on resolve" );
1120 QUnit
.test( "jQuery.when(...) - opportunistically synchronous", function( assert
) {
1124 var when
= "before",
1125 resolved
= jQuery
.Deferred().resolve( true ),
1126 rejected
= jQuery
.Deferred().reject( false ),
1127 validate = function( label
) {
1129 assert
.equal( when
, "before", label
);
1132 done
= assert
.async( 5 );
1134 jQuery
.when().done( validate( "jQuery.when()" ) ).always( done
);
1135 jQuery
.when( when
).done( validate( "jQuery.when(nonThenable)" ) ).always( done
);
1136 jQuery
.when( resolved
).done( validate( "jQuery.when(alreadyFulfilled)" ) ).always( done
);
1137 jQuery
.when( rejected
).fail( validate( "jQuery.when(alreadyRejected)" ) ).always( done
);
1138 jQuery
.when( resolved
, rejected
)
1139 .always( validate( "jQuery.when(alreadyFulfilled, alreadyRejected)" ) )