Skip to content

jQuery v3.6.0 breaks Bootstrap's test suite in IE #4859

Closed

Description

@XhmikosR

Opening the issue after quickly chatting with mgol on IRC

I made a branch to update jQuery to v3.6.0 in twbs/bootstrap#33243. I notice our BrowserStack tests fail consistently on Internet Explorer 10 and 11. v3.5.1 works fine.

git clone https://github.com/twbs/bootstrap.git -b v4-dev-xmr-update-jquery
npm i
npm run js-test-cloud #assumes you have BrowserStack credentials set up

The failures seem to point to https://github.com/twbs/bootstrap/blob/v4-dev/js/tests/unit/dropdown.js#L860 and https://github.com/twbs/bootstrap/blob/v4-dev/js/tests/unit/dropdown.js#L870

EDIT: using jQuery v3.3.1 also works fine.

Activity

  1. added
    Discuss in MeetingReserved for Issues and PRs that anyone would like to discuss in the weekly meeting.
    on Mar 15, 2021
  2. changed the title [-]v3.6.0 Internet Explorer breaks our test suite[/-] [+]jQuery v3.6.0 breaks Bootstrap's test suite in IE[/+] on Mar 15, 2021
  3. mgol commented on Mar 15, 2021

    @mgol
    Member

    An isolated test case is basicaly:

    input1.trigger('focus');
    input2.trigger('focus');
    input1.trigger('focus');

    In IE, focus stays on input2.

    See versions with jQuery:

    The 3.6.0 version fails in IE, the older ones succeed.

    jQuery 3.4 should be similar to 3.5 as there weren't major changes in relevant areas.

    I think this is the same bug that makes some tests fail in jQuery UI only with jQuery 3.6.0+:

    Also related to #4856, although that issue manifests itself in all 3.4+ versions.

  4. added this to the 3.6.1 milestone on Mar 15, 2021
  5. removed
    Discuss in MeetingReserved for Issues and PRs that anyone would like to discuss in the weekly meeting.
    on Mar 15, 2021
  6. timmywil commented on Mar 15, 2021

    @timmywil
    Member

    We'll address this in a patch. Related: dbcffb3

  7. gibson042 commented on Mar 15, 2021

    @gibson042
    Member

    @mgol The idea discussed in today's weekly meeting:

     // Ensure the presence of an event listener that handles manually-triggered
     // synthetic events by interrupting progress until reinvoked in response to
     // *native* events that it fires directly, ensuring that state changes have
     // already occurred before other listeners are invoked.
     function leverageNative( el, type, expectSync ) {
    +	var result = {}, queue = [];
     
     	// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
     	if ( !expectSync ) {
     		if ( dataPriv.get( el, type ) === undefined ) {
     			jQuery.event.add( el, type, returnTrue );
     		}
     		return;
     	}
     
     	// Register the controller as a special universal handler for all event namespaces
     	dataPriv.set( el, type, false );
     	jQuery.event.add( el, type, {
     		namespace: false,
     		handler: function( event ) {
    -			var notAsync, result,
    -				saved = dataPriv.get( this, type );
    +			var forceSync,
    +				i = 0,
    +				length = queue.length,
    +				oldResult = result;
     
     			if ( ( event.isTrigger & 1 ) && this[ type ] ) {
     
     				// Interrupt processing of the outer synthetic .trigger()ed event
    -				// Saved data should be false in such cases, but might be a leftover capture object
    -				// from an async native handler (gh-4350)
    -				if ( !saved.length ) {
    +				if ( !event.isInner ) {
     
     					// Store arguments for use when handling the inner native event
    -					// There will always be at least one argument (an event object), so this array
    -					// will not be confused with a leftover capture object.
    -					saved = slice.call( arguments );
    -					dataPriv.set( this, type, saved );
    +					queue.push( slice.call( arguments ) );
     
     					// Trigger the native event and capture its result
     					// Support: IE <=9 - 11+
     					// focus() and blur() are asynchronous
    -					notAsync = expectSync( this, type );
    +					forceSync = expectSync( this, type );
     					this[ type ]();
    -					result = dataPriv.get( this, type );
    -					if ( saved !== result || notAsync ) {
    -						dataPriv.set( this, type, false );
    -					} else {
    -						result = {};
    -					}
    -					if ( saved !== result ) {
    +					if ( result === oldResult && !forceSync ) {
    +						result = {};
    +					}
    +					if ( result !== oldResult ) {
     
     						// Cancel the outer synthetic event
     						event.stopImmediatePropagation();
     						event.preventDefault();
     
     						// Support: Chrome 86+
     						// In Chrome, if an element having a focusout handler is blurred by
     						// clicking outside of it, it invokes the handler synchronously. If
     						// that handler calls `.remove()` on the element, the data is cleared,
     						// leaving `result` undefined. We need to guard against this.
     						return result && result.value;
     					}
     
     				// If this is an inner synthetic event for an event with a bubbling surrogate
     				// (focus or blur), assume that the surrogate already propagated from triggering the
     				// native event and prevent that from happening again here.
     				// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
     				// bubbling surrogate propagates *after* the non-bubbling base), but that seems
     				// less bad than duplication.
     				} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
     					event.stopPropagation();
     				}
     
     			// If this is a native event triggered above, everything is now in order
     			// Fire an inner synthetic event with the original arguments
    +			// for each queued event, and capture the last result
    -			} else if ( saved.length ) {
    +			} else if ( length ) {
     
    -				// ...and capture the result
    -				dataPriv.set( this, type, {
    +				for ( ; i < length; i++ ) {
    +				result = ( {
     					value: jQuery.event.trigger(
     
     						// Support: IE <=9 - 11+
     						// Extend with the prototype to reset the above stopImmediatePropagation()
    -						jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
    -						saved.slice( 1 ),
    +						jQuery.extend( queue[ 0 ][ 0 ], jQuery.Event.prototype, { isInner: true } ),
    +						queue.shift().slice( 1 ),
     						this
     					)
     				} );
    +				}
     
     				// Abort handling of the native event
     				event.stopImmediatePropagation();
     			}
     		}
     	} );
     }

    The concept should be sufficient to invoke handlers as expected, even with code like input1.trigger('focus', 0); input2.trigger('focus'); input1.trigger('focus', 1).

  8. mgol commented on Mar 15, 2021

    @mgol
    Member

    @gibson042 Thanks! Do you want to put that in a PR or just to provide a starting point for others to pick up?

  9. jimmywarting commented on May 9, 2021

    @jimmywarting
  10. mgol commented on May 9, 2021

    @mgol
  11. jimmywarting commented on May 9, 2021

    @jimmywarting
  12. 26 remaining items

  13. added 2 commits that reference this issue on Mar 20, 2023
    5addd41
    71e6bbe
  14. mgol commented on Mar 27, 2023

    @mgol
    Member

    Fixed on main (future 4.x) via #5223 and on 3.x-stable via #5224.

  15. mgol commented on Apr 4, 2023

    @mgol
    Member

    @XhmikosR could you check whether https://releases.jquery.com/git/jquery-3.x-git.js works for you? This should be more or less what we'll release as jQuery 3.7.0.

  16. XhmikosR commented on Apr 4, 2023

    @XhmikosR
    Author
  17. mgol commented on Apr 4, 2023

    @mgol
    Member

    I understand, but my hope was to check before we release. 😉 Our release process is quite complex, so we don’t do a lot of pre-releases for minor updates.

    FWIW, I did test manually using steps you provided above with jQuery swapped for the 3.x-git version and they passed. Is there anything else to test?

  18. XhmikosR commented on Apr 4, 2023

    @XhmikosR
    Author

    If you tried the following and works on BrowserStack then it should be fine:

    git clone https://github.com/twbs/bootstrap.git -b v4-dev
    npm i
    # change the jquery version to the one you want to test
    npm run js-test-cloud #assumes you have BrowserStack credentials set up
  19. mgol commented on Apr 4, 2023

    @mgol
    Member

    Yes, that’s what I did. It looks like we’re good then!

  20. XhmikosR commented on Apr 4, 2023

    @XhmikosR
    Author

    Perfect, thanks for fixing the issue!

  21. mgol commented on May 12, 2023

    @mgol
    Member

    @XhmikosR jQuery 3.7.0 has been released, you should be able to update it in Bootstrap v4 now.

    https://blog.jquery.com/2023/05/11/jquery-3-7-0-released-staying-in-order/

  22. locked as resolved and limited conversation to collaborators on Sep 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions