]> source.dussan.org Git - jquery.git/commitdiff
Deferred: Separate the two paths in jQuery.when
authorRichard Gibson <richard.gibson@gmail.com>
Fri, 15 Apr 2016 03:59:30 +0000 (23:59 -0400)
committerRichard Gibson <richard.gibson@gmail.com>
Mon, 2 May 2016 16:30:31 +0000 (12:30 -0400)
Single- and no-argument calls act like Promise.resolve.
Multi-argument calls act like Promise.all.

Fixes gh-3029
Closes gh-3059

build/tasks/promises_aplus_tests.js
src/deferred.js
test/promises_aplus_adapter.js [deleted file]
test/promises_aplus_adapter_deferred.js [new file with mode: 0644]
test/promises_aplus_adapter_when.js [new file with mode: 0644]
test/unit/deferred.js
test/unit/effects.js

index 3e770a07966f42a862f86fa1a148676b534e4776..c4fb86d4c27e5e51bcba541f91a9ca7a5e3db48a 100644 (file)
@@ -4,10 +4,20 @@ module.exports = function( grunt ) {
 
        var spawnTest = require( "./lib/spawn_test.js" );
 
-       grunt.registerTask( "promises_aplus_tests", function() {
+       grunt.registerTask( "promises_aplus_tests",
+               [ "promises_aplus_tests_deferred", "promises_aplus_tests_when" ] );
+
+       grunt.registerTask( "promises_aplus_tests_deferred", function() {
+               spawnTest( this.async(),
+                       "./node_modules/.bin/promises-aplus-tests",
+                       "test/promises_aplus_adapter_deferred.js"
+               );
+       } );
+
+       grunt.registerTask( "promises_aplus_tests_when", function() {
                spawnTest( this.async(),
                        "./node_modules/.bin/promises-aplus-tests",
-                       "test/promises_aplus_adapter.js"
+                       "test/promises_aplus_adapter_when.js"
                );
        } );
 };
index 0ea1e7f1f0d0fe611ba6bd218ebc2a89e8082d42..6e4d43b315ac0489161dbd26d3972fbd822564d9 100644 (file)
@@ -13,6 +13,38 @@ function Thrower( ex ) {
        throw ex;
 }
 
+function adoptValue( value, resolve, reject ) {
+       var method;
+
+       try {
+
+               // Check for promise aspect first to privilege synchronous behavior
+               if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
+                       method.call( value ).done( resolve ).fail( reject );
+
+               // Other thenables
+               } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
+                       method.call( value, resolve, reject );
+
+               // Other non-thenables
+               } else {
+
+                       // Support: Android 4.0 only
+                       // Strict mode functions invoked without .call/.apply get global-object context
+                       resolve.call( undefined, value );
+               }
+
+       // For Promises/A+, convert exceptions into rejections
+       // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+       // Deferred#then to conditionally suppress rejection.
+       } catch ( /*jshint -W002 */ value ) {
+
+               // Support: Android 4.0 only
+               // Strict mode functions invoked without .call/.apply get global-object context
+               reject.call( undefined, value );
+       }
+}
+
 jQuery.extend( {
 
        Deferred: function( func ) {
@@ -305,67 +337,45 @@ jQuery.extend( {
        },
 
        // Deferred helper
-       when: function() {
-               var method, resolveContexts,
-                       i = 0,
-                       resolveValues = slice.call( arguments ),
-                       length = resolveValues.length,
+       when: function( singleValue ) {
+               var
+
+                       // count of uncompleted subordinates
+                       remaining = arguments.length,
 
-                       // the count of uncompleted subordinates
-                       remaining = length,
+                       // count of unprocessed arguments
+                       i = remaining,
+
+                       // subordinate fulfillment data
+                       resolveContexts = Array( i ),
+                       resolveValues = slice.call( arguments ),
 
-                       // the master Deferred.
+                       // the master Deferred
                        master = jQuery.Deferred(),
 
-                       // Update function for both resolving subordinates
+                       // subordinate callback factory
                        updateFunc = function( i ) {
                                return function( value ) {
                                        resolveContexts[ i ] = this;
                                        resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
                                        if ( !( --remaining ) ) {
-                                               master.resolveWith(
-                                                       resolveContexts.length === 1 ? resolveContexts[ 0 ] : resolveContexts,
-                                                       resolveValues
-                                               );
+                                               master.resolveWith( resolveContexts, resolveValues );
                                        }
                                };
                        };
 
-               // Add listeners to promise-like subordinates; treat others as resolved
-               if ( length > 0 ) {
-                       resolveContexts = new Array( length );
-                       for ( ; i < length; i++ ) {
-
-                               // jQuery.Deferred - treated specially to get resolve-sync behavior
-                               if ( resolveValues[ i ] &&
-                                       jQuery.isFunction( ( method = resolveValues[ i ].promise ) ) ) {
-
-                                       method.call( resolveValues[ i ] )
-                                               .done( updateFunc( i ) )
-                                               .fail( master.reject );
-
-                               // Other thenables
-                               } else if ( resolveValues[ i ] &&
-                                       jQuery.isFunction( ( method = resolveValues[ i ].then ) ) ) {
-
-                                       method.call(
-                                               resolveValues[ i ],
-                                               updateFunc( i ),
-                                               master.reject
-                                       );
-                               } else {
-
-                                       // Support: Android 4.0 only
-                                       // Strict mode functions invoked without .call/.apply get global-object context
-                                       updateFunc( i ).call( undefined, resolveValues[ i ] );
-                               }
-                       }
+               // Single- and empty arguments are adopted like Promise.resolve
+               if ( remaining <= 1 ) {
+                       adoptValue( singleValue, master.resolve, master.reject );
 
-               // If we're not waiting on anything, resolve the master
-               } else {
-                       master.resolveWith();
+                       // Use .then() to unwrap secondary thenables (cf. gh-3000)
+                       return master.then();
                }
 
+               // Multiple arguments are aggregated like Promise.all array elements
+               while ( i-- ) {
+                       adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
+               }
                return master.promise();
        }
 } );
diff --git a/test/promises_aplus_adapter.js b/test/promises_aplus_adapter.js
deleted file mode 100644 (file)
index c7440b9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* jshint node: true */
-
-"use strict";
-
-require( "jsdom" ).env( "", function( errors, window ) {
-       if ( errors ) {
-               console.error( errors );
-               return;
-       }
-
-       var jQuery = require( ".." )( window );
-
-       exports.deferred = function() {
-               var deferred = jQuery.Deferred();
-
-               return {
-                       promise: deferred.promise(),
-                       resolve: deferred.resolve.bind( deferred ),
-                       reject: deferred.reject.bind( deferred )
-               };
-       };
-} );
diff --git a/test/promises_aplus_adapter_deferred.js b/test/promises_aplus_adapter_deferred.js
new file mode 100644 (file)
index 0000000..c7440b9
--- /dev/null
@@ -0,0 +1,22 @@
+/* jshint node: true */
+
+"use strict";
+
+require( "jsdom" ).env( "", function( errors, window ) {
+       if ( errors ) {
+               console.error( errors );
+               return;
+       }
+
+       var jQuery = require( ".." )( window );
+
+       exports.deferred = function() {
+               var deferred = jQuery.Deferred();
+
+               return {
+                       promise: deferred.promise(),
+                       resolve: deferred.resolve.bind( deferred ),
+                       reject: deferred.reject.bind( deferred )
+               };
+       };
+} );
diff --git a/test/promises_aplus_adapter_when.js b/test/promises_aplus_adapter_when.js
new file mode 100644 (file)
index 0000000..0a5ec67
--- /dev/null
@@ -0,0 +1,51 @@
+/* jshint node: true */
+
+"use strict";
+
+require( "jsdom" ).env( "", function( errors, window ) {
+       if ( errors ) {
+               console.error( errors );
+               return;
+       }
+
+       var jQuery = require( ".." )( window );
+
+       exports.deferred = function() {
+               var adopted, promised,
+                       obj = {
+                               resolve: function() {
+                                       if ( !adopted ) {
+                                               adopted = jQuery.when.apply( jQuery, arguments );
+                                               if ( promised ) {
+                                                       adopted.then( promised.resolve, promised.reject );
+                                               }
+                                       }
+                                       return adopted;
+                               },
+                               reject: function( value ) {
+                                       if ( !adopted ) {
+                                               adopted = jQuery.when( jQuery.Deferred().reject( value ) );
+                                               if ( promised ) {
+                                                       adopted.then( promised.resolve, promised.reject );
+                                               }
+                                       }
+                                       return adopted;
+                               },
+
+                               // A manually-constructed thenable that works even if calls precede resolve/reject
+                               promise: {
+                                       then: function() {
+                                               if ( !adopted ) {
+                                                       if ( !promised ) {
+                                                               promised = jQuery.Deferred();
+                                                       }
+                                                       return promised.then.apply( promised, arguments );
+                                               }
+                                               return adopted.then.apply( adopted, arguments );
+                                       }
+                               }
+                       };
+
+               return obj;
+       };
+} );
index 305740fa4df9d48f6121f3d452db5ad5ed636012..830103eeb5d2cf978ded62367985955544e80d96 100644 (file)
@@ -761,11 +761,30 @@ QUnit.test( "jQuery.Deferred - notify and resolve", function( assert ) {
        } );
 } );
 
-QUnit.test( "jQuery.when", function( assert ) {
 
-       assert.expect( 37 );
+QUnit.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert ) {
+       "use strict";
+
+       assert.expect( 44 );
+
+       var
+
+               // Support: Android 4.0 only
+               // Strict mode functions invoked without .call/.apply get global-object context
+               defaultContext = (function getDefaultContext() { return this; }).call(),
+
+               done = assert.async( 20 );
+
+       jQuery.when()
+               .done( function( resolveValue ) {
+                       assert.strictEqual( resolveValue, undefined, "Resolved .done with no arguments" );
+                       assert.strictEqual( this, defaultContext, "Default .done context with no arguments" );
+               } )
+               .then( function( resolveValue ) {
+                       assert.strictEqual( resolveValue, undefined, "Resolved .then with no arguments" );
+                       assert.strictEqual( this, defaultContext, "Default .then context with no arguments" );
+               } );
 
-       // Some other objects
        jQuery.each( {
                "an empty string": "",
                "a non-empty string": "some string",
@@ -778,51 +797,136 @@ QUnit.test( "jQuery.when", function( assert ) {
                "a plain object": {},
                "an array": [ 1, 2, 3 ]
        }, function( message, value ) {
-               assert.ok(
-                       jQuery.isFunction(
-                               jQuery.when( value ).done( function( resolveValue ) {
-                                       assert.strictEqual( this, window, "Context is the global object with " + message );
-                                       assert.strictEqual( resolveValue, value, "Test the promise was resolved with " + message );
-                               } ).promise
-                       ),
-                       "Test " + message + " triggers the creation of a new Promise"
-               );
-       } );
-
-       assert.ok(
-               jQuery.isFunction(
-                       jQuery.when().done( function( resolveValue ) {
-                               assert.strictEqual( this, window, "Test the promise was resolved with window as its context" );
-                               assert.strictEqual( resolveValue, undefined, "Test the promise was resolved with no parameter" );
-                       } ).promise
-               ),
-               "Test calling when with no parameter triggers the creation of a new Promise"
-       );
-
-       var cache,
-               context = {};
-
-       jQuery.when( jQuery.Deferred().resolveWith( context ) ).done( function() {
-               assert.strictEqual( this, context, "when( promise ) propagates context" );
-       } );
-
-       jQuery.each( [ 1, 2, 3 ], function( k, i ) {
-               jQuery.when( cache || jQuery.Deferred( function() {
-                               this.resolve( i );
-                       } )
-               ).done( function( value ) {
-                       assert.strictEqual( value, 1, "Function executed" + ( i > 1 ? " only once" : "" ) );
-                       cache = value;
-               } );
+               var code = "jQuery.when( " + message + " )",
+                       onFulfilled = function( method ) {
+                               var call = code + "." + method;
+                               return function( resolveValue ) {
+                                       assert.strictEqual( resolveValue, value, call + " resolve" );
+                                       assert.strictEqual( this, defaultContext, call + " context" );
+                                       done();
+                               };
+                       },
+                       onRejected = function( method ) {
+                               var call = code + "." + method;
+                               return function() {
+                                       assert.ok( false, call + " reject" );
+                                       done();
+                               };
+                       };
 
+               jQuery.when( value )
+                       .done( onFulfilled( "done" ) )
+                       .fail( onRejected( "done" ) )
+                       .then( onFulfilled( "then" ), onRejected( "then" ) );
        } );
 } );
 
-QUnit.test( "jQuery.when - joined", function( assert ) {
+QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
+       "use strict";
+
+       assert.expect( 56 );
+
+       var slice = [].slice,
+               sentinel = { context: "explicit" },
+               eventuallyFulfilled = jQuery.Deferred().notify( true ),
+               eventuallyRejected = jQuery.Deferred().notify( true ),
+               inputs = {
+                       promise: Promise.resolve( true ),
+                       rejectedPromise: Promise.reject( false ),
+                       deferred: jQuery.Deferred().resolve( true ),
+                       eventuallyFulfilled: eventuallyFulfilled,
+                       secondaryFulfilled: jQuery.Deferred().resolve( eventuallyFulfilled ),
+                       multiDeferred: jQuery.Deferred().resolve( "foo", "bar" ),
+                       deferredWith: jQuery.Deferred().resolveWith( sentinel, [ true ] ),
+                       multiDeferredWith: jQuery.Deferred().resolveWith( sentinel, [ "foo", "bar" ] ),
+                       rejectedDeferred: jQuery.Deferred().reject( false ),
+                       eventuallyRejected: eventuallyRejected,
+                       secondaryRejected: jQuery.Deferred().resolve( eventuallyRejected ),
+                       multiRejectedDeferred: jQuery.Deferred().reject( "baz", "quux" ),
+                       rejectedDeferredWith: jQuery.Deferred().rejectWith( sentinel, [ false ] ),
+                       multiRejectedDeferredWith: jQuery.Deferred().rejectWith( sentinel, [ "baz", "quux" ] )
+               },
+               contexts = {
+                       deferredWith: sentinel,
+                       multiDeferredWith: sentinel,
+                       rejectedDeferredWith: sentinel,
+                       multiRejectedDeferredWith: sentinel
+               },
+               willSucceed = {
+                       promise: [ true ],
+                       deferred: [ true ],
+                       eventuallyFulfilled: [ true ],
+                       secondaryFulfilled: [ true ],
+                       multiDeferred: [ "foo", "bar" ],
+                       deferredWith: [ true ],
+                       multiDeferredWith: [ "foo", "bar" ]
+               },
+               willError = {
+                       rejectedPromise: [ false ],
+                       rejectedDeferred: [ false ],
+                       eventuallyRejected: [ false ],
+                       secondaryRejected: [ false ],
+                       multiRejectedDeferred: [ "baz", "quux" ],
+                       rejectedDeferredWith: [ false ],
+                       multiRejectedDeferredWith: [ "baz", "quux" ]
+               },
+
+               // Support: Android 4.0 only
+               // Strict mode functions invoked without .call/.apply get global-object context
+               defaultContext = (function getDefaultContext() { return this; }).call(),
+
+               done = assert.async( 28 );
+
+       jQuery.each( inputs, function( message, value ) {
+               var code = "jQuery.when( " + message + " )",
+                       shouldResolve = willSucceed[ message ],
+                       shouldError = willError[ message ],
+                       context = contexts[ message ] || defaultContext,
+                       onFulfilled = function( method ) {
+                               var call = code + "." + method;
+                               return function() {
+                                       if ( shouldResolve ) {
+                                               assert.deepEqual( slice.call( arguments ), shouldResolve,
+                                                       call + " resolve" );
+                                               assert.strictEqual( this, context, call + " context" );
+                                       } else {
+                                               assert.ok( false,  call + " resolve" );
+                                       }
+                                       done();
+                               };
+                       },
+                       onRejected = function( method ) {
+                               var call = code + "." + method;
+                               return function() {
+                                       if ( shouldError ) {
+                                               assert.deepEqual( slice.call( arguments ), shouldError, call + " reject" );
+                                               assert.strictEqual( this, context, call + " context" );
+                                       } else {
+                                               assert.ok( false, call + " reject" );
+                                       }
+                                       done();
+                               };
+                       };
+
+               jQuery.when( value )
+                       .done( onFulfilled( "done" ) )
+                       .fail( onRejected( "done" ) )
+                       .then( onFulfilled( "then" ), onRejected( "then" ) );
+       } );
+
+       setTimeout( function() {
+               eventuallyFulfilled.resolve( true );
+               eventuallyRejected.reject( false );
+       }, 50 );
+} );
 
-       assert.expect( 81 );
+QUnit.test( "jQuery.when(a, b) - like Promise.all", function( assert ) {
+       "use strict";
 
-       var deferreds = {
+       assert.expect( 196 );
+
+       var slice = [].slice,
+               deferreds = {
                        rawValue: 1,
                        fulfilled: jQuery.Deferred().resolve( 1 ),
                        rejected: jQuery.Deferred().reject( 0 ),
@@ -842,46 +946,91 @@ QUnit.test( "jQuery.when - joined", function( assert ) {
                        eventuallyRejected: true,
                        rejectedStandardPromise: true
                },
-               counter = 49,
 
                // Support: Android 4.0 only
                // Strict mode functions invoked without .call/.apply get global-object context
-               expectedContext = (function() { "use strict"; return this; }).call();
-
-       QUnit.stop();
+               defaultContext = (function getDefaultContext() { return this; }).call(),
 
-       function restart() {
-               if ( !--counter ) {
-                       QUnit.start();
-               }
-       }
+               done = assert.async( 98 );
 
-       jQuery.each( deferreds, function( id1, defer1 ) {
-               jQuery.each( deferreds, function( id2, defer2 ) {
-                       var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
+       jQuery.each( deferreds, function( id1, v1 ) {
+               jQuery.each( deferreds, function( id2, v2 ) {
+                       var code = "jQuery.when( " + id1 + ", " + id2 + " )",
+                               shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
                                shouldError = willError[ id1 ] || willError[ id2 ],
-                               expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ],
-                               code = "jQuery.when( " + id1 + ", " + id2 + " )";
-
-                       jQuery.when( defer1, defer2 ).done( function( a, b ) {
-                               if ( shouldResolve ) {
-                                       assert.deepEqual( [ a, b ], expected, code + " => resolve" );
-                                       assert.strictEqual( this[ 0 ], expectedContext, code + " => context[0] OK" );
-                                       assert.strictEqual( this[ 1 ], expectedContext, code + " => context[1] OK" );
-                               } else {
-                                       assert.ok( false,  code + " => resolve" );
-                               }
-                       } ).fail( function( a, b ) {
-                               if ( shouldError ) {
-                                       assert.deepEqual( [ a, b ], expected, code + " => reject" );
-                               } else {
-                                       assert.ok( false, code + " => reject" );
-                               }
-                       } ).always( restart );
+                               expected = shouldResolve ? [ 1, 1 ] : [ 0 ],
+                               context = shouldResolve ? [ defaultContext, defaultContext ] : defaultContext,
+                               onFulfilled = function( method ) {
+                                       var call = code + "." + method;
+                                       return function() {
+                                               if ( shouldResolve ) {
+                                                       assert.deepEqual( slice.call( arguments ), expected,
+                                                               call + " resolve" );
+                                                       assert.deepEqual( this, context, code + " context" );
+                                               } else {
+                                                       assert.ok( false,  call + " resolve" );
+                                               }
+                                               done();
+                                       };
+                               },
+                               onRejected = function( method ) {
+                                       var call = code + "." + method;
+                                       return function() {
+                                               if ( shouldError ) {
+                                                       assert.deepEqual( slice.call( arguments ), expected, call + " reject" );
+                                                       assert.deepEqual( this, context, code + " context" );
+                                               } else {
+                                                       assert.ok( false, call + " reject" );
+                                               }
+                                               done();
+                                       };
+                               };
+
+                       jQuery.when( v1, v2 )
+                               .done( onFulfilled( "done" ) )
+                               .fail( onRejected( "done" ) )
+                               .then( onFulfilled( "then" ), onRejected( "then" ) );
+               } );
+       } );
+
+       setTimeout( function() {
+               deferreds.eventuallyFulfilled.resolve( 1 );
+               deferreds.eventuallyRejected.reject( 0 );
+       }, 50 );
+} );
+
+QUnit.test( "jQuery.when - always returns a new promise", function( assert ) {
+
+       assert.expect( 42 );
+
+       jQuery.each( {
+               "no arguments": [],
+               "non-thenable": [ "foo" ],
+               "promise": [ Promise.resolve( "bar" ) ],
+               "rejected promise": [ Promise.reject( "bar" ) ],
+               "deferred": [ jQuery.Deferred().resolve( "baz" ) ],
+               "rejected deferred": [ jQuery.Deferred().reject( "baz" ) ],
+               "multi-resolved deferred": [ jQuery.Deferred().resolve( "qux", "quux" ) ],
+               "multiple non-thenables": [ "corge", "grault" ],
+               "multiple deferreds": [
+                       jQuery.Deferred().resolve( "garply" ),
+                       jQuery.Deferred().resolve( "waldo" )
+               ]
+       }, function( label, args ) {
+               var result = jQuery.when.apply( jQuery, args );
+
+               assert.ok( jQuery.isFunction( result.then ), "Thenable returned from " + label );
+               assert.strictEqual( result.resolve, undefined, "Non-deferred returned from " + label );
+               assert.strictEqual( result.promise(), result, "Promise returned from " + label );
+
+               jQuery.each( args, function( i, arg ) {
+                       assert.notStrictEqual( result, arg, "Returns distinct from arg " + i + " of " + label );
+                       if ( arg.promise ) {
+                               assert.notStrictEqual( result, arg.promise(),
+                                       "Returns distinct from promise of arg " + i + " of " + label );
+                       }
                } );
        } );
-       deferreds.eventuallyFulfilled.resolve( 1 );
-       deferreds.eventuallyRejected.reject( 0 );
 } );
 
 QUnit.test( "jQuery.when - notify does not affect resolved", function( assert ) {
@@ -900,107 +1049,3 @@ QUnit.test( "jQuery.when - notify does not affect resolved", function( assert )
                assert.ok( false, "Error on resolve" );
        } );
 } );
-
-QUnit.test( "jQuery.when - filtering", function( assert ) {
-
-       assert.expect( 2 );
-
-       function increment( x ) {
-               return x + 1;
-       }
-
-       QUnit.stop();
-
-       jQuery.when(
-               jQuery.Deferred().resolve( 3 ).then( increment ),
-               jQuery.Deferred().reject( 5 ).then( null, increment )
-       ).done( function( four, six ) {
-               assert.strictEqual( four, 4, "resolved value incremented" );
-               assert.strictEqual( six, 6, "rejected value incremented" );
-               QUnit.start();
-       } );
-} );
-
-QUnit.test( "jQuery.when - exceptions", function( assert ) {
-
-       assert.expect( 2 );
-
-       function woops() {
-               throw "exception thrown";
-       }
-
-       QUnit.stop();
-
-       jQuery.Deferred().resolve().then( woops ).fail( function( doneException ) {
-               assert.strictEqual( doneException, "exception thrown", "throwing in done handler" );
-               jQuery.Deferred().reject().then( null, woops ).fail( function( failException ) {
-                       assert.strictEqual( failException, "exception thrown", "throwing in fail handler" );
-                       QUnit.start();
-               } );
-       } );
-} );
-
-QUnit.test( "jQuery.when - chaining", function( assert ) {
-
-       assert.expect( 4 );
-
-       var defer = jQuery.Deferred();
-
-       function chain() {
-               return defer;
-       }
-
-       function chainStandard() {
-               return Promise.resolve( "std deferred" );
-       }
-
-       QUnit.stop();
-
-       jQuery.when(
-               jQuery.Deferred().resolve( 3 ).then( chain ),
-               jQuery.Deferred().reject( 5 ).then( null, chain ),
-               jQuery.Deferred().resolve( 3 ).then( chainStandard ),
-               jQuery.Deferred().reject( 5 ).then( null, chainStandard )
-       ).done( function( v1, v2, s1, s2 ) {
-               assert.strictEqual( v1, "other deferred", "chaining in done handler" );
-               assert.strictEqual( v2, "other deferred", "chaining in fail handler" );
-               assert.strictEqual( s1, "std deferred", "chaining thenable in done handler" );
-               assert.strictEqual( s2, "std deferred", "chaining thenable in fail handler" );
-               QUnit.start();
-       } );
-
-       defer.resolve( "other deferred" );
-} );
-
-QUnit.test( "jQuery.when - solitary thenables", function( assert ) {
-
-       assert.expect( 1 );
-
-       var done = assert.async(),
-               rejected = new Promise( function( resolve, reject ) {
-                       setTimeout( function() {
-                               reject( "rejected" );
-                       }, 100 );
-               } );
-
-       jQuery.when( rejected ).then(
-               function() {
-                       assert.ok( false, "Rejected, solitary, non-Deferred thenable should not resolve" );
-                       done();
-               },
-               function() {
-                       assert.ok( true, "Rejected, solitary, non-Deferred thenable rejected properly" );
-                       done();
-               }
-       );
-} );
-
-QUnit.test( "jQuery.when does not reuse a solitary jQuery Deferred (gh-2018)", function( assert ) {
-
-       assert.expect( 2 );
-       var defer = jQuery.Deferred().resolve(),
-               promise = jQuery.when( defer );
-
-       assert.equal( promise.state(), "resolved", "Master Deferred is immediately resolved" );
-       assert.notStrictEqual( defer.promise(), promise, "jQuery.when returns the master deferred's promise" );
-} );
index 5f1913575b3d01526ad1512788b57beaab53ef64..2b953cd3528829f75ff215ab3f645f2d6b0b0ae8 100644 (file)
@@ -1028,7 +1028,7 @@ jQuery.each( {
                                jQuery( elem ).remove();
 
                        } );
-                       this.clock.tick( 50 );
+                       this.clock.tick( 100 );
                } );
        } );
 } );