diff options
author | Richard Gibson <richard.gibson@gmail.com> | 2017-04-24 12:39:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-24 12:39:25 -0400 |
commit | a16339b8933f115da3661f3d3f64854c3fa60bdc (patch) | |
tree | e6903c05f9949bab4ca524da7d16ed96c8fb936c /test | |
parent | 1d2df772b4d6e5dbf91df6e75f4a1809f7879ab0 (diff) | |
download | jquery-a16339b8933f115da3661f3d3f64854c3fa60bdc.tar.gz jquery-a16339b8933f115da3661f3d3f64854c3fa60bdc.zip |
Core: Update isFunction to handle unusual-@@toStringTag input
Ref gh-3597
Fixes gh-3600
Fixes gh-3596
Closes gh-3617
Diffstat (limited to 'test')
-rw-r--r-- | test/unit/core.js | 64 | ||||
-rw-r--r-- | test/unit/deferred.js | 44 |
2 files changed, 100 insertions, 8 deletions
diff --git a/test/unit/core.js b/test/unit/core.js index adccfb58f..c717711da 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -406,7 +406,7 @@ QUnit[ "assign" in Object ? "test" : "skip" ]( "isPlainObject(Object.assign(...) QUnit.test( "isFunction", function( assert ) { - assert.expect( 19 ); + assert.expect( 20 ); var mystr, myarr, myfunction, fn, obj, nodes, first, input, a; @@ -439,9 +439,11 @@ QUnit.test( "isFunction", function( assert ) { fn = function() {}; assert.ok( jQuery.isFunction( fn ), "Normal Function" ); + assert.notOk( jQuery.isFunction( Object.create( fn ) ), "custom Function subclass" ); + obj = document.createElement( "object" ); - // Firefox says this is a function + // Some versions of Firefox and Chrome say this is a function assert.ok( !jQuery.isFunction( obj ), "Object Element" ); // Since 1.3, this isn't supported (#2968) @@ -491,6 +493,64 @@ QUnit.test( "isFunction", function( assert ) { } ); } ); +QUnit.test( "isFunction(cross-realm function)", function( assert ) { + assert.expect( 1 ); + + var iframe, doc, + done = assert.async(); + + // Functions from other windows should be matched + Globals.register( "iframeDone" ); + window.iframeDone = function( fn, detail ) { + window.iframeDone = undefined; + assert.ok( jQuery.isFunction( fn ), "cross-realm function" + + ( detail ? " - " + detail : "" ) ); + done(); + }; + + iframe = jQuery( "#qunit-fixture" )[ 0 ].appendChild( document.createElement( "iframe" ) ); + doc = iframe.contentDocument || iframe.contentWindow.document; + doc.open(); + doc.write( "<body onload='window.parent.iframeDone( function() {} );'>" ); + doc.close(); +} ); + +supportjQuery.each( + { + GeneratorFunction: "function*() {}", + AsyncFunction: "async function() {}" + }, + function( subclass, source ) { + var fn; + try { + fn = Function( "return " + source )(); + } catch ( e ) {} + + QUnit[ fn ? "test" : "skip" ]( "isFunction(" + subclass + ")", + function( assert ) { + assert.expect( 1 ); + + assert.equal( jQuery.isFunction( fn ), true, source ); + } + ); + } +); + +QUnit[ typeof Symbol === "function" && Symbol.toStringTag ? "test" : "skip" ]( + "isFunction(custom @@toStringTag)", + function( assert ) { + assert.expect( 2 ); + + var obj = {}, + fn = function() {}; + obj[ Symbol.toStringTag ] = "Function"; + fn[ Symbol.toStringTag ] = "Object"; + + assert.equal( jQuery.isFunction( obj ), false, "function-mimicking object" ); + assert.equal( jQuery.isFunction( fn ), true, "object-mimicking function" ); + } +); + QUnit.test( "isNumeric", function( assert ) { assert.expect( 43 ); diff --git a/test/unit/deferred.js b/test/unit/deferred.js index 426af4b5f..f64d4fec8 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -526,9 +526,10 @@ QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) { assert.expect( 1 ); - var done = assert.async(); + var done = assert.async(), + defer = jQuery.Deferred(); - var defer = jQuery.Deferred().done( function() { + defer.done( function() { setTimeout( done ); throw new Error(); } ); @@ -542,6 +543,26 @@ QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) { } catch ( _ ) {} } ); +QUnit[ typeof Symbol === "function" && Symbol.toStringTag ? "test" : "skip" ]( + "jQuery.Deferred.then - IsCallable determination (gh-3596)", + function( assert ) { + + assert.expect( 1 ); + + var done = assert.async(), + defer = jQuery.Deferred(); + + function faker() { + assert.ok( true, "handler with non-'Function' @@toStringTag gets invoked" ); + } + faker[ Symbol.toStringTag ] = "String"; + + defer.then( faker ).then( done ); + + defer.resolve(); + } +); + // Test fails in IE9 but is skipped there because console is not active QUnit[ window.console ? "test" : "skip" ]( "jQuery.Deferred.exceptionHook", function( assert ) { @@ -861,8 +882,16 @@ QUnit.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) { "use strict"; - var CASES = 16, - slice = [].slice, + var customToStringThen = { + then: function( onFulfilled ) { + onFulfilled(); + } + }; + if ( typeof Symbol === "function" ) { + customToStringThen.then[ Symbol.toStringTag ] = "String"; + } + + var slice = [].slice, sentinel = { context: "explicit" }, eventuallyFulfilled = jQuery.Deferred().notify( true ), eventuallyRejected = jQuery.Deferred().notify( true ), @@ -870,6 +899,7 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) { secondaryRejected = jQuery.Deferred().resolve( eventuallyRejected ), inputs = { promise: Promise.resolve( true ), + customToStringThen: customToStringThen, rejectedPromise: Promise.reject( false ), deferred: jQuery.Deferred().resolve( true ), eventuallyFulfilled: eventuallyFulfilled, @@ -894,6 +924,7 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) { }, willSucceed = { promise: [ true ], + customToStringThen: [], deferred: [ true ], eventuallyFulfilled: [ true ], secondaryFulfilled: [ true ], @@ -912,14 +943,15 @@ QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) { rejectedDeferredWith: [ false ], multiRejectedDeferredWith: [ "baz", "quux" ] }, + numCases = Object.keys( willSucceed ).length + Object.keys( willError ).length, // 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( CASES * 2 ); + done = assert.async( numCases * 2 ); - assert.expect( CASES * 4 ); + assert.expect( numCases * 4 ); jQuery.each( inputs, function( message, value ) { var code = "jQuery.when( " + message + " )", |