@@ -526,9 +526,10 @@ QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) {
526526
527527 assert . expect ( 1 ) ;
528528
529- var done = assert . async ( ) ;
529+ var done = assert . async ( ) ,
530+ defer = jQuery . Deferred ( ) ;
530531
531- var defer = jQuery . Deferred ( ) . done ( function ( ) {
532+ defer . done ( function ( ) {
532533 setTimeout ( done ) ;
533534 throw new Error ( ) ;
534535 } ) ;
@@ -542,6 +543,26 @@ QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) {
542543 } catch ( _ ) { }
543544} ) ;
544545
546+ QUnit [ typeof Symbol === "function" && Symbol . toStringTag ? "test" : "skip" ] (
547+ "jQuery.Deferred.then - IsCallable determination (gh-3596)" ,
548+ function ( assert ) {
549+
550+ assert . expect ( 1 ) ;
551+
552+ var done = assert . async ( ) ,
553+ defer = jQuery . Deferred ( ) ;
554+
555+ function faker ( ) {
556+ assert . ok ( true , "handler with non-'Function' @@toStringTag gets invoked" ) ;
557+ }
558+ faker [ Symbol . toStringTag ] = "String" ;
559+
560+ defer . then ( faker ) . then ( done ) ;
561+
562+ defer . resolve ( ) ;
563+ }
564+ ) ;
565+
545566// Test fails in IE9 but is skipped there because console is not active
546567QUnit [ window . console ? "test" : "skip" ] ( "jQuery.Deferred.exceptionHook" , function ( assert ) {
547568
@@ -861,15 +882,24 @@ QUnit.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert
861882QUnit . test ( "jQuery.when(thenable) - like Promise.resolve" , function ( assert ) {
862883 "use strict" ;
863884
864- var CASES = 16 ,
865- slice = [ ] . slice ,
885+ var customToStringThen = {
886+ then : function ( onFulfilled ) {
887+ onFulfilled ( ) ;
888+ }
889+ } ;
890+ if ( typeof Symbol === "function" ) {
891+ customToStringThen . then [ Symbol . toStringTag ] = "String" ;
892+ }
893+
894+ var slice = [ ] . slice ,
866895 sentinel = { context : "explicit" } ,
867896 eventuallyFulfilled = jQuery . Deferred ( ) . notify ( true ) ,
868897 eventuallyRejected = jQuery . Deferred ( ) . notify ( true ) ,
869898 secondaryFulfilled = jQuery . Deferred ( ) . resolve ( eventuallyFulfilled ) ,
870899 secondaryRejected = jQuery . Deferred ( ) . resolve ( eventuallyRejected ) ,
871900 inputs = {
872901 promise : Promise . resolve ( true ) ,
902+ customToStringThen : customToStringThen ,
873903 rejectedPromise : Promise . reject ( false ) ,
874904 deferred : jQuery . Deferred ( ) . resolve ( true ) ,
875905 eventuallyFulfilled : eventuallyFulfilled ,
@@ -894,6 +924,7 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
894924 } ,
895925 willSucceed = {
896926 promise : [ true ] ,
927+ customToStringThen : [ ] ,
897928 deferred : [ true ] ,
898929 eventuallyFulfilled : [ true ] ,
899930 secondaryFulfilled : [ true ] ,
@@ -912,14 +943,15 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
912943 rejectedDeferredWith : [ false ] ,
913944 multiRejectedDeferredWith : [ "baz" , "quux" ]
914945 } ,
946+ numCases = Object . keys ( willSucceed ) . length + Object . keys ( willError ) . length ,
915947
916948 // Support: Android 4.0 only
917949 // Strict mode functions invoked without .call/.apply get global-object context
918950 defaultContext = ( function getDefaultContext ( ) { return this ; } ) . call ( ) ,
919951
920- done = assert . async ( CASES * 2 ) ;
952+ done = assert . async ( numCases * 2 ) ;
921953
922- assert . expect ( CASES * 4 ) ;
954+ assert . expect ( numCases * 4 ) ;
923955
924956 jQuery . each ( inputs , function ( message , value ) {
925957 var code = "jQuery.when( " + message + " )" ,
0 commit comments