mirror of
https://github.com/jquery/jquery.git
synced 2025-01-10 18:24:24 +00:00
Core: Update isFunction to handle unusual-@@toStringTag input
Ref gh-3597 Fixes gh-3600 Fixes gh-3596 Closes gh-3617
This commit is contained in:
parent
1d2df772b4
commit
a16339b893
@ -212,7 +212,12 @@ jQuery.extend( {
|
||||
noop: function() {},
|
||||
|
||||
isFunction: function( obj ) {
|
||||
return jQuery.type( obj ) === "function";
|
||||
|
||||
// Support: Chrome <=57, Firefox <=52
|
||||
// In some browsers, typeof returns "function" for HTML <object> elements
|
||||
// (i.e., `typeof document.createElement( "object" ) === "function"`).
|
||||
// We don't want to classify *any* DOM node as a function.
|
||||
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
||||
},
|
||||
|
||||
isWindow: function( obj ) {
|
||||
@ -464,7 +469,7 @@ function isArrayLike( obj ) {
|
||||
var length = !!obj && "length" in obj && obj.length,
|
||||
type = jQuery.type( obj );
|
||||
|
||||
if ( type === "function" || jQuery.isWindow( obj ) ) {
|
||||
if ( jQuery.isFunction( obj ) || jQuery.isWindow( obj ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 + " )",
|
||||
|
Loading…
Reference in New Issue
Block a user