diff --git a/src/jquery/deferred.js b/src/jquery/deferred.js index 7a1ea3a2..f1d4cc80 100644 --- a/src/jquery/deferred.js +++ b/src/jquery/deferred.js @@ -48,9 +48,13 @@ Object.defineProperty( jQuery.Deferred, "getStackHook", { }, set: function( newValue ) { if ( jQuery.migrateIsPatchEnabled( "deferred-getStackHook" ) ) { - migrateWarn( "deferred-getStackHook", - "jQuery.Deferred.getStackHook is removed; use jQuery.Deferred.getErrorHook" ); - jQuery.Deferred.getErrorHook = newValue; + + // Only warn if `getErrorHook` wasn't set to the same value first. + if ( jQuery.Deferred.getErrorHook !== newValue ) { + migrateWarn( "deferred-getStackHook", + "jQuery.Deferred.getStackHook is removed; use jQuery.Deferred.getErrorHook" ); + jQuery.Deferred.getErrorHook = newValue; + } } else { unpatchedGetStackHookValue = newValue; } diff --git a/test/unit/jquery/deferred.js b/test/unit/jquery/deferred.js index 07eeb0d3..66e6a93e 100644 --- a/test/unit/jquery/deferred.js +++ b/test/unit/jquery/deferred.js @@ -76,7 +76,7 @@ QUnit.test( "jQuery.Deferred.getStackHook - getter, no getErrorHook", function( } ); QUnit.test( "jQuery.Deferred.getStackHook - setter", function( assert ) { - assert.expect( 5 ); + assert.expect( 6 ); var exceptionHookSpy, done = assert.async(); @@ -90,6 +90,11 @@ QUnit.test( "jQuery.Deferred.getStackHook - setter", function( assert ) { "getStackHook mirrors getErrorHook (setter)" ); } ); + expectNoMessage( assert, "jQuery.Deferred.getStackHook - setter", 1, function() { + var mockFn = function() {}; + jQuery.Deferred.getStackHook = jQuery.Deferred.getErrorHook = mockFn; + } ); + expectMessage( assert, "asyncHook from jQuery.Deferred.getStackHook reported", 1, function() { jQuery.Deferred.getStackHook = function() { diff --git a/warnings.md b/warnings.md index b41ebe9c..2bf15c21 100644 --- a/warnings.md +++ b/warnings.md @@ -161,15 +161,15 @@ This is _not_ a warning, but a console log message the plugin shows when it firs ### \[jsonp-promotion\] JQMIGRATE: JSON-to-JSONP auto-promotion is removed -**Cause:** `jQuery.ajax` calls with `dataType: 'json'` with a provided callback are automatically converted by jQuery to JSONP requests unless the options also specify `jsonp: false`. Auto-promoting JSON requests to JSONP introduces a security risk as the developer may be unaware they're not just downloading data but executing code from a remote domain. This auto-promoting behavior is deprecated and will be removed in jQuery 4.0.0. +**Cause:** `jQuery.ajax` calls with `dataType: 'json'` with a provided callback are automatically converted by jQuery to JSONP requests unless the options also specify `jsonp: false`. Auto-promoting JSON requests to JSONP introduces a security risk as the developer may be unaware they're not just downloading data but executing code from a remote domain. This auto-promoting behavior has been removed in jQuery 4.0.0. **Solution:** To trigger a JSONP request, specify the `dataType: "jsonp"` option. ### \[deferred-getStackHook\] JQMIGRATE: jQuery.Deferred.getStackHook is removed; use jQuery.Deferred.getErrorHook -**Cause:** `jQuery.Deferred.getStackHook` was originally created to pass the stack trace from before an async barrier to report when a user error (like calling a non-existing function) causes a promise to be rejected. However, passing a stack trace doesn't take source maps into account, so we started advising to pass the whole error object. To make it clearer, we also renamed the API to `jQuery.Deferred.getErrorHook`. The legacy alias will be removed in jQuery 4.0.0 +**Cause:** `jQuery.Deferred.getStackHook` was originally created to pass the stack trace from before an async barrier to report when a user error (like calling a non-existing function) causes a promise to be rejected. However, passing a stack trace doesn't take source maps into account, so we started advising to pass the whole error object. To make it clearer, we also renamed the API to `jQuery.Deferred.getErrorHook`. The legacy alias has been removed in jQuery 4.0.0. -**Solution:** Rename all usage of `jQuery.Deferred.getStackHook` to `jQuery.Deferred.getErrorHook`. If you previously assigned a function returning an error stack to `jQuery.Deferred.getStackHook` or `jQuery.Deferred.getErrorHook`, change it to return a full error object. +**Solution:** Rename all usage of `jQuery.Deferred.getStackHook` to `jQuery.Deferred.getErrorHook`. If you previously assigned a function returning an error stack to `jQuery.Deferred.getStackHook` or `jQuery.Deferred.getErrorHook`, change it to return a full error object. If you aim to still support jQuery <3.7, assign the hook to `jQuery.Deferred.getErrorHook` first and only later to `jQuery.Deferred.getStackHook` to avoid a Migrate warning. ## Deprecated APIs