CSS: Avoid unit-conversion interference from CSS upper bounds
[jquery.git] / test / unit / effects.js
blobec1669f54e915c9858a96949f4d7114e36dc4742
1 ( function() {
3 // Can't test what ain't there
4 if ( !jQuery.fx ) {
5         return;
8 var oldRaf = window.requestAnimationFrame,
9         hideOptions = {
10                 inline: function() { jQuery.style( this, "display", "none" ); },
11                 cascade: function() { this.className = "hidden"; }
12         };
14 QUnit.module( "effects", {
15         setup: function() {
16                 window.requestAnimationFrame = null;
17                 this.sandbox = sinon.sandbox.create();
18                 this.clock = this.sandbox.useFakeTimers( 505877050 );
19                 this._oldInterval = jQuery.fx.interval;
20                 jQuery.fx.step = {};
21                 jQuery.fx.interval = 10;
22                 jQuery.now = Date.now;
23         },
24         teardown: function() {
25                 this.sandbox.restore();
26                 jQuery.now = Date.now;
27                 jQuery.fx.stop();
28                 jQuery.fx.interval = this._oldInterval;
29                 window.requestAnimationFrame = oldRaf;
30                 return moduleTeardown.apply( this, arguments );
31         }
32 } );
34 QUnit[ jQuery.find.compile ? "test" : "skip" ]( "sanity check", function( assert ) {
35         assert.expect( 1 );
36         assert.equal( jQuery( "#dl:visible, #qunit-fixture:visible, #foo:visible" ).length, 3, "QUnit state is correct for testing effects" );
37 } );
39 QUnit.test( "show() basic", function( assert ) {
40         assert.expect( 1 );
42         var div = jQuery( "<div>" ).hide().appendTo( "#qunit-fixture" ).show();
44         assert.equal( div.css( "display" ), "block", "Make sure pre-hidden divs show" );
46         // Clean up the detached node
47         div.remove();
48 } );
50 QUnit.test( "show()", function( assert ) {
51         assert.expect( 27 );
53         var div, speeds, test,
54                 hiddendiv = jQuery( "div.hidden" );
56         assert.equal( jQuery.css( hiddendiv[ 0 ], "display" ), "none", "hiddendiv is display: none" );
58         hiddendiv.css( "display", "block" );
59         assert.equal( jQuery.css( hiddendiv[ 0 ], "display" ), "block", "hiddendiv is display: block" );
61         hiddendiv.show();
62         assert.equal( jQuery.css( hiddendiv[ 0 ], "display" ), "block", "hiddendiv is display: block" );
64         hiddendiv.css( "display", "" );
66         div = jQuery( "#fx-queue div" ).slice( 0, 4 );
67         div.show().each( function() {
68                 assert.notEqual( this.style.display, "none", "don't change any <div> with display block" );
69         } );
71         speeds = {
72                 "null speed": null,
73                 "undefined speed": undefined,
74                 "false speed": false
75         };
77         jQuery.each( speeds, function( name, speed ) {
78                 var pass = true;
79                 div.hide().show( speed ).each( function() {
80                         if ( this.style.display === "none" ) {
81                                 pass = false;
82                         }
83                 } );
84                 assert.ok( pass, "Show with " + name );
85         } );
87         jQuery.each( speeds, function( name, speed ) {
88                 var pass = true;
89                 div.hide().show( speed, function() {
90                         pass = false;
91                 } );
92                 assert.ok( pass, "Show with " + name + " does not call animate callback" );
93         } );
95         // Tolerate data from show()/hide()
96         assert.expectJqData( this, div, "olddisplay" );
98         jQuery(
99                 "<div id='show-tests'>" +
100                 "<div><p><a href='#'></a></p><code></code><pre></pre><span></span></div>" +
101                 "<table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody></table>" +
102                 "<ul><li></li></ul></div>"
103         ).appendTo( "#qunit-fixture" ).find( "*" ).css( "display", "none" );
105         test = {
106                 "div": "block",
107                 "p": "block",
108                 "a": "inline",
109                 "code": "inline",
110                 "pre": "block",
111                 "span": "inline",
112                 "table": "table",
113                 "thead": "table-header-group",
114                 "tbody": "table-row-group",
115                 "tr": "table-row",
116                 "th": "table-cell",
117                 "td": "table-cell",
118                 "ul": "block",
119                 "li": "list-item"
120         };
122         jQuery.each( test, function( selector, expected ) {
123                 var elem = jQuery( selector, "#show-tests" ).show();
124                 assert.equal( elem.css( "display" ), expected, "Show using correct display type for " + selector );
125         } );
127         jQuery( "#show-tests" ).remove();
129         // Make sure that showing or hiding a text node doesn't cause an error
130         jQuery( "<div>test</div> text <span>test</span>" ).show().remove();
131         jQuery( "<div>test</div> text <span>test</span>" ).hide().remove();
132 } );
134 supportjQuery.each( hideOptions, function( type, setup ) {
135         QUnit.test( "show(Number) - " + type + " hidden", function( assert ) {
136                 assert.expect( 30 );
138                 jQuery(
139                         "<div id='show-tests'>" +
140                         "<div><p><a href='#'></a></p><code></code><pre></pre><span></span></div>" +
141                         "<table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody>" +
142                                 "</table>" +
143                         "<ul><li></li></ul></div>"
144                 ).appendTo( "#qunit-fixture" ).find( "*" ).each( setup );
146                 // Note: inline elements are expected to be inline-block
147                 // because we're showing width/height
148                 // Can't animate width/height inline
149                 // See #14344
150                 var test = {
151                         "div": "block",
152                         "p": "block",
153                         "a": "inline",
154                         "code": "inline",
155                         "pre": "block",
156                         "span": "inline",
157                         "table": "table",
158                         "thead": "table-header-group",
159                         "tbody": "table-row-group",
160                         "tr": "table-row",
161                         "th": "table-cell",
162                         "td": "table-cell",
163                         "ul": "block",
164                         "li": "list-item"
165                 };
167                 jQuery.each( test, function( selector ) {
168                         jQuery( selector, "#show-tests" ).show( 100 );
169                 } );
170                 this.clock.tick( 50 );
171                 jQuery.each( test, function( selector, expected ) {
172                         jQuery( selector, "#show-tests" ).each( function() {
173                                 assert.equal(
174                                         jQuery( this ).css( "display" ),
175                                         expected === "inline" ? "inline-block" : expected,
176                                         "Correct display type during animation for " + selector
177                                 );
178                         } );
179                 } );
180                 this.clock.tick( 50 );
181                 jQuery.each( test, function( selector, expected ) {
182                         jQuery( selector, "#show-tests" ).each( function() {
183                                 assert.equal( jQuery( this ).css( "display" ), expected,
184                                         "Correct display type after animation for " + selector );
185                         } );
186                 } );
188                 jQuery( "#show-tests" ).remove();
189         } );
190 } );
192 // Supports #7397
193 supportjQuery.each( hideOptions, function( type, setup ) {
194         QUnit.test( "Persist correct display value - " + type + " hidden", function( assert ) {
195                 assert.expect( 3 );
197                 jQuery( "<div id='show-tests'><span style='position:absolute;'>foo</span></div>" )
198                         .appendTo( "#qunit-fixture" ).find( "*" ).each( setup );
200                 var $span = jQuery( "#show-tests span" ),
201                         displayNone = $span.css( "display" ),
202                         display = "",
203                         clock = this.clock;
205                 $span.show();
207                 display = $span.css( "display" );
209                 $span.hide();
211                 $span.fadeIn( 100, function() {
212                         assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
213                         $span.fadeOut( 100, function() {
214                                 assert.equal( $span.css( "display" ), displayNone, "Expecting display: " + displayNone );
215                                 $span.fadeIn( 100, function() {
216                                         assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
217                                 } );
218                         } );
219                 } );
221                 clock.tick( 300 );
223                 assert.expectJqData( this, $span, "olddisplay" );
224         } );
225 } );
227 QUnit.test( "animate(Hash, Object, Function)", function( assert ) {
228         assert.expect( 1 );
229         var hash = { opacity: "show" },
230                 hashCopy = jQuery.extend( {}, hash );
231         jQuery( "#foo" ).animate( hash, 0, function() {
232                 assert.equal( hash.opacity, hashCopy.opacity, "Check if animate changed the hash parameter" );
233         } );
234 } );
236 QUnit.test( "animate relative values", function( assert ) {
238         var value = 40,
239                 clock = this.clock,
240                 bases = [ "%", "px", "em" ],
241                 adjustments = [ "px", "em" ],
242                 container = jQuery( "<div></div>" )
243                         .css( { position: "absolute", height: "50em", width: "50em" } ),
244                 animations = bases.length * adjustments.length;
246         assert.expect( 2 * animations );
248         jQuery.each( bases, function( _, baseUnit ) {
249                 jQuery.each( adjustments, function( _, adjustUnit ) {
250                         var base = value + baseUnit,
251                                 adjust = { height: "+=2" + adjustUnit, width: "-=2" + adjustUnit },
252                                 elem = jQuery( "<div></div>" )
253                                         .appendTo( container.clone().appendTo( "#qunit-fixture" ) )
254                                         .css( {
255                                                 position: "absolute",
256                                                 height: base,
257                                                 width: value + adjustUnit
258                                         } ),
259                                 baseScale = elem[ 0 ].offsetHeight / value,
260                                 adjustScale = elem[ 0 ].offsetWidth / value;
262                         elem.css( "width", base ).animate( adjust, 100, function() {
263                                 assert.equal( this.offsetHeight, value * baseScale + 2 * adjustScale,
264                                         baseUnit + "+=" + adjustUnit );
265                                 assert.equal( this.offsetWidth, value * baseScale - 2 * adjustScale,
266                                         baseUnit + "-=" + adjustUnit );
268                         } );
270                         clock.tick( 100 );
271                 } );
272         } );
273 } );
275 QUnit.test( "animate negative height", function( assert ) {
276         assert.expect( 1 );
277         jQuery( "#foo" ).animate( { height: -100 }, 100, function() {
278                 assert.equal( this.offsetHeight, 0, "Verify height." );
279         } );
280         this.clock.tick( 100 );
281 } );
283 QUnit.test( "animate negative margin", function( assert ) {
284         assert.expect( 1 );
285         jQuery( "#foo" ).animate( { "marginTop": -100 }, 100, function() {
286                 assert.equal( jQuery( this ).css( "marginTop" ), "-100px", "Verify margin." );
287         } );
288         this.clock.tick( 100 );
289 } );
291 QUnit.test( "animate negative margin with px", function( assert ) {
292         assert.expect( 1 );
293         jQuery( "#foo" ).animate( { marginTop: "-100px" }, 100, function() {
294                 assert.equal( jQuery( this ).css( "marginTop" ), "-100px", "Verify margin." );
295         } );
296         this.clock.tick( 100 );
297 } );
299 QUnit.test( "animate negative padding", function( assert ) {
300         assert.expect( 1 );
301         jQuery( "#foo" ).animate( { "paddingBottom": -100 }, 100, function() {
302                 assert.equal( jQuery( this ).css( "paddingBottom" ), "0px", "Verify paddingBottom." );
303         } );
304         this.clock.tick( 100 );
305 } );
307 QUnit.test( "animate block as inline width/height", function( assert ) {
308         assert.expect( 3 );
310         jQuery( "#foo" ).css( { display: "inline", width: "", height: "" } ).animate( { width: 42, height: 42 }, 100, function() {
311                 assert.equal( jQuery( this ).css( "display" ), "inline-block", "inline-block was set on non-floated inline element when animating width/height" );
312                 assert.equal( this.offsetWidth, 42, "width was animated" );
313                 assert.equal( this.offsetHeight, 42, "height was animated" );
314         } );
315         this.clock.tick( 100 );
316 } );
318 QUnit.test( "animate native inline width/height", function( assert ) {
319         assert.expect( 3 );
321         jQuery( "#foo" ).css( { display: "", width: "", height: "" } )
322                 .append( "<span>text</span>" )
323                 .children( "span" )
324                         .animate( { width: 42, height: 42 }, 100, function() {
325                                 assert.equal( jQuery( this ).css( "display" ), "inline-block", "inline-block was set on non-floated inline element when animating width/height" );
326                                 assert.equal( this.offsetWidth, 42, "width was animated" );
327                                 assert.equal( this.offsetHeight, 42, "height was animated" );
328                         } );
329         this.clock.tick( 100 );
330 } );
332 QUnit.test( "animate block width/height", function( assert ) {
333         assert.expect( 3 );
335         jQuery( "<div>" ).appendTo( "#qunit-fixture" ).css( {
336                 display: "block",
337                 width: 20,
338                 height: 20,
339                 paddingLeft: 60
340         } ).animate( {
341                 width: 42,
342                 height: 42
343         }, {
344                 duration: 100,
345                 step: function() {
346                         if ( jQuery( this ).width() > 42 ) {
347                                 assert.ok( false, "width was incorrectly augmented during animation" );
348                         }
349                 },
350                 complete: function() {
351                         assert.equal( jQuery( this ).css( "display" ), "block", "inline-block was not set on block element when animating width/height" );
352                         assert.equal( jQuery( this ).width(), 42, "width was animated" );
353                         assert.equal( jQuery( this ).height(), 42, "height was animated" );
354                 }
355         } );
356         this.clock.tick( 100 );
357 } );
359 QUnit.test( "animate table width/height", function( assert ) {
360         assert.expect( 1 );
362         jQuery( "#table" ).animate( { width: 42, height: 42 }, 100, function() {
363                 assert.equal( jQuery( this ).css( "display" ), "table", "display mode is correct" );
364         } );
365         this.clock.tick( 100 );
366 } );
368 QUnit.test( "animate table-row width/height", function( assert ) {
369         assert.expect( 3 );
370         var tr = jQuery( "#table" )
371                         .attr( { "cellspacing": 0, "cellpadding": 0, "border": 0 } )
372                         .html( "<tr style='height:42px;'><td style='padding:0;'><div style='width:20px;height:20px;'></div></td></tr>" )
373                         .find( "tr" );
375         tr.animate( { width: 10, height: 10 }, 100, function() {
376                 assert.equal( jQuery( this ).css( "display" ), "table-row", "display mode is correct" );
377                 assert.equal( this.offsetWidth, 20, "width animated to shrink wrap point" );
378                 assert.equal( this.offsetHeight, 20, "height animated to shrink wrap point" );
379         } );
380         this.clock.tick( 100 );
381 } );
383 QUnit.test( "animate table-cell width/height", function( assert ) {
384         assert.expect( 3 );
386         var td = jQuery( "#table" )
387                         .attr( { "cellspacing": 0, "cellpadding": 0, "border": 0 } )
388                         .html( "<tr><td style='width:42px;height:42px;padding:0;'><div style='width:20px;height:20px;'></div></td></tr>" )
389                         .find( "td" );
391         td.animate( { width: 10, height: 10 }, 100, function() {
392                 assert.equal( jQuery( this ).css( "display" ), "table-cell", "display mode is correct" );
393                 assert.equal( this.offsetWidth, 20, "width animated to shrink wrap point" );
394                 assert.equal( this.offsetHeight, 20, "height animated to shrink wrap point" );
395         } );
396         this.clock.tick( 100 );
397 } );
399 QUnit.test( "animate percentage(%) on width/height", function( assert ) {
400         assert.expect( 2 );
402         var $div = jQuery( "<div style='position:absolute;top:-999px;left:-999px;width:60px;height:60px;'><div style='width:50%;height:50%;'></div></div>" )
403                 .appendTo( "#qunit-fixture" ).children( "div" );
405         $div.animate( { width: "25%", height: "25%" }, 13, function() {
406                 var $this = jQuery( this );
407                 assert.equal( $this.css( "width" ), "15px", "Width was animated to 15px rather than 25px" );
408                 assert.equal( $this.css( "height" ), "15px", "Height was animated to 15px rather than 25px" );
409         } );
410         this.clock.tick( 20 );
411 } );
413 QUnit.test( "animate resets overflow-x and overflow-y when finished", function( assert ) {
414         assert.expect( 2 );
415         jQuery( "#foo" )
416                 .css( { display: "block", width: 20, height: 20, overflowX: "visible", overflowY: "auto" } )
417                 .animate( { width: 42, height: 42 }, 100, function() {
418                         assert.equal( this.style.overflowX, "visible", "overflow-x is visible" );
419                         assert.equal( this.style.overflowY, "auto", "overflow-y is auto" );
420                 } );
421         this.clock.tick( 100 );
422 } );
424 /* // This test ends up being flaky depending upon the CPU load
425 QUnit.test("animate option (queue === false)", function( assert ) {
426         assert.expect(1);
427         QUnit.stop();
429         var order = [];
431         var $foo = jQuery("#foo");
432         $foo.animate({width:"100px"}, 3000, function () {
433                 // should finish after unqueued animation so second
434                 order.push(2);
435                 assert.deepEqual( order, [ 1, 2 ], "Animations finished in the correct order" );
436                 QUnit.start();
437         });
438         $foo.animate({fontSize:"2em"}, {queue:false, duration:10, complete:function () {
439                 // short duration and out of queue so should finish first
440                 order.push(1);
441         }});
445 QUnit.test( "animate option { queue: false }", function( assert ) {
446         assert.expect( 2 );
447         var foo = jQuery( "#foo" );
449         foo.animate( {
450                 fontSize: "2em"
451         }, {
452                 queue: false,
453                 duration: 10,
454                 complete: function() {
455                         assert.ok( true, "Animation Completed" );
456                 }
457         } );
458         this.clock.tick( 10 );
460         assert.equal( foo.queue().length, 0, "Queue is empty" );
461 } );
463 QUnit.test( "animate option { queue: true }", function( assert ) {
464         assert.expect( 2 );
465         var foo = jQuery( "#foo" );
467         foo.animate( {
468                 fontSize: "2em"
469         }, {
470                 queue: true,
471                 duration: 10,
472                 complete: function() {
473                         assert.ok( true, "Animation Completed" );
474                 }
475         } );
477         assert.notEqual( foo.queue().length, 0, "Default queue is not empty" );
479         //clear out existing timers before next test
480         this.clock.tick( 10 );
481 } );
483 QUnit.test( "animate option { queue: 'name' }", function( assert ) {
484         assert.expect( 5 );
485         var foo = jQuery( "#foo" ),
486                 origWidth = parseFloat( foo.css( "width" ) ),
487                 order = [];
489         foo.animate( { width: origWidth + 100 }, {
490                 queue: "name",
491                 duration: 1,
492                 complete: function() {
494                         // second callback function
495                         order.push( 2 );
496                         assert.equal( parseFloat( foo.css( "width" ) ), origWidth + 100, "Animation ended" );
497                         assert.equal( foo.queue( "name" ).length, 1, "Queue length of 'name' queue" );
498                 }
499         } ).queue( "name", function() {
501                 // last callback function
502                 assert.deepEqual( order, [ 1, 2 ], "Callbacks in expected order" );
503         } );
505         // this is the first callback function that should be called
506         order.push( 1 );
507         assert.equal( parseFloat( foo.css( "width" ) ), origWidth, "Animation does not start on its own." );
508         assert.equal( foo.queue( "name" ).length, 2, "Queue length of 'name' queue" );
510         foo.dequeue( "name" );
511         this.clock.tick( 10 );
513 } );
515 QUnit.test( "animate with no properties", function( assert ) {
516         assert.expect( 2 );
518         var foo,
519                 divs = jQuery( "div" ),
520                 count = 0;
522         divs.animate( {}, function() {
523                 count++;
524         } );
526         assert.equal( divs.length, count, "Make sure that callback is called for each element in the set." );
528         foo = jQuery( "#foo" );
530         foo.animate( {} );
531         foo.animate( { top: 10 }, 100, function() {
532                 assert.ok( true, "Animation was properly dequeued." );
533         } );
534         this.clock.tick( 100 );
535 } );
537 QUnit.test( "animate duration 0", function( assert ) {
538         assert.expect( 11 );
540         var $elem,
541                 $elems = jQuery( [ { a:0 }, { a:0 } ] ),
542                 counter = 0;
544         assert.equal( jQuery.timers.length, 0, "Make sure no animation was running from another test" );
546         $elems.eq( 0 ).animate( { a:1 }, 0, function() {
547                 assert.ok( true, "Animate a simple property." );
548                 counter++;
549         } );
551         // Failed until [6115]
552         assert.equal( jQuery.timers.length, 0, "Make sure synchronic animations are not left on jQuery.timers" );
554         assert.equal( counter, 1, "One synchronic animations" );
556         $elems.animate( { a:2 }, 0, function() {
557                 assert.ok( true, "Animate a second simple property." );
558                 counter++;
559         } );
561         assert.equal( counter, 3, "Multiple synchronic animations" );
563         $elems.eq( 0 ).animate( { a:3 }, 0, function() {
564                 assert.ok( true, "Animate a third simple property." );
565                 counter++;
566         } );
567         $elems.eq( 1 ).animate( { a:3 }, 200, function() {
568                 counter++;
570                 // Failed until [6115]
571                 assert.equal( counter, 5, "One synchronic and one asynchronic" );
572         } );
573         this.clock.tick( 200 );
575         $elem = jQuery( "<div />" );
576         $elem.show( 0, function() {
577                 assert.ok( true, "Show callback with no duration" );
578         } );
579         $elem.hide( 0, function() {
580                 assert.ok( true, "Hide callback with no duration" );
581         } );
583         // manually clean up detached elements
584         $elem.remove();
585 } );
587 QUnit.test( "animate hyphenated properties", function( assert ) {
588         assert.expect( 1 );
590         jQuery( "#foo" )
591                 .css( "font-size", 10 )
592                 .animate( { "font-size": 20 }, 200, function() {
593                         assert.equal( this.style.fontSize, "20px", "The font-size property was animated." );
594                 } );
596         // FIXME why is this double only when run with other tests
597         this.clock.tick( 400 );
599 } );
601 QUnit.test( "animate non-element", function( assert ) {
602         assert.expect( 1 );
604         var obj = { test: 0 };
606         jQuery( obj ).animate( { test: 200 }, 200, function() {
607                 assert.equal( obj.test, 200, "The custom property should be modified." );
608         } );
609         this.clock.tick( 200 );
610 } );
612 QUnit.test( "stop()", function( assert ) {
613         assert.expect( 4 );
615         var $one, $two,
616                 $foo = jQuery( "#foo" ),
617                 w = 0,
618                 nw;
620         $foo.hide().css( "width", 200 )
621                 .animate( { "width": "show" }, 1500 );
623         this.clock.tick( 100 );
624         nw = $foo.css( "width" );
625         assert.notEqual( parseFloat( nw ), w, "An animation occurred " + nw + " " + w + "px" );
626         $foo.stop();
628         nw = $foo.css( "width" );
629         assert.notEqual( parseFloat( nw ), w, "Stop didn't reset the animation " + nw + " " + w + "px" );
631         this.clock.tick( 100 );
633         $foo.removeData();
634         $foo.removeData( undefined, true );
635         assert.equal( nw, $foo.css( "width" ), "The animation didn't continue" );
637         $one = jQuery( "#fadein" );
638         $two = jQuery( "#show" );
639         $one.fadeTo( 100, 0, function() {
640                 $one.stop();
641         } );
642         this.clock.tick( 100 );
643         $two.fadeTo( 100, 0, function() {
644                 assert.equal( $two.css( "opacity" ), "0", "Stop does not interfere with animations on other elements (#6641)" );
646                 // Reset styles
647                 $one.add( $two ).css( "opacity", "" );
648         } );
649         this.clock.tick( 100 );
650 } );
652 // In IE9 inside testswarm this test doesn't work properly
653 ( function() {
654         var type = "test";
656         if ( QUnit.isSwarm && /msie 9\.0/i.test( window.navigator.userAgent ) ) {
657                 type = "skip";
658         }
660         QUnit[ type ]( "stop() - several in queue", function( assert ) {
661                 assert.expect( 5 );
663                 var nw, $foo = jQuery( "#foo" );
665                 // default duration is 400ms, so 800px ensures we aren't 0 or 1 after 1ms
666                 $foo.hide().css( "width", 800 );
668                 $foo.animate( { "width": "show" }, 400, "linear" );
669                 $foo.animate( { "width": "hide" } );
670                 $foo.animate( { "width": "show" } );
672                 this.clock.tick( 1 );
674                 jQuery.fx.tick();
675                 assert.equal( $foo.queue().length, 3, "3 in the queue" );
677                 nw = $foo.css( "width" );
678                 assert.notEqual( parseFloat( nw ), 1, "An animation occurred " + nw );
679                 $foo.stop();
681                 assert.equal( $foo.queue().length, 2, "2 in the queue" );
682                 nw = $foo.css( "width" );
683                 assert.notEqual( parseFloat( nw ), 1, "Stop didn't reset the animation " + nw );
685                 $foo.stop( true );
687                 assert.equal( $foo.queue().length, 0, "0 in the queue" );
688         } );
689 } )();
691 QUnit.test( "stop(clearQueue)", function( assert ) {
692         assert.expect( 4 );
694         var $foo = jQuery( "#foo" ),
695                 w = 0,
696                 nw;
697         $foo.hide().css( "width", 200 ).css( "width" );
699         $foo.animate( { "width": "show" }, 1000 );
700         $foo.animate( { "width": "hide" }, 1000 );
701         $foo.animate( { "width": "show" }, 1000 );
702         this.clock.tick( 100 );
703         nw = $foo.css( "width" );
704         assert.ok( parseFloat( nw ) !== w, "An animation occurred " + nw + " " + w + "px" );
705         $foo.stop( true );
707         nw = $foo.css( "width" );
708         assert.ok( parseFloat( nw ) !== w, "Stop didn't reset the animation " + nw + " " + w + "px" );
710         assert.equal( $foo.queue().length, 0, "The animation queue was cleared" );
711         this.clock.tick( 100 );
712         assert.equal( nw, $foo.css( "width" ), "The animation didn't continue" );
713 } );
715 QUnit.test( "stop(clearQueue, gotoEnd)", function( assert ) {
716         assert.expect( 1 );
718         var $foo = jQuery( "#foo" ),
719                 w = 0,
720                 nw;
721         $foo.hide().css( "width", 200 ).css( "width" );
723         $foo.animate( { width: "show" }, 1000 );
724         $foo.animate( { width: "hide" }, 1000 );
725         $foo.animate( { width: "show" }, 1000 );
726         $foo.animate( { width: "hide" }, 1000 );
727         this.clock.tick( 100 );
728         nw = $foo.css( "width" );
729         assert.ok( parseFloat( nw ) !== w, "An animation occurred " + nw + " " + w + "px" );
730         $foo.stop( false, true );
732         nw = $foo.css( "width" );
734         // Disabled, being flaky
735         //equal( nw, 1, "Stop() reset the animation" );
737         this.clock.tick( 100 );
739         // Disabled, being flaky
740         //equal( $foo.queue().length, 2, "The next animation continued" );
741         $foo.stop( true );
742 } );
744 QUnit.test( "stop( queue, ..., ... ) - Stop single queues", function( assert ) {
745         assert.expect( 3 );
746         var saved,
747                 foo = jQuery( "#foo" ).css( { width: 200, height: 200 } );
749         foo.animate( {
750                 width: 400
751         }, {
752                 duration: 500,
753                 complete: function() {
754                         assert.equal( parseFloat( foo.css( "width" ) ), 400, "Animation completed for standard queue" );
755                         assert.equal( parseFloat( foo.css( "height" ) ), saved, "Height was not changed after the second stop" );
756                 }
757         } );
759         foo.animate( {
760                 height: 400
761         }, {
762                 duration: 1000,
763                 queue: "height"
764         } ).dequeue( "height" ).stop( "height", false, true );
766         assert.equal( parseFloat( foo.css( "height" ) ), 400, "Height was stopped with gotoEnd" );
768         foo.animate( {
769                 height: 200
770         }, {
771                 duration: 1000,
772                 queue: "height"
773         } ).dequeue( "height" ).stop( "height", false, false );
774         saved = parseFloat( foo.css( "height" ) );
775         this.clock.tick( 500 );
776 } );
778 QUnit[ jQuery.find.compile ? "test" : "skip" ]( "toggle()", function( assert ) {
779         assert.expect( 6 );
780         var x = jQuery( "#foo" );
781         assert.ok( x.is( ":visible" ), "is visible" );
782         x.toggle();
783         assert.ok( x.is( ":hidden" ), "is hidden" );
784         x.toggle();
785         assert.ok( x.is( ":visible" ), "is visible again" );
787         x.toggle( true );
788         assert.ok( x.is( ":visible" ), "is visible" );
789         x.toggle( false );
790         assert.ok( x.is( ":hidden" ), "is hidden" );
791         x.toggle( true );
792         assert.ok( x.is( ":visible" ), "is visible again" );
793 } );
795 QUnit.test( "jQuery.fx.prototype.cur() - <1.8 Back Compat", function( assert ) {
796         assert.expect( 7 );
798         var div = jQuery( "<div></div>" ).appendTo( "#qunit-fixture" ).css( {
799                         color: "#ABC",
800                         border: "5px solid black",
801                         left: "auto",
802                         marginBottom: "-11000px"
803                 } )[ 0 ];
805         assert.equal(
806                 ( new jQuery.fx( div, {}, "color" ) ).cur(),
807                 jQuery.css( div, "color" ),
808                 "Return the same value as jQuery.css for complex properties (bug #7912)"
809         );
811         assert.strictEqual(
812                 ( new jQuery.fx( div, {}, "borderLeftWidth" ) ).cur(),
813                 5,
814                 "Return simple values parsed as Float"
815         );
817         // backgroundPosition actually returns 0% 0% in most browser
818         // this fakes a "" return
819         // hook now gets called twice because Tween will grab the current
820         // value as it is being newed
821         jQuery.cssHooks.backgroundPosition = {
822                 get: function() {
823                         assert.ok( true, "hook used" );
824                         return "";
825                 }
826         };
828         assert.strictEqual(
829                 ( new jQuery.fx( div, {}, "backgroundPosition" ) ).cur(),
830                 0,
831                 "Return 0 when jQuery.css returns an empty string"
832         );
834         delete jQuery.cssHooks.backgroundPosition;
836         assert.strictEqual(
837                 ( new jQuery.fx( div, {}, "left" ) ).cur(),
838                 0,
839                 "Return 0 when jQuery.css returns 'auto'"
840         );
842         assert.equal(
843                 ( new jQuery.fx( div, {}, "marginBottom" ) ).cur(),
844                 -11000,
845                 "support negative values < -10000 (bug #7193)"
846         );
848         jQuery( div ).remove();
849 } );
851 QUnit.test( "Overflow and Display", function( assert ) {
852         assert.expect( 4 );
854         var
855                 testClass = jQuery.makeTest( "Overflow and Display" )
856                         .addClass( "overflow inline" ),
857                 testStyle = jQuery.makeTest( "Overflow and Display (inline style)" )
858                         .css( { overflow: "visible", display: "inline" } ),
859                 done = function() {
860                         assert.equal( jQuery.css( this, "overflow" ), "visible", "Overflow should be 'visible'" );
861                         assert.equal( jQuery.css( this, "display" ), "inline", "Display should be 'inline'" );
862                 };
864         testClass.add( testStyle )
865                 .addClass( "widewidth" )
866                 .text( "Some sample text." )
867                 .before( "text before" )
868                 .after( "text after" )
869                 .animate( { opacity: 0.5 }, "slow", done );
870         this.clock.tick( 600 );
871 } );
873 jQuery.each( {
874         "CSS Auto": function( elem, prop ) {
875                 jQuery( elem ).addClass( "auto" + prop )
876                         .text( "This is a long string of text." );
877                 return "";
878         },
879         "JS Auto": function( elem, prop ) {
880                 jQuery( elem ).css( prop, "" )
881                         .text( "This is a long string of text." );
882                 return "";
883         },
884         "CSS 100": function( elem, prop ) {
885                 jQuery( elem ).addClass( "large" + prop );
886                 return "";
887         },
888         "JS 100": function( elem, prop ) {
889                 jQuery( elem ).css( prop, prop === "opacity" ? 1 : "100px" );
890                 return prop === "opacity" ? 1 : 100;
891         },
892         "CSS 50": function( elem, prop ) {
893                 jQuery( elem ).addClass( "med" + prop );
894                 return "";
895         },
896         "JS 50": function( elem, prop ) {
897                 jQuery( elem ).css( prop, prop === "opacity" ? 0.50 : "50px" );
898                 return prop === "opacity" ? 0.5 : 50;
899         },
900         "CSS 0": function( elem, prop ) {
901                 jQuery( elem ).addClass( "no" + prop );
902                 return "";
903         },
904         "JS 0": function( elem, prop ) {
905                 jQuery( elem ).css( prop, prop === "opacity" ? 0 : "0px" );
906                 return 0;
907         }
908 }, function( fn, f ) {
909         jQuery.each( {
910                 "show": function( elem, prop ) {
911                         jQuery( elem ).hide().addClass( "wide" + prop );
912                         return "show";
913                 },
914                 "hide": function( elem, prop ) {
915                         jQuery( elem ).addClass( "wide" + prop );
916                         return "hide";
917                 },
918                 "100": function( elem, prop ) {
919                         jQuery( elem ).addClass( "wide" + prop );
920                         return prop === "opacity" ? 1 : 100;
921                 },
922                 "50": function( elem, prop ) {
923                         return prop === "opacity" ? 0.50 : 50;
924                 },
925                 "0": function( elem ) {
926                         jQuery( elem ).addClass( "noback" );
927                         return 0;
928                 }
929         }, function( tn, t ) {
930                 QUnit.test( fn + " to " + tn, function( assert ) {
931                         var num, anim,
932                                 elem = jQuery.makeTest( fn + " to " + tn ),
933                                 t_w = t( elem, "width" ),
934                                 f_w = f( elem, "width" ),
935                                 t_h = t( elem, "height" ),
936                                 f_h = f( elem, "height" ),
937                                 t_o = t( elem, "opacity" ),
938                                 f_o = f( elem, "opacity" );
940                         if ( f_o === "" ) {
941                                 f_o = 1;
942                         }
944                         num = 0;
946                         // TODO: uncrowd this
947                         if ( t_h === "show" ) { num++; }
948                         if ( t_w === "show" ) { num++; }
949                         if ( t_w === "hide" || t_w === "show" ) { num++; }
950                         if ( t_h === "hide" || t_h === "show" ) { num++; }
951                         if ( t_o === "hide" || t_o === "show" ) { num++; }
952                         if ( t_w === "hide" ) { num++; }
953                         if ( t_o.constructor === Number ) { num += 2; }
954                         if ( t_w.constructor === Number ) { num += 2; }
955                         if ( t_h.constructor === Number ) { num += 2; }
957                         assert.expect( num );
959                         anim = { width: t_w, height: t_h, opacity: t_o };
961                         elem.animate( anim, 50 );
963                         jQuery.when( elem ).done( function( $elem ) {
964                                 var cur_o, cur_w, cur_h, old_h,
965                                         elem = $elem[ 0 ];
967                                 if ( t_w === "show" ) {
968                                         assert.equal( $elem.css( "display" ), "block",
969                                                 "Showing, display should block: " + elem.style.display );
970                                 }
972                                 if ( t_w === "hide" || t_w === "show" ) {
973                                         assert.ok( f_w === "" ? elem.style.width === f_w : elem.style.width.indexOf( f_w ) === 0, "Width must be reset to " + f_w + ": " + elem.style.width );
974                                 }
976                                 if ( t_h === "hide" || t_h === "show" ) {
977                                         assert.ok( f_h === "" ? elem.style.height === f_h : elem.style.height.indexOf( f_h ) === 0, "Height must be reset to " + f_h + ": " + elem.style.height );
978                                 }
980                                 cur_o = jQuery.style( elem, "opacity" );
982                                 if ( f_o !== jQuery.css( elem, "opacity" ) ) {
983                                         f_o = f( elem, "opacity" );
984                                 }
986                                 if ( t_o === "hide" || t_o === "show" ) {
987                                         assert.equal( cur_o, f_o, "Opacity must be reset to " + f_o + ": " + cur_o );
988                                 }
990                                 if ( t_w === "hide" ) {
991                                         assert.equal( elem.style.display, "none", "Hiding, display should be none: " + elem.style.display );
992                                 }
994                                 if ( t_o.constructor === Number ) {
995                                         assert.equal( cur_o, t_o, "Final opacity should be " + t_o + ": " + cur_o );
997                                         assert.ok( jQuery.css( elem, "opacity" ) !== "" || cur_o === t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o );
998                                 }
1000                                 if ( t_w.constructor === Number ) {
1001                                         assert.equal( elem.style.width, t_w + "px", "Final width should be " + t_w + ": " + elem.style.width );
1003                                         cur_w = jQuery.css( elem, "width" );
1005                                         assert.ok( elem.style.width !== "" || cur_w === t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w );
1006                                 }
1008                                 if ( t_h.constructor === Number ) {
1009                                         assert.equal( elem.style.height, t_h + "px", "Final height should be " + t_h + ": " + elem.style.height );
1011                                         cur_h = jQuery.css( elem, "height" );
1013                                         assert.ok( elem.style.height !== "" || cur_h === t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_h );
1014                                 }
1016                                 if ( t_h === "show" ) {
1017                                         old_h = jQuery.css( elem, "height" );
1018                                         jQuery( elem ).append( "<br/>Some more text<br/>and some more..." );
1020                                         if ( /Auto/.test( fn ) ) {
1021                                                 assert.notEqual( jQuery.css( elem, "height" ), old_h, "Make sure height is auto." );
1022                                         } else {
1023                                                 assert.equal( jQuery.css( elem, "height" ), old_h, "Make sure height is not auto." );
1024                                         }
1025                                 }
1027                                 // manually remove generated element
1028                                 jQuery( elem ).remove();
1030                         } );
1031                         this.clock.tick( 100 );
1032                 } );
1033         } );
1034 } );
1036 QUnit.test( "Effects chaining", function( assert ) {
1037         var remaining = 16,
1038                 props = [ "opacity", "height", "width", "display", "overflow" ],
1039                 setup = function( name, selector ) {
1040                         var $el = jQuery( selector );
1041                         return $el.data( getProps( $el[ 0 ] ) ).data( "name", name );
1042                 },
1043                 check = function() {
1044                         var data = jQuery.data( this ),
1045                                 name = data.name;
1046                         delete data.name;
1048                         assert.deepEqual( getProps( this ), data, name );
1050                         jQuery.removeData( this );
1051                 },
1052                 getProps = function( el ) {
1053                         var obj = {};
1054                         jQuery.each( props, function( i, prop ) {
1055                                 obj[ prop ] = prop === "overflow" && el.style[ prop ] || jQuery.css( el, prop );
1056                         } );
1057                         return obj;
1058                 };
1060         assert.expect( remaining );
1062         setup( ".fadeOut().fadeIn()", "#fadein div" ).fadeOut( "fast" ).fadeIn( "fast", check );
1063         setup( ".fadeIn().fadeOut()", "#fadeout div" ).fadeIn( "fast" ).fadeOut( "fast", check );
1064         setup( ".hide().show()", "#show div" ).hide( "fast" ).show( "fast", check );
1065         setup( ".show().hide()", "#hide div" ).show( "fast" ).hide( "fast", check );
1066         setup( ".show().hide(easing)", "#easehide div" ).show( "fast" ).hide( "fast", "linear", check );
1067         setup( ".toggle().toggle() - in", "#togglein div" ).toggle( "fast" ).toggle( "fast", check );
1068         setup( ".toggle().toggle() - out", "#toggleout div" ).toggle( "fast" ).toggle( "fast", check );
1069         setup( ".toggle().toggle(easing) - out", "#easetoggleout div" ).toggle( "fast" ).toggle( "fast", "linear", check );
1070         setup( ".slideDown().slideUp()", "#slidedown div" ).slideDown( "fast" ).slideUp( "fast", check );
1071         setup( ".slideUp().slideDown()", "#slideup div" ).slideUp( "fast" ).slideDown( "fast", check );
1072         setup( ".slideUp().slideDown(easing)", "#easeslideup div" ).slideUp( "fast" ).slideDown( "fast", "linear", check );
1073         setup( ".slideToggle().slideToggle() - in", "#slidetogglein div" ).slideToggle( "fast" ).slideToggle( "fast", check );
1074         setup( ".slideToggle().slideToggle() - out", "#slidetoggleout div" ).slideToggle( "fast" ).slideToggle( "fast", check );
1075         setup( ".fadeToggle().fadeToggle() - in", "#fadetogglein div" ).fadeToggle( "fast" ).fadeToggle( "fast", check );
1076         setup( ".fadeToggle().fadeToggle() - out", "#fadetoggleout div" ).fadeToggle( "fast" ).fadeToggle( "fast", check );
1077         setup( ".fadeTo(0.5).fadeTo(1.0, easing)", "#fadeto div" ).fadeTo( "fast", 0.5 ).fadeTo( "fast", 1.0, "linear", check );
1079     this.clock.tick( 400 );
1080 } );
1082 jQuery.makeTest = function( text ) {
1083         var elem = jQuery( "<div></div>" )
1084                 .attr( "id", "test" + jQuery.makeTest.id++ )
1085                 .addClass( "box" );
1087         jQuery( "<h4></h4>" )
1088                 .text( text )
1089                 .appendTo( "#fx-tests" )
1090                 .after( elem );
1092         return elem;
1095 jQuery.makeTest.id = 1;
1097 QUnit.test( "jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function( assert ) {
1098         assert.expect( 4 );
1100         var $checkedtest = jQuery( "#checkedtest" );
1101         $checkedtest.hide().show( "fast", function() {
1102                 assert.ok( jQuery( "input[type='radio']", $checkedtest ).first().attr( "checked" ), "Check first radio still checked." );
1103                 assert.ok( !jQuery( "input[type='radio']", $checkedtest ).last().attr( "checked" ), "Check last radio still NOT checked." );
1104                 assert.ok( jQuery( "input[type='checkbox']", $checkedtest ).first().attr( "checked" ), "Check first checkbox still checked." );
1105                 assert.ok( !jQuery( "input[type='checkbox']", $checkedtest ).last().attr( "checked" ), "Check last checkbox still NOT checked." );
1106         } );
1107         this.clock.tick( 200 );
1108 } );
1110 QUnit.test( "interrupt toggle", function( assert ) {
1111         assert.expect( 24 );
1113         var env = this,
1114                 longDuration = 2000,
1115                 shortDuration = 500,
1116                 remaining = 0,
1117                 $elems = jQuery( ".chain-test" ),
1118                 clock = this.clock,
1119                 finish = function() {
1120                 };
1122         jQuery.each( { slideToggle: "height", fadeToggle: "opacity", toggle: "width" }, function( method, prop ) {
1123                 var $methodElems = $elems.filter( "[id^='" + method.toLowerCase() + "']" ).each( function() {
1125                         // Don't end test until we're done with this element
1126                         remaining++;
1128                         // Save original property value for comparison
1129                         jQuery.data( this, "startVal", jQuery( this ).css( prop ) );
1131                         // Expect olddisplay data from our .hide() call below
1132                         assert.expectJqData( env, this, "olddisplay" );
1133                 } );
1135                 // Interrupt a hiding toggle
1136                 $methodElems[ method ]( longDuration );
1137                 setTimeout( function() {
1138                         $methodElems.stop().each( function() {
1139                                 assert.notEqual( jQuery( this ).css( prop ), jQuery.data( this, "startVal" ), ".stop() before completion of hiding ." + method + "() - #" + this.id );
1140                         } );
1142                         // Restore
1143                         $methodElems[ method ]( shortDuration, function() {
1144                                 var id = this.id,
1145                                         $elem = jQuery( this ),
1146                                         startVal = $elem.data( "startVal" );
1148                                 $elem.removeData( "startVal" );
1150                                 assert.equal( $elem.css( prop ), startVal, "original value restored by ." + method + "() - #" + id );
1152                                 // Interrupt a showing toggle
1153                                 $elem.hide()[ method ]( longDuration );
1154                                 setTimeout( function() {
1155                                         $elem.stop();
1156                                         assert.notEqual( $elem.css( prop ), startVal, ".stop() before completion of showing ." + method + "() - #" + id );
1158                                         // Restore
1159                                         $elem[ method ]( shortDuration, function() {
1160                                                 assert.equal( $elem.css( prop ), startVal, "original value restored by ." + method + "() - #" + id );
1161                                                 finish();
1162                                         } );
1163                                 }, shortDuration );
1164                         } );
1165                 }, shortDuration );
1166         } );
1167         clock.tick( longDuration );
1169         // FIXME untangle the set timeouts
1170 } );
1172 QUnit.test( "animate with per-property easing", function( assert ) {
1174         assert.expect( 5 );
1176         var data = { a: 0, b: 0, c: 0 },
1177                 test1Called = false,
1178                 test2Called = false,
1179                 defaultTestCalled = false,
1180                 props = {
1181                         a: [ 100, "_test1" ],
1182                         b: [ 100, "_test2" ],
1183                         c: 100
1184                 };
1186         jQuery.easing._test1 = function( p ) {
1187                 test1Called = true;
1188                 return p;
1189         };
1191         jQuery.easing._test2 = function( p ) {
1192                 test2Called = true;
1193                 return p;
1194         };
1196         jQuery.easing._defaultTest = function( p ) {
1197                 defaultTestCalled = true;
1198                 return p;
1199         };
1201         jQuery( data ).animate( props, 400, "_defaultTest", function() {
1202                 assert.ok( test1Called, "Easing function (_test1) called" );
1203                 assert.ok( test2Called, "Easing function (_test2) called" );
1204                 assert.ok( defaultTestCalled, "Easing function (_default) called" );
1205                 assert.equal( props.a[ 1 ], "_test1", "animate does not change original props (per-property easing would be lost)" );
1206                 assert.equal( props.b[ 1 ], "_test2", "animate does not change original props (per-property easing would be lost)" );
1207         } );
1209         this.clock.tick( 400 );
1210 } );
1212 QUnit.test( "animate with CSS shorthand properties", function( assert ) {
1213         assert.expect( 11 );
1215         var easeAnimation_count = 0,
1216                 easeProperty_count = 0,
1217                 propsBasic = { "padding": "10 20 30" },
1218                 propsSpecial = { "padding": [ "1 2 3", "propertyScope" ] };
1220         jQuery.easing.animationScope = function( p ) {
1221                 if ( p >= 1 ) {
1222                         easeAnimation_count++;
1223                 }
1224                 return p;
1225         };
1227         jQuery.easing.propertyScope = function( p ) {
1228                 if ( p >= 1 ) {
1229                         easeProperty_count++;
1230                 }
1231                 return p;
1232         };
1234         jQuery( "#foo" )
1235                 .animate( propsBasic, 200, "animationScope", function() {
1236                         assert.equal( this.style.paddingTop, "10px", "padding-top was animated" );
1237                         assert.equal( this.style.paddingLeft, "20px", "padding-left was animated" );
1238                         assert.equal( this.style.paddingRight, "20px", "padding-right was animated" );
1239                         assert.equal( this.style.paddingBottom, "30px", "padding-bottom was animated" );
1240                         assert.equal( easeAnimation_count, 4, "per-animation default easing called for each property" );
1241                         easeAnimation_count = 0;
1242                 } )
1243                 .animate( propsSpecial, 200, "animationScope", function() {
1244                         assert.equal( this.style.paddingTop, "1px", "padding-top was animated again" );
1245                         assert.equal( this.style.paddingLeft, "2px", "padding-left was animated again" );
1246                         assert.equal( this.style.paddingRight, "2px", "padding-right was animated again" );
1247                         assert.equal( this.style.paddingBottom, "3px", "padding-bottom was animated again" );
1248                         assert.equal( easeAnimation_count, 0, "per-animation default easing not called" );
1249                         assert.equal( easeProperty_count, 4, "special easing called for each property" );
1251                         jQuery( this ).css( "padding", "0" );
1252                         delete jQuery.easing.animationScope;
1253                         delete jQuery.easing.propertyScope;
1254                 } );
1255                 this.clock.tick( 400 );
1256 } );
1258 QUnit.test( "hide hidden elements, with animation (bug #7141)", function( assert ) {
1259         assert.expect( 4 );
1261         var div = jQuery( "<div id='bug7141' style='display:none'/>" ).appendTo( "#qunit-fixture" );
1262         assert.equal( div.css( "display" ), "none", "Element is initially hidden" );
1263         div.hide( 10, function() {
1264                 assert.equal( div.css( "display" ), "none", "Element is hidden in .hide() callback" );
1265                 div.show( 11, function() {
1266                         assert.equal( div.css( "display" ), "block", "Element is visible in .show() callback" );
1267                 } );
1268         } );
1269         this.clock.tick( 50 );
1270         assert.equal( div.css( "display" ), "block", "Element is visible after animations" );
1271 } );
1273 QUnit.test( "animate unit-less properties (#4966)", function( assert ) {
1274         assert.expect( 2 );
1276         var div = jQuery( "<div style='z-index: 0; position: absolute;'></div>" ).appendTo( "#qunit-fixture" );
1277         assert.equal( div.css( "z-index" ), "0", "z-index is 0" );
1278         div.animate( { zIndex: 2 }, function() {
1279                 assert.equal( div.css( "z-index" ), "2", "z-index is 2" );
1280         } );
1281         this.clock.tick( 400 );
1282 } );
1284 QUnit.test( "animate properties missing px w/ opacity as last (#9074)", function( assert ) {
1285         assert.expect( 6 );
1287         var ml, l,
1288                 div = jQuery( "<div style='position: absolute; margin-left: 0; left: 0px;'></div>" )
1289                 .appendTo( "#qunit-fixture" );
1290         function cssInt( prop ) {
1291                 return parseInt( div.css( prop ), 10 );
1292         }
1293         assert.equal( cssInt( "marginLeft" ), 0, "Margin left is 0" );
1294         assert.equal( cssInt( "left" ), 0, "Left is 0" );
1295         div.animate( {
1296                 left: 200,
1297                 marginLeft: 200,
1298                 opacity: 0
1299         }, 2000 );
1301         this.clock.tick( 500 );
1303         ml = cssInt( "marginLeft" );
1304         l = cssInt( "left" );
1305         assert.notEqual( ml, 0, "Margin left is not 0 after partial animate" );
1306         assert.notEqual( ml, 200, "Margin left is not 200 after partial animate" );
1307         assert.notEqual( l, 0, "Left is not 0 after partial animate" );
1308         assert.notEqual( l, 200, "Left is not 200 after partial animate" );
1309         div.stop().remove();
1310 } );
1312 QUnit.test( "callbacks should fire in correct order (#9100)", function( assert ) {
1313         assert.expect( 1 );
1315         var a = 1,
1316                 cb = 0;
1318         jQuery( "<p data-operation='*2'></p><p data-operation='^2'></p>" ).appendTo( "#qunit-fixture" )
1320                 // The test will always pass if no properties are animated or if the duration is 0
1321                 .animate( { fontSize: 12 }, 13, function() {
1322                         a *= jQuery( this ).data( "operation" ) === "*2" ? 2 : a;
1323                         cb++;
1324                         if ( cb === 2 ) {
1325                                 assert.equal( a, 4, "test value has been *2 and _then_ ^2" );
1326                         }
1327                 } );
1328         this.clock.tick( 20 );
1329 } );
1331 QUnit.test( "callbacks that throw exceptions will be removed (#5684)", function( assert ) {
1332         assert.expect( 2 );
1334         var foo = jQuery( "#foo" );
1336         function TestException() {
1337         }
1339         foo.animate( { height: 1 }, 1, function() {
1340                 throw new TestException();
1341         } );
1343         // this test thoroughly abuses undocumented methods - please feel free to update
1344         // with any changes internally to these functions.
1346         // make sure that the standard timer loop will NOT run.
1347         jQuery.fx.stop();
1349         this.clock.tick( 1 );
1350         assert.throws( jQuery.fx.tick, TestException, "Exception was thrown" );
1352         // the second call shouldn't
1353         jQuery.fx.tick();
1355         assert.ok( true, "Test completed without throwing a second exception" );
1357 } );
1359 QUnit.test( "animate will scale margin properties individually", function( assert ) {
1360         assert.expect( 2 );
1362         var foo = jQuery( "#foo" ).css( {
1363                 "margin": 0,
1364                 "marginLeft": 100
1365         } );
1367         assert.ok( foo.css( "marginLeft" ) !== foo.css( "marginRight" ), "Sanity Check" );
1369         foo.animate( {
1370                 "margin": 200
1371         } ).stop();
1373         assert.ok( foo.css( "marginLeft" ) !== foo.css( "marginRight" ), "The margin properties are different" );
1375         // clean up for next test
1376         foo.css( {
1377                 "marginLeft": "",
1378                 "marginRight": "",
1379                 "marginTop": "",
1380                 "marginBottom": ""
1381         } );
1382 } );
1384 QUnit.test( "Do not append px to 'fill-opacity' #9548", function( assert ) {
1385         assert.expect( 1 );
1387         var $div = jQuery( "<div>" ).appendTo( "#qunit-fixture" );
1389         $div.css( "fill-opacity", 0 ).animate( { "fill-opacity": 1.0 }, 0, function() {
1390                 assert.equal( jQuery( this ).css( "fill-opacity" ), 1, "Do not append px to 'fill-opacity'" );
1391                 $div.remove();
1392         } );
1393 } );
1395 QUnit.test( "line-height animates correctly (#13855)", function( assert ) {
1396         assert.expect( 12 );
1398         var t0,
1399                 clock = this.clock,
1400                 longDuration = 2000,
1401                 shortDuration = 500,
1402                 animated = jQuery(
1403                         "<p style='line-height: 100;'>unitless</p>" +
1404                         "<p style='line-height: 5000px;'>px</p>" +
1405                         "<p style='line-height: 5000%;'>percent</p>" +
1406                         "<p style='line-height: 100em;'>em</p>"
1407                 ).appendTo( "#qunit-fixture" ),
1408                 initialHeight = jQuery.map( animated, function( el ) {
1409                         return jQuery( el ).height();
1410                 } ),
1411                 tolerance = 1.5;
1413         // Delay start to improve test stability
1414         setTimeout( function() {
1416                 t0 = +( new Date() );
1417                 animated.animate( { "line-height": "hide" }, longDuration, "linear" );
1419                 setTimeout( function() {
1420                         var progress = ( ( new Date() ) - t0 ) / longDuration;
1422                         animated.each( function( i ) {
1423                                 var label = jQuery.text( this ),
1424                                         initial = initialHeight[ i ],
1425                                         height = jQuery( this ).height(),
1426                                         lower = initial * ( 1 - progress ) / tolerance;
1427                                 assert.ok( height < initial, "hide " + label + ": upper bound; " +
1428                                         height + " < " + initial + " @ " + ( progress * 100 ) + "%" );
1429                                 assert.ok( height > lower, "hide " + label + ": lower bound; "  +
1430                                         height + " > " + lower + " @ " + ( progress * 100 ) + "%" );
1431                         } );
1433                         t0 = +( new Date() );
1434                         animated.stop( true, true ).hide()
1435                                         .animate( { "line-height": "show" }, longDuration, "linear" );
1437                         setTimeout( function() {
1438                                 var progress = ( ( new Date() ) - t0 ) / longDuration;
1440                                 animated.each( function( i ) {
1441                                         var label = jQuery.text( this ),
1442                                                 initial = initialHeight[ i ],
1443                                                 height = jQuery( this ).height(),
1444                                                 upper = initial * progress * tolerance;
1445                                         assert.ok( height < upper, "show " + label + ": upper bound; " +
1446                                                 height + " < " + upper + " @ " + ( progress * 100 ) + "%" );
1447                                 } );
1449                                 animated.stop( true, true );
1450                         }, shortDuration );
1451 clock.tick( shortDuration );
1452                 }, shortDuration );
1453 clock.tick( shortDuration );
1454         }, 50 );
1455 clock.tick( 50 );
1456 } );
1458 // Start 1.8 Animation tests
1459 QUnit.test( "jQuery.Animation( object, props, opts )", function( assert ) {
1460         assert.expect( 4 );
1462         var animation,
1463                 testObject = {
1464                         "foo": 0,
1465                         "bar": 1,
1466                         "width": 100
1467                 },
1468                 testDest = {
1469                         "foo": 1,
1470                         "bar": 0,
1471                         "width": 200
1472                 };
1474         animation = jQuery.Animation( testObject, testDest, { "duration": 1 } );
1475         animation.done( function() {
1476                 for ( var prop in testDest ) {
1477                         assert.equal( testObject[ prop ], testDest[ prop ], "Animated: " + prop );
1478                 }
1479                 animation.done( function() {
1480                         assert.deepEqual( testObject, testDest, "No unexpected properties" );
1481                 } );
1482         } );
1483         this.clock.tick( 10 );
1484 } );
1486 QUnit.test( "Animate Option: step: function( percent, tween )", function( assert ) {
1487         assert.expect( 1 );
1489         var counter = {};
1490         jQuery( "#foo" ).animate( {
1491                 prop1: 1,
1492                 prop2: 2,
1493                 prop3: 3
1494         }, {
1495                 duration: 1,
1496                 step: function( value, tween ) {
1497                         var calls = counter[ tween.prop ] = counter[ tween.prop ] || [];
1499                         // in case this is called multiple times for either, lets store it in
1500                         // 0 or 1 in the array
1501                         calls[ value === 0 ? 0 : 1 ] = value;
1502                 }
1503         } ).queue( function( next ) {
1504                 assert.deepEqual( counter, {
1505                         prop1: [ 0, 1 ],
1506                         prop2: [ 0, 2 ],
1507                         prop3: [ 0, 3 ]
1508                 }, "Step function was called once at 0% and once at 100% for each property" );
1509                 next();
1510         } );
1511         this.clock.tick( 10 );
1512 } );
1514 QUnit.test( "Animate callbacks have correct context", function( assert ) {
1515         assert.expect( 2 );
1517         var foo = jQuery( "#foo" );
1518         foo.animate( {
1519                 height: 10
1520         }, 10, function() {
1521                 assert.equal( foo[ 0 ], this, "Complete callback after stop(true) `this` is element" );
1522         } ).stop( true, true );
1523         foo.animate( {
1524                 height: 100
1525         }, 10, function() {
1526                 assert.equal( foo[ 0 ], this, "Complete callback `this` is element" );
1527         } );
1528         this.clock.tick( 10 );
1529 } );
1531 QUnit.test( "User supplied callback called after show when fx off (#8892)", function( assert ) {
1532         assert.expect( 2 );
1534         var foo = jQuery( "#foo" );
1535         jQuery.fx.off = true;
1536         foo.hide();
1537         foo.fadeIn( 500, function() {
1538                 assert.ok( supportjQuery( this ).is( ":visible" ), "Element is visible in callback" );
1539                 foo.fadeOut( 500, function() {
1540                         assert.ok( supportjQuery( this ).is( ":hidden" ), "Element is hidden in callback" );
1541                         jQuery.fx.off = false;
1542                 } );
1543         } );
1544         this.clock.tick( 1000 );
1545 } );
1547 QUnit.test( "animate should set display for disconnected nodes", function( assert ) {
1548         assert.expect( 20 );
1550         var env = this,
1551                 showMethods = {
1552                         fadeIn: [],
1553                         fadeTo: [ "fast", 0.5 ],
1554                         slideDown: [ "fast" ],
1555                         show: [ 1 ],
1556                         animate: [ { width: "show" } ]
1557                 },
1558                 toggleMethods = {
1559                         toggle: [ 1 ],
1560                         slideToggle: []
1561                 },
1562                 $divEmpty = jQuery( "<div/>" ),
1563                 $divTest = jQuery( "<div>test</div>" ),
1564                 $divNone = jQuery( "<div style='display: none;'/>" ),
1565                 $divInline = jQuery( "<div style='display: inline;'/>" ),
1566                 nullParentDisplay = $divEmpty.css( "display" ),
1567                 underFragmentDisplay = $divTest.css( "display" ),
1568                 clock = this.clock;
1570         assert.strictEqual( $divEmpty[ 0 ].parentNode, null, "Setup: element with null parentNode" );
1571         assert.strictEqual( ( $divTest[ 0 ].parentNode || {} ).nodeType, 11, "Setup: element under fragment" );
1573         assert.strictEqual( $divEmpty.show()[ 0 ].style.display, "",
1574                 "set display with show() for element with null parentNode" );
1575         assert.strictEqual( $divTest.show()[ 0 ].style.display, "",
1576                 "set display with show() for element under fragment" );
1577         assert.strictEqual( $divNone.show()[ 0 ].style.display, "",
1578                 "show() should change display if it already set to none" );
1579         assert.strictEqual( $divInline.show()[ 0 ].style.display, "inline",
1580                 "show() should not change display if it already set" );
1582         assert.expectJqData( env, $divNone[ 0 ], "olddisplay" );
1584         jQuery.each( showMethods, function( name, opt ) {
1585                 jQuery.fn[ name ].apply( jQuery( "<div/>" ), opt.concat( [ function() {
1586                         assert.strictEqual( jQuery( this ).css( "display" ), nullParentDisplay,
1587                                 "." + name + " block with null parentNode" );
1588                 } ] ) );
1590                 jQuery.fn[ name ].apply( jQuery( "<div>test</div>" ), opt.concat( [ function() {
1591                         assert.strictEqual( jQuery( this ).css( "display" ), underFragmentDisplay,
1592                                 "." + name + " block under fragment" );
1593                 } ] ) );
1594         } );
1595         jQuery.each( toggleMethods, function( name, opt ) {
1596                 jQuery.fn[ name ].apply( jQuery( "<div/>" ), opt.concat( [ function() {
1597                         assert.strictEqual( jQuery( this ).css( "display" ), "none",
1598                                 "." + name + " block with null parentNode" );
1599                 } ] ) );
1601                 jQuery.fn[ name ].apply( jQuery( "<div>test</div>" ), opt.concat( [ function() {
1602                         assert.strictEqual( jQuery( this ).css( "display" ), "none",
1603                                 "." + name + " block under fragment" );
1604                 } ] ) );
1605         } );
1606         clock.tick( 400 );
1607 } );
1609 QUnit[ jQuery.find.compile ? "test" : "skip" ]( "Animation callback should not show animated element as :animated (#7157)", function( assert ) {
1610         assert.expect( 1 );
1612         var foo = jQuery( "#foo" );
1614         foo.animate( {
1615                 opacity: 0
1616         }, 100, function() {
1617                 assert.ok( !foo.is( ":animated" ), "The element is not animated" );
1618         } );
1619         this.clock.tick( 100 );
1620 } );
1622 QUnit[ jQuery.find.compile ? "test" : "skip" ]( "Initial step callback should show element as :animated (#14623)", function( assert ) {
1623         assert.expect( 1 );
1625         var foo = jQuery( "#foo" );
1627         foo.animate( {
1628                 opacity: 0
1629         }, {
1630                 duration: 100,
1631                 step: function() {
1632                         assert.ok( foo.is( ":animated" ), "The element matches :animated inside step function" );
1633                 }
1634         } );
1635         this.clock.tick( 1 );
1636         foo.stop();
1637 } );
1639 QUnit.test( "hide called on element within hidden parent should set display to none (#10045)", function( assert ) {
1640         assert.expect( 3 );
1642         var hidden = jQuery( ".hidden" ),
1643                 elems = jQuery( "<div>hide</div><div>hide0</div><div>hide1</div>" );
1645         hidden.append( elems );
1647         jQuery.when(
1648                 elems.eq( 0 ).hide(),
1649                 elems.eq( 1 ).hide( 0 ),
1650                 elems.eq( 2 ).hide( 1 )
1651         ).done( function() {
1652                 assert.strictEqual( elems.get( 0 ).style.display, "none", "hide() called on element within hidden parent should set display to none" );
1653                 assert.strictEqual( elems.get( 1 ).style.display, "none", "hide( 0 ) called on element within hidden parent should set display to none" );
1654                 assert.strictEqual( elems.get( 2 ).style.display, "none", "hide( 1 ) called on element within hidden parent should set display to none" );
1656                 elems.remove();
1657         } );
1658         this.clock.tick( 10 );
1659 } );
1661 QUnit.test( "hide, fadeOut and slideUp called on element width height and width = 0 should set display to none", function( assert ) {
1662         assert.expect( 5 );
1664         var foo = jQuery( "#foo" ),
1665                 i = 0,
1666                 elems = jQuery();
1668         for ( ; i < 5; i++ ) {
1669                 elems = elems.add( "<div style='width:0;height:0;'></div>" );
1670         }
1672         foo.append( elems );
1674         jQuery.when(
1675                 elems.eq( 0 ).hide(),
1676                 elems.eq( 1 ).hide( jQuery.noop ),
1677                 elems.eq( 2 ).hide( 1 ),
1678                 elems.eq( 3 ).fadeOut(),
1679                 elems.eq( 4 ).slideUp()
1680         ).done( function() {
1681                 assert.strictEqual( elems.get( 0 ).style.display, "none", "hide() called on element width height and width = 0 should set display to none" );
1682                 assert.strictEqual( elems.get( 1 ).style.display, "none",
1683                                                                                                 "hide( jQuery.noop ) called on element width height and width = 0 should set display to none" );
1684                 assert.strictEqual( elems.get( 2 ).style.display, "none", "hide( 1 ) called on element width height and width = 0 should set display to none" );
1685                 assert.strictEqual( elems.get( 3 ).style.display, "none", "fadeOut() called on element width height and width = 0 should set display to none" );
1686                 assert.strictEqual( elems.get( 4 ).style.display, "none", "slideUp() called on element width height and width = 0 should set display to none" );
1688         } );
1689         this.clock.tick( 400 );
1690 } );
1692 QUnit.test( "hide should not leave hidden inline elements visible (#14848)", function( assert ) {
1693         assert.expect( 2 );
1695         var el = jQuery( "#simon1" );
1697         el.hide( 1, function() {
1698                 assert.equal( el.css( "display" ), "none", "hidden" );
1699                 el.hide( 1, function() {
1700                         assert.equal( el.css( "display" ), "none", "still hidden" );
1701                 } );
1702         } );
1704         this.clock.tick( 100 );
1705 } );
1707 QUnit.test( "Handle queue:false promises", function( assert ) {
1708         assert.expect( 10 );
1710         var foo = jQuery( "#foo" ).clone().addBack(),
1711                 step = 1;
1713         foo.animate( {
1714                 top: 1
1715         }, {
1716                 duration: 10,
1717                 queue: false,
1718                 complete: function() {
1719                         assert.ok( step++ <= 2, "Step one or two" );
1720                 }
1721         } ).animate( {
1722                 bottom: 1
1723         }, {
1724                 duration: 10,
1725                 complete: function() {
1726                         assert.ok( step > 2 && step < 5, "Step three or four" );
1727                         step++;
1728                 }
1729         } );
1731         this.clock.tick( 10 );
1733         foo.promise().done( function() {
1734                 assert.equal( step++, 5, "steps 1-5: queue:false then queue:fx done" );
1735                 foo.animate( {
1736                         top: 10
1737                 }, {
1738                         duration: 10,
1739                         complete: function() {
1740                                 assert.ok( step > 5 && step < 8, "Step six or seven" );
1741                                 step++;
1742                         }
1743                 } ).animate( {
1744                         bottom: 10
1745                 }, {
1746                         duration: 10,
1747                         queue: false,
1748                         complete: function() {
1749                                 assert.ok( step > 7 && step < 10, "Step eight or nine" );
1750                                 step++;
1751                         }
1752                 } ).promise().done( function() {
1753                         assert.equal( step++, 10, "steps 6-10: queue:fx then queue:false" );
1754                 } );
1756         } );
1757         this.clock.tick( 10 );
1758 } );
1760 QUnit.test( "multiple unqueued and promise", function( assert ) {
1761         assert.expect( 4 );
1763         var foo = jQuery( "#foo" ),
1764                 step = 1;
1765         foo.animate( {
1766                 marginLeft: 300
1767         }, {
1768                 duration: 500,
1769                 queue: false,
1770                 complete: function() {
1771                         assert.strictEqual( step++, 2, "Step 2" );
1772                 }
1773         } ).animate( {
1774                 top: 100
1775         }, {
1776                 duration: 1000,
1777                 queue: false,
1778                 complete: function() {
1779                         assert.strictEqual( step++, 3, "Step 3" );
1780                 }
1781         } ).animate( {}, {
1782                 duration: 2000,
1783                 queue: false,
1784                 complete: function() {
1786                         // no properties is a non-op and finishes immediately
1787                         assert.strictEqual( step++, 1, "Step 1" );
1788                 }
1789         } ).promise().done( function() {
1790                 assert.strictEqual( step++, 4, "Step 4" );
1791         } );
1792         this.clock.tick( 1000 );
1793 } );
1795 QUnit.test( "animate does not change start value for non-px animation (#7109)", function( assert ) {
1796         assert.expect( 1 );
1798         var parent = jQuery( "<div><div></div></div>" ).css( { width: 284, height: 1 } ).appendTo( "#qunit-fixture" ),
1799                 child = parent.children().css( { fontSize: "98.6in", width: "0.01em", height: 1 } ),
1800                 actual = parseFloat( child.css( "width" ) ),
1801                 computed = [];
1803         child.animate( { width: "0%" }, {
1804                 duration: 1,
1805                 step: function() {
1806                         computed.push( parseFloat( child.css( "width" ) ) );
1807                 }
1808         } ).queue( function( next ) {
1809                 var ratio = computed[ 0 ] / actual;
1810                 assert.ok( ratio > 0.9 && ratio < 1.1,
1811                         "Starting width was close enough (" + computed[ 0 ] + " approximates " + actual + ")" );
1812                 next();
1813                 parent.remove();
1814         } );
1815         this.clock.tick( 10 );
1816 } );
1818 QUnit.test( "non-px animation handles non-numeric start (#11971)", function( assert ) {
1819         assert.expect( 2 );
1821         var foo = jQuery( "#foo" ),
1822                 initial = foo.css( "backgroundPositionX" );
1824         if ( !initial ) {
1825                 assert.expect( 1 );
1826                 assert.ok( true, "Style property not understood" );
1827                 return;
1828         }
1830         foo.animate( { backgroundPositionX: "42%" }, {
1831                 duration: 1,
1832                 progress: function( anim, percent ) {
1833                         if ( percent ) {
1834                                 return;
1835                         }
1837                         if ( parseFloat( initial ) ) {
1838                                 assert.equal( jQuery.style( this, "backgroundPositionX" ), initial, "Numeric start preserved" );
1839                         } else {
1840                                 assert.equal( jQuery.style( this, "backgroundPositionX" ), "0%", "Non-numeric start zeroed" );
1841                         }
1842                 },
1843                 done: function() {
1844                         assert.equal( jQuery.style( this, "backgroundPositionX" ), "42%", "End reached" );
1845                 }
1846         } );
1847         this.clock.tick( 10 );
1848 } );
1850 QUnit.test( "Animation callbacks (#11797)", function( assert ) {
1851         assert.expect( 15 );
1853         var prog = 0,
1854                 targets = jQuery( "#foo" ).children(),
1855                 done = false,
1856                 expectedProgress = 1;
1858         targets.eq( 0 ).animate( {}, {
1859                 duration: 1,
1860                 start: function() {
1861                         assert.ok( true, "empty: start" );
1862                 },
1863                 progress: function( anim, percent ) {
1864                         assert.equal( percent, prog, "empty: progress " + prog );
1865                         prog = 1;
1866                 },
1867                 done: function() {
1868                         assert.ok( true, "empty: done" );
1869                 },
1870                 fail: function() {
1871                         assert.ok( false, "empty: fail" );
1872                 },
1873                 always: function() {
1874                         assert.ok( true, "empty: always" );
1875                         done = true;
1876                 }
1877         } );
1879         assert.ok( done, "empty: done immediately" );
1881         done = false;
1882         targets.eq( 1 ).animate( {
1883                 opacity: 0
1884         }, {
1885                 duration: 1,
1886                 start: function() {
1887                         assert.ok( true, "stopped: start" );
1888                 },
1889                 progress: function( anim, percent ) {
1890                         assert.equal( percent, 0, "stopped: progress 0" );
1891                 },
1892                 done: function() {
1893                         assert.ok( false, "stopped: done" );
1894                 },
1895                 fail: function() {
1896                         assert.ok( true, "stopped: fail" );
1897                 },
1898                 always: function() {
1899                         assert.ok( true, "stopped: always" );
1900                         done = true;
1901                 }
1902         } ).stop();
1904         assert.ok( done, "stopped: stopped immediately" );
1906         targets.eq( 2 ).animate( {
1907                 opacity: 0
1908         }, {
1909                 duration: 1,
1910                 start: function() {
1911                         assert.ok( true, "async: start" );
1912                 },
1913                 progress: function( anim, percent ) {
1914                         assert.equal( percent, expectedProgress, "async: progress " + expectedProgress );
1915                         expectedProgress++;
1916                 },
1917                 done: function() {
1918                         assert.ok( true, "async: done" );
1919                 },
1920                 fail: function() {
1921                         assert.ok( false, "async: fail" );
1922                 },
1923                 always: function() {
1924                         assert.ok( true, "async: always" );
1925                 }
1926         } );
1927         this.clock.tick( 10 );
1928 } );
1930 QUnit.test( "Animation callbacks in order (#2292)", function( assert ) {
1931         assert.expect( 9 );
1933         var step = 0,
1934                 dur = 50;
1936         // assert? -> github.com/JamesMGreene/qunit-assert-step
1937         jQuery( "#foo" ).animate( {
1938                 width: "5px"
1939         }, {
1940                 duration: dur,
1941                 start: function() {
1942                         assert.step( 1 );
1943                 },
1944                 progress: function( anim, p, ms ) {
1945                         if ( !( step++ ) ) {
1946                                 assert.step( 2 );
1947                                 assert.strictEqual( p, 0, "first progress callback: progress ratio" );
1948                                 assert.strictEqual( ms, dur, "first progress callback: remaining ms" );
1949                         } else {
1950                                 assert.step( 3 );
1951                                 assert.strictEqual( p, 1, "last progress callback: progress ratio" );
1952                                 assert.strictEqual( ms, 0, "last progress callback: remaining ms" );
1953                         }
1954                 },
1955                 done: function() {
1956                         assert.step( 4 );
1957                 },
1958                 fail: function() {
1959                         assert.ok( false, "Animation failed" );
1960                 },
1961                 always: function() {
1962                         assert.step( 5 );
1963                 }
1964         } ).finish();
1966         this.clock.tick( dur + 10 );
1967 } );
1969 QUnit.test( "Animate properly sets overflow hidden when animating width/height (#12117)", function( assert ) {
1970         assert.expect( 8 );
1972         jQuery.each( [ "height", "width" ], function( _, prop ) {
1973                 jQuery.each( [ 100, 0 ], function( _, value ) {
1974                         var div = jQuery( "<div>" ).css( "overflow", "auto" ),
1975                                 props = {};
1976                         props[ prop ] = value;
1977                         div.animate( props, 1 );
1978                         assert.equal( div.css( "overflow" ), "hidden",
1979                                 "overflow: hidden set when animating " + prop + " to " + value );
1980                         div.stop();
1981                         assert.equal( div.css( "overflow" ), "auto",
1982                                 "overflow: auto restored after animating " + prop + " to " + value );
1983                 } );
1984         } );
1985 } );
1987 QUnit.test( "Each tick of the timer loop uses a fresh time (#12837)", function( assert ) {
1988         var lastVal,
1989                 tmp = jQuery( {
1990                         test: 0
1991                 } );
1992         assert.expect( 3 );
1993         tmp.animate( {
1994                 test: 100
1995         }, {
1996                 step: function( p, fx ) {
1997                         assert.ok( fx.now !== lastVal, "Current value is not the last value: " + lastVal + " - " + fx.now );
1998                         lastVal = fx.now;
1999                 }
2000         } );
2001         this.clock.tick( 1 );
2003         // now that we have a new time, run another tick
2004         jQuery.fx.tick();
2006         this.clock.tick( 1 );
2008         jQuery.fx.tick();
2009         tmp.stop();
2010 } );
2012 QUnit.test( "Animations with 0 duration don't ease (#12273)", function( assert ) {
2013         assert.expect( 1 );
2015         jQuery.easing.test = function() {
2016                 assert.ok( false, "Called easing" );
2017         };
2019         jQuery( "#foo" ).animate( {
2020                 height: 100
2021         }, {
2022                 duration: 0,
2023                 easing: "test",
2024                 complete: function() {
2025                         assert.equal( jQuery( this ).height(), 100, "Height is 100" );
2026                 }
2027         } );
2029         delete jQuery.easing.test;
2030 } );
2032 jQuery.map( [ "toggle", "slideToggle", "fadeToggle" ], function( method ) {
2034         // this test would look a lot better if we were using something to override
2035         // the default timers
2036         var duration = 1500;
2037         QUnit.test( "toggle state tests: " + method + " (#8685)", function( assert ) {
2038                 function secondToggle() {
2039                         var stopped = parseFloat( element.css( check ) );
2040                         tested = false;
2041                         element[ method ]( {
2042                                 duration: duration,
2043                                 step: function( p, fx ) {
2044                                         if ( fx.pos > 0.1 && fx.prop === check && !tested ) {
2045                                                 tested = true;
2046                                                 assert.equal( fx.start, stopped, check + " starts at " + stopped + " where it stopped" );
2047                                                 assert.equal( fx.end, original, check + " ending value is " + original );
2048                                                 element.stop();
2049                                         }
2050                                 }
2051                         } );
2052                 }
2054                 var tested,
2055                         original,
2056                         check = method === "slideToggle" ? "height" : "opacity",
2057                         element = jQuery( "#foo" ).height( 200 );
2059                 assert.expect( 4 );
2061                 element[ method ]( {
2062                         duration: duration,
2063                         easing: "linear",
2064                         step: function( p, fx ) {
2065                                 if ( fx.pos > 0.1 && fx.prop === check && !tested ) {
2066                                         tested = true;
2067                                         original = fx.start;
2068                                         assert.ok( fx.start !== 0, check + " is starting at " + original + " on first toggle (non-zero)" );
2069                                         assert.equal( fx.end, 0, check + " is ending at 0 on first toggle" );
2070                                         element.stop();
2071                                 }
2072                         },
2073                         always: secondToggle
2074                 } );
2076                 //FIXME figure out why 470
2077                 this.clock.tick( 470 );
2078         } );
2079 } );
2081 QUnit.test( "jQuery.fx.start & jQuery.fx.stop hook points", function( assert ) {
2082         var oldStart = jQuery.fx.start,
2083                 oldStop = jQuery.fx.stop,
2084                 foo = jQuery( { foo: 0 } );
2086         assert.expect( 3 );
2088         jQuery.fx.start = function() {
2089                 assert.ok( true, "start called" );
2090         };
2091         jQuery.fx.stop = function() {
2092                 assert.ok( true, "stop called" );
2093         };
2095         // calls start
2096         foo.animate( { foo: 1 }, { queue: false } );
2098         // calls start
2099         foo.animate( { foo: 2 }, { queue: false } );
2100         foo.stop();
2102         // calls stop
2103         jQuery.fx.tick();
2105         // cleanup
2106         jQuery.fx.start = oldStart;
2107         jQuery.fx.stop = oldStop;
2108 } );
2110 QUnit.test( ".finish() completes all queued animations", function( assert ) {
2111         var animations = {
2112                         top: 100,
2113                         left: 100,
2114                         height: 100,
2115                         width: 100
2116                 },
2117                 div = jQuery( "<div>" );
2119         assert.expect( 11 );
2121         jQuery.each( animations, function( prop, value ) {
2122                 var anim = {};
2123                 anim[ prop ] = value;
2125                 // the delay shouldn't matter at all!
2126                 div.css( prop, 1 ).animate( anim, function() {
2127                         assert.ok( true, "Called animation callback for " + prop );
2128                 } ).delay( 100 );
2129         } );
2130         assert.equal( div.queue().length, 8, "8 animations in the queue" );
2131         div.finish();
2132         jQuery.each( animations, function( prop, value ) {
2133                 assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
2134         } );
2135         assert.equal( div.queue().length, 0, "empty queue when done" );
2137         if ( jQuery.find.compile ) {
2138                 assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
2139         } else {
2140                 assert.ok( "skip", ":animated selector not supported with selector-native" );
2141         }
2143         // cleanup
2144         div.remove();
2146         // leaves a "shadow timer" which does nothing around, need to force a tick
2147         jQuery.fx.tick();
2148 } );
2150 QUnit.test( ".finish( false ) - unqueued animations", function( assert ) {
2151         var animations = {
2152                         top: 100,
2153                         left: 100,
2154                         height: 100,
2155                         width: 100
2156                 },
2157                 div = jQuery( "<div>" );
2159         assert.expect( 10 );
2161         jQuery.each( animations, function( prop, value ) {
2162                 var anim = {};
2163                 anim[ prop ] = value;
2164                 div.css( prop, 1 ).animate( anim, {
2165                         queue: false,
2166                         complete: function() {
2167                                 assert.ok( true, "Called animation callback for " + prop );
2168                         }
2169                 } );
2170         } );
2171         assert.equal( div.queue().length, 0, "0 animations in the queue" );
2172         div.finish( false );
2173         jQuery.each( animations, function( prop, value ) {
2174                 assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
2175         } );
2177         if ( jQuery.find.compile ) {
2178                 assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
2179         } else {
2180                 assert.ok( "skip", ":animated selector not supported with selector-native" );
2181         }
2183         // cleanup
2184         div.remove();
2186         // leaves a "shadow timer" which does nothing around, need to force a tick
2187         jQuery.fx.tick();
2188 } );
2190 QUnit.test( ".finish( \"custom\" ) - custom queue animations", function( assert ) {
2191         var animations = {
2192                         top: 100,
2193                         left: 100,
2194                         height: 100,
2195                         width: 100
2196                 },
2197                 div = jQuery( "<div>" );
2199         assert.expect( 11 );
2201         jQuery.each( animations, function( prop, value ) {
2202                 var anim = {};
2203                 anim[ prop ] = value;
2204                 div.css( prop, 1 ).animate( anim, {
2205                         queue: "custom",
2206                         complete: function() {
2207                                 assert.ok( true, "Called animation callback for " + prop );
2208                         }
2209                 } );
2210         } );
2211         assert.equal( div.queue( "custom" ).length, 4, "4 animations in the queue" );
2213         // start the first animation
2214         div.dequeue( "custom" );
2216         if ( jQuery.find.compile ) {
2217                 assert.equal( div.is( ":animated" ), true, ":animated matches" );
2218         } else {
2219                 assert.ok( "skip", ":animated selector not supported with selector-native" );
2220         }
2222         div.finish( "custom" );
2223         jQuery.each( animations, function( prop, value ) {
2224                 assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
2225         } );
2227         if ( jQuery.find.compile ) {
2228                 assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
2229         } else {
2230                 assert.ok( "skip", ":animated selector not supported with selector-native" );
2231         }
2233         // cleanup
2234         div.remove();
2236         // leaves a "shadow timer" which does nothing around, need to force a tick
2237         jQuery.fx.tick();
2238 } );
2240 QUnit.test( ".finish() calls finish of custom queue functions", function( assert ) {
2241         function queueTester( next, hooks ) {
2242                 hooks.stop = function( gotoEnd ) {
2243                         inside++;
2244                         assert.equal( this, div[ 0 ] );
2245                         assert.ok( gotoEnd, "hooks.stop(true) called" );
2246                 };
2247         }
2248         var div = jQuery( "<div>" ),
2249                 inside = 0,
2250                 outside = 0;
2252         assert.expect( 6 );
2253         queueTester.finish = function() {
2254                 outside++;
2255                 assert.ok( true, "Finish called on custom queue function" );
2256         };
2258         div.queue( queueTester ).queue( queueTester ).queue( queueTester ).finish();
2260         assert.equal( inside, 1, "1 stop(true) callback" );
2261         assert.equal( outside, 2, "2 finish callbacks" );
2263         div.remove();
2264 } );
2266 QUnit.test( ".finish() is applied correctly when multiple elements were animated (#13937)", function( assert ) {
2267         assert.expect( 3 );
2269         var elems = jQuery( "<a>0</a><a>1</a><a>2</a>" );
2271         elems.animate( { opacity: 0 }, 1500 ).animate( { opacity: 1 }, 1500 );
2272         setTimeout( function() {
2273                 elems.eq( 1 ).finish();
2274                 assert.ok( !elems.eq( 1 ).queue().length, "empty queue for .finish()ed element" );
2275                 assert.ok( elems.eq( 0 ).queue().length, "non-empty queue for preceding element" );
2276                 assert.ok( elems.eq( 2 ).queue().length, "non-empty queue for following element" );
2277                 elems.stop( true );
2279         }, 100 );
2280         this.clock.tick( 1500 );
2281 } );
2283 QUnit.test( "slideDown() after stop() (#13483)", function( assert ) {
2284                 assert.expect( 2 );
2286                 var ul = jQuery( "<ul style='height: 100px; display: block;'></ul>" )
2287                                 .appendTo( "#qunit-fixture" ),
2288                         origHeight = ul.height(),
2289                         clock = this.clock;
2291         // First test. slideUp() -> stop() in the middle -> slideDown() until the end
2292                 ul.slideUp( 1000 );
2293                 clock.tick( 500 );
2294                 ul.stop( true );
2295                 ul.slideDown( 1, function() {
2296                                 assert.equal( ul.height(), origHeight, "slideDown() after interrupting slideUp() with stop(). Height must be in original value" );
2298                                 // Second test. slideDown() -> stop() in the middle -> slideDown() until the end
2299                                 ul.slideUp( 1 );
2300                                 clock.tick( 10 );
2301                                 ul.slideDown( 1000 );
2302                                 clock.tick( 500 );
2303                                 ul.stop( true );
2304                                 ul.slideDown( 1 );
2305                                 assert.equal( ul.height(), origHeight, "slideDown() after interrupting slideDown() with stop(). Height must be in original value" );
2307                                 // Cleanup
2308                                 ul.remove();
2309                                 clock.tick( 10 );
2311                 } );
2313                 clock.tick( 10 );
2314 } );
2316 QUnit.test( "Respect display value on inline elements (#14824)", function( assert ) {
2317         assert.expect( 2 );
2319         var clock = this.clock,
2320                 fromStyleSheet = jQuery( "<span id='span-14824' />" ),
2321                 fromStyleAttr = jQuery( "<span style='display: block;' />" );
2323         jQuery( "#qunit-fixture" ).append( fromStyleSheet, fromStyleAttr );
2325         fromStyleSheet.slideUp( function() {
2326                 jQuery( this ).slideDown( function() {
2327                         assert.equal( jQuery( this ).css( "display" ), "block",
2328                                 "Respect previous display value (from stylesheet) on span element" );
2329                 } );
2330         } );
2332         fromStyleAttr.slideUp( function() {
2333                 jQuery( this ).slideDown( function() {
2334                         assert.equal( jQuery( this ).css( "display" ), "block",
2335                                 "Respect previous display value (from style attribute) on span element" );
2336                 } );
2337         } );
2339         clock.tick( 800 );
2340 } );
2342 QUnit.test( "jQuery.easing._default (gh-2218)", function( assert ) {
2343         assert.expect( 2 );
2345         jQuery( "#foo" )
2346                 .animate( { width: "5px" }, {
2347                         duration: 5,
2348                         start: function( anim ) {
2349                                 assert.equal( anim.opts.easing, jQuery.easing._default,
2350                                         "anim.opts.easing should be equal to jQuery.easing._default when the easing argument is not given" );
2351                         }
2352                 } )
2353                 .animate( { height: "5px" }, {
2354                         duration: 5,
2355                         easing: "linear",
2356                         start: function( anim ) {
2357                                 assert.equal( anim.opts.easing, "linear",
2358                                         "anim.opts.easing should be equal to the easing argument" );
2359                         }
2360                 } )
2361                 .stop();
2363         this.clock.tick( 25 );
2364 } );
2366 QUnit.test( "jQuery.easing._default in Animation (gh-2218", function( assert ) {
2367         assert.expect( 3 );
2369         var animation,
2370                 defaultEasing = jQuery.easing._default,
2371                 called = false,
2372                 testObject = { "width": 100 },
2373                 testDest = { "width": 200 };
2375         jQuery.easing.custom = function( p ) {
2376                 called = true;
2377                 return p;
2378         };
2379         jQuery.easing._default = "custom";
2381         animation = jQuery.Animation( testObject, testDest, { "duration": 1 } );
2382         animation.done( function() {
2383                 assert.equal( testObject.width, testDest.width, "Animated width" );
2384                 assert.ok( called, "Custom jQuery.easing._default called" );
2385                 assert.strictEqual( animation.opts.easing, "custom",
2386                         "Animation used custom jQuery.easing._default" );
2387                 jQuery.easing._default = defaultEasing;
2388                 delete jQuery.easing.custom;
2389         } );
2391         this.clock.tick( 10 );
2392 } );
2394 QUnit.test( "jQuery.easing._default in Tween (gh-2218)", function( assert ) {
2395         assert.expect( 3 );
2397         var tween,
2398                 defaultEasing = jQuery.easing._default,
2399                 called = false,
2400                 testObject = { "width": 100 };
2402         jQuery.easing.custom = function( p ) {
2403                 called = true;
2404                 return p;
2405         };
2406         jQuery.easing._default = "custom";
2408         tween = jQuery.Tween( testObject, { "duration": 1 }, "width", 200 );
2409         tween.run( 1 );
2410         assert.equal( testObject.width, 200, "Animated width" );
2411         assert.ok( called, "Custom jQuery.easing._default called" );
2412         assert.strictEqual( tween.easing, "custom",
2413                 "Animation used custom jQuery.easing._default" );
2414         jQuery.easing._default = defaultEasing;
2415         delete jQuery.easing.custom;
2416 } );
2418 QUnit.test( "Display value is correct for disconnected nodes (trac-13310)", function( assert ) {
2419         assert.expect( 3 );
2421         var div = jQuery( "<div/>" );
2423         assert.equal( div.css( "display", "inline" ).hide().show().appendTo( "body" ).css( "display" ), "inline", "Initialized display value has returned" );
2424         div.remove();
2426         div.css( "display", "none" ).hide();
2427         assert.equal( jQuery._data( div[ 0 ], "olddisplay" ), undefined, "olddisplay is undefined after hiding a detached and hidden element" );
2428         div.remove();
2430         div.css( "display", "inline-block" ).hide().appendTo( "body" ).fadeIn( function() {
2431                 assert.equal( div.css( "display" ), "inline-block", "Initialized display value has returned" );
2432                 div.remove();
2433         } );
2434         this.clock.tick( 1000 );
2435 } );
2437 QUnit.test( "Show/hide/toggle and display: inline", function( assert ) {
2438         assert.expect( 40 );
2440         var clock = this.clock;
2442         jQuery( "<span/><div style='display:inline' title='inline div'/>" ).each( function() {
2443                 var completed, interrupted,
2444                         N = 100,
2445                         fixture = jQuery( "#qunit-fixture" ),
2446                         $el = jQuery( this ),
2447                         kind = this.title || this.nodeName.toLowerCase();
2449                 // Animations allowed to complete
2450                 completed = jQuery.map( [
2451                         $el.clone().data( { call: "hide", done: "none" } ).appendTo( fixture ).hide( N ),
2452                         $el.clone().data( { call: "toggle", done: "none" } ).appendTo( fixture ).toggle( N ),
2453                         $el.clone().data( { call: "hide+show", done: "inline" } ).appendTo( fixture )
2454                                 .hide().show( N ),
2455                         $el.clone().data( { call: "hide+toggle", done: "inline" } ).appendTo( fixture )
2456                                 .hide().toggle( N )
2457                 ], function( $clone ) { return $clone[ 0 ]; } );
2459                 // Animations not allowed to complete
2460                 interrupted = jQuery.map( [
2461                         $el.clone().data( { call: "hide+stop" } ).appendTo( fixture ).hide( N ),
2462                         $el.clone().data( { call: "toggle+stop" } ).appendTo( fixture ).toggle( N ),
2463                         $el.clone().data( { call: "hide+show+stop" } ).appendTo( fixture ).hide().show( N ),
2464                         $el.clone().data( { call: "hide+toggle+stop" } ).appendTo( fixture ).hide().toggle( N )
2465                 ], function( $clone ) { return $clone[ 0 ]; } );
2467                 // All elements should be inline-block during the animation
2468                 clock.tick( N / 2 );
2469                 jQuery( completed ).each( function() {
2470                         var $el = jQuery( this ),
2471                                 call = $el.data( "call" );
2472                         assert.strictEqual( $el.css( "display" ), "inline-block", kind + " display during " + call );
2473                 } );
2475                 // Interrupted elements should remain inline-block
2476                 jQuery( interrupted ).stop();
2477                 clock.tick( N / 2 );
2478                 jQuery( interrupted ).each( function() {
2479                         var $el = jQuery( this ),
2480                                 call = $el.data( "call" );
2481                         assert.strictEqual( $el.css( "display" ), "inline-block", kind + " display after " + call );
2482                 } );
2484                 // Completed elements should not remain inline-block
2485                 clock.tick( N / 2 );
2486                 jQuery( completed ).each( function() {
2487                         var $el = jQuery( this ),
2488                                 call = $el.data( "call" ),
2489                                 display = $el.data( "done" );
2490                         assert.strictEqual( $el.css( "display" ), display, kind + " display after " + call );
2491                 } );
2493                 // A post-animation toggle should not make any element inline-block
2494                 completed = jQuery( completed.concat( interrupted ) );
2495                 completed.toggle( N / 2 );
2496                 clock.tick( N );
2497                 completed.each( function() {
2498                         var $el = jQuery( this ),
2499                                 call = $el.data( "call" );
2500                         assert.ok( $el.css( "display" ) !== "inline-block",
2501                                 kind + " display is not inline-block after " + call + "+toggle" );
2502                 } );
2503         } );
2504 } );
2506 function testEasing( assert, speed, easing, complete ) {
2507         assert.expect( 4 );
2508         var options = jQuery.speed( speed, easing, complete );
2510         assert.equal( options.duration, 10, "Duration set properly" );
2511         assert.equal(
2512                 jQuery.isFunction( options.easing ) ? options.easing() : options.easing,
2513                 "linear",
2514                 "Easing set properly"
2515         );
2516         assert.equal( options.queue, "fx", "Queue defaults to fx" );
2517         options.complete();
2520 QUnit.test( "jQuery.speed( speed, easing, complete )", function( assert ) {
2521         testEasing( assert, 10, "linear", function() {
2522                 assert.ok( true, "Complete called" );
2523         } );
2524 } );
2526 QUnit.test( "jQuery.speed( speed, easing, complete ) - with easing function", function( assert ) {
2527         testEasing(
2528                 assert,
2529                 10,
2530                 function() {
2531                         return "linear";
2532                 },
2533                 function() {
2534                         assert.ok( true, "Complete called" );
2535                 }
2536         );
2537 } );
2539 QUnit.test( "jQuery.speed( options )", function( assert ) {
2540         testEasing( assert, {
2541                 duration: 10,
2542                 easing: "linear",
2543                 complete: function() {
2544                         assert.ok( true, "Complete called" );
2545                 }
2546         } );
2547 } );
2549 QUnit.test( "jQuery.speed( options ) - with easing function", function( assert ) {
2550         testEasing( assert, {
2551                 duration: 10,
2552                 easing: function() {
2553                         return "linear";
2554                 },
2555                 complete: function() {
2556                         assert.ok( true, "Complete called" );
2557                 }
2558         } );
2559 } );
2561 QUnit.test( "jQuery.speed( options ) - queue values", function( assert ) {
2562         assert.expect( 5 );
2564         var get = function( queue ) {
2565                 return jQuery.speed( { queue: queue } ).queue;
2566         };
2568         assert.equal( get( null ), "fx", "null defaults to 'fx'" );
2569         assert.equal( get( undefined ), "fx", "undefined defaults to 'fx'" );
2570         assert.equal( get( true ), "fx", "true defaults to 'fx'" );
2571         assert.equal( get( "fx" ), "fx", "'fx' passed through" );
2572         assert.equal( get( "custom" ), "custom", "'custom' passed through" );
2573 } );
2575 QUnit.test( "jQuery.speed() - durations", function( assert ) {
2576         assert.expect( 5 );
2578         var get = function( duration ) {
2579                 return jQuery.speed( duration ).duration;
2580         };
2582         assert.equal( get( 100 ), 100, "jQuery.speed sets number duration" );
2583         assert.equal( get(), jQuery.fx.speeds._default, "jQuery.speed falls back default duration" );
2584         assert.equal( get( "slow" ), jQuery.fx.speeds.slow, "jQuery.speed uses preset speeds" );
2585         assert.equal( get( "fast" ), jQuery.fx.speeds.fast, "jQuery.speed uses preset speeds" );
2586         jQuery.fx.off = true;
2587         assert.equal( get( 100 ), 0, "jQuery.speed defaults duration to zero if fx is off" );
2588         jQuery.fx.off = false;
2589 } );
2591 } )();