Tests: Make the beforeunload event tests work regardless of extensions
[jquery.git] / test / unit / event.js
blobac309d22dee6be20335e6a267bbf645481afc32f
1 QUnit.module( "event", {
2         beforeEach: function() {
3                 document.body.focus();
4         },
5         afterEach: moduleTeardown
6 } );
8 QUnit.test( "null or undefined handler", function( assert ) {
9         assert.expect( 4 );
11         // Supports Fixes bug trac-7229
12         try {
13                 jQuery( "#firstp" ).on( "click", null );
14                 assert.ok( true, "Passing a null handler will not throw an exception" );
15         } catch ( e ) {}
17         try {
18                 jQuery( "#firstp" ).on( "click", undefined );
19                 assert.ok( true, "Passing an undefined handler will not throw an exception" );
20         } catch ( e ) {}
22         var expectedElem = jQuery( "#firstp" );
23         var actualElem = expectedElem.on( "click", null );
24         assert.equal( actualElem, expectedElem, "Passing a null handler should return the original element" );
26         actualElem = expectedElem.on( "click", undefined );
27         assert.equal( actualElem, expectedElem, "Passing a null handler should return the original element" );
28 } );
30 QUnit.test( "on() with non-null,defined data", function( assert ) {
32         assert.expect( 2 );
34         var handler = function( event, data ) {
35                 assert.equal( data, 0, "non-null, defined data (zero) is correctly passed" );
36         };
38         jQuery( "#foo" ).on( "foo.on", handler );
39         jQuery( "div" ).on( "foo.delegate", "#foo", handler );
41         jQuery( "#foo" ).trigger( "foo", 0 );
43         jQuery( "#foo" ).off( "foo.on", handler );
44         jQuery( "div" ).off( "foo.delegate", "#foo" );
46 } );
48 QUnit.test( "Handler changes and .trigger() order", function( assert ) {
49         assert.expect( 1 );
51         var markup = jQuery(
52                 "<div><div><p><span><b class=\"a\">b</b></span></p></div></div>"
53         ),
54         path = "";
56         markup
57                 .find( "*" ).addBack().on( "click", function() {
58                         path += this.nodeName.toLowerCase() + " ";
59                 } )
60                 .filter( "b" ).on( "click", function( e ) {
62                         // Removing span should not stop propagation to original parents
63                         if ( e.target === this ) {
64                                 jQuery( this ).parent().remove();
65                         }
66                 } );
68         markup.find( "b" ).trigger( "click" );
70         assert.equal( path, "b p div div ", "Delivered all events" );
72         markup.remove();
73 } );
75 QUnit.test( "on(), with data", function( assert ) {
76         assert.expect( 4 );
77         var test, handler, handler2;
79         handler = function( event ) {
80                 assert.ok( event.data, "on() with data, check passed data exists" );
81                 assert.equal( event.data.foo, "bar", "on() with data, Check value of passed data" );
82         };
83         jQuery( "#firstp" ).on( "click", { "foo": "bar" }, handler ).trigger( "click" ).off( "click", handler );
85         assert.ok( !jQuery._data( jQuery( "#firstp" )[ 0 ], "events" ), "Event handler unbound when using data." );
87         test = function() {};
88         handler2 = function( event ) {
89                 assert.equal( event.data, test, "on() with function data, Check value of passed data" );
90         };
91         jQuery( "#firstp" ).on( "click", test, handler2 ).trigger( "click" ).off( "click", handler2 );
92 } );
94 QUnit.test( "click(), with data", function( assert ) {
95         assert.expect( 3 );
96         var handler = function( event ) {
97                 assert.ok( event.data, "on() with data, check passed data exists" );
98                 assert.equal( event.data.foo, "bar", "on() with data, Check value of passed data" );
99         };
100         jQuery( "#firstp" ).on( "click", { "foo": "bar" }, handler ).trigger( "click" ).off( "click", handler );
102         assert.ok( !jQuery._data( jQuery( "#firstp" )[ 0 ], "events" ), "Event handler unbound when using data." );
103 } );
105 QUnit.test( "on(), with data, trigger with data", function( assert ) {
106         assert.expect( 4 );
107         var handler = function( event, data ) {
108                 assert.ok( event.data, "check passed data exists" );
109                 assert.equal( event.data.foo, "bar", "Check value of passed data" );
110                 assert.ok( data, "Check trigger data" );
111                 assert.equal( data.bar, "foo", "Check value of trigger data" );
112         };
113         jQuery( "#firstp" ).on( "click", { foo: "bar" }, handler ).trigger( "click", [ { bar: "foo" } ] ).off( "click", handler );
114 } );
116 QUnit.test( "on(), multiple events at once", function( assert ) {
117         assert.expect( 2 );
118         var handler,
119                 clickCounter = 0,
120                 mouseoverCounter = 0;
121         handler = function( event ) {
122                 if ( event.type === "click" ) {
123                         clickCounter += 1;
124                 } else if ( event.type === "mouseover" ) {
125                         mouseoverCounter += 1;
126                 }
127         };
129         jQuery( "#firstp" ).on( "click mouseover", handler ).trigger( "click" ).trigger( "mouseover" );
130         assert.equal( clickCounter, 1, "on() with multiple events at once" );
131         assert.equal( mouseoverCounter, 1, "on() with multiple events at once" );
132 } );
134 QUnit.test( "on(), five events at once", function( assert ) {
135         assert.expect( 1 );
137         var count = 0,
138                 handler = function() {
139                         count++;
140                 };
142         jQuery( "#firstp" ).on( "click mouseover foo bar baz", handler )
143         .trigger( "click" ).trigger( "mouseover" )
144                 .trigger( "foo" ).trigger( "bar" )
145                 .trigger( "baz" );
147         assert.equal( count, 5, "on() five events at once" );
148 } );
150 QUnit.test( "on(), multiple events at once and namespaces", function( assert ) {
151         assert.expect( 7 );
153         var cur, div,
154                 obj = {};
156         div = jQuery( "<div></div>" ).on( "focusin.a", function( e ) {
157                 assert.equal( e.type, cur, "Verify right single event was fired." );
158         } );
160         cur = "focusin";
161         div.trigger( "focusin.a" );
163         // manually clean up detached elements
164         div.remove();
166         div = jQuery( "<div></div>" ).on( "click mouseover", obj, function( e ) {
167                 assert.equal( e.type, cur, "Verify right multi event was fired." );
168                 assert.equal( e.data, obj, "Make sure the data came in correctly." );
169         } );
171         cur = "click";
172         div.trigger( "click" );
174         cur = "mouseover";
175         div.trigger( "mouseover" );
177         // manually clean up detached elements
178         div.remove();
180         div = jQuery( "<div></div>" ).on( "focusin.a focusout.b", function( e ) {
181                 assert.equal( e.type, cur, "Verify right multi event was fired." );
182         } );
184         cur = "focusin";
185         div.trigger( "focusin.a" );
187         cur = "focusout";
188         div.trigger( "focusout.b" );
190         // manually clean up detached elements
191         div.remove();
192 } );
194 QUnit.test( "on(), namespace with special add", function( assert ) {
195         assert.expect( 27 );
197         var i = 0,
198                 div = jQuery( "<div></div>" ).appendTo( "#qunit-fixture" ).on( "test", function() {
199                         assert.ok( true, "Test event fired." );
200                 } );
202         jQuery.event.special.test = {
203                 _default: function( e, data ) {
204                         assert.equal( e.type, "test", "Make sure we're dealing with a test event." );
205                         assert.ok( data, "And that trigger data was passed." );
206                         assert.strictEqual( e.target, div[ 0 ], "And that the target is correct." );
207                         assert.equal( this, window, "And that the context is correct." );
208                 },
209                 setup: function() {},
210                 teardown: function() {
211                         assert.ok( true, "Teardown called." );
212                 },
213                 add: function( handleObj ) {
214                         var handler = handleObj.handler;
215                         handleObj.handler = function( e ) {
216                                 e.xyz = ++i;
217                                 handler.apply( this, arguments );
218                         };
219                 },
220                 remove: function() {
221                         assert.ok( true, "Remove called." );
222                 }
223         };
225         div.on( "test.a", { x: 1 }, function( e ) {
226                 assert.ok( !!e.xyz, "Make sure that the data is getting passed through." );
227                 assert.equal( e.data.x, 1, "Make sure data is attached properly." );
228         } );
230         div.on( "test.b", { x: 2 }, function( e ) {
231                 assert.ok( !!e.xyz, "Make sure that the data is getting passed through." );
232                 assert.equal( e.data.x, 2, "Make sure data is attached properly." );
233         } );
235         // Should trigger 5
236         div.trigger( "test", 33.33 );
238         // Should trigger 2
239         div.trigger( "test.a", "George Harrison" );
241         // Should trigger 2
242         div.trigger( "test.b", { year: 1982 } );
244         // Should trigger 4
245         div.off( "test" );
247         div = jQuery( "<div></div>" ).on( "test", function() {
248                 assert.ok( true, "Test event fired." );
249         } );
251         // Should trigger 2
252         div.appendTo( "#qunit-fixture" ).remove();
254         delete jQuery.event.special.test;
255 } );
257 QUnit.test( "on(), no data", function( assert ) {
258         assert.expect( 1 );
259         var handler = function( event ) {
260                 assert.ok( !event.data, "Check that no data is added to the event object" );
261         };
262         jQuery( "#firstp" ).on( "click", handler ).trigger( "click" );
263 } );
265 QUnit.test( "on/one/off(Object)", function( assert ) {
266         assert.expect( 6 );
268         var $elem,
269                 clickCounter = 0,
270                 mouseoverCounter = 0;
272         function handler( event ) {
273                 if ( event.type === "click" ) {
274                         clickCounter++;
275                 } else if ( event.type === "mouseover" ) {
276                         mouseoverCounter++;
277                 }
278         }
280         function handlerWithData( event ) {
281                 if ( event.type === "click" ) {
282                         clickCounter += event.data;
283                 } else if ( event.type === "mouseover" ) {
284                         mouseoverCounter += event.data;
285                 }
286         }
288         function trigger() {
289                 $elem.trigger( "click" ).trigger( "mouseover" );
290         }
292         $elem = jQuery( "#firstp" )
294                 // Regular bind
295                 .on( {
296                         "click": handler,
297                         "mouseover": handler
298                 } )
300                 // Bind with data
301                 .one( {
302                         "click": handlerWithData,
303                         "mouseover": handlerWithData
304                 }, 2 );
306         trigger();
308         assert.equal( clickCounter, 3, "on(Object)" );
309         assert.equal( mouseoverCounter, 3, "on(Object)" );
311         trigger();
312         assert.equal( clickCounter, 4, "on(Object)" );
313         assert.equal( mouseoverCounter, 4, "on(Object)" );
315         jQuery( "#firstp" ).off( {
316                 "click": handler,
317                 "mouseover": handler
318         } );
320         trigger();
321         assert.equal( clickCounter, 4, "on(Object)" );
322         assert.equal( mouseoverCounter, 4, "on(Object)" );
323 } );
325 QUnit.test( "on/off(Object), on/off(Object, String)", function( assert ) {
326         assert.expect( 6 );
328         var events,
329                 clickCounter = 0,
330                 mouseoverCounter = 0,
331                 $p = jQuery( "#firstp" ),
332                 $a = $p.find( "a" ).eq( 0 );
334         events = {
335                 "click": function( event ) {
336                         clickCounter += ( event.data || 1 );
337                 },
338                 "mouseover": function( event ) {
339                         mouseoverCounter += ( event.data || 1 );
340                 }
341         };
343         function trigger() {
344                 $a.trigger( "click" ).trigger( "mouseover" );
345         }
347         jQuery( document ).on( events, "#firstp a" );
348         $p.on( events, "a", 2 );
350         trigger();
351         assert.equal( clickCounter, 3, "on" );
352         assert.equal( mouseoverCounter, 3, "on" );
354         $p.off( events, "a" );
356         trigger();
357         assert.equal( clickCounter, 4, "off" );
358         assert.equal( mouseoverCounter, 4, "off" );
360         jQuery( document ).off( events, "#firstp a" );
362         trigger();
363         assert.equal( clickCounter, 4, "off" );
364         assert.equal( mouseoverCounter, 4, "off" );
365 } );
367 QUnit.test( "on immediate propagation", function( assert ) {
368         assert.expect( 2 );
370         var lastClick,
371                 $p = jQuery( "#firstp" ),
372                 $a = $p.find( "a" ).eq( 0 );
374         lastClick = "";
375         jQuery( document ).on( "click", "#firstp a", function( e ) {
376                 lastClick = "click1";
377                 e.stopImmediatePropagation();
378         } );
379         jQuery( document ).on( "click", "#firstp a", function() {
380                 lastClick = "click2";
381         } );
382         $a.trigger( "click" );
383         assert.equal( lastClick, "click1", "on stopImmediatePropagation" );
384         jQuery( document ).off( "click", "#firstp a" );
386         lastClick = "";
387         $p.on( "click", "a", function( e ) {
388                 lastClick = "click1";
389                 e.stopImmediatePropagation();
390         } );
391         $p.on( "click", "a", function() {
392                 lastClick = "click2";
393         } );
394         $a.trigger( "click" );
395         assert.equal( lastClick, "click1", "on stopImmediatePropagation" );
396         $p.off( "click", "**" );
397 } );
399 QUnit.test( "on bubbling, isDefaultPrevented, stopImmediatePropagation", function( assert ) {
400         assert.expect( 3 );
402         var $anchor2 = jQuery( "#anchor2" ),
403                 $main = jQuery( "#qunit-fixture" ),
404                 neverCallMe = function() {
405                         assert.ok( false, "immediate propagation should have been stopped" );
406                 },
407                 fakeClick = function( $jq ) {
409                         // Use a native click so we don't get jQuery simulated bubbling
410                         var e = document.createEvent( "MouseEvents" );
411                         e.initEvent( "click", true, true );
412                         $jq[ 0 ].dispatchEvent( e );
413                 };
414         $anchor2.on( "click", function( e ) {
415                 e.preventDefault();
416         } );
417         $main.on( "click", "#foo", function( e ) {
418                 assert.equal( e.isDefaultPrevented(), true, "isDefaultPrevented true passed to bubbled event" );
419         } );
420         fakeClick( $anchor2 );
421         $anchor2.off( "click" );
422         $main.off( "click", "**" );
423         $anchor2.on( "click", function() {
425                 // Let the default action occur
426         } );
427         $main.on( "click", "#foo", function( e ) {
428                 assert.equal( e.isDefaultPrevented(), false, "isDefaultPrevented false passed to bubbled event" );
429         } );
430         fakeClick( $anchor2 );
431         $anchor2.off( "click" );
432         $main.off( "click", "**" );
434         $anchor2.on( "click", function( e ) {
435                 e.stopImmediatePropagation();
436                 assert.ok( true, "anchor was clicked and prop stopped" );
437         } );
438         $anchor2[ 0 ].addEventListener( "click", neverCallMe, false );
439         fakeClick( $anchor2 );
440         $anchor2[ 0 ].removeEventListener( "click", neverCallMe );
441 } );
443 QUnit.test( "triggered events stopPropagation() for natively-bound events", function( assert ) {
444         assert.expect( 1 );
446         var $button = jQuery( "#button" ),
447                 $parent = $button.parent(),
448                 neverCallMe = function() {
449                         assert.ok( false, "propagation should have been stopped" );
450                 },
451                 stopPropagationCallback = function( e ) {
452                         assert.ok( true, "propagation is stopped" );
453                         e.stopPropagation();
454                 };
456         $parent[ 0 ].addEventListener( "click", neverCallMe );
457         $button.on( "click", stopPropagationCallback );
458         $button.trigger( "click" );
459         $parent[ 0 ].removeEventListener( "click", neverCallMe );
460         $button.off( "click", stopPropagationCallback );
461 } );
463 QUnit.test( "trigger() works with events that were previously stopped", function( assert ) {
464         assert.expect( 0 );
466         var $button = jQuery( "#button" ),
467                 $parent = $button.parent(),
468                 neverCallMe = function() {
469                         assert.ok( false, "propagation should have been stopped" );
470                 };
472         $parent[ 0 ].addEventListener( "click", neverCallMe );
473         $button.on( "click", neverCallMe );
475         var clickEvent =  jQuery.Event( "click" );
476         clickEvent.stopPropagation();
477         $button.trigger( clickEvent );
479         $parent[ 0 ].removeEventListener( "click", neverCallMe );
480         $button.off( "click", neverCallMe );
481 } );
484 QUnit.test( "on(), iframes", function( assert ) {
485         assert.expect( 1 );
487         // events don't work with iframes, see trac-939 - this test fails in IE because of contentDocument
488         var doc = jQuery( "#loadediframe" ).contents();
490         jQuery( "div", doc ).on( "click", function() {
491                 assert.ok( true, "Binding to element inside iframe" );
492         } ).trigger( "click" ).off( "click" );
493 } );
495 QUnit.test( "on(), trigger change on select", function( assert ) {
496         assert.expect( 5 );
497         var counter = 0;
498         function selectOnChange( event ) {
499                 assert.equal( event.data, counter++, "Event.data is not a global event object" );
500         }
501         jQuery( "#form select" ).each( function( i ) {
502                 jQuery( this ).on( "change", i, selectOnChange );
503         } ).trigger( "change" );
504 } );
506 QUnit.test( "on(), namespaced events, cloned events", function( assert ) {
507         assert.expect( 18 );
509         var firstp = jQuery( "#firstp" );
511         firstp.on( "custom.test", function() {
512                 assert.ok( false, "Custom event triggered" );
513         } );
515         firstp.on( "click", function( e ) {
516                 assert.ok( true, "Normal click triggered" );
517                 assert.equal( e.type + e.namespace, "click", "Check that only click events trigger this fn" );
518         } );
520         firstp.on( "click.test", function( e ) {
521                 var check = "click";
522                 assert.ok( true, "Namespaced click triggered" );
523                 if ( e.namespace ) {
524                         check += "test";
525                 }
526                 assert.equal( e.type + e.namespace, check, "Check that only click/click.test events trigger this fn" );
527         } );
529         //clone(true) element to verify events are cloned correctly
530         firstp = firstp.add( firstp.clone( true ).attr( "id", "firstp2" ).insertBefore( firstp ) );
532         // Trigger both bound fn (8)
533         firstp.trigger( "click" );
535         // Trigger one bound fn (4)
536         firstp.trigger( "click.test" );
538         // Remove only the one fn
539         firstp.off( "click.test" );
541         // Trigger the remaining fn (4)
542         firstp.trigger( "click" );
544         // Remove the remaining namespaced fn
545         firstp.off( ".test" );
547         // Try triggering the custom event (0)
548         firstp.trigger( "custom" );
550         // using contents will get comments regular, text, and comment nodes
551         jQuery( "#nonnodes" ).contents().on( "tester", function() {
552                 assert.equal( this.nodeType, 1, "Check node,textnode,comment on just does real nodes" );
553         } ).trigger( "tester" );
555         // Make sure events stick with appendTo'd elements (which are cloned) trac-2027
556         jQuery( "<a href='#fail' class='test'>test</a>" ).on( "click", function() {
557                 return false;
558         } ).appendTo( "#qunit-fixture" );
559         assert.ok( jQuery( "a.test" ).eq( 0 ).triggerHandler( "click" ) === false, "Handler is bound to appendTo'd elements" );
560 } );
562 QUnit.test( "on(), multi-namespaced events", function( assert ) {
563         assert.expect( 6 );
565         var order = [
566                 "click.test.abc",
567                 "click.test.abc",
568                 "click.test",
569                 "click.test.abc",
570                 "click.test",
571                 "custom.test2"
572         ];
574         function check( name, msg ) {
575                 assert.deepEqual( name, order.shift(), msg );
576         }
578         jQuery( "#firstp" ).on( "custom.test", function() {
579                 check( "custom.test", "Custom event triggered" );
580         } );
582         jQuery( "#firstp" ).on( "custom.test2", function() {
583                 check( "custom.test2", "Custom event triggered" );
584         } );
586         jQuery( "#firstp" ).on( "click.test", function() {
587                 check( "click.test", "Normal click triggered" );
588         } );
590         jQuery( "#firstp" ).on( "click.test.abc", function() {
591                 check( "click.test.abc", "Namespaced click triggered" );
592         } );
594         // Those would not trigger/off (trac-5303)
595         jQuery( "#firstp" ).trigger( "click.a.test" );
596         jQuery( "#firstp" ).off( "click.a.test" );
598         // Trigger both bound fn (1)
599         jQuery( "#firstp" ).trigger( "click.test.abc" );
601         // Trigger one bound fn (1)
602         jQuery( "#firstp" ).trigger( "click.abc" );
604         // Trigger two bound fn (2)
605         jQuery( "#firstp" ).trigger( "click.test" );
607         // Remove only the one fn
608         jQuery( "#firstp" ).off( "click.abc" );
610         // Trigger the remaining fn (1)
611         jQuery( "#firstp" ).trigger( "click" );
613         // Remove the remaining fn
614         jQuery( "#firstp" ).off( ".test" );
616         // Trigger the remaining fn (1)
617         jQuery( "#firstp" ).trigger( "custom" );
618 } );
620 QUnit.test( "namespace-only event binding is a no-op", function( assert ) {
621         assert.expect( 2 );
623         jQuery( "#firstp" )
624                 .on( ".whoops", function() {
625                         assert.ok( false, "called a namespace-only event" );
626                 } )
627                 .on( "whoops", function() {
628                         assert.ok( true, "called whoops" );
629                 } )
630                 .trigger( "whoops" )    // 1
631                 .off( ".whoops" )
632                 .trigger( "whoops" )    // 2
633                 .off( "whoops" );
634 } );
636 QUnit.test( "Empty namespace is ignored", function( assert ) {
637         assert.expect( 1 );
639         jQuery( "#firstp" )
640                 .on( "meow.", function( e ) {
641                         assert.equal( e.namespace, "", "triggered a namespace-less meow event" );
642                 } )
643                 .trigger( "meow." )
644                 .off( "meow." );
645 } );
647 QUnit.test( "on(), with same function", function( assert ) {
648         assert.expect( 2 );
650         var count = 0, func = function() {
651                 count++;
652         };
654         jQuery( "#liveHandlerOrder" ).on( "foo.bar", func ).on( "foo.zar", func );
655         jQuery( "#liveHandlerOrder" ).trigger( "foo.bar" );
657         assert.equal( count, 1, "Verify binding function with multiple namespaces." );
659         jQuery( "#liveHandlerOrder" ).off( "foo.bar", func ).off( "foo.zar", func );
660         jQuery( "#liveHandlerOrder" ).trigger( "foo.bar" );
662         assert.equal( count, 1, "Verify that removing events still work." );
663 } );
665 QUnit.test( "on(), make sure order is maintained", function( assert ) {
666         assert.expect( 1 );
668         var elem = jQuery( "#firstp" ), log = [], check = [];
670         jQuery.each( new Array( 100 ), function( i ) {
671                 elem.on( "click", function() {
672                         log.push( i );
673                 } );
675                 check.push( i );
677         } );
679         elem.trigger( "click" );
681         assert.equal( log.join( "," ), check.join( "," ), "Make sure order was maintained." );
683         elem.off( "click" );
684 } );
686 QUnit.test( "on(), with different this object", function( assert ) {
687         assert.expect( 4 );
688         var thisObject = { myThis: true },
689                 data = { myData: true },
690                 handler1 = function() {
691                         assert.equal( this, thisObject, "on() with different this object" );
692                 }.bind( thisObject ),
693                 handler2 = function( event ) {
694                         assert.equal( this, thisObject, "on() with different this object and data" );
695                         assert.equal( event.data, data, "on() with different this object and data" );
696                 }.bind( thisObject );
698         jQuery( "#firstp" )
699                 .on( "click", handler1 ).trigger( "click" ).off( "click", handler1 )
700                 .on( "click", data, handler2 ).trigger( "click" ).off( "click", handler2 );
702         assert.ok( !jQuery._data( jQuery( "#firstp" )[ 0 ], "events" ), "Event handler unbound when using different this object and data." );
703 } );
705 QUnit.test( "on(name, false), off(name, false)", function( assert ) {
706         assert.expect( 3 );
708         var main = 0;
709         jQuery( "#qunit-fixture" ).on( "click", function() {
710                 main++;
711         } );
712         jQuery( "#ap" ).trigger( "click" );
713         assert.equal( main, 1, "Verify that the trigger happened correctly." );
715         main = 0;
716         jQuery( "#ap" ).on( "click", false );
717         jQuery( "#ap" ).trigger( "click" );
718         assert.equal( main, 0, "Verify that no bubble happened." );
720         main = 0;
721         jQuery( "#ap" ).off( "click", false );
722         jQuery( "#ap" ).trigger( "click" );
723         assert.equal( main, 1, "Verify that the trigger happened correctly." );
725         // manually clean up events from elements outside the fixture
726         jQuery( "#qunit-fixture" ).off( "click" );
727 } );
729 QUnit.test( "on(name, selector, false), off(name, selector, false)", function( assert ) {
730         assert.expect( 3 );
732         var main = 0;
734         jQuery( "#qunit-fixture" ).on( "click", "#ap", function() {
735                 main++;
736         } );
737         jQuery( "#ap" ).trigger( "click" );
738         assert.equal( main, 1, "Verify that the trigger happened correctly." );
740         main = 0;
741         jQuery( "#ap" ).on( "click", "#groups", false );
742         jQuery( "#groups" ).trigger( "click" );
743         assert.equal( main, 0, "Verify that no bubble happened." );
745         main = 0;
746         jQuery( "#ap" ).off( "click", "#groups", false );
747         jQuery( "#groups" ).trigger( "click" );
748         assert.equal( main, 1, "Verify that the trigger happened correctly." );
749         jQuery( "#qunit-fixture" ).off( "click", "#ap" );
750 } );
752 QUnit.test( "on()/trigger()/off() on plain object", function( assert ) {
753         assert.expect( 7 );
755         var events,
756                 obj = {};
758         // Make sure it doesn't complain when no events are found
759         jQuery( obj ).trigger( "test" );
761         // Make sure it doesn't complain when no events are found
762         jQuery( obj ).off( "test" );
764         jQuery( obj ).on( {
765                 "test": function() {
766                         assert.ok( true, "Custom event run." );
767                 },
768                 "submit": function() {
769                         assert.ok( true, "Custom submit event run." );
770                 }
771         } );
773         events = jQuery._data( obj, "events" );
774         assert.ok( events, "Object has events bound." );
775         assert.equal( obj.events, undefined, "Events object on plain objects is not events" );
776         assert.equal( obj.test, undefined, "Make sure that test event is not on the plain object." );
777         assert.equal( obj.handle, undefined, "Make sure that the event handler is not on the plain object." );
779         // Should trigger 1
780         jQuery( obj ).trigger( "test" );
781         jQuery( obj ).trigger( "submit" );
783         jQuery( obj ).off( "test" );
784         jQuery( obj ).off( "submit" );
786         // Should trigger 0
787         jQuery( obj ).trigger( "test" );
789         // Make sure it doesn't complain when no events are found
790         jQuery( obj ).off( "test" );
792         assert.equal( obj && obj[ jQuery.expando ] &&
793                         obj[ jQuery.expando ][ jQuery.expando ] &&
794                         obj[ jQuery.expando ][ jQuery.expando ].events, undefined, "Make sure events object is removed" );
795 } );
797 QUnit.test( "off(type)", function( assert ) {
798         assert.expect( 1 );
800         var message, func,
801                 $elem = jQuery( "#firstp" );
803         function error() {
804                 assert.ok( false, message );
805         }
807         message = "unbind passing function";
808         $elem.on( "error1", error ).off( "error1", error ).triggerHandler( "error1" );
810         message = "unbind all from event";
811         $elem.on( "error1", error ).off( "error1" ).triggerHandler( "error1" );
813         message = "unbind all";
814         $elem.on( "error1", error ).off().triggerHandler( "error1" );
816         message = "unbind many with function";
817         $elem.on( "error1 error2", error )
818                 .off( "error1 error2", error )
819                 .trigger( "error1" ).triggerHandler( "error2" );
821         message = "unbind many"; // trac-3538
822         $elem.on( "error1 error2", error )
823                 .off( "error1 error2" )
824                 .trigger( "error1" ).triggerHandler( "error2" );
826         message = "unbind without a type or handler";
827         $elem.on( "error1 error2.test", error )
828                 .off()
829                 .trigger( "error1" ).triggerHandler( "error2" );
831         // Should only unbind the specified function
832         jQuery( document ).on( "click", function() {
833                 assert.ok( true, "called handler after selective removal" );
834         } );
835         func = function() {};
836         jQuery( document )
837                 .on( "click", func )
838                 .off( "click", func )
839                 .trigger( "click" )
840                 .off( "click" );
841 } );
843 QUnit.test( "off(eventObject)", function( assert ) {
844         assert.expect( 4 );
846         var $elem = jQuery( "#firstp" ),
847                 num;
849         function check( expected ) {
850                 num = 0;
851                 $elem.trigger( "foo" ).triggerHandler( "bar" );
852                 assert.equal( num, expected, "Check the right handlers are triggered" );
853         }
855         $elem
857                 // This handler shouldn't be unbound
858                 .on( "foo", function() {
859                         num += 1;
860                 } )
861                 .on( "foo", function( e ) {
862                         $elem.off( e );
863                         num += 2;
864                 } )
866                 // Neither this one
867                 .on( "bar", function() {
868                         num += 4;
869                 } );
871         check( 7 );
872         check( 5 );
874         $elem.off( "bar" );
875         check( 1 );
877         $elem.off();
878         check( 0 );
879 } );
881 QUnit.test( "mouseover triggers mouseenter", function( assert ) {
882         assert.expect( 1 );
884         var count = 0,
885                 elem = jQuery( "<a></a>" );
886         elem.on( "mouseenter", function() {
887                 count++;
888         } );
889         elem.trigger( "mouseover" );
890         assert.equal( count, 1, "make sure mouseover triggers a mouseenter" );
892         elem.remove();
893 } );
895 QUnit.test( "pointerover triggers pointerenter", function( assert ) {
896         assert.expect( 1 );
898         var count = 0,
899                 elem = jQuery( "<a></a>" );
900         elem.on( "pointerenter", function() {
901                 count++;
902         } );
903         elem.trigger( "pointerover" );
904         assert.equal( count, 1, "make sure pointerover triggers a pointerenter" );
906         elem.remove();
907 } );
909 QUnit.test( "withinElement implemented with jQuery.contains()", function( assert ) {
911         assert.expect( 1 );
913         jQuery( "#qunit-fixture" ).append( "<div id='jc-outer'><div id='jc-inner'></div></div>" );
915         jQuery( "#jc-outer" ).on( "mouseenter mouseleave", function( event ) {
916                 assert.equal( this.id, "jc-outer", this.id + " " + event.type );
917         } );
919         jQuery( "#jc-inner" ).trigger( "mouseenter" );
920 } );
922 QUnit.test( "mouseenter, mouseleave don't catch exceptions", function( assert ) {
923         assert.expect( 2 );
925         var elem = jQuery( "#firstp" ).on( "mouseenter mouseleave", function() {
926                         throw "an Exception";
927                 } );
929         try {
930                 elem.trigger( "mouseenter" );
931         } catch ( e ) {
932                 assert.equal( e, "an Exception", "mouseenter doesn't catch exceptions" );
933         }
935         try {
936                 elem.trigger( "mouseleave" );
937         } catch ( e ) {
938                 assert.equal( e, "an Exception", "mouseleave doesn't catch exceptions" );
939         }
940 } );
942 QUnit.test( "trigger() bubbling", function( assert ) {
943         assert.expect( 18 );
945         var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0;
947         jQuery( window ).on( "click", function() {
948                 win++;
949         } );
950         jQuery( document ).on( "click", function( e ) {
951                 if ( e.target !== document ) {
952                         doc++;
953                 }
954         } );
955         jQuery( "html" ).on( "click", function() {
956                 html++;
957         } );
958         jQuery( "body" ).on( "click", function() {
959                 body++;
960         } );
961         jQuery( "#qunit-fixture" ).on( "click", function() {
962                 main++;
963         } );
964         jQuery( "#ap" ).on( "click", function() {
965                 ap++; return false;
966         } );
968         jQuery( "html" ).trigger( "click" );
969         assert.equal( win, 1, "HTML bubble" );
970         assert.equal( doc, 1, "HTML bubble" );
971         assert.equal( html, 1, "HTML bubble" );
973         jQuery( "body" ).trigger( "click" );
974         assert.equal( win, 2, "Body bubble" );
975         assert.equal( doc, 2, "Body bubble" );
976         assert.equal( html, 2, "Body bubble" );
977         assert.equal( body, 1, "Body bubble" );
979         jQuery( "#qunit-fixture" ).trigger( "click" );
980         assert.equal( win, 3, "Main bubble" );
981         assert.equal( doc, 3, "Main bubble" );
982         assert.equal( html, 3, "Main bubble" );
983         assert.equal( body, 2, "Main bubble" );
984         assert.equal( main, 1, "Main bubble" );
986         jQuery( "#ap" ).trigger( "click" );
987         assert.equal( doc, 3, "ap bubble" );
988         assert.equal( html, 3, "ap bubble" );
989         assert.equal( body, 2, "ap bubble" );
990         assert.equal( main, 1, "ap bubble" );
991         assert.equal( ap, 1, "ap bubble" );
993         jQuery( document ).trigger( "click" );
994         assert.equal( win, 4, "doc bubble" );
996         // manually clean up events from elements outside the fixture
997         jQuery( window ).off( "click" );
998         jQuery( document ).off( "click" );
999         jQuery( "html, body, #qunit-fixture" ).off( "click" );
1000 } );
1002 QUnit.test( "trigger(type, [data], [fn])", function( assert ) {
1003         assert.expect( 16 );
1005         var $elem, pass, form, elem2,
1006                 handler = function( event, a, b, c ) {
1007                 assert.equal( event.type, "click", "check passed data" );
1008                 assert.equal( a, 1, "check passed data" );
1009                 assert.equal( b, "2", "check passed data" );
1010                 assert.equal( c, "abc", "check passed data" );
1011                 return "test";
1012         };
1014         $elem = jQuery( "#firstp" );
1016         // Simulate a "native" click
1017         $elem[ 0 ].click = function() {
1018                 assert.ok( true, "Native call was triggered" );
1019         };
1021         jQuery( document ).on( "mouseenter", "#firstp", function() {
1022                 assert.ok( true, "Trigger mouseenter bound by on" );
1023         } );
1025         jQuery( document ).on( "mouseleave", "#firstp", function() {
1026                 assert.ok( true, "Trigger mouseleave bound by on" );
1027         } );
1029         $elem.trigger( "mouseenter" );
1031         $elem.trigger( "mouseleave" );
1033         jQuery( document ).off( "mouseenter mouseleave", "#firstp" );
1035         // Triggers handlers and native
1036         // Trigger 5
1037         $elem.on( "click", handler ).trigger( "click", [ 1, "2", "abc" ] );
1039         // Simulate a "native" click
1040         $elem[ 0 ].click = function() {
1041                 assert.ok( false, "Native call was triggered" );
1042         };
1044         // Trigger only the handlers (no native)
1045         // Triggers 5
1046         assert.equal( $elem.triggerHandler( "click", [ 1, "2", "abc" ] ), "test", "Verify handler response" );
1048         pass = true;
1049         try {
1050                 elem2 = jQuery( "#form input" ).eq( 0 );
1051                 elem2.get( 0 ).style.display = "none";
1052                 elem2.trigger( "focus" );
1053         } catch ( e ) {
1054                 pass = false;
1055         }
1056         assert.ok( pass, "Trigger focus on hidden element" );
1058         pass = true;
1059         try {
1060                 jQuery( "#qunit-fixture table" ).eq( 0 ).on( "test:test", function() {} ).trigger( "test:test" );
1061         } catch ( e ) {
1062                 pass = false;
1063         }
1064         assert.ok( pass, "Trigger on a table with a colon in the even type, see trac-3533" );
1066         form = jQuery( "<form action=''></form>" ).appendTo( "body" );
1068         // Make sure it can be prevented locally
1069         form.on( "submit", function() {
1070                 assert.ok( true, "Local `on` still works." );
1071                 return false;
1072         } );
1074         // Trigger 1
1075         form.trigger( "submit" );
1077         form.off( "submit" );
1079         jQuery( document ).on( "submit", function() {
1080                 assert.ok( true, "Make sure bubble works up to document." );
1081                 return false;
1082         } );
1084         // Trigger 1
1085         form.trigger( "submit" );
1087         jQuery( document ).off( "submit" );
1089         form.remove();
1090 } );
1092 QUnit.test( "submit event bubbles on copied forms (trac-11649)", function( assert ) {
1093         assert.expect( 3 );
1095         var $formByClone, $formByHTML,
1096                 $testForm = jQuery( "#testForm" ),
1097                 $fixture = jQuery( "#qunit-fixture" ),
1098                 $wrapperDiv = jQuery( "<div></div>" ).appendTo( $fixture );
1100         function noSubmit( e ) {
1101                 e.preventDefault();
1102         }
1103         function delegatedSubmit() {
1104                 assert.ok( true, "Make sure submit event bubbles up." );
1105                 return false;
1106         }
1108         // Attach a delegated submit handler to the parent element
1109         $fixture.on( "submit", "form", delegatedSubmit );
1111         // Trigger form submission to introduce the _submit_attached property
1112         $testForm.on( "submit", noSubmit ).find( "input[name=sub1]" ).trigger( "click" );
1114         // Copy the form via .clone() and .html()
1115         $formByClone = $testForm.clone( true, true ).removeAttr( "id" );
1116         $formByHTML = jQuery( jQuery.parseHTML( $fixture.html() ) ).filter( "#testForm" ).removeAttr( "id" );
1117         $wrapperDiv.append( $formByClone, $formByHTML );
1119         // Check submit bubbling on the copied forms
1120         $wrapperDiv.find( "form" ).on( "submit", noSubmit ).find( "input[name=sub1]" ).trigger( "click" );
1122         // Clean up
1123         $wrapperDiv.remove();
1124         $fixture.off( "submit", "form", delegatedSubmit );
1125         $testForm.off( "submit", noSubmit );
1126 } );
1128 QUnit.test( "change event bubbles on copied forms (trac-11796)", function( assert ) {
1129         assert.expect( 3 );
1131         var $formByClone, $formByHTML,
1132                 $form = jQuery( "#form" ),
1133                 $fixture = jQuery( "#qunit-fixture" ),
1134                 $wrapperDiv = jQuery( "<div></div>" ).appendTo( $fixture );
1136         function delegatedChange() {
1137                 assert.ok( true, "Make sure change event bubbles up." );
1138                 return false;
1139         }
1141         // Attach a delegated change handler to the form
1142         $fixture.on( "change", "form", delegatedChange );
1144         // Trigger change event to introduce the _change_attached property
1145         $form.find( "select[name=select1]" ).val( "1" ).trigger( "change" );
1147         // Copy the form via .clone() and .html()
1148         $formByClone = $form.clone( true, true ).removeAttr( "id" );
1149         $formByHTML = jQuery( jQuery.parseHTML( $fixture.html() ) ).filter( "#form" ).removeAttr( "id" );
1150         $wrapperDiv.append( $formByClone, $formByHTML );
1152         // Check change bubbling on the copied forms
1153         $wrapperDiv.find( "form select[name=select1]" ).val( "2" ).trigger( "change" );
1155         // Clean up
1156         $wrapperDiv.remove();
1157         $fixture.off( "change", "form", delegatedChange );
1158 } );
1160 QUnit.test( "trigger(eventObject, [data], [fn])", function( assert ) {
1161         assert.expect( 28 );
1163         var event,
1164                 $parent = jQuery( "<div id='par'></div>" ).appendTo( "body" ),
1165                 $child = jQuery( "<p id='child'>foo</p>" ).appendTo( $parent );
1167         $parent.get( 0 ).style.display = "none";
1169         event = jQuery.Event( "noNew" );
1170         assert.ok( event !== window, "Instantiate jQuery.Event without the 'new' keyword" );
1171         assert.equal( event.type, "noNew", "Verify its type" );
1173         assert.equal( event.isDefaultPrevented(), false, "Verify isDefaultPrevented" );
1174         assert.equal( event.isPropagationStopped(), false, "Verify isPropagationStopped" );
1175         assert.equal( event.isImmediatePropagationStopped(), false, "Verify isImmediatePropagationStopped" );
1177         event.preventDefault();
1178         assert.equal( event.isDefaultPrevented(), true, "Verify isDefaultPrevented" );
1179         event.stopPropagation();
1180         assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" );
1182         event.isPropagationStopped = function() {
1183                 return false;
1184         };
1185         event.stopImmediatePropagation();
1186         assert.equal( event.isPropagationStopped(), true, "Verify isPropagationStopped" );
1187         assert.equal( event.isImmediatePropagationStopped(), true, "Verify isPropagationStopped" );
1189         $parent.on( "foo", function( e ) {
1191                 // Tries bubbling
1192                 assert.equal( e.type, "foo", "Verify event type when passed passing an event object" );
1193                 assert.equal( e.target.id, "child", "Verify event.target when passed passing an event object" );
1194                 assert.equal( e.currentTarget.id, "par", "Verify event.currentTarget when passed passing an event object" );
1195                 assert.equal( e.secret, "boo!", "Verify event object's custom attribute when passed passing an event object" );
1196         } );
1198         // test with an event object
1199         event = new jQuery.Event( "foo" );
1200         event.secret = "boo!";
1201         $child.trigger( event );
1203         // test with a literal object
1204         $child.trigger( { "type": "foo", "secret": "boo!" } );
1206         $parent.off();
1208         function error() {
1209                 assert.ok( false, "This assertion shouldn't be reached" );
1210         }
1212         $parent.on( "foo", error );
1214         $child.on( "foo", function( e, a, b, c ) {
1215                 assert.equal( arguments.length, 4, "Check arguments length" );
1216                 assert.equal( a, 1, "Check first custom argument" );
1217                 assert.equal( b, 2, "Check second custom argument" );
1218                 assert.equal( c, 3, "Check third custom argument" );
1220                 assert.equal( e.isDefaultPrevented(), false, "Verify isDefaultPrevented" );
1221                 assert.equal( e.isPropagationStopped(), false, "Verify isPropagationStopped" );
1222                 assert.equal( e.isImmediatePropagationStopped(), false, "Verify isImmediatePropagationStopped" );
1224                 // Skips both errors
1225                 e.stopImmediatePropagation();
1227                 return "result";
1228         } );
1230         // We should add this back in when we want to test the order
1231         // in which event handlers are iterated.
1232         //$child.on("foo", error );
1234         event = new jQuery.Event( "foo" );
1235         $child.trigger( event, [ 1, 2, 3 ] ).off();
1236         assert.equal( event.result, "result", "Check event.result attribute" );
1238         // Will error if it bubbles
1239         $child.triggerHandler( "foo" );
1241         $child.off();
1242         $parent.off().remove();
1244         // Ensure triggerHandler doesn't molest its event object (#xxx)
1245         event = jQuery.Event( "zowie" );
1246         jQuery( document ).triggerHandler( event );
1247         assert.equal( event.type, "zowie", "Verify its type" );
1248         assert.equal( event.isPropagationStopped(), false, "propagation not stopped" );
1249         assert.equal( event.isDefaultPrevented(), false, "default not prevented" );
1250 } );
1252 QUnit.test( ".trigger() bubbling on disconnected elements (trac-10489)", function( assert ) {
1253         assert.expect( 2 );
1255         jQuery( window ).on( "click", function() {
1256                 assert.ok( false, "click fired on window" );
1257         } );
1259         jQuery( "<div><p>hi</p></div>" )
1260                 .on( "click", function() {
1261                         assert.ok( true, "click fired on div" );
1262                 } )
1263                 .find( "p" )
1264                         .on( "click", function() {
1265                                 assert.ok( true, "click fired on p" );
1266                         } )
1267                         .trigger( "click" )
1268                         .off( "click" )
1269                 .end()
1270                 .off( "click" )
1271                 .remove();
1273         jQuery( window ).off( "click" );
1274 } );
1276 QUnit.test( ".trigger() doesn't bubble load event (trac-10717)", function( assert ) {
1277         assert.expect( 1 );
1279         jQuery( window ).on( "load", function() {
1280                 assert.ok( false, "load fired on window" );
1281         } );
1283         jQuery( "<img src='" + baseURL + "1x1.jpg' />" )
1284                 .appendTo( "body" )
1285                 .on( "load", function() {
1286                         assert.ok( true, "load fired on img" );
1287                 } )
1288                 .trigger( "load" )
1289                 .remove();
1291         jQuery( window ).off( "load" );
1292 } );
1294 QUnit.test( "Delegated events in SVG (trac-10791; trac-13180)", function( assert ) {
1295         assert.expect( 2 );
1297         var useElem, e,
1298                 svg = jQuery(
1299                         "<svg height='1' version='1.1' width='1' xmlns='http://www.w3.org/2000/svg'>" +
1300                         "<defs><rect id='ref' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect></defs>" +
1301                         "<rect class='svg-by-class' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect>" +
1302                         "<rect id='svg-by-id' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect>" +
1303                         "<use id='use' xlink:href='#ref'></use>" +
1304                         "</svg>"
1305                 );
1307         jQuery( "#qunit-fixture" )
1308                 .append( svg )
1309                 .on( "click", "#svg-by-id", function() {
1310                         assert.ok( true, "delegated id selector" );
1311                 } )
1312                 .on( "click", "[class~='svg-by-class']", function() {
1313                         assert.ok( true, "delegated class selector" );
1314                 } )
1315                 .find( "#svg-by-id, [class~='svg-by-class']" )
1316                         .trigger( "click" )
1317                 .end();
1319         // Fire a native click on an SVGElementInstance (the instance tree of an SVG <use>)
1320         // to confirm that it doesn't break our event delegation handling (trac-13180)
1321         useElem = svg.find( "#use" )[ 0 ];
1322         if ( document.createEvent && useElem && useElem.instanceRoot ) {
1323                 e = document.createEvent( "MouseEvents" );
1324                 e.initEvent( "click", true, true );
1325                 useElem.instanceRoot.dispatchEvent( e );
1326         }
1328         jQuery( "#qunit-fixture" ).off( "click" );
1329 } );
1331 QUnit.test( "Delegated events with malformed selectors (gh-3071)", function( assert ) {
1332         assert.expect( 3 );
1334         assert.throws( function() {
1335                 jQuery( "#foo" ).on( "click", ":not", function() {} );
1336         }, "malformed selector throws on attach" );
1338         assert.throws( function() {
1339                 jQuery( "#foo" ).on( "click", "nonexistent:not", function() {} );
1340         }, "short-circuitable malformed selector throws on attach" );
1342         jQuery( "#foo > :first-child" ).trigger( "click" );
1343         assert.ok( true, "malformed selector does not throw on event" );
1344 } );
1346 QUnit.test( "Delegated events in forms (trac-10844; trac-11145; trac-8165; trac-11382, trac-11764)", function( assert ) {
1347         assert.expect( 5 );
1349         // Alias names like "id" cause havoc
1350         var form = jQuery(
1351                         "<form id='myform'>" +
1352                                 "<input type='text' name='id' value='secret agent man' />" +
1353                         "</form>"
1354                 )
1355                 .on( "submit", function( event ) {
1356                         event.preventDefault();
1357                 } )
1358                 .appendTo( "body" );
1360         jQuery( "body" )
1361                 .on( "submit", "#myform", function() {
1362                         assert.ok( true, "delegated id selector with aliased id" );
1363                 } )
1364                 .find( "#myform" )
1365                         .trigger( "submit" )
1366                 .end()
1367                 .off( "submit" );
1369         form.append( "<input type='text' name='disabled' value='differently abled' />" );
1370         jQuery( "body" )
1371                 .on( "submit", "#myform", function() {
1372                         assert.ok( true, "delegated id selector with aliased disabled" );
1373                 } )
1374                 .find( "#myform" )
1375                         .trigger( "submit" )
1376                 .end()
1377                 .off( "submit" );
1379         form
1380                 .append( "<button id='nestyDisabledBtn'><span>Zing</span></button>" )
1381                 .on( "click", "#nestyDisabledBtn", function() {
1382                         assert.ok( true, "click on enabled/disabled button with nesty elements" );
1383                 } )
1384                 .on( "mouseover", "#nestyDisabledBtn", function() {
1385                         assert.ok( true, "mouse on enabled/disabled button with nesty elements" );
1386                 } )
1387                 .find( "span" )
1388                         .trigger( "click" )             // yep
1389                         .trigger( "mouseover" ) // yep
1390                 .end()
1391                 .find( "#nestyDisabledBtn" ).prop( "disabled", true ).end()
1392                 .find( "span" )
1393                         .trigger( "click" )             // nope
1394                         .trigger( "mouseover" ) // yep
1395                 .end()
1396                 .off( "click" );
1398         form.remove();
1399 } );
1401 QUnit.test( "Submit event can be stopped (trac-11049)", function( assert ) {
1402         assert.expect( 1 );
1404         // Since we manually bubble in IE, make sure inner handlers get a chance to cancel
1405         var form = jQuery(
1406                         "<form id='myform'>" +
1407                                 "<input type='text' name='sue' value='bawls' />" +
1408                                 "<input type='submit' />" +
1409                         "</form>"
1410                 )
1411                 .appendTo( "body" );
1413         jQuery( "body" )
1414                 .on( "submit", function() {
1415                         assert.ok( true, "submit bubbled on first handler" );
1416                         return false;
1417                 } )
1418                 .find( "#myform input[type=submit]" )
1419                         .each( function() {
1420                                 this.click();
1421                         } )
1422                 .end()
1423                 .on( "submit", function() {
1424                         assert.ok( false, "submit bubbled on second handler" );
1425                         return false;
1426                 } )
1427                 .find( "#myform input[type=submit]" )
1428                         .each( function() {
1429                                 jQuery( this.form ).on( "submit", function( e ) {
1430                                         e.preventDefault();
1431                                         e.stopPropagation();
1432                                 } );
1433                                 this.click();
1434                         } )
1435                 .end()
1436                 .off( "submit" );
1438         form.remove();
1439 } );
1441 // Support: iOS <=7 - 12+
1442 // iOS has the window.onbeforeunload field but doesn't support the beforeunload
1443 // handler making it impossible to feature-detect the support.
1444 QUnit[ /(ipad|iphone|ipod)/i.test( navigator.userAgent ) ? "skip" : "test" ](
1445         "on(beforeunload)", function( assert ) {
1446         assert.expect( 1 );
1447         var iframe = jQuery( jQuery.parseHTML( "<iframe src='" + baseURL + "event/onbeforeunload.html'><iframe>" ) );
1448         var done = assert.async();
1450         window.onmessage = function( event ) {
1451                 try {
1452                         var payload = JSON.parse( event.data );
1454                         // Ignore unrelated messages
1455                         if ( payload.source === "jQuery onbeforeunload iframe test" ) {
1456                                 assert.ok( payload.event, "beforeunload", "beforeunload event" );
1458                                 iframe.remove();
1459                                 window.onmessage = null;
1460                                 done();
1461                         }
1462                 } catch ( e ) {
1464                         // Messages may come from other sources, like browser extensions;
1465                         // some may not be valid JSONs and thus cannot be `JSON.parse`d.
1466                 }
1467         };
1469         iframe.appendTo( "#qunit-fixture" );
1470 } );
1472 QUnit.test( "jQuery.Event( type, props )", function( assert ) {
1474         assert.expect( 6 );
1476         var event = jQuery.Event( "keydown", { keyCode: 64 } ),
1477                         handler = function( event ) {
1478                                 assert.ok( "keyCode" in event, "Special property 'keyCode' exists" );
1479                                 assert.equal( event.keyCode, 64, "event.keyCode has explicit value '64'" );
1480                         };
1482         // Supports jQuery.Event implementation
1483         assert.equal( event.type, "keydown", "Verify type" );
1485         // ensure "type" in props won't clobber the one set by constructor
1486         assert.equal( jQuery.inArray( "type", jQuery.event.props ), -1, "'type' property not in props (trac-10375)" );
1488         assert.ok( "keyCode" in event, "Special 'keyCode' property exists" );
1490         assert.strictEqual( jQuery.isPlainObject( event ), false, "Instances of $.Event should not be identified as a plain object." );
1492         jQuery( "body" ).on( "keydown", handler ).trigger( event );
1494         jQuery( "body" ).off( "keydown" );
1496 } );
1498 QUnit.test( "jQuery.Event properties", function( assert ) {
1499         assert.expect( 12 );
1501         var handler,
1502                 $structure = jQuery( "<div id='ancestor'><p id='delegate'><span id='target'>shiny</span></p></div>" ),
1503                 $target = $structure.find( "#target" );
1505         handler = function( e ) {
1506                 assert.strictEqual( e.currentTarget, this, "currentTarget at " + this.id );
1507                 assert.equal( e.isTrigger, 3, "trigger at " + this.id );
1508         };
1509         $structure.one( "click", handler );
1510         $structure.one( "click", "p", handler );
1511         $target.one( "click", handler );
1512         $target[ 0 ].onclick = function( e ) {
1513                 assert.strictEqual( e.currentTarget, this, "currentTarget at target (native handler)" );
1514                 assert.equal( e.isTrigger, 3, "trigger at target (native handler)" );
1515         };
1516         $target.trigger( "click" );
1518         $target.one( "click", function( e ) {
1519                 assert.equal( e.isTrigger, 2, "triggerHandler at target" );
1520         } );
1521         $target[ 0 ].onclick = function( e ) {
1522                 assert.equal( e.isTrigger, 2, "triggerHandler at target (native handler)" );
1523         };
1524         $target.triggerHandler( "click" );
1526         handler = function( e ) {
1527                 assert.strictEqual( e.isTrigger, undefined, "native event at " + this.id );
1528         };
1529         $target.one( "click", handler );
1530         $target[ 0 ].onclick = function( e ) {
1531                 assert.strictEqual( e.isTrigger, undefined, "native event at target (native handler)" );
1532         };
1533         fireNative( $target[ 0 ], "click" );
1534 } );
1536 QUnit.test( ".on()/.off()", function( assert ) {
1537         assert.expect( 65 );
1539         var event, clicked, hash, called, livec, lived, livee,
1540                 submit = 0, div = 0, livea = 0, liveb = 0;
1542         jQuery( "#body" ).on( "submit", "#qunit-fixture div", function() {
1543                 submit++; return false;
1544         } );
1545         jQuery( "#body" ).on( "click", "#qunit-fixture div", function() {
1546                 div++;
1547         } );
1548         jQuery( "#body" ).on( "click", "div#nothiddendiv", function() {
1549                 livea++;
1550 } );
1551         jQuery( "#body" ).on( "click", "div#nothiddendivchild", function() {
1552                 liveb++;
1553         } );
1555         // Nothing should trigger on the body
1556         jQuery( "body" ).trigger( "click" );
1557         assert.equal( submit, 0, "Click on body" );
1558         assert.equal( div, 0, "Click on body" );
1559         assert.equal( livea, 0, "Click on body" );
1560         assert.equal( liveb, 0, "Click on body" );
1562         // This should trigger two events
1563         submit = 0; div = 0; livea = 0; liveb = 0;
1564         jQuery( "div#nothiddendiv" ).trigger( "click" );
1565         assert.equal( submit, 0, "Click on div" );
1566         assert.equal( div, 1, "Click on div" );
1567         assert.equal( livea, 1, "Click on div" );
1568         assert.equal( liveb, 0, "Click on div" );
1570         // This should trigger three events (w/ bubbling)
1571         submit = 0; div = 0; livea = 0; liveb = 0;
1572         jQuery( "div#nothiddendivchild" ).trigger( "click" );
1573         assert.equal( submit, 0, "Click on inner div" );
1574         assert.equal( div, 2, "Click on inner div" );
1575         assert.equal( livea, 1, "Click on inner div" );
1576         assert.equal( liveb, 1, "Click on inner div" );
1578         // This should trigger one submit
1579         submit = 0; div = 0; livea = 0; liveb = 0;
1580         jQuery( "div#nothiddendivchild" ).trigger( "submit" );
1581         assert.equal( submit, 1, "Submit on div" );
1582         assert.equal( div, 0, "Submit on div" );
1583         assert.equal( livea, 0, "Submit on div" );
1584         assert.equal( liveb, 0, "Submit on div" );
1586         // Make sure no other events were removed in the process
1587         submit = 0; div = 0; livea = 0; liveb = 0;
1588         jQuery( "div#nothiddendivchild" ).trigger( "click" );
1589         assert.equal( submit, 0, "off Click on inner div" );
1590         assert.equal( div, 2, "off Click on inner div" );
1591         assert.equal( livea, 1, "off Click on inner div" );
1592         assert.equal( liveb, 1, "off Click on inner div" );
1594         // Now make sure that the removal works
1595         submit = 0; div = 0; livea = 0; liveb = 0;
1596         jQuery( "#body" ).off( "click", "div#nothiddendivchild" );
1597         jQuery( "div#nothiddendivchild" ).trigger( "click" );
1598         assert.equal( submit, 0, "off Click on inner div" );
1599         assert.equal( div, 2, "off Click on inner div" );
1600         assert.equal( livea, 1, "off Click on inner div" );
1601         assert.equal( liveb, 0, "off Click on inner div" );
1603         // Make sure that the click wasn't removed too early
1604         submit = 0; div = 0; livea = 0; liveb = 0;
1605         jQuery( "div#nothiddendiv" ).trigger( "click" );
1606         assert.equal( submit, 0, "off Click on inner div" );
1607         assert.equal( div, 1, "off Click on inner div" );
1608         assert.equal( livea, 1, "off Click on inner div" );
1609         assert.equal( liveb, 0, "off Click on inner div" );
1611         // Make sure that stopPropagation doesn't stop live events
1612         submit = 0; div = 0; livea = 0; liveb = 0;
1613         jQuery( "#body" ).on( "click", "div#nothiddendivchild", function( e ) {
1614                 liveb++; e.stopPropagation();
1615         } );
1616         jQuery( "div#nothiddendivchild" ).trigger( "click" );
1617         assert.equal( submit, 0, "stopPropagation Click on inner div" );
1618         assert.equal( div, 1, "stopPropagation Click on inner div" );
1619         assert.equal( livea, 0, "stopPropagation Click on inner div" );
1620         assert.equal( liveb, 1, "stopPropagation Click on inner div" );
1622         // Make sure click events only fire with primary click
1623         submit = 0; div = 0; livea = 0; liveb = 0;
1624         event = jQuery.Event( "click" );
1625         event.button = 1;
1626         jQuery( "div#nothiddendiv" ).trigger( event );
1628         assert.equal( livea, 0, "on secondary click" );
1630         jQuery( "#body" ).off( "click", "div#nothiddendivchild" );
1631         jQuery( "#body" ).off( "click", "div#nothiddendiv" );
1632         jQuery( "#body" ).off( "click", "#qunit-fixture div" );
1633         jQuery( "#body" ).off( "submit", "#qunit-fixture div" );
1635         // Test binding with a different context
1636         clicked = 0;
1637         jQuery( "#qunit-fixture" ).on( "click", "#foo", function() {
1638                 clicked++;
1639         } );
1640         jQuery( "#qunit-fixture div" ).trigger( "click" );
1641         jQuery( "#foo" ).trigger( "click" );
1642         jQuery( "#qunit-fixture" ).trigger( "click" );
1643         jQuery( "body" ).trigger( "click" );
1644         assert.equal( clicked, 2, "on with a context" );
1646         // Test unbinding with a different context
1647         jQuery( "#qunit-fixture" ).off( "click", "#foo" );
1648         jQuery( "#foo" ).trigger( "click" );
1649         assert.equal( clicked, 2, "off with a context" );
1651         // Test binding with event data
1652         jQuery( "#body" ).on( "click", "#foo", true, function( e ) {
1653                 assert.equal( e.data, true, "on with event data" );
1654         } );
1655         jQuery( "#foo" ).trigger( "click" );
1656         jQuery( "#body" ).off( "click", "#foo" );
1658         // Test binding with trigger data
1659         jQuery( "#body" ).on( "click", "#foo", function( e, data ) {
1660                 assert.equal( data, true, "on with trigger data" );
1661         } );
1662         jQuery( "#foo" ).trigger( "click", true );
1663         jQuery( "#body" ).off( "click", "#foo" );
1665         // Test binding with different this object
1666         jQuery( "#body" ).on( "click", "#foo", function() {
1667                         assert.equal( this.foo, "bar", "on with event scope" );
1668         }.bind( { "foo": "bar" } ) );
1670         jQuery( "#foo" ).trigger( "click" );
1671         jQuery( "#body" ).off( "click", "#foo" );
1673         // Test binding with different this object, event data, and trigger data
1674         jQuery( "#body" ).on( "click", "#foo", true, function( e, data ) {
1675                 assert.equal( e.data, true, "on with with different this object, event data, and trigger data" );
1676                 assert.equal( this.foo, "bar", "on with with different this object, event data, and trigger data" );
1677                 assert.equal( data, true, "on with with different this object, event data, and trigger data" );
1678         }.bind( { "foo": "bar" } ) );
1679         jQuery( "#foo" ).trigger( "click", true );
1680         jQuery( "#body" ).off( "click", "#foo" );
1682         // Verify that return false prevents default action
1683         jQuery( "#body" ).on( "click", "#anchor2", function() {
1684                 return false;
1685         } );
1686         hash = window.location.hash;
1687         jQuery( "#anchor2" ).trigger( "click" );
1688         assert.equal( window.location.hash, hash, "return false worked" );
1689         jQuery( "#body" ).off( "click", "#anchor2" );
1691         // Verify that .preventDefault() prevents default action
1692         jQuery( "#body" ).on( "click", "#anchor2", function( e ) {
1693                 e.preventDefault();
1694         } );
1695         hash = window.location.hash;
1696         jQuery( "#anchor2" ).trigger( "click" );
1697         assert.equal( window.location.hash, hash, "e.preventDefault() worked" );
1698         jQuery( "#body" ).off( "click", "#anchor2" );
1700         // Test binding the same handler to multiple points
1701         called = 0;
1702         function callback() {
1703                 called++; return false;
1704         }
1706         jQuery( "#body" ).on( "click", "#nothiddendiv", callback );
1707         jQuery( "#body" ).on( "click", "#anchor2", callback );
1709         jQuery( "#nothiddendiv" ).trigger( "click" );
1710         assert.equal( called, 1, "Verify that only one click occurred." );
1712         called = 0;
1713         jQuery( "#anchor2" ).trigger( "click" );
1714         assert.equal( called, 1, "Verify that only one click occurred." );
1716         // Make sure that only one callback is removed
1717         jQuery( "#body" ).off( "click", "#anchor2", callback );
1719         called = 0;
1720         jQuery( "#nothiddendiv" ).trigger( "click" );
1721         assert.equal( called, 1, "Verify that only one click occurred." );
1723         called = 0;
1724         jQuery( "#anchor2" ).trigger( "click" );
1725         assert.equal( called, 0, "Verify that no click occurred." );
1727         // Make sure that it still works if the selector is the same,
1728         // but the event type is different
1729         jQuery( "#body" ).on( "foo", "#nothiddendiv", callback );
1731         // Cleanup
1732         jQuery( "#body" ).off( "click", "#nothiddendiv", callback );
1734         called = 0;
1735         jQuery( "#nothiddendiv" ).trigger( "click" );
1736         assert.equal( called, 0, "Verify that no click occurred." );
1738         called = 0;
1739         jQuery( "#nothiddendiv" ).trigger( "foo" );
1740         assert.equal( called, 1, "Verify that one foo occurred." );
1742         // Cleanup
1743         jQuery( "#body" ).off( "foo", "#nothiddendiv", callback );
1745         // Make sure we don't loose the target by DOM modifications
1746         // after the bubble already reached the liveHandler
1747         livec = 0;
1748         jQuery( "#nothiddendivchild" ).html( "<span></span>" );
1750         jQuery( "#body" ).on( "click", "#nothiddendivchild", function() {
1751                 jQuery( "#nothiddendivchild" ).html( "" );
1752         } );
1753         jQuery( "#body" ).on( "click", "#nothiddendivchild", function( e ) {
1754                 if ( e.target ) {
1755                         livec++;
1756                 }
1757         } );
1759         jQuery( "#nothiddendiv span" ).trigger( "click" );
1760         assert.equal( jQuery( "#nothiddendiv span" ).length, 0, "Verify that first handler occurred and modified the DOM." );
1761         assert.equal( livec, 1, "Verify that second handler occurred even with nuked target." );
1763         // Cleanup
1764         jQuery( "#body" ).off( "click", "#nothiddendivchild" );
1766         // Verify that .live() occurs and cancel bubble in the same order as
1767         // we would expect .on() and .click() without delegation
1768         lived = 0;
1769         livee = 0;
1771         // bind one pair in one order
1772         jQuery( "#body" ).on( "click", "span#liveSpan1 a", function() {
1773                 lived++;
1774                 return false;
1775         } );
1776         jQuery( "#body" ).on( "click", "span#liveSpan1", function() {
1777                 livee++;
1778         } );
1780         jQuery( "span#liveSpan1 a" ).trigger( "click" );
1781         assert.equal( lived, 1, "Verify that only one first handler occurred." );
1782         assert.equal( livee, 0, "Verify that second handler doesn't." );
1784         // and one pair in inverse
1785         jQuery( "#body" ).on( "click", "span#liveSpan2", function() {
1786                 livee++;
1787         } );
1788         jQuery( "#body" ).on( "click", "span#liveSpan2 a", function() {
1789                 lived++;
1790                 return false;
1791         } );
1793         lived = 0;
1794         livee = 0;
1795         jQuery( "span#liveSpan2 a" ).trigger( "click" );
1796         assert.equal( lived, 1, "Verify that only one first handler occurred." );
1797         assert.equal( livee, 0, "Verify that second handler doesn't." );
1799         // Cleanup
1800         jQuery( "#body" ).off( "click", "**" );
1802         // Test this, target and currentTarget are correct
1803         jQuery( "#body" ).on( "click", "span#liveSpan1", function( e ) {
1804                 assert.equal( this.id, "liveSpan1", "Check the this within a on handler" );
1805                 assert.equal( e.currentTarget.id, "liveSpan1", "Check the event.currentTarget within a on handler" );
1806                 assert.equal( e.delegateTarget, document.body, "Check the event.delegateTarget within a on handler" );
1807                 assert.equal( e.target.nodeName.toUpperCase(), "A", "Check the event.target within a on handler" );
1808         } );
1810         jQuery( "span#liveSpan1 a" ).trigger( "click" );
1812         jQuery( "#body" ).off( "click", "span#liveSpan1" );
1814         // Work with deep selectors
1815         livee = 0;
1817         function clickB() {
1818                 livee++;
1819         }
1821         jQuery( "#body" ).on( "click", "#nothiddendiv div", function() {
1822                 livee++;
1823         } );
1824         jQuery( "#body" ).on( "click", "#nothiddendiv div", clickB );
1825         jQuery( "#body" ).on( "mouseover", "#nothiddendiv div", function() {
1826                 livee++;
1827         } );
1829         assert.equal( livee, 0, "No clicks, deep selector." );
1831         livee = 0;
1832         jQuery( "#nothiddendivchild" ).trigger( "click" );
1833         assert.equal( livee, 2, "Click, deep selector." );
1835         livee = 0;
1836         jQuery( "#nothiddendivchild" ).trigger( "mouseover" );
1837         assert.equal( livee, 1, "Mouseover, deep selector." );
1839         jQuery( "#body" ).off( "mouseover", "#nothiddendiv div" );
1841         livee = 0;
1842         jQuery( "#nothiddendivchild" ).trigger( "click" );
1843         assert.equal( livee, 2, "Click, deep selector." );
1845         livee = 0;
1846         jQuery( "#nothiddendivchild" ).trigger( "mouseover" );
1847         assert.equal( livee, 0, "Mouseover, deep selector." );
1849         jQuery( "#body" ).off( "click", "#nothiddendiv div", clickB );
1851         livee = 0;
1852         jQuery( "#nothiddendivchild" ).trigger( "click" );
1853         assert.equal( livee, 1, "Click, deep selector." );
1855         jQuery( "#body" ).off( "click", "#nothiddendiv div" );
1856 } );
1858 QUnit.test( "jQuery.off using dispatched jQuery.Event", function( assert ) {
1859         assert.expect( 1 );
1861         var markup = jQuery( "<p><a href='#'>target</a></p>" ),
1862                 count = 0;
1863         markup
1864                 .on( "click.name", "a", function( event ) {
1865                         assert.equal( ++count, 1, "event called once before removal" );
1866                         jQuery().off( event );
1867                 } )
1868                 .find( "a" ).trigger( "click" ).trigger( "click" ).end()
1869                 .remove();
1870 } );
1872 QUnit.test( "events with type matching an Object.prototype property (gh-3256)", function( assert ) {
1873         assert.expect( 1 );
1875         var elem = jQuery( "<div></div>" ),
1876                 eventFired = false;
1878         elem.appendTo( "#qunit-fixture" );
1880         try {
1881                 elem
1882                         .one( "hasOwnProperty", function() {
1883                                 eventFired = true;
1884                         } )
1885                         .trigger( "hasOwnProperty" );
1886         } finally {
1887                 assert.strictEqual( eventFired, true, "trigger fired without crashing" );
1888         }
1889 } );
1891 QUnit.test( "events with type matching an Object.prototype property, cloned element (gh-3256)",
1892         function( assert ) {
1893         assert.expect( 1 );
1895         var elem = jQuery( "<div></div>" ),
1896                 eventFired = false;
1898         elem.appendTo( "#qunit-fixture" );
1900         try {
1902                 // Make sure the original element has some event data.
1903                 elem.on( "click", function() {} );
1905                 elem
1906                         .clone( true )
1907                         .one( "hasOwnProperty", function() {
1908                                 eventFired = true;
1909                         } )
1910                         .trigger( "hasOwnProperty" );
1911         } finally {
1912                 assert.strictEqual( eventFired, true, "trigger fired without crashing" );
1913         }
1914 } );
1916 // selector-native does not support scope-fixing in delegation
1917 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
1918         assert.expect( 3 );
1919         var markup = jQuery( "<div><ul><li><a id=\"a0\"></a><ul id=\"ul0\"><li class=test><a id=\"a0_0\"></a></li><li><a id=\"a0_1\"></a></li></ul></li></ul></div>" ).appendTo( "#qunit-fixture" );
1921         // Non-positional selector (trac-12383)
1922         markup.find( "#ul0" )
1923                 .on( "click", "div li a", function() {
1924                         assert.ok( false, "div is ABOVE the delegation point!" );
1925                 } )
1926                 .on( "click", "ul a", function() {
1927                         assert.ok( false, "ul IS the delegation point!" );
1928                 } )
1929                 .on( "click", "li.test a", function() {
1930                         assert.ok( true, "li.test is below the delegation point." );
1931                 } )
1932                 .find( "#a0_0" ).trigger( "click" ).end()
1933                 .off( "click" );
1935         if ( QUnit.jQuerySelectorsPos ) {
1937                 // Positional selector (trac-11315)
1938                 markup.find( "ul" ).eq( 0 )
1939                         .on( "click", ">li>a", function() {
1940                                 assert.ok( this.id === "a0", "child li was clicked" );
1941                         } )
1942                         .find( "#ul0" )
1943                                 .on( "click", "li:first>a", function() {
1944                                         assert.ok( this.id === "a0_0", "first li under #u10 was clicked" );
1945                                 } )
1946                         .end()
1947                         .find( "a" ).trigger( "click" ).end()
1948                         .find( "#ul0" ).off();
1949         } else {
1950                 assert.ok( "skip", "Positional selectors are not supported" );
1951                 assert.ok( "skip", "Positional selectors are not supported" );
1952         }
1954         markup.remove();
1955 } );
1957 QUnit.test( "delegated event with selector matching Object.prototype property (trac-13203)", function( assert ) {
1958         assert.expect( 1 );
1960         var matched = 0;
1962         jQuery( "#foo" ).on( "click", "toString", function() {
1963                 matched++;
1964         } );
1966         jQuery( "#anchor2" ).trigger( "click" );
1968         assert.equal( matched, 0, "Nothing matched 'toString'" );
1969 } );
1971 QUnit.test( "delegated event with intermediate DOM manipulation (trac-13208)", function( assert ) {
1972         assert.expect( 1 );
1974         jQuery( "#foo" ).on( "click", "[id=sap]", function() {} );
1975         jQuery( "#sap" ).on( "click", "[id=anchor2]", function() {
1976                 document.createDocumentFragment().appendChild( this.parentNode );
1977                 assert.ok( true, "Element removed" );
1978         } );
1979         jQuery( "#anchor2" ).trigger( "click" );
1980 } );
1982 QUnit.test( "ignore comment nodes in event delegation (gh-2055)", function( assert ) {
1983         assert.expect( 1 );
1985         // Test if DOMNodeInserted is supported
1986         // This is a back-up for when DOMNodeInserted support
1987         // is eventually removed from browsers
1988         function test() {
1989                 var ret = false;
1990                 var $fixture = jQuery( "#qunit-fixture" );
1991                 $fixture.on( "DOMNodeInserted", function() {
1992                         ret = true;
1993                         $fixture.off( "DOMNodeInserted" );
1994                 } ).append( "<div></div>" );
1995                 return ret;
1996         }
1998         var $foo = jQuery( "#foo" ).on( "DOMNodeInserted", "[id]", function() {
1999                 assert.ok( true, "No error thrown on comment node" );
2000         } ),
2001                 $comment = jQuery( document.createComment( "comment" ) )
2002                         .appendTo( $foo.find( "#sap" ) );
2004         if ( !test() ) {
2005                 fireNative( $comment[ 0 ], "DOMNodeInserted" );
2006         }
2007 } );
2009 QUnit.test( "stopPropagation() stops directly-bound events on delegated target", function( assert ) {
2010         assert.expect( 1 );
2012         var markup = jQuery( "<div><p><a href=\"#\">target</a></p></div>" );
2013         markup
2014                 .on( "click", function() {
2015                         assert.ok( false, "directly-bound event on delegate target was called" );
2016                 } )
2017                 .on( "click", "a", function( e ) {
2018                         e.stopPropagation();
2019                         assert.ok( true, "delegated handler was called" );
2020                 } )
2021                 .find( "a" ).trigger( "click" ).end()
2022                 .remove();
2023 } );
2025 QUnit.test( "off all bound delegated events", function( assert ) {
2026         assert.expect( 2 );
2028         var count = 0,
2029                 clicks = 0,
2030                 div = jQuery( "#body" );
2032         div.on( "click submit", "div#nothiddendivchild", function() {
2033                 count++;
2034         } );
2035         div.on( "click", function() {
2036                 clicks++;
2037         } );
2038         div.off( undefined, "**" );
2040         jQuery( "div#nothiddendivchild" ).trigger( "click" );
2041         jQuery( "div#nothiddendivchild" ).trigger( "submit" );
2043         assert.equal( count, 0, "Make sure no events were triggered." );
2045         div.trigger( "click" );
2046         assert.equal( clicks, 2, "Make sure delegated and directly bound event occurred." );
2047         div.off( "click" );
2048 } );
2050 QUnit.test( "on with multiple delegated events", function( assert ) {
2051         assert.expect( 1 );
2053         var count = 0,
2054                 div = jQuery( "#body" );
2056         div.on( "click submit", "div#nothiddendivchild", function() {
2057                 count++;
2058         } );
2060         jQuery( "div#nothiddendivchild" ).trigger( "click" );
2061         jQuery( "div#nothiddendivchild" ).trigger( "submit" );
2063         assert.equal( count, 2, "Make sure both the click and submit were triggered." );
2065         jQuery( "#body" ).off( undefined, "**" );
2066 } );
2068 QUnit.test( "delegated on with change", function( assert ) {
2069         assert.expect( 8 );
2071         var select, checkbox, checkboxFunction,
2072                 text, textChange, oldTextVal,
2073                 password, passwordChange, oldPasswordVal,
2074                 selectChange = 0,
2075                 checkboxChange = 0;
2077         select = jQuery( "select[name='S1']" );
2078         jQuery( "#body" ).on( "change", "select[name='S1']", function() {
2079                 selectChange++;
2080         } );
2082         checkbox = jQuery( "#check2" );
2083         checkboxFunction = function() {
2084                 checkboxChange++;
2085         };
2086         jQuery( "#body" ).on( "change", "#check2", checkboxFunction );
2088         // test click on select
2090         // second click that changed it
2091         selectChange = 0;
2092         select[ 0 ].selectedIndex = select[ 0 ].selectedIndex ? 0 : 1;
2093         select.trigger( "change" );
2094         assert.equal( selectChange, 1, "Change on click." );
2096         // test keys on select
2097         selectChange = 0;
2098         select[ 0 ].selectedIndex = select[ 0 ].selectedIndex ? 0 : 1;
2099         select.trigger( "change" );
2100         assert.equal( selectChange, 1, "Change on keyup." );
2102         // test click on checkbox
2103         checkbox.trigger( "change" );
2104         assert.equal( checkboxChange, 1, "Change on checkbox." );
2106         // test blur/focus on text
2107         text = jQuery( "#name" );
2108         textChange = 0;
2109         oldTextVal = text.val();
2111         jQuery( "#body" ).on( "change", "#name", function() {
2112                 textChange++;
2113         } );
2115         text.val( oldTextVal + "foo" );
2116         text.trigger( "change" );
2117         assert.equal( textChange, 1, "Change on text input." );
2119         text.val( oldTextVal );
2120         jQuery( "#body" ).off( "change", "#name" );
2122         // test blur/focus on password
2123         password = jQuery( "#name" );
2124         passwordChange = 0;
2125         oldPasswordVal = password.val();
2126         jQuery( "#body" ).on( "change", "#name", function() {
2127                 passwordChange++;
2128         } );
2130         password.val( oldPasswordVal + "foo" );
2131         password.trigger( "change" );
2132         assert.equal( passwordChange, 1, "Change on password input." );
2134         password.val( oldPasswordVal );
2135         jQuery( "#body" ).off( "change", "#name" );
2137         // make sure die works
2139         // die all changes
2140         selectChange = 0;
2141         jQuery( "#body" ).off( "change", "select[name='S1']" );
2142         select[ 0 ].selectedIndex = select[ 0 ].selectedIndex ? 0 : 1;
2143         select.trigger( "change" );
2144         assert.equal( selectChange, 0, "Die on click works." );
2146         selectChange = 0;
2147         select[ 0 ].selectedIndex = select[ 0 ].selectedIndex ? 0 : 1;
2148         select.trigger( "change" );
2149         assert.equal( selectChange, 0, "Die on keyup works." );
2151         // die specific checkbox
2152         jQuery( "#body" ).off( "change", "#check2", checkboxFunction );
2153         checkbox.trigger( "change" );
2154         assert.equal( checkboxChange, 1, "Die on checkbox." );
2155 } );
2157 QUnit.test( "delegated on with submit", function( assert ) {
2158         assert.expect( 2 );
2160         var count1 = 0, count2 = 0;
2162         jQuery( "#body" ).on( "submit", "#testForm", function( ev ) {
2163                 count1++;
2164                 ev.preventDefault();
2165         } );
2167         jQuery( document ).on( "submit", "body", function( ev ) {
2168                 count2++;
2169                 ev.preventDefault();
2170         } );
2172         jQuery( "#testForm input[name=sub1]" ).trigger( "submit" );
2173         assert.equal( count1, 1, "Verify form submit." );
2174         assert.equal( count2, 1, "Verify body submit." );
2176         jQuery( "#body" ).off( undefined, "**" );
2177         jQuery( document ).off( undefined, "**" );
2178 } );
2180 QUnit.test( "delegated off() with only namespaces", function( assert ) {
2181         assert.expect( 2 );
2183         var $delegate = jQuery( "#liveHandlerOrder" ),
2184                 count = 0;
2186         $delegate.on( "click.ns", "a", function() {
2187                 count++;
2188         } );
2190         jQuery( "a", $delegate ).eq( 0 ).trigger( "click.ns" );
2192         assert.equal( count, 1, "delegated click.ns" );
2194         $delegate.off( ".ns", "**" );
2196         jQuery( "a", $delegate ).eq( 1 ).trigger( "click.ns" );
2198         assert.equal( count, 1, "no more .ns after off" );
2199 } );
2201 QUnit.test( "Non DOM element events", function( assert ) {
2202         assert.expect( 1 );
2204         var o = {};
2206         jQuery( o ).on( "nonelementobj", function() {
2207                 assert.ok( true, "Event on non-DOM object triggered" );
2208         } );
2210         jQuery( o ).trigger( "nonelementobj" ).off( "nonelementobj" );
2211 } );
2213 QUnit.test( "inline handler returning false stops default", function( assert ) {
2214         assert.expect( 1 );
2216         var markup = jQuery( "<div><a href=\"#\" onclick=\"return false\">x</a></div>" );
2217         markup.on( "click", function( e ) {
2218                 assert.ok( e.isDefaultPrevented(), "inline handler prevented default" );
2219                 return false;
2220         } );
2221         markup.find( "a" ).trigger( "click" );
2222         markup.off( "click" );
2223 } );
2225 QUnit.test( "window resize", function( assert ) {
2226         assert.expect( 2 );
2228         jQuery( window ).off();
2230         jQuery( window ).on( "resize", function() {
2231                 assert.ok( true, "Resize event fired." );
2232         } ).trigger( "resize" ).off( "resize" );
2234         assert.ok( !jQuery._data( window, "events" ), "Make sure all the events are gone." );
2235 } );
2237 QUnit.test( "focusin bubbles", function( assert ) {
2238         assert.expect( 3 );
2240         var input = jQuery( "<input type='text' />" ).prependTo( "body" ),
2241                 order = 0;
2243         // focus the element so DOM focus won't fire
2244         input[ 0 ].focus();
2246         jQuery( "body" ).on( "focusin.focusinBubblesTest", function() {
2247                 assert.equal( 1, order++, "focusin on the body second" );
2248         } );
2250         input.on( "focusin.focusinBubblesTest", function() {
2251                 assert.equal( 0, order++, "focusin on the element first" );
2252         } );
2254         // DOM focus method
2255         input[ 0 ].focus();
2257         // To make the next focus test work, we need to take focus off the input.
2258         // This will fire another focusin event, so set order to reflect that.
2259         order = 1;
2260         jQuery( "#text1" )[ 0 ].focus();
2262         // jQuery trigger, which calls DOM focus
2263         order = 0;
2264         input.trigger( "focus" );
2266         input.remove();
2267         jQuery( "body" ).off( "focusin.focusinBubblesTest" );
2268 } );
2270 QUnit.test( "focus does not bubble", function( assert ) {
2271         assert.expect( 1 );
2273         var done = assert.async(),
2274                 input = jQuery( "<input type='text' />" ).prependTo( "body" );
2276         // focus the element so DOM focus won't fire
2277         input[ 0 ].focus();
2279         jQuery( "body" ).on( "focus.focusDoesNotBubbleTest", function() {
2280                 assert.ok( false, "focus doesn't fire on body" );
2281         } );
2283         input.on( "focus.focusDoesNotBubbleTest", function() {
2284                 assert.ok( true, "focus on the element" );
2285         } );
2287         // DOM focus method
2288         input[ 0 ].focus();
2290         // To make the next focus test work, we need to take focus off the input.
2291         // This will fire another focusin event, so set order to reflect that.
2292         jQuery( "#text1" )[ 0 ].focus();
2294         // jQuery trigger, which calls DOM focus
2295         input.trigger( "focus" );
2297         input.remove();
2298         jQuery( "body" ).off( "focus.focusDoesNotBubbleTest" );
2300         setTimeout( function() {
2301                 done();
2302         }, 50 );
2303 } );
2305 QUnit.test( "custom events with colons (trac-3533, trac-8272)", function( assert ) {
2306         assert.expect( 1 );
2308         var tab = jQuery( "<table><tr><td>trigger</td></tr></table>" ).appendTo( "body" );
2309         try {
2310                 tab.trigger( "back:forth" );
2311                 assert.ok( true, "colon events don't throw" );
2312         } catch ( e ) {
2313                 assert.ok( false, "colon events die" );
2314         }
2315         tab.remove();
2317 } );
2319 QUnit.test( ".on and .off", function( assert ) {
2320         assert.expect( 9 );
2321         var counter, mixfn, data,
2322                 $onandoff = jQuery( "<div id=\"onandoff\"><p>on<b>and</b>off</p><div>worked<em>or</em>borked?</div></div>" ).appendTo( "body" );
2324         // Simple case
2325         jQuery( "#onandoff" )
2326                 .on( "whip", function() {
2327                         assert.ok( true, "whipped it good" );
2328                 } )
2329                 .trigger( "whip" )
2330                 .off();
2332         // Direct events only
2333         counter = 0;
2334         jQuery( "#onandoff b" )
2335                 .on( "click", 5, function( e, trig ) {
2336                         counter += e.data + ( trig || 9 );      // twice, 5+9+5+17=36
2337                 } )
2338                 .one( "click", 7, function( e, trig ) {
2339                         counter += e.data + ( trig || 11 );     // once, 7+11=18
2340                 } )
2341                 .trigger( "click" )
2342                 .trigger( "click", 17 )
2343                 .off( "click" );
2344         assert.equal( counter, 54, "direct event bindings with data" );
2346         // Delegated events only
2347         counter = 0;
2348         jQuery( "#onandoff" )
2349                 .on( "click", "em", 5, function( e, trig ) {
2350                         counter += e.data + ( trig || 9 );      // twice, 5+9+5+17=36
2351                 } )
2352                 .one( "click", "em", 7, function( e, trig ) {
2353                         counter += e.data + ( trig || 11 );     // once, 7+11=18
2354                 } )
2355                 .find( "em" )
2356                         .trigger( "click" )
2357                         .trigger( "click", 17 )
2358                 .end()
2359                 .off( "click", "em" );
2360         assert.equal( counter, 54, "delegated event bindings with data" );
2362         // Mixed event bindings and types
2363         counter = 0;
2364         mixfn = function( e, trig ) {
2365                 counter += ( e.data || 0 ) + ( trig || 1 );
2366         };
2367         jQuery( "#onandoff" )
2368                 .on( " click  clack cluck ", "em", 2, mixfn )
2369                 .on( "cluck", "b", 7, mixfn )
2370                 .on( "cluck", mixfn )
2371                 .trigger( "what!" )
2372                 .each( function() {
2373                         assert.equal( counter, 0, "nothing triggered yet" );
2374                 } )
2375                 .find( "em" )
2376                         .one( "cluck", 3, mixfn )
2377                         .trigger( "cluck", 8 )                  // 3+8 2+8 + 0+8 = 29
2378                         .off()
2379                         .trigger( "cluck", 9 )                  // 2+9 + 0+9 = 20
2380                 .end()
2381                 .each( function() {
2382                         assert.equal( counter, 49, "after triggering em element" );
2383                 } )
2384                 .off( "cluck", function() {} )          // shouldn't remove anything
2385                 .trigger( "cluck", 2 )                          // 0+2 = 2
2386                 .each( function() {
2387                         assert.equal( counter, 51, "after triggering #onandoff cluck" );
2388                 } )
2389                 .find( "b" )
2390                         .on( "click", 95, mixfn )
2391                         .on( "clack", "p", 97, mixfn )
2392                         .one( "cluck", 3, mixfn )
2393                         .trigger( "quack", 19 )                 // 0
2394                         .off( "click clack cluck" )
2395                 .end()
2396                 .each( function() {
2397                         assert.equal( counter, 51, "after triggering b" );
2398                 } )
2399                 .trigger( "cluck", 3 )                          // 0+3 = 3
2400                 .off( "clack", "em", mixfn )
2401                 .find( "em" )
2402                         .trigger( "clack" )                             // 0
2403                 .end()
2404                 .each( function() {
2405                         assert.equal( counter, 54, "final triggers" );
2406                 } )
2407                 .off( "click cluck" );
2409         // We should have removed all the event handlers ... kinda hacky way to check this
2410         data = jQuery.data[ jQuery( "#onandoff" )[ 0 ].expando ] || {};
2411         assert.equal( data.events, undefined, "no events left" );
2413         $onandoff.remove();
2414 } );
2416 QUnit.test( "special on name mapping", function( assert ) {
2417         assert.expect( 7 );
2419         jQuery.event.special.slap = {
2420                 bindType: "click",
2421                 delegateType: "swing",
2422                 handle: function( event ) {
2423                         assert.equal( event.handleObj.origType, "slap", "slapped your mammy, " + event.type );
2424                 }
2425         };
2427         var comeback = function( event ) {
2428                 assert.ok( true, "event " + event.type + " triggered" );
2429         };
2431         jQuery( "<div><button id=\"mammy\">Are We Not Men?</button></div>" )
2432                 .on( "slap", "button", jQuery.noop )
2433                 .on( "swing", "button", comeback )
2434                 .find( "button" )
2435                         .on( "slap", jQuery.noop )
2436                         .on( "click", comeback )
2437                         .trigger( "click" )             // bindType-slap and click
2438                         .off( "slap" )
2439                         .trigger( "click" )             // click
2440                         .off( "click" )
2441                         .trigger( "swing" )             // delegateType-slap and swing
2442                 .end()
2443                 .off( "slap swing", "button" )
2444                 .find( "button" )                       // everything should be gone
2445                         .trigger( "slap" )
2446                         .trigger( "click" )
2447                         .trigger( "swing" )
2448                 .end()
2449                 .remove();
2450         delete jQuery.event.special.slap;
2452         jQuery.event.special.gutfeeling = {
2453                 bindType: "click",
2454                 delegateType: "click",
2455                 handle: function( event ) {
2456                         assert.equal( event.handleObj.origType, "gutfeeling", "got a gutfeeling" );
2458                         // Need to call the handler since .one() uses it to unbind
2459                         return event.handleObj.handler.call( this, event );
2460                 }
2461         };
2463         // Ensure a special event isn't removed by its mapped type
2464         jQuery( "<p>Gut Feeling</p>" )
2465                 .on( "click", jQuery.noop )
2466                 .on( "gutfeeling", jQuery.noop )
2467                 .off( "click" )
2468                 .trigger( "gutfeeling" )
2469                 .remove();
2471         // Ensure special events are removed when only a namespace is provided
2472         jQuery( "<p>Gut Feeling</p>" )
2473                 .on( "gutfeeling.Devo", jQuery.noop )
2474                 .off( ".Devo" )
2475                 .trigger( "gutfeeling" )
2476                 .remove();
2478         // Ensure .one() events are removed after their maiden voyage
2479         jQuery( "<p>Gut Feeling</p>" )
2480                 .one( "gutfeeling", jQuery.noop )
2481                 .trigger( "gutfeeling" )        // This one should
2482                 .trigger( "gutfeeling" )        // This one should not
2483                 .remove();
2485         delete jQuery.event.special.gutfeeling;
2486 } );
2488 QUnit.test( ".on and .off, selective mixed removal (trac-10705)", function( assert ) {
2489         assert.expect( 7 );
2491         var timingx = function( e ) {
2492                 assert.ok( true, "triggered " + e.type );
2493         };
2495         jQuery( "<p>Strange Pursuit</p>" )
2496                 .on( "click", timingx )
2497                 .on( "click.duty", timingx )
2498                 .on( "click.now", timingx )
2499                 .on( "devo", timingx )
2500                 .on( "future", timingx )
2501                 .trigger( "click" )             // 3
2502                 .trigger( "devo" )              // 1
2503                 .off( ".duty devo " )   // trailing space
2504                 .trigger( "future" )    // 1
2505                 .trigger( "click" )             // 2
2506                 .off( "future click" )
2507                 .trigger( "click" );    // 0
2508 } );
2510 QUnit.test( "special interference with Object.prototype", function( assert ) {
2511         assert.expect( 1 );
2513         var triggered = false;
2515         Object.prototype.jqfake = {
2516                 trigger: function() {
2517                         triggered = true;
2518                 }
2519         };
2521         jQuery( "<div></div>" )
2522                 .appendTo( "#qunit-fixture" )
2523                 .trigger( "jqfake" );
2525         delete Object.prototype.jqfake;
2527         assert.ok( !triggered, "Object.prototype.jqfake.trigger not called" );
2528 } );
2530 QUnit.test( ".on( event-map, null-selector, data ) trac-11130", function( assert ) {
2532         assert.expect( 1 );
2534         var $p = jQuery( "<p>Strange Pursuit</p>" ),
2535                 data = "bar",
2536                 map = {
2537                         "foo": function( event ) {
2538                                 assert.equal( event.data, "bar", "event.data correctly relayed with null selector" );
2539                                 $p.remove();
2540                         }
2541                 };
2543         $p.on( map, null, data ).trigger( "foo" );
2544 } );
2546 QUnit.test( "clone() delegated events (trac-11076)", function( assert ) {
2547         assert.expect( 3 );
2549         var counter = { "center": 0, "fold": 0, "centerfold": 0 },
2550                 clicked = function() {
2551                         counter[ jQuery( this ).text().replace( /\s+/, "" ) ]++;
2552                 },
2553                 table =
2554                         jQuery( "<table><tr><td>center</td><td>fold</td></tr></table>" )
2555                         .on( "click", "tr", clicked )
2556                         .on( "click", "td:first-child", clicked )
2557                         .on( "click", "td:last-child", clicked ),
2558                 clone = table.clone( true );
2560         clone.find( "td" ).trigger( "click" );
2561         assert.equal( counter.center, 1, "first child" );
2562         assert.equal( counter.fold, 1, "last child" );
2563         assert.equal( counter.centerfold, 2, "all children" );
2565         table.remove();
2566         clone.remove();
2567 } );
2569 QUnit.test( "checkbox state (trac-3827)", function( assert ) {
2570         assert.expect( 16 );
2572         var markup = jQuery( "<div class='parent'><input type=checkbox><div>" ),
2573                 cb = markup.find( "input" )[ 0 ];
2575         markup.appendTo( "#qunit-fixture" );
2577         jQuery( cb ).on( "click", function() {
2578                 assert.equal( this.checked, false, "just-clicked checkbox is not checked" );
2579         } );
2580         markup.on( "click", function() {
2581                 assert.equal( cb.checked, false, "checkbox is not checked in bubbled event" );
2582         } );
2584         // Native click
2585         cb.checked = true;
2586         assert.equal( cb.checked, true, "native event - checkbox is initially checked" );
2587         cb.click();
2588         assert.equal( cb.checked, false, "native event - checkbox is no longer checked" );
2590         // jQuery click
2591         cb.checked = true;
2592         assert.equal( cb.checked, true, "jQuery event - checkbox is initially checked" );
2593         jQuery( cb ).trigger( "click" );
2594         assert.equal( cb.checked, false, "jQuery event - checkbox is no longer checked" );
2596         // Handlers only; checkbox state remains false
2597         jQuery( cb ).triggerHandler( "click" );
2598         assert.equal( cb.checked, false, "handlers only - checkbox is still unchecked" );
2600         // Trigger parameters are preserved (trac-13353, gh-4139)
2601         cb.checked = true;
2602         assert.equal( cb.checked, true, "jQuery event with data - checkbox is initially checked" );
2603         jQuery( cb ).on( "click", function( e, data ) {
2604                 assert.equal( data, "clicked", "trigger data passed to handler" );
2605         } );
2606         markup.on( "click", function( e, data ) {
2607                 assert.equal( data, "clicked", "trigger data passed to bubbled handler" );
2608         } );
2609         jQuery( cb ).trigger( "click", [ "clicked" ] );
2610         assert.equal( cb.checked, false, "jQuery event with data - checkbox is no longer checked" );
2611 } );
2613 QUnit.test( "event object properties on natively-triggered event", function( assert ) {
2614         assert.expect( 3 );
2616         var link = document.createElement( "a" ),
2617                 $link = jQuery( link ),
2618                 evt = document.createEvent( "MouseEvents" );
2620         // Support: IE <=9 - 11+
2621         // IE requires element to be in the body before it will dispatch
2622         $link.appendTo( "body" ).on( "click", function( e ) {
2624                 // Not trying to assert specific values here, just ensure the property exists
2625                 assert.equal( "detail" in e, true, "has .detail" );
2626                 assert.equal( "cancelable" in e, true, "has .cancelable" );
2627                 assert.equal( "bubbles" in e, true, "has .bubbles" );
2628         } );
2629         evt.initEvent( "click", true, true );
2630         link.dispatchEvent( evt );
2631         $link.off( "click" ).remove();
2632 } );
2634 QUnit.test( "addProp extensions", function( assert ) {
2635         assert.expect( 2 );
2637         var $fixture = jQuery( "<div>" ).appendTo( "#qunit-fixture" );
2639         // Ensure the property doesn't exist
2640         $fixture.on( "click", function( event ) {
2641                 assert.ok( !( "testProperty" in event ), "event.testProperty does not exist" );
2642         } );
2643         fireNative( $fixture[ 0 ], "click" );
2644         $fixture.off( "click" );
2646         jQuery.event.addProp( "testProperty", function() {
2647                 return 42;
2648         } );
2650         // Trigger a native click and ensure the property is set
2651         $fixture.on( "click", function( event ) {
2652                 assert.equal( event.testProperty, 42, "event.testProperty getter was invoked" );
2653         } );
2654         fireNative( $fixture[ 0 ], "click" );
2655         $fixture.off( "click" );
2657         $fixture.remove();
2658 } );
2660 QUnit.test( "drag/drop events copy mouse-related event properties (gh-1925, gh-2009)", function( assert ) {
2661         assert.expect( 4 );
2663         var $fixture = jQuery( "<div id='drag-fixture'></div>" ).appendTo( "body" );
2665         $fixture.on( "dragmove", function( evt ) {
2666                 assert.ok( "pageX" in evt, "checking for pageX property on dragmove" );
2667                 assert.ok( "pageY" in evt, "checking for pageY property on dragmove" );
2668         } );
2669         fireNative( $fixture[ 0 ], "dragmove" );
2671         $fixture.on( "drop", function( evt ) {
2672                 assert.ok( "pageX" in evt, "checking for pageX property on drop" );
2673                 assert.ok( "pageY" in evt, "checking for pageY property on drop" );
2674         } );
2676         fireNative( $fixture[ 0 ], "drop" );
2678         $fixture.off( "dragmove drop" ).remove();
2679 } );
2681 QUnit.test( "focusin using non-element targets", function( assert ) {
2682         assert.expect( 2 );
2684         jQuery( document ).on( "focusin", function( e ) {
2685                 assert.ok( e.type === "focusin", "got a focusin event on a document" );
2686         } ).trigger( "focusin" ).off( "focusin" );
2688         jQuery( window ).on( "focusin", function( e ) {
2689                 assert.ok( e.type === "focusin", "got a focusin event on a window" );
2690         } ).trigger( "focusin" ).off( "focusin" );
2692 } );
2694 testIframe(
2695         "focusin from an iframe",
2696         "event/focusinCrossFrame.html",
2697         function( assert, framejQuery, frameWin, frameDoc ) {
2698                 assert.expect( 1 );
2700                 var done = assert.async(),
2701                         focus = false,
2702                         input = jQuery( frameDoc ).find( "#frame-input" );
2704                 // Create a focusin handler on the parent; shouldn't affect the iframe's fate
2705                 jQuery( "body" ).on( "focusin.iframeTest", function() {
2707                         // Support: IE 9 - 11+
2708                         // IE does propagate the event to the parent document. In this test
2709                         // we mainly care about the inner element so we'll just skip this one
2710                         // assertion in IE.
2711                         if ( !document.documentMode ) {
2712                                 assert.ok( false, "fired a focusin event in the parent document" );
2713                         }
2714                 } );
2716                 input.on( "focusin", function() {
2717                         focus = true;
2718                         assert.ok( true, "fired a focusin event in the iframe" );
2719                 } );
2721                 // Avoid a native event; Chrome can't force focus to another frame
2722                 input[ 0 ].focus();
2724                 // Remove body handler manually since it's outside the fixture
2725                 jQuery( "body" ).off( "focusin.iframeTest" );
2727                 setTimeout( done, 50 );
2728         }
2731 QUnit.test( "focusin on document & window", function( assert ) {
2732         assert.expect( 1 );
2734         var counter = 0,
2735                 input = jQuery( "<input />" );
2737         function increment() {
2738                 counter++;
2739         }
2741         input.appendTo( "#qunit-fixture" );
2743         input[ 0 ].focus();
2745         jQuery( window ).on( "focusout", increment );
2746         jQuery( document ).on( "focusout", increment );
2748         input[ 0 ].blur();
2750         assert.strictEqual( counter, 2,
2751                 "focusout handlers on document/window fired once only" );
2753         jQuery( window ).off( "focusout", increment );
2754         jQuery( document ).off( "focusout", increment );
2755 } );
2757 QUnit.test( "element removed during focusout (gh-4417)", function( assert ) {
2758         assert.expect( 1 );
2760         var button = jQuery( "<button>Click me</button>" );
2762         button.appendTo( "#qunit-fixture" );
2764         button.on( "click", function() {
2765                 button.trigger( "blur" );
2766                 assert.ok( true, "Removing the element didn't crash" );
2767         } );
2769         // Support: Chrome 86+
2770         // In Chrome, if an element having a focusout handler is blurred by
2771         // clicking outside of it, it invokes the handler synchronously. However,
2772         // if the click happens programmatically, the invocation is asynchronous.
2773         // As we have no way to simulate real user input in unit tests, simulate
2774         // this behavior by calling `jQuery.cleanData` & removing the element using
2775         // native APIs.
2776         button[ 0 ].blur = function() {
2777                 jQuery.cleanData( [ this ] );
2778                 this.parentNode.removeChild( this );
2780                 // Redefine `blur` to avoid a hard crash in Karma tests that stop
2781                 // the test runner in case this test fails.
2782                 this.blur = jQuery.noop;
2783         };
2785         button[ 0 ].click();
2786 } );
2788 testIframe(
2789         "jQuery.ready promise",
2790         "event/promiseReady.html",
2791         function( assert, jQuery, window, document, isOk ) {
2792                 assert.expect( 1 );
2793                 assert.ok( isOk, "$.when( $.ready ) works" );
2794         },
2795         jQuery.when ? QUnit.test : QUnit.skip
2798 // need PHP here to make the incepted IFRAME hang
2799 if ( hasPHP ) {
2800         testIframe(
2801                 "jQuery.ready uses interactive",
2802                 "event/interactiveReady.html",
2803         function( assert, jQuery, window, document, isOk ) {
2804                         assert.expect( 1 );
2805                         assert.ok( isOk, "jQuery fires ready when the DOM can truly be interacted with" );
2806                 }
2807         );
2810 testIframe(
2811         "Focusing iframe element",
2812         "event/focusElem.html",
2813         function( assert, jQuery, window, document, isOk ) {
2814                 assert.expect( 1 );
2815                 assert.ok( isOk, "Focused an element in an iframe" );
2816         }
2819 testIframe(
2820         "triggerHandler(onbeforeunload)",
2821         "event/triggerunload.html",
2822         function( assert, jQuery, window, document, isOk ) {
2823                 assert.expect( 1 );
2824                 assert.ok( isOk, "Triggered onbeforeunload without an error" );
2825         }
2828 // need PHP here to make the incepted IFRAME hang
2829 if ( hasPHP ) {
2830         testIframe(
2831                 "jQuery.ready synchronous load with long loading subresources",
2832                 "event/syncReady.html",
2833                 function( assert, jQuery, window, document, isOk ) {
2834                         assert.expect( 1 );
2835                         assert.ok( isOk, "jQuery loaded synchronously fires ready when the DOM can truly be interacted with" );
2836                 }
2837         );
2840 QUnit.test( "change handler should be detached from element", function( assert ) {
2841         assert.expect( 2 );
2843         var $fixture = jQuery( "<input type='text' id='change-ie-leak' />" ).appendTo( "body" ),
2844                 originRemoveEvent = jQuery.removeEvent,
2845                 wrapperRemoveEvent =  function( elem, type, handle ) {
2846                         assert.equal( "change", type, "Event handler for 'change' event should be removed" );
2847                         assert.equal( "change-ie-leak", jQuery( elem ).attr( "id" ), "Event handler for 'change' event should be removed from appropriate element" );
2848                         originRemoveEvent( elem, type, handle );
2849                 };
2851         jQuery.removeEvent = wrapperRemoveEvent;
2853         $fixture.on( "change", function() {} );
2854         $fixture.off( "change" );
2856         $fixture.remove();
2858         jQuery.removeEvent = originRemoveEvent;
2859 } );
2861 QUnit.test( "trigger click on checkbox, fires change event", function( assert ) {
2862         assert.expect( 1 );
2864         var check = jQuery( "#check2" );
2865         var done = assert.async();
2867         check.on( "change", function() {
2869                 // get it?
2870                 check.off( "change" );
2871                 assert.ok( true, "Change event fired as a result of triggered click" );
2872                 done();
2873         } ).trigger( "click" );
2874 } );
2876 QUnit.test( "Namespace preserved when passed an Event (trac-12739)", function( assert ) {
2877         assert.expect( 4 );
2879         var markup = jQuery(
2880                         "<div id='parent'><div id='child'></div></div>"
2881                 ),
2882                 triggered = 0,
2883                 fooEvent;
2885         markup.find( "div" )
2886                 .addBack()
2887                 .on( "foo.bar", function( e ) {
2888                         if ( !e.handled ) {
2889                                 triggered++;
2890                                 e.handled = true;
2891                                 assert.equal( e.namespace, "bar", "namespace is bar" );
2892                                 jQuery( e.target ).find( "div" ).each( function() {
2893                                         jQuery( this ).triggerHandler( e );
2894                                 } );
2895                         }
2896                 } )
2897                 .on( "foo.bar2", function() {
2898                         assert.ok( false, "foo.bar2 called on trigger " + triggered + " id " + this.id );
2899                 } );
2901         markup.trigger( "foo.bar" );
2902         markup.trigger( jQuery.Event( "foo.bar" ) );
2903         fooEvent = jQuery.Event( "foo" );
2904         fooEvent.namespace = "bar";
2905         markup.trigger( fooEvent );
2906         markup.remove();
2908         assert.equal( triggered, 3, "foo.bar triggered" );
2909 } );
2911 QUnit.test( "make sure events cloned correctly", function( assert ) {
2912         assert.expect( 18 );
2914         var clone,
2915                 fixture = jQuery( "#qunit-fixture" ),
2916                 checkbox = jQuery( "#check1" ),
2917                 p = jQuery( "#firstp" );
2919         fixture.on( "click change", function( event, result ) {
2920                 assert.ok( result,  event.type + " on original element is fired" );
2922         } ).on( "click", "#firstp", function( event, result ) {
2923                 assert.ok( result, "Click on original child element though delegation is fired" );
2925         } ).on( "change", "#check1", function( event, result ) {
2926                 assert.ok( result, "Change on original child element though delegation is fired" );
2927         } );
2929         p.on( "click", function() {
2930                 assert.ok( true, "Click on original child element is fired" );
2931         } );
2933         checkbox.on( "change", function() {
2934                 assert.ok( true, "Change on original child element is fired" );
2935         } );
2937         fixture.clone().trigger( "click" ).trigger( "change" ); // 0 events should be fired
2939         clone = fixture.clone( true );
2941         clone.find( "p" ).eq( 0 ).trigger( "click", true ); // 3 events should fire
2942         clone.find( "#check1" ).trigger( "change", true ); // 3 events should fire
2943         clone.remove();
2945         clone = fixture.clone( true, true );
2946         clone.find( "p" ).eq( 0 ).trigger( "click", true ); // 3 events should fire
2947         clone.find( "#check1" ).trigger( "change", true ); // 3 events should fire
2949         fixture.off();
2950         p.off();
2951         checkbox.off();
2953         p.trigger( "click" ); // 0 should be fired
2954         checkbox.trigger( "change" ); // 0 should be fired
2956         clone.find( "p" ).eq( 0 ).trigger( "click", true );  // 3 events should fire
2957         clone.find( "#check1" ).trigger( "change", true ); // 3 events should fire
2958         clone.remove();
2960         clone.find( "p" ).eq( 0 ).trigger( "click" );  // 0 should be fired
2961         clone.find( "#check1" ).trigger( "change" ); // 0 events should fire
2962 } );
2964 QUnit.test( "String.prototype.namespace does not cause trigger() to throw (trac-13360)", function( assert ) {
2965         assert.expect( 1 );
2966         var errored = false;
2968         String.prototype.namespace = function() {};
2970         try {
2971                 jQuery( "<p>" ).trigger( "foo.bar" );
2972         } catch ( e ) {
2973                 errored = true;
2974         }
2975         assert.equal( errored, false, "trigger() did not throw exception" );
2976         delete String.prototype.namespace;
2977 } );
2979 QUnit.test( "Inline event result is returned (trac-13993)", function( assert ) {
2980         assert.expect( 1 );
2982         var result = jQuery( "<p onclick='return 42'>hello</p>" ).triggerHandler( "click" );
2984         assert.equal( result, 42, "inline handler returned value" );
2985 } );
2987 QUnit.test( ".off() removes the expando when there's no more data", function( assert ) {
2988         assert.expect( 2 );
2990         var key,
2991                 div = jQuery( "<div></div>" ).appendTo( "#qunit-fixture" );
2993         div.on( "click", false );
2994         div.on( "custom", function() {
2995                 assert.ok( true, "Custom event triggered" );
2996         } );
2997         div.trigger( "custom" );
2998         div.off( "click custom" );
3000         // Make sure the expando is gone
3001         for ( key in div[ 0 ] ) {
3002                 if ( /^jQuery/.test( key ) ) {
3003                         assert.strictEqual(
3004                                 div[ 0 ][ key ], undefined,
3005                                 "Expando was not removed when there was no more data"
3006                         );
3007                 }
3008         }
3009 } );
3011 QUnit.test( "jQuery.Event( src ) does not require a target property", function( assert ) {
3012         assert.expect( 2 );
3014         var event = jQuery.Event( { type: "offtarget" } );
3016         assert.equal( event.type, "offtarget", "correct type" );
3017         assert.equal( event.target, undefined, "no target" );
3018 } );
3020 QUnit.test( "preventDefault() on focusin does not throw exception", function( assert ) {
3021         assert.expect( 1 );
3023         var done = assert.async(),
3024                 input = jQuery( "<input/>" ).appendTo( "#form" );
3026         input.on( "focusin", function( event ) {
3027                 if ( !done ) {
3028                         return;
3029                 }
3031                 var exceptionCaught;
3032                 try {
3033                         event.preventDefault();
3034                 } catch ( theException ) {
3035                         exceptionCaught = theException;
3036                 }
3038                 assert.strictEqual( exceptionCaught, undefined,
3039                         "Preventing default on focusin throws no exception" );
3041                 done();
3042         } );
3043         input.trigger( "focus" );
3044 } );
3046 QUnit.test( ".on('focus', fn) on a text node doesn't throw", function( assert ) {
3047         assert.expect( 1 );
3049         jQuery( document.createTextNode( "text" ) )
3050                 .on( "focus", function() {} );
3052         assert.ok( true, "No crash" );
3053 } );
3055 QUnit.test( "Donor event interference", function( assert ) {
3056         assert.expect( 8 );
3058         var outer = jQuery(
3059                         "<div id='donor-outer'>" +
3060                                 "<form id='donor-form'>" +
3061                                         "<input id='donor-input' type='checkbox' />" +
3062                                 "</form>" +
3063                         "</div>"
3064                 ).appendTo( "#qunit-fixture" ),
3065                 input = jQuery( "#donor-input" );
3067         input.on( "click", function( event ) {
3068                 assert.equal( event.type, "click", "click event at input" );
3069                 assert.ok( !event.isPropagationStopped(), "click event at input is still propagating" );
3070                 assert.equal( typeof event.originalEvent, "object",
3071                         "click event at input has originalEvent property" );
3072         } );
3073         outer.on( "click", function( event ) {
3074                 assert.equal( event.type, "click", "click event at ancestor" );
3075                 assert.ok( !event.isPropagationStopped(), "click event at ancestor is still propagating" );
3076                 assert.equal( typeof event.originalEvent, "object",
3077                         "click event at ancestor has originalEvent property" );
3078         } );
3079         input.on( "change", function( event ) {
3080                 assert.equal( event.type, "change", "change event at input" );
3081                 assert.equal( typeof event.originalEvent, "object",
3082                         "change event at input has originalEvent property" );
3083                 event.stopPropagation();
3084         } );
3085         input[ 0 ].click();
3086 } );
3088 QUnit.test(
3089         "simulated events shouldn't forward stopPropagation/preventDefault methods",
3090         function( assert ) {
3091                 assert.expect( 3 );
3093                 var outer = jQuery(
3094                                 "<div id='donor-outer'>" +
3095                                         "<form id='donor-form'>" +
3096                                                 "<input id='donor-input' type='checkbox' />" +
3097                                         "</form>" +
3098                                 "</div>"
3099                         ).appendTo( "#qunit-fixture" ),
3100                         input = jQuery( "#donor-input" ),
3101                         spy = {};
3103                 jQuery( "#donor-form" )
3104                         .on( "simulated", function( event ) {
3105                                 spy.prevent = sinon.stub( event.originalEvent, "preventDefault" );
3106                                 event.preventDefault();
3107                         } )
3108                         .on( "simulated", function( event ) {
3109                                 spy.stop = sinon.stub( event.originalEvent, "stopPropagation" );
3110                                 event.stopPropagation();
3111                         } )
3112                         .on( "simulated", function( event ) {
3113                                 spy.immediate = sinon.stub( event.originalEvent, "stopImmediatePropagation" );
3114                                 event.stopImmediatePropagation();
3115                         } )
3116                         .on( "simulated", function( event ) {
3117                                 assert.ok( false, "simulated event immediate propagation stopped" );
3118                         } );
3119                 outer
3120                         .on( "simulated", function( event ) {
3121                                 assert.ok( false, "simulated event propagation stopped" );
3122                         } );
3124                 // Force a simulated event
3125                 input[ 0 ].addEventListener( "click", function( nativeEvent ) {
3126                         jQuery.event.simulate( "simulated", this, jQuery.event.fix( nativeEvent ) );
3127                 } );
3128                 input[ 0 ].click();
3130                 assert.strictEqual( spy.prevent.called, false, "Native preventDefault not called" );
3131                 assert.strictEqual( spy.stop.called, false, "Native stopPropagation not called" );
3132                 assert.strictEqual( spy.immediate.called, false,
3133                         "Native stopImmediatePropagation not called" );
3134         }
3137 QUnit.test( "originalEvent type of simulated event", function( assert ) {
3138         assert.expect( 2 );
3140         var outer = jQuery(
3141                         "<div id='donor-outer'>" +
3142                                 "<form id='donor-form'>" +
3143                                         "<input id='donor-input' type='text' />" +
3144                                 "</form>" +
3145                         "</div>"
3146                 ).appendTo( "#qunit-fixture" ),
3147                 input = jQuery( "#donor-input" ),
3148                 done = assert.async(),
3149                 finish = function() {
3151                         // Remove jQuery handlers to ensure removal of capturing handlers on the document
3152                         outer.off( "focusin" );
3154                         done();
3155                 };
3157         outer.on( "focusin", function( event ) {
3158                 assert.equal( event.type, "focusin", "focusin event at ancestor" );
3159                 assert.equal( event.originalEvent.type, "click",
3160                         "focus event at ancestor has correct originalEvent type" );
3161                 setTimeout( finish );
3162         } );
3164         input[ 0 ].addEventListener( "click", function( nativeEvent ) {
3165                 jQuery.event.simulate( "focusin", this, jQuery.event.fix( nativeEvent ) );
3166         } );
3167         input[ 0 ].click();
3168 } );
3170 QUnit.test( "trigger('click') on radio passes extra params", function( assert ) {
3171         assert.expect( 1 );
3172         var $radio = jQuery( "<input type='radio' />" ).appendTo( "#qunit-fixture" )
3173                 .on( "click", function( e, data ) {
3174                         assert.ok( data, "Trigger data is passed to radio click handler" );
3175                 } );
3177         $radio.trigger( "click", [ true ] );
3178 } );
3180 QUnit.test( "focusout/focusin support", function( assert ) {
3181         assert.expect( 6 );
3183         var focus,
3184                 parent = jQuery( "<div>" ),
3185                 input = jQuery( "<input>" ),
3186                 inputExternal = jQuery( "<input>" );
3188         parent.append( input );
3189         jQuery( "#qunit-fixture" ).append( parent ).append( inputExternal );
3191         // initially, lose focus
3192         inputExternal[ 0 ].focus();
3194         parent
3195                 .on( "focus", function() {
3196                         assert.ok( false, "parent: focus not fired" );
3197                 } )
3198                 .on( "focusin", function() {
3199                         assert.ok( true, "parent: focusin fired" );
3200                 } )
3201                 .on( "blur", function() {
3202                         assert.ok( false, "parent: blur not fired" );
3203                 } )
3204                 .on( "focusout", function() {
3205                         assert.ok( true, "parent: focusout fired" );
3206                 } );
3208         input
3209                 .on( "focus", function() {
3210                         assert.ok( true, "element: focus fired" );
3211                 } )
3212                 .on( "focusin", function() {
3213                         assert.ok( true, "element: focusin fired" );
3214                         focus = true;
3215                 } )
3216                 .on( "blur", function() {
3217                         assert.ok( true, "parent: blur fired" );
3218                 } )
3219                 .on( "focusout", function() {
3220                         assert.ok( true, "element: focusout fired" );
3221                 } );
3223         // gain focus
3224         input[ 0 ].focus();
3226         // then lose it
3227         inputExternal[ 0 ].focus();
3229         // cleanup
3230         parent.off();
3231         input.off();
3232 } );
3234 QUnit.test( "focus-blur order (trac-12868)", function( assert ) {
3235         assert.expect( 5 );
3237         var order,
3238                 $text = jQuery( "#text1" ),
3239                 $radio = jQuery( "#radio1" );
3241         $radio[ 0 ].focus();
3243         $text
3244                 .on( "focus", function() {
3245                         assert.equal( order++, 1, "text focus" );
3246                 } )
3247                 .on( "blur", function() {
3248                         assert.equal( order++, 0, "text blur" );
3249                 } );
3250         $radio
3251                 .on( "focus", function() {
3252                         assert.equal( order++, 1, "radio focus" );
3253                 } )
3254                 .on( "blur", function() {
3255                         assert.equal( order++, 0, "radio blur" );
3256                 } );
3258         // Enabled input getting focus
3259         order = 0;
3260         assert.equal( document.activeElement, $radio[ 0 ], "radio has focus" );
3261         $text.trigger( "focus" );
3263         assert.equal( document.activeElement, $text[ 0 ], "text has focus" );
3265         // Run handlers without native method on an input
3266         order = 1;
3267         $radio.triggerHandler( "focus" );
3269         // Clean up
3270         $text.off();
3271         $radio.off();
3272 } );
3274 QUnit.test( "Event handling works with multiple async focus events (gh-4350)", function( assert ) {
3275         assert.expect( 3 );
3277         var remaining = 3,
3278                 input = jQuery( "#name" ),
3279                 done = assert.async();
3281         input
3282                 .on( "focus", function() {
3283                         remaining--;
3284                         assert.ok( true, "received focus event, expecting " + remaining + " more" );
3285                         if ( remaining > 0 ) {
3286                                 input.trigger( "blur" );
3287                         } else {
3289                                 if ( QUnit.isIE ) {
3291                                         // Support: <=IE 11+
3292                                         // In IE, one of the blurs sometimes triggers a focus on body
3293                                         // which in turn restores focus to the input, leading to 4 assertions
3294                                         // firing instead of three. This only happens if other tests are
3295                                         // running on the same test page. Avoid this issue in tests by removing
3296                                         // the handler early.
3297                                         input.off( "focus" );
3298                                 }
3299                                 done();
3300                         }
3301                 } )
3302                 .on( "blur", function() {
3303                         setTimeout( function() {
3304                                 input.trigger( "focus" );
3305                         } );
3306                 } );
3308         // gain focus
3309         input.trigger( "focus" );
3310 } );
3312 // Support: IE <=9 - 11+
3313 // focus and blur events are asynchronous.
3314 // The browser window must be topmost for this to work properly!!
3315 QUnit.test( "async focus queues properly (gh-4859)", function( assert ) {
3316         assert.expect( 1 );
3318         var $text = jQuery( "#text1" ),
3319                 $radio = jQuery( "#radio1" ),
3320                 done = assert.async();
3322         $text.trigger( "focus" );
3323         $radio.trigger( "focus" );
3324         $text.trigger( "focus" );
3326         setTimeout( function() {
3327                 assert.equal( document.activeElement, $text[ 0 ], "focus follows the last trigger" );
3328                 done();
3329         }, 500 );
3330 } );
3332 // Support: IE <=9 - 11+
3333 // focus and blur events are asynchronous.
3334 // The browser window must be topmost for this to work properly!!
3335 QUnit.test( "async focus queues properly with blur (gh-4856)", function( assert ) {
3336         assert.expect( 1 );
3338         var $text = jQuery( "#text1" ),
3339                 done = assert.async();
3341         $text.trigger( "focus" );
3342         $text.trigger( "blur" );
3343         $text.trigger( "focus" );
3345         setTimeout( function() {
3346                 assert.equal( document.activeElement, $text[ 0 ], "focus-after-blur is respected" );
3347                 done();
3348         }, 500 );
3349 } );
3351 QUnit.test( "native-backed events preserve trigger data (gh-1741, gh-4139)", function( assert ) {
3352         assert.expect( 17 );
3354         var parent = supportjQuery(
3355                         "<div class='parent'><input type='checkbox'><input type='radio'></div>"
3356                 ).appendTo( "#qunit-fixture" ),
3357                 targets = jQuery( parent[ 0 ].childNodes ),
3358                 checkbox = jQuery( targets[ 0 ] ),
3359                 data = [ "arg1", "arg2" ],
3360                 slice = data.slice;
3362         // click (gh-4139)
3363         assert.strictEqual( targets[ 0 ].checked, false, "checkbox unchecked before click" );
3364         assert.strictEqual( targets[ 1 ].checked, false, "radio unchecked before click" );
3365         targets.add( parent ).on( "click", function( event ) {
3366                 var type = event.target.type,
3367                         level = event.currentTarget === parent[ 0 ] ? "parent" : "";
3368                 assert.strictEqual( event.target.checked, true,
3369                         type + " toggled before invoking " + level + " handler" );
3370                 assert.deepEqual( slice.call( arguments, 1 ), data,
3371                         type + " " + level + " handler received correct data" );
3372         } );
3373         targets.trigger( "click", data );
3374         assert.strictEqual( targets[ 0 ].checked, true,
3375                 "checkbox toggled after click (default action)" );
3376         assert.strictEqual( targets[ 1 ].checked, true,
3377                 "radio toggled after event (default action)" );
3379         // focus (gh-1741)
3380         assert.notEqual( document.activeElement, checkbox[ 0 ],
3381                 "element not focused before focus event" );
3382         checkbox.on( "focus blur", function( event ) {
3383                 var type = event.type;
3384                 assert.deepEqual( slice.call( arguments, 1 ), data,
3385                         type + " handler received correct data" );
3387                 if ( QUnit.isIE && type === "focus" ) {
3389                         // Support: <=IE 11+
3390                         // In IE, one of the blurs sometimes triggers a focus on body
3391                         // which in turn restores focus to the input, leading to 4 assertions
3392                         // firing instead of three. This only happens if other tests are
3393                         // running on the same test page. Avoid this issue in tests by removing
3394                         // the handler early.
3395                         checkbox.off( "focus" );
3396                 }
3397         } );
3398         checkbox.trigger( "focus", data );
3400         assert.strictEqual( document.activeElement, checkbox[ 0 ],
3401                 "element focused after focus event (default action)" );
3402         checkbox.trigger( "blur", data );
3404         assert.notEqual( document.activeElement, checkbox[ 0 ],
3405                 "element not focused after blur event (default action)" );
3406 } );
3408 QUnit.test( "focus change during a focus handler (gh-4382)", function( assert ) {
3409         assert.expect( 2 );
3411         var done = assert.async(),
3412                 select = jQuery( "<select><option selected='selected'>A</option></select>" ),
3413                 button = jQuery( "<button>Focus target</button>" );
3415         jQuery( "#qunit-fixture" )
3416                 .append( select )
3417                 .append( button );
3419         select.on( "focus", function() {
3420                 button.trigger( "focus" );
3421         } );
3423         jQuery( document ).on( "focusin.focusTests", function( ev ) {
3425                 // Support: IE 11+
3426                 // In IE focus is async so focusin on document is fired multiple times,
3427                 // for each of the elements. In other browsers it's fired just once, for
3428                 // the last one.
3429                 if ( ev.target === button[ 0 ] ) {
3430                         assert.ok( true, "focusin propagated to document from the button" );
3431                 }
3432         } );
3434         select.trigger( "focus" );
3436         setTimeout( function() {
3437                 assert.strictEqual( document.activeElement, button[ 0 ], "Focus redirect worked" );
3438                 jQuery( document ).off( ".focusTests" );
3439                 done();
3440         } );
3441 } );
3443 QUnit.test( "trigger(focus) works after .on(focus).off(focus) (gh-4867)", function( assert ) {
3444         assert.expect( 1 );
3446         var input = jQuery( "<input />" );
3448         input.appendTo( "#qunit-fixture" );
3450         input
3451                 .on( "focus", function() {} )
3452                 .off( "focus" );
3454         input.trigger( "focus" );
3456         assert.equal( document.activeElement, input[ 0 ], "input has focus" );
3457 } );
3459 QUnit.test( "trigger(focus) works after focusing when hidden (gh-4950)", function( assert ) {
3460         assert.expect( 1 );
3462         var input = jQuery( "<input />" );
3464         input.appendTo( "#qunit-fixture" );
3466         input
3467                 .css( "display", "none" )
3468                 .trigger( "focus" )
3469                 .css( "display", "" )
3470                 .trigger( "focus" );
3472         assert.equal( document.activeElement, input[ 0 ], "input has focus" );
3473 } );
3475 QUnit.test( "trigger(focus) fires native & jQuery handlers (gh-5015)", function( assert ) {
3476         assert.expect( 3 );
3478         var input = jQuery( "<input />" ),
3480                 // Support: IE 9 - 11+
3481                 // focus is async in IE; we now emulate it via sync focusin in jQuery
3482                 // but this test also attaches native handlers.
3483                 done = assert.async( 3 );
3485         input.appendTo( "#qunit-fixture" );
3487         input[ 0 ].addEventListener( "focus", function() {
3488                 assert.ok( true, "1st native handler fired" );
3489                 done();
3490         } );
3492         input.on( "focus", function() {
3493                 assert.ok( true, "jQuery handler fired" );
3494                 done();
3495         } );
3497         input[ 0 ].addEventListener( "focus", function() {
3498                 assert.ok( true, "2nd native handler fired" );
3499                 done();
3500         } );
3502         input.trigger( "focus" );
3503 } );
3505 // TODO replace with an adaptation of
3506 // https://github.com/jquery/jquery/pull/1367/files#diff-a215316abbaabdf71857809e8673ea28R2464
3507 ( function() {
3508         supportjQuery.each(
3509                 {
3510                         checkbox: "<input type='checkbox'>",
3511                         radio: "<input type='radio'>"
3512                 },
3513                 function( type, html ) {
3514                         makeTestForGh3751( type, html );
3515                         makeTestForGh5015( type, html );
3516                 }
3517         );
3519         function makeTestForGh3751( type, html ) {
3520                 var testName = "native-backed namespaced clicks are handled correctly (gh-3751) - " + type;
3521                 QUnit.test( testName, function( assert ) {
3522                         assert.expect( 2 );
3524                         var parent = supportjQuery( "<div class='parent'>" + html + "</div>" ),
3525                                 target = jQuery( parent[ 0 ].firstChild );
3527                         parent.appendTo( "#qunit-fixture" );
3529                         target.add( parent )
3530                                 .on( "click.notFired", function( event ) {
3531                                         assert.ok( false, "namespaced event should not be received" +
3532                                                 " by wrong-namespace listener at " + event.currentTarget.nodeName );
3533                                 } )
3534                                 .on( "click.fired", function( event ) {
3535                                         assert.equal( event.target.checked, true,
3536                                                 "toggled before invoking handler at " + event.currentTarget.nodeName );
3537                                 } )
3538                                 .on( "click", function( event ) {
3539                                         assert.ok( false, "namespaced event should not be received" +
3540                                                 " by non-namespaced listener at " + event.currentTarget.nodeName );
3541                                 } );
3543                         target.trigger( "click.fired" );
3544                 } );
3545         }
3547         function makeTestForGh5015( type, html ) {
3548                 var testName = "trigger(click) fires native & jQuery handlers (gh-5015) - " + type;
3549                 QUnit.test( testName, function( assert ) {
3550                         assert.expect( 3 );
3552                         var parent = supportjQuery( "<div class='parent'>" + html + "</div>" ),
3553                                 input = jQuery( parent[ 0 ].firstChild );
3555                         parent.appendTo( "#qunit-fixture" );
3557                         input[ 0 ].addEventListener( "click", function() {
3558                                 assert.ok( true, "1st native handler fired" );
3559                         } );
3561                         input.on( "click", function() {
3562                                 assert.ok( true, "jQuery handler fired" );
3563                         } );
3565                         input[ 0 ].addEventListener( "click", function() {
3566                                 assert.ok( true, "2nd native handler fired" );
3567                         } );
3569                         input.trigger( "click" );
3570                 } );
3571         }
3572 } )();