diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/csp.php | 30 | ||||
-rw-r--r-- | test/data/errorWithText.php | 5 | ||||
-rw-r--r-- | test/data/headers.php | 16 | ||||
-rw-r--r-- | test/data/jsonp.php | 4 | ||||
-rw-r--r-- | test/data/params_html.php | 6 | ||||
-rw-r--r-- | test/data/testinit.js | 49 | ||||
-rw-r--r-- | test/delegatetest.html | 6 | ||||
-rw-r--r-- | test/index.html | 9 | ||||
-rw-r--r-- | test/polluted.php | 4 | ||||
-rw-r--r-- | test/unit/ajax.js | 1070 | ||||
-rw-r--r-- | test/unit/attributes.js | 78 | ||||
-rw-r--r-- | test/unit/core.js | 346 | ||||
-rw-r--r-- | test/unit/css.js | 79 | ||||
-rw-r--r-- | test/unit/data.js | 251 | ||||
-rw-r--r-- | test/unit/dimensions.js | 48 | ||||
-rw-r--r-- | test/unit/effects.js | 99 | ||||
-rw-r--r-- | test/unit/event.js | 380 | ||||
-rw-r--r-- | test/unit/manipulation.js | 131 | ||||
-rw-r--r-- | test/unit/offset.js | 102 | ||||
-rw-r--r-- | test/unit/queue.js | 48 | ||||
-rw-r--r-- | test/unit/selector.js | 110 | ||||
-rw-r--r-- | test/unit/traversing.js | 43 |
22 files changed, 1929 insertions, 985 deletions
diff --git a/test/csp.php b/test/csp.php new file mode 100644 index 000000000..acf8f32c9 --- /dev/null +++ b/test/csp.php @@ -0,0 +1,30 @@ +<?php header("X-Content-Security-Policy-Report-Only: allow *"); ?> +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>CSP Test Page</title> + + <script src="../src/core.js"></script> + <script src="../src/support.js"></script> + <script src="../src/data.js"></script> + <script src="../src/queue.js"></script> + <script src="../src/attributes.js"></script> + <script src="../src/event.js"></script> + <script src="../src/sizzle/sizzle.js"></script> + <script src="../src/sizzle-jquery.js"></script> + <script src="../src/traversing.js"></script> + <script src="../src/manipulation.js"></script> + <script src="../src/css.js"></script> + <script src="../src/ajax.js"></script> + <script src="../src/ajax/jsonp.js"></script> + <script src="../src/ajax/script.js"></script> + <script src="../src/ajax/xhr.js"></script> + <script src="../src/effects.js"></script> + <script src="../src/offset.js"></script> + <script src="../src/dimensions.js"></script> +</head> +<body> + <p>CSP Test Page</p> +</body> +</html> diff --git a/test/data/errorWithText.php b/test/data/errorWithText.php new file mode 100644 index 000000000..abd873217 --- /dev/null +++ b/test/data/errorWithText.php @@ -0,0 +1,5 @@ +<?php + +header("HTTP/1.0 400 Bad Request"); + +echo "plain text message";
\ No newline at end of file diff --git a/test/data/headers.php b/test/data/headers.php index f2c21c0cc..d500b16f4 100644 --- a/test/data/headers.php +++ b/test/data/headers.php @@ -4,17 +4,13 @@ header( "Sample-Header: Hello World" ); $headers = array(); -foreach( $_SERVER as $key => $value ) { - - if ( substr( $key , 0 , 5 ) == "HTTP_" ) { - - $key = str_replace( "_" , "-" , substr( $key , 5) ); - $headers[ $key ] = $value; +foreach( $_SERVER as $key => $value ) { - } - -} + $key = str_replace( "_" , "-" , substr( $key , 0 , 5 ) == "HTTP_" ? substr( $key , 5 ) : $key ); + $headers[ $key ] = $value; + +} foreach( explode( "_" , $_GET[ "keys" ] ) as $key ) { - echo "$key: " . $headers[ strtoupper( $key ) ] . "\n"; + echo "$key: " . @$headers[ strtoupper( $key ) ] . "\n"; } diff --git a/test/data/jsonp.php b/test/data/jsonp.php index 9ae1d8487..6c13d72e9 100644 --- a/test/data/jsonp.php +++ b/test/data/jsonp.php @@ -1,6 +1,10 @@ <?php error_reporting(0); $callback = $_REQUEST['callback']; +if ( ! $callback ) { + $callback = explode("?",end(explode("/",$_SERVER['REQUEST_URI']))); + $callback = $callback[0]; +} $json = $_REQUEST['json']; if($json) { echo $callback . '([ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ])'; diff --git a/test/data/params_html.php b/test/data/params_html.php index 0bab00f29..e88ef1521 100644 --- a/test/data/params_html.php +++ b/test/data/params_html.php @@ -1,12 +1,12 @@ <div id="post"> -<?php +<?php foreach( $_POST as $key=>$value ) echo "<b id='$key'>$value</b>"; -?> +?> </div> <div id="get"> <?php foreach( $_GET as $key=>$value ) echo "<b id='$key'>$value</b>"; -?> +?> </div>
\ No newline at end of file diff --git a/test/data/testinit.js b/test/data/testinit.js index a66f71d25..c478390d5 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -45,3 +45,52 @@ function t(a,b,c) { function url(value) { return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); } + +(function () { + // Store the old counts so that we only assert on tests that have actually leaked, + // instead of asserting every time a test has leaked sometime in the past + var oldCacheLength = 0, + oldFragmentsLength = 0, + oldTimersLength = 0, + oldActive = 0; + + /** + * Ensures that tests have cleaned up properly after themselves. Should be passed as the + * teardown function on all modules' lifecycle object. + */ + this.moduleTeardown = function () { + var i, fragmentsLength = 0, cacheLength = 0; + + // Allow QUnit.reset to clean up any attached elements before checking for leaks + QUnit.reset(); + + for ( i in jQuery.cache ) { + ++cacheLength; + } + + jQuery.fragments = {}; + + for ( i in jQuery.fragments ) { + ++fragmentsLength; + } + + // Because QUnit doesn't have a mechanism for retrieving the number of expected assertions for a test, + // if we unconditionally assert any of these, the test will fail with too many assertions :| + if ( cacheLength !== oldCacheLength ) { + equals( cacheLength, oldCacheLength, "No unit tests leak memory in jQuery.cache" ); + oldCacheLength = cacheLength; + } + if ( fragmentsLength !== oldFragmentsLength ) { + equals( fragmentsLength, oldFragmentsLength, "No unit tests leak memory in jQuery.fragments" ); + oldFragmentsLength = fragmentsLength; + } + if ( jQuery.timers.length !== oldTimersLength ) { + equals( jQuery.timers.length, oldTimersLength, "No timers are still running" ); + oldTimersLength = jQuery.timers.length; + } + if ( jQuery.active !== oldActive ) { + equals( jQuery.active, 0, "No AJAX requests are still active" ); + oldActive = jQuery.active; + } + } +}());
\ No newline at end of file diff --git a/test/delegatetest.html b/test/delegatetest.html index 327085c84..6479d26ec 100644 --- a/test/delegatetest.html +++ b/test/delegatetest.html @@ -206,7 +206,7 @@ $(document).bind("focusin", function() { jQuery("#boundFocus").blink(); }); - + $(document).bind("focusout", function() { jQuery("#boundBlur").blink(); }); @@ -229,14 +229,14 @@ $(document).bind("change", function(){ jQuery("#boundChange").blink(); }); - + $("#text_submit").addSubmitTest("#textSubmit", true); $("#password_submit").addSubmitTest("#passwordSubmit", true); $("#submit_submit").addSubmitTest("#submitSubmit", true); $(document).bind("submit", function(){ jQuery("#boundSubmit").blink(); }); - + </script> </body> </html> diff --git a/test/index.html b/test/index.html index 238b7d582..fc5f667d2 100644 --- a/test/index.html +++ b/test/index.html @@ -20,10 +20,9 @@ <script src="../src/manipulation.js"></script> <script src="../src/css.js"></script> <script src="../src/ajax.js"></script> - <script src="../src/xhr.js"></script> - <script src="../src/transports/jsonp.js"></script> - <script src="../src/transports/script.js"></script> - <script src="../src/transports/xhr.js"></script> + <script src="../src/ajax/jsonp.js"></script> + <script src="../src/ajax/script.js"></script> + <script src="../src/ajax/xhr.js"></script> <script src="../src/effects.js"></script> <script src="../src/offset.js"></script> <script src="../src/dimensions.js"></script> @@ -265,7 +264,7 @@ Z</textarea> <div id="slidetoggleout" class='chain test out'>slideToggleOut<div>slideToggleOut</div></div> <div id="fadetogglein" class='chain test'>fadeToggleIn<div>fadeToggleIn</div></div> - <div id="fadetoggleout" class='chain test out'>fadeToggleOut<div>fadeToggleOut</div></div> + <div id="fadetoggleout" class='chain test out'>fadeToggleOut<div>fadeToggleOut</div></div> <div id="fadeto" class='chain test'>fadeTo<div>fadeTo</div></div> </div> diff --git a/test/polluted.php b/test/polluted.php index 3ddb7acd2..55df0dd89 100644 --- a/test/polluted.php +++ b/test/polluted.php @@ -15,7 +15,7 @@ $suite = file_get_contents('index.html'); echo str_replace( '<!-- Includes -->', $includes, $suite ); exit; - } + } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> @@ -43,7 +43,7 @@ <h1 id="header">jQuery Test Suite</h1> <h2 id="banner" class="fail"></h2> <h2 id="userAgent">Choose other libraries to include</h2> - + <form class="otherlibs" action="" method="post"> <?php $libs = scandir('otherlibs'); diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 35c030247..b44f0773f 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1,4 +1,4 @@ -module("ajax"); +module("ajax", { teardown: moduleTeardown }); // Safari 3 randomly crashes when running these tests, // but only in the full suite - you can run just the Ajax @@ -70,44 +70,6 @@ test("jQuery.ajax() - success callbacks - (url, options) syntax", function() { }, 13); }); -test("jQuery.ajax() - success/error callbacks (remote)", function() { - - var supports = jQuery.support.cors; - - expect( supports ? 9 : 6 ); - - jQuery.ajaxSetup({ timeout: 0 }); - - stop(); - - setTimeout(function(){ - jQuery('#foo').ajaxStart(function(){ - ok( true, "ajaxStart" ); - }).ajaxStop(function(){ - ok( true, "ajaxStop" ); - start(); - }).ajaxSend(function(){ - ok( supports , "ajaxSend" ); - }).ajaxComplete(function(){ - ok( true, "ajaxComplete" ); - }).ajaxError(function(){ - ok( ! supports, "ajaxError" ); - }).ajaxSuccess(function(){ - ok( supports, "ajaxSuccess" ); - }); - - jQuery.ajax({ - // JULIAN TODO: Get an url especially for jQuery - url: "http://rockstarapps.com/test.php", - dataType: "text", - beforeSend: function(){ ok(supports, "beforeSend"); }, - success: function( val ){ ok(supports, "success"); ok(supports && val.length, "data received"); }, - error: function(_ , a , b ){ ok(!supports, "error"); }, - complete: function(){ ok(true, "complete"); } - }); - }, 13); -}); - test("jQuery.ajax() - success callbacks (late binding)", function() { expect( 8 ); @@ -173,7 +135,7 @@ test("jQuery.ajax() - success callbacks (oncomplete binding)", function() { .error(function(){ ok(false, "error"); }) .complete(function(){ start(); }); } - }) + }); }, 13); }); @@ -211,7 +173,7 @@ test("jQuery.ajax() - success callbacks (very late binding)", function() { .complete(function(){ start(); }); },100); } - }) + }); }, 13); }); @@ -221,7 +183,7 @@ test("jQuery.ajax() - success callbacks (order)", function() { jQuery.ajaxSetup({ timeout: 0 }); stop(); - + var testString = ""; setTimeout(function(){ @@ -278,12 +240,52 @@ test("jQuery.ajax() - error callbacks", function() { }); }); +test("jQuery.ajax() - responseText on error", function() { + + expect( 1 ); + + stop(); + + jQuery.ajax({ + url: url("data/errorWithText.php"), + error: function(xhr) { + strictEqual( xhr.responseText , "plain text message" , "Test jXHR.responseText is filled for HTTP errors" ); + }, + complete: function() { + start(); + } + }); +}); + +test(".ajax() - retry with jQuery.ajax( this )", function() { + + expect( 1 ); + + stop(); + + var firstTime = 1; + + jQuery.ajax({ + url: url("data/errorWithText.php"), + error: function() { + if ( firstTime ) { + firstTime = 0; + jQuery.ajax( this ); + } else { + ok( true , "Test retrying with jQuery.ajax(this) works" ); + start(); + } + } + }); + +}); + test(".ajax() - headers" , function() { expect( 2 ); - + stop(); - + var requestHeaders = { siMPle: "value", "SometHing-elsE": "other value", @@ -291,11 +293,11 @@ test(".ajax() - headers" , function() { }, list = [], i; - + for( i in requestHeaders ) { list.push( i ); } - + jQuery.ajax(url("data/headers.php?keys="+list.join( "_" ) ), { headers: requestHeaders, success: function( data , _ , xhr ) { @@ -304,19 +306,77 @@ test(".ajax() - headers" , function() { tmp.push( i , ": " , requestHeaders[ i ] , "\n" ); } tmp = tmp.join( "" ); - + equals( data , tmp , "Headers were sent" ); equals( xhr.getResponseHeader( "Sample-Header" ) , "Hello World" , "Sample header received" ); start(); }, error: function(){ ok(false, "error"); } }); - + +}); + +test(".ajax() - Accept header" , function() { + + expect( 1 ); + + stop(); + + jQuery.ajax(url("data/headers.php?keys=accept"), { + headers: { + Accept: "very wrong accept value" + }, + beforeSend: function( xhr ) { + xhr.setRequestHeader( "Accept", "*/*" ); + }, + success: function( data ) { + strictEqual( data , "accept: */*\n" , "Test Accept header is set to last value provided" ); + start(); + }, + error: function(){ ok(false, "error"); } + }); + +}); + +test(".ajax() - contentType" , function() { + + expect( 2 ); + + stop(); + + var count = 2; + + function restart() { + if ( ! --count ) { + start(); + } + } + + jQuery.ajax(url("data/headers.php?keys=content-type" ), { + contentType: "test", + success: function( data ) { + strictEqual( data , "content-type: test\n" , "Test content-type is sent when options.contentType is set" ); + }, + complete: function() { + restart(); + } + }); + + jQuery.ajax(url("data/headers.php?keys=content-type" ), { + contentType: false, + success: function( data ) { + strictEqual( data , "content-type: \n" , "Test content-type is not sent when options.contentType===false" ); + }, + complete: function() { + restart(); + } + }); + }); test(".ajax() - hash", function() { expect(3); - + jQuery.ajax({ url: "data/name.html#foo", beforeSend: function( xhr, settings ) { @@ -324,7 +384,7 @@ test(".ajax() - hash", function() { return false; } }); - + jQuery.ajax({ url: "data/name.html?abc#foo", beforeSend: function( xhr, settings ) { @@ -332,7 +392,7 @@ test(".ajax() - hash", function() { return false; } }); - + jQuery.ajax({ url: "data/name.html?abc#foo", data: { "test": 123 }, @@ -343,10 +403,57 @@ test(".ajax() - hash", function() { }); }); +test("jQuery ajax - cross-domain detection", function() { + + expect( 4 ); + + var loc = document.location, + otherPort = loc.port === 666 ? 667 : 666, + otherProtocol = loc.protocol === "http:" ? "https:" : "http:"; + + jQuery.ajax({ + dataType: "jsonp", + url: otherProtocol + "//" + loc.host, + beforeSend: function( _ , s ) { + ok( s.crossDomain , "Test different protocols are detected as cross-domain" ); + return false; + } + }); + + jQuery.ajax({ + dataType: "jsonp", + url: loc.protocol + '//somewebsitethatdoesnotexist-656329477541.com:' + ( loc.port || 80 ), + beforeSend: function( _ , s ) { + ok( s.crossDomain , "Test different hostnames are detected as cross-domain" ); + return false; + } + }); + + jQuery.ajax({ + dataType: "jsonp", + url: loc.protocol + "//" + loc.hostname + ":" + otherPort, + beforeSend: function( _ , s ) { + ok( s.crossDomain , "Test different ports are detected as cross-domain" ); + return false; + } + }); + + jQuery.ajax({ + dataType: "jsonp", + url: loc.protocol + "//" + loc.host, + crossDomain: true, + beforeSend: function( _ , s ) { + ok( s.crossDomain , "Test forced crossDomain is detected as cross-domain" ); + return false; + } + }); + +}); + test(".ajax() - 304", function() { expect( 1 ); stop(); - + jQuery.ajax({ url: url("data/notmodified.php"), success: function(){ ok(true, "304 ok"); }, @@ -409,142 +516,12 @@ test("jQuery.ajax() - abort", function() { equals( xhr.readyState, 0, "XHR readyState indicates successful abortion" ); }); -test("jQuery.ajax() - readyState (success)", function() { - expect( 1 ); - - jQuery.ajaxSetup({ timeout: 0 }); - - stop(); - - var control = ""; - - setTimeout(function(){ - jQuery.ajax({ - url: url("data/name.html"), - beforeSend: function( xhr ) { - xhr.onreadystatechange = function() { - control += xhr.readyState; - } - }, - complete: function(){ - setTimeout( function() { - equals( control , "1234" , "onreadystatechange was properly called" ); - }, 13 ); - start(); - } - }); - }, 13); -}); - -test("jQuery.ajax() - readyState (abort)", function() { - expect( 2 ); - - jQuery.ajaxSetup({ timeout: 0 }); - - stop(); - - var control = ""; - - setTimeout(function(){ - - jQuery.ajaxSetup({ timeout: 500 }); - - jQuery.ajax({ - url: url("data/name.php?wait=5"), - beforeSend: function( xhr ) { - xhr.onreadystatechange = function() { - control += xhr.readyState; - } - }, - complete: function( xhr ){ - setTimeout( function() { - equals( control , "14" , "onreadystatechange was properly called" ); - equals( xhr.readyState, 0 , "readyState is 0" ); - }, 13 ); - start(); - } - }); - }, 13); -}); - -test("jQuery.xhr() - reuse", function() { - expect( 15 ); - - jQuery.ajaxSetup({ timeout: 0 }); - - stop(); - - var number = 0; - - setTimeout(function(){ - jQuery('#foo').ajaxStart(function(){ - ok( true, "ajaxStart" ); - }).ajaxStop(function(){ - ok( true, "ajaxStop" ); - start(); - }).ajaxSend(function(){ - number++; - ok( true, "ajaxSend (" + number +")" ); - }).ajaxComplete(function(){ - ok( true, "ajaxComplete (" + number +")" ); - }).ajaxError(function(){ - ok( false, "ajaxError (" + number +")" ); - }).ajaxSuccess(function(){ - ok( true, "ajaxSuccess (" + number +")" ); - }); - - jQuery.ajax({ - url: url("data/name.html"), - beforeSend: function(){ ok(true, "beforeSend (1)"); }, - success: function( _1 , _2 , xhr ){ - ok(true, "success (1)"); - xhr.complete(function() { - ok(true, "complete (1bis)"); - }); - xhr.open( "GET", url("data/name.html") ); - xhr.success( function(){ ok(true, "beforeSend (2)"); } ) - xhr.send( null, { - success: function(){ ok(true, "success (2)"); }, - error: function(){ ok(false, "error (2)"); }, - complete: function(){ ok(true, "complete (2)"); } - } ); - }, - error: function(){ ok(false, "error (1)"); }, - complete: function(){ ok(true, "complete (1)"); } - }); - }, 13); -}); - -test("jQuery.xhr() - early binding", function() { - expect( 2 ); - - jQuery.ajaxSetup({ timeout: 0 }); - - stop(); - - jQuery.xhr() - .success( function(){ ok(true, "success"); } ) - .error( function(){ ok(false, "error"); } ) - .complete( function(){ ok(true, "complete"); start(); } ) - .open( "GET", url("data/name.html") ) - .send(); -}); - -test("jQuery.xhr() - get native implementation", function() { - - var xhr = jQuery.xhr(true); - - ok( xhr.readyState !== undefined , "implements XMLHttpRequest" ); - ok( ! jQuery.isFunction( xhr.success ) , "is not jQuery's abstraction" ); - -}); - test("Ajax events with context", function() { expect(14); - + stop(); var context = document.createElement("div"); - + function event(e){ equals( this, context, e.type ); } @@ -560,7 +537,7 @@ test("Ajax events with context", function() { equals( typeof this.url, "string", "context is settings on callback " + msg ); }; } - + jQuery('#foo').add(context) .ajaxSend(event) .ajaxComplete(event) @@ -606,7 +583,7 @@ test("jQuery.ajax context modification", function() { stop(); - var obj = {} + var obj = {}; jQuery.ajax({ url: url("data/name.html"), @@ -622,6 +599,47 @@ test("jQuery.ajax context modification", function() { equals( obj.test, "foo", "Make sure the original object is maintained." ); }); +test("jQuery.ajax context modification through ajaxSetup", function() { + expect(4); + + stop(); + + var obj = {}; + + jQuery.ajaxSetup({ + context: obj + }); + + strictEqual( jQuery.ajaxSettings.context, obj, "Make sure the context is properly set in ajaxSettings." ); + + jQuery.ajax({ + url: url("data/name.html"), + complete: function() { + strictEqual( this, obj, "Make sure the original object is maintained." ); + jQuery.ajax({ + url: url("data/name.html"), + context: {}, + complete: function() { + ok( this !== obj, "Make sure overidding context is possible." ); + jQuery.ajaxSetup({ + context: false + }); + jQuery.ajax({ + url: url("data/name.html"), + beforeSend: function(){ + this.test = "foo2"; + }, + complete: function() { + ok( this !== obj, "Make sure unsetting context is possible." ); + start(); + } + }); + } + }); + } + }); +}); + test("jQuery.ajax() - disabled globals", function() { expect( 3 ); stop(); @@ -653,34 +671,6 @@ test("jQuery.ajax() - disabled globals", function() { }); }); -test("jQuery.xhr() - disabled globals through xhr.send(data , false)", function() { - expect( 2 ); - stop(); - - jQuery('#foo').ajaxStart(function(){ - ok( false, "ajaxStart" ); - }).ajaxStop(function(){ - ok( false, "ajaxStop" ); - }).ajaxSend(function(){ - ok( false, "ajaxSend" ); - }).ajaxComplete(function(){ - ok( false, "ajaxComplete" ); - }).ajaxError(function(){ - ok( false, "ajaxError" ); - }).ajaxSuccess(function(){ - ok( false, "ajaxSuccess" ); - }); - - jQuery.xhr() - .success(function(){ ok(true, "success"); }) - .error(function(){ ok(false, "error"); }) - .complete(function(){ - ok(true, "complete"); - setTimeout(function(){ start(); }, 13); - }) - .open("GET", url("data/name.html")).send(undefined, false); -}); - test("jQuery.ajax - xml: non-namespace elements inside namespaced elements", function() { expect(3); stop(); @@ -707,6 +697,10 @@ test("jQuery.ajax - xml: non-namespace elements inside namespaced elements (over equals( jQuery("jsconf", resp).length, 1, 'jsconf in responseXML' ); equals( jQuery("thing", resp).length, 2, 'things in responseXML' ); start(); + }, + error: function(_1,_2,error) { + ok( false, error ); + start(); } }); }); @@ -721,7 +715,7 @@ test("jQuery.ajax - HEAD requests", function() { success: function(data, status, xhr){ var h = xhr.getAllResponseHeaders(); ok( /Date/i.test(h), 'No Date in HEAD response' ); - + jQuery.ajax({ url: url("data/name.html"), data: { whip_it: "good" }, @@ -842,20 +836,20 @@ test("serialize()", function() { 'Check input serialization as query string'); equals( jQuery('#testForm').serialize(), - 'T3=%3F%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=', + 'T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=', 'Check form serialization as query string'); equals( jQuery('#testForm :input').serialize(), - 'T3=%3F%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=', + 'T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=', 'Check input serialization as query string'); equals( jQuery('#form, #testForm').serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", 'Multiple form serialization as query string'); /* Temporarily disabled. Opera 10 has problems with form serialization. equals( jQuery('#form, #testForm :input').serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&T3=%3F%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", 'Mixed form/input serialization as query string'); */ jQuery("#html5email, #html5number").remove(); @@ -863,9 +857,9 @@ test("serialize()", function() { test("jQuery.param()", function() { expect(22); - + equals( !jQuery.ajaxSettings.traditional, true, "traditional flag, falsy by default" ); - + var params = {foo:"bar", baz:42, quux:"All your base are belong to us"}; equals( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); @@ -880,13 +874,13 @@ test("jQuery.param()", function() { params = {foo: { bar: 'baz', beep: 42, quux: 'All your base are belong to us' } }; equals( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; equals( decodeURIComponent( jQuery.param(params) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=undefined&i[]=10&i[]=11&j=true&k=false&l[]=undefined&l[]=0&m=cowboy+hat?", "huge structure" ); - + params = { a: [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { b: [ 7, [ 8, 9 ], [ { c: 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { e: { f: { g: [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; equals( decodeURIComponent( jQuery.param(params) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); - + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; equals( jQuery.param(params,true), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=undefined&l=0&m=cowboy+hat%3F", "huge structure, forced traditional" ); @@ -898,7 +892,7 @@ test("jQuery.param()", function() { equals( jQuery.param({"foo": {"bar": {}} }), "foo%5Bbar%5D=", "Empty object param" ); jQuery.ajaxSetup({ traditional: true }); - + var params = {foo:"bar", baz:42, quux:"All your base are belong to us"}; equals( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); @@ -913,16 +907,16 @@ test("jQuery.param()", function() { params = {"foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us"}; equals( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; equals( jQuery.param(params), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=undefined&l=0&m=cowboy+hat%3F", "huge structure" ); - + params = { a: [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { b: [ 7, [ 8, 9 ], [ { c: 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { e: { f: { g: [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; equals( jQuery.param(params), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject+Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); - + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; equals( decodeURIComponent( jQuery.param(params,false) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=undefined&i[]=10&i[]=11&j=true&k=false&l[]=undefined&l[]=0&m=cowboy+hat?", "huge structure, forced not traditional" ); - + params = { param1: null }; equals( jQuery.param(params,false), "param1=null", "Make sure that null params aren't traversed." ); }); @@ -971,7 +965,7 @@ test("pass-through request object", function() { test("ajax cache", function () { expect(18); - + stop(); var count = 0; @@ -1094,6 +1088,18 @@ test("load(String, Function) - check file with only a script tag", function() { }); }); +test("load(String, Function) - dataFilter in ajaxSettings", function() { + expect(2); + stop(); + jQuery.ajaxSetup({ dataFilter: function() { return "Hello World"; } }); + var div = jQuery("<div/>").load(url("data/name.html"), function(responseText) { + strictEqual( div.html(), "Hello World" , "Test div was filled with filtered data" ); + strictEqual( responseText, "Hello World" , "Test callback receives filtered data" ); + jQuery.ajaxSetup({ dataFilter: 0 }); + start(); + }); +}); + test("load(String, Object, Function)", function() { expect(2); stop(); @@ -1149,217 +1155,249 @@ test("jQuery.getScript(String, Function) - no callback", function() { }); }); -test("jQuery.ajax() - JSONP, Local", function() { - expect(9); +jQuery.each( [ "Same Domain", "Cross Domain" ] , function( crossDomain , label ) { - var count = 0; - function plus(){ if ( ++count == 9 ) start(); } + test("jQuery.ajax() - JSONP, " + label, function() { + expect(17); - stop(); - - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (GET, no callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, no callback)" ); - plus(); - } - }); + var count = 0; + function plus(){ if ( ++count == 17 ) start(); } - jQuery.ajax({ - url: "data/jsonp.php?callback=?", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (GET, url callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, url callback)" ); - plus(); - } - }); + stop(); - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - data: "callback=?", - success: function(data){ - ok( data.data, "JSON results returned (GET, data callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, data callback)" ); - plus(); - } - }); - - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - jsonp: "callback", - success: function(data){ - ok( data.data, "JSON results returned (GET, data obj callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, data obj callback)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (GET, no callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, no callback)" ); + plus(); + } + }); - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - jsonpCallback: "jsonpResults", - success: function(data){ - ok( data.data, "JSON results returned (GET, custom callback name)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, custom callback name)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php?callback=?", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (GET, url callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, url callback)" ); + plus(); + } + }); - jQuery.ajax({ - type: "POST", - url: "data/jsonp.php", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (POST, no callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, data obj callback)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + data: "callback=?", + success: function(data){ + ok( data.data, "JSON results returned (GET, data callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, data callback)" ); + plus(); + } + }); - jQuery.ajax({ - type: "POST", - url: "data/jsonp.php", - data: "callback=?", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (POST, data callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (POST, data callback)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php?callback=??", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (GET, url context-free callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, url context-free callback)" ); + plus(); + } + }); - jQuery.ajax({ - type: "POST", - url: "data/jsonp.php", - jsonp: "callback", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (POST, data obj callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (POST, data obj callback)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + data: "callback=??", + success: function(data){ + ok( data.data, "JSON results returned (GET, data context-free callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, data context-free callback)" ); + plus(); + } + }); - //#7578 - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - beforeSend: function(){ - strictEqual( this.cache, false, "cache must be false on JSON request" ); - plus(); - return false; - } - }); -}); + jQuery.ajax({ + url: "data/jsonp.php/??", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (GET, REST-like)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, REST-like)" ); + plus(); + } + }); -test("jQuery.ajax() - JSONP - Custom JSONP Callback", function() { - expect(1); - stop(); + jQuery.ajax({ + url: "data/jsonp.php/???json=1", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + strictEqual( jQuery.type(data), "array", "JSON results returned (GET, REST-like with param)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, REST-like with param)" ); + plus(); + } + }); - window.jsonpResults = function(data) { - ok( data.data, "JSON results returned (GET, custom callback function)" ); - window.jsonpResults = undefined; - start(); - }; + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + data: { + callback: "?" + }, + success: function(data){ + ok( data.data, "JSON results returned (GET, processed data callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, processed data callback)" ); + plus(); + } + }); - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - jsonpCallback: "jsonpResults" - }); -}); + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonp: "callback", + success: function(data){ + ok( data.data, "JSON results returned (GET, data obj callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, data obj callback)" ); + plus(); + } + }); -test("jQuery.ajax() - JSONP, Remote", function() { - expect(4); + window.jsonpResults = function(data) { + ok( data.data, "JSON results returned (GET, custom callback function)" ); + window.jsonpResults = undefined; + plus(); + }; - var count = 0; - function plus(){ if ( ++count == 4 ) start(); } + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonpCallback: "jsonpResults", + success: function(data){ + ok( data.data, "JSON results returned (GET, custom callback name)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, custom callback name)" ); + plus(); + } + }); - var base = window.location.href.replace(/[^\/]*$/, ""); + jQuery.ajax({ + type: "POST", + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (POST, no callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, data obj callback)" ); + plus(); + } + }); - stop(); + jQuery.ajax({ + type: "POST", + url: "data/jsonp.php", + data: "callback=?", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (POST, data callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (POST, data callback)" ); + plus(); + } + }); - jQuery.ajax({ - url: base + "data/jsonp.php", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (GET, no callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, no callback)" ); - plus(); - } - }); + jQuery.ajax({ + type: "POST", + url: "data/jsonp.php", + jsonp: "callback", + dataType: "jsonp", + crossDomain: crossDomain, + success: function(data){ + ok( data.data, "JSON results returned (POST, data obj callback)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (POST, data obj callback)" ); + plus(); + } + }); - jQuery.ajax({ - url: base + "data/jsonp.php?callback=?", - dataType: "jsonp", - success: function(data){ - ok( data.data, "JSON results returned (GET, url callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, url callback)" ); - plus(); - } - }); + //#7578 + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + beforeSend: function(){ + strictEqual( this.cache, false, "cache must be false on JSON request" ); + plus(); + return false; + } + }); - jQuery.ajax({ - url: base + "data/jsonp.php", - dataType: "jsonp", - data: "callback=?", - success: function(data){ - ok( data.data, "JSON results returned (GET, data callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, data callback)" ); - plus(); - } - }); + jQuery.ajax({ + url: "data/jsonp.php?callback=XXX", + dataType: "jsonp", + jsonp: false, + jsonpCallback: "XXX", + crossDomain: crossDomain, + beforeSend: function() { + ok( /^data\/jsonp.php\?callback=XXX&_=\d+$/.test( this.url ) , + "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); + plus(); + }, + success: function(data){ + ok( data.data, "JSON results returned (GET, custom callback name with no url manipulation)" ); + plus(); + }, + error: function(data){ + ok( false, "Ajax error JSON (GET, custom callback name with no url manipulation)" ); + plus(); + } + }); - jQuery.ajax({ - url: base + "data/jsonp.php", - dataType: "jsonp", - jsonp: "callback", - success: function(data){ - ok( data.data, "JSON results returned (GET, data obj callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, data obj callback)" ); - plus(); - } }); }); @@ -1384,7 +1422,7 @@ test("jQuery.ajax() - script, Remote with POST", function() { expect(3); var base = window.location.href.replace(/[^\/]*$/, ""); - + stop(); jQuery.ajax({ @@ -1482,12 +1520,12 @@ test("jQuery.ajax() - json by content-type disabled with options", function() { jQuery.ajax({ url: url("data/json.php"), data: { header: "json", json: "array" }, - autoDataType: { + contents: { json: false }, success: function( text ) { equals( typeof text , "string" , "json wasn't auto-determined" ); - var json = this.dataConverters["text => json"]( text ); + var json = jQuery.parseJSON( text ); ok( json.length >= 2, "Check length"); equals( json[0].name, 'John', 'Check JSON: first, name' ); equals( json[0].age, 21, 'Check JSON: first, age' ); @@ -1525,7 +1563,7 @@ test("jQuery.getJSON(String, Function) - JSON object", function() { test("jQuery.getJSON - Using Native JSON", function() { expect(2); - + var old = window.JSON; JSON = { parse: function(str){ @@ -1714,7 +1752,7 @@ test("data option: evaluate function values (#2806)", function() { equals( result, "key=value" ); start(); } - }) + }); }); test("data option: empty bodies for non-GET requests", function() { @@ -1727,7 +1765,7 @@ test("data option: empty bodies for non-GET requests", function() { equals( result, "" ); start(); } - }) + }); }); test("jQuery.ajax - If-Modified-Since support", function() { @@ -1740,19 +1778,19 @@ test("jQuery.ajax - If-Modified-Since support", function() { jQuery.ajax({ url: url, ifModified: true, - success: function(data, status) { + success: function(data, status) { equals(status, "success"); - + jQuery.ajax({ url: url, ifModified: true, - success: function(data, status) { + success: function(data, status) { if ( data === "FAIL" ) { ok(true, "Opera is incapable of doing .setRequestHeader('If-Modified-Since')."); ok(true, "Opera is incapable of doing .setRequestHeader('If-Modified-Since')."); } else { equals(status, "notmodified"); - ok(data == null, "response body should be empty") + ok(data == null, "response body should be empty"); } start(); }, @@ -1787,19 +1825,19 @@ test("jQuery.ajax - Etag support", function() { jQuery.ajax({ url: url, ifModified: true, - success: function(data, status) { + success: function(data, status) { equals(status, "success"); - + jQuery.ajax({ url: url, ifModified: true, - success: function(data, status) { + success: function(data, status) { if ( data === "FAIL" ) { ok(true, "Opera is incapable of doing .setRequestHeader('If-None-Match')."); ok(true, "Opera is incapable of doing .setRequestHeader('If-None-Match')."); } else { equals(status, "notmodified"); - ok(data == null, "response body should be empty") + ok(data == null, "response body should be empty"); } start(); }, @@ -1826,42 +1864,38 @@ test("jQuery.ajax - Etag support", function() { test("jQuery ajax - failing cross-domain", function() { expect( 2 ); - + stop(); - + var i = 2; - + jQuery.ajax({ - url: 'http://somewebsitethatdoesnotexist.com', + url: 'http://somewebsitethatdoesnotexist-67864863574657654.com', success: function(){ ok( false , "success" ); }, error: function(xhr,_,e){ ok( true , "file not found: " + xhr.status + " => " + e ); }, complete: function() { if ( ! --i ) start(); } }); - + jQuery.ajax({ url: 'http://www.google.com', success: function(){ ok( false , "success" ); }, error: function(xhr,_,e){ ok( true , "access denied: " + xhr.status + " => " + e ); }, complete: function() { if ( ! --i ) start(); } }); - + }); test("jQuery ajax - atom+xml", function() { stop(); - + jQuery.ajax({ url: url( 'data/atom+xml.php' ), success: function(){ ok( true , "success" ); }, error: function(){ ok( false , "error" ); }, complete: function() { start(); } }); - -}); -test("jQuery.ajax - active counter", function() { - ok( jQuery.active == 0, "ajax active counter should be zero: " + jQuery.active ); }); test( "jQuery.ajax - Location object as url (#7531)", 1, function () { @@ -1875,6 +1909,150 @@ test( "jQuery.ajax - Location object as url (#7531)", 1, function () { ok( success, "document.location did not generate exception" ); }); +test( "jQuery.ajax - statusCode" , function() { + + var count = 12; + + expect( 20 ); + stop(); + + function countComplete() { + if ( ! --count ) { + start(); + } + } + + function createStatusCodes( name , isSuccess ) { + name = "Test " + name + " " + ( isSuccess ? "success" : "error" ); + return { + 200: function() { + ok( isSuccess , name ); + }, + 404: function() { + ok( ! isSuccess , name ); + } + }; + } + + jQuery.each( { + "data/name.html": true, + "data/someFileThatDoesNotExist.html": false + } , function( uri , isSuccess ) { + + jQuery.ajax( url( uri ) , { + statusCode: createStatusCodes( "in options" , isSuccess ), + complete: countComplete + }); + + jQuery.ajax( url( uri ) , { + complete: countComplete + }).statusCode( createStatusCodes( "immediately with method" , isSuccess ) ); + + jQuery.ajax( url( uri ) , { + complete: function(jXHR) { + jXHR.statusCode( createStatusCodes( "on complete" , isSuccess ) ); + countComplete(); + } + }); + + jQuery.ajax( url( uri ) , { + complete: function(jXHR) { + setTimeout( function() { + jXHR.statusCode( createStatusCodes( "very late binding" , isSuccess ) ); + countComplete(); + } , 100 ); + } + }); + + jQuery.ajax( url( uri ) , { + statusCode: createStatusCodes( "all (options)" , isSuccess ), + complete: function(jXHR) { + jXHR.statusCode( createStatusCodes( "all (on complete)" , isSuccess ) ); + setTimeout( function() { + jXHR.statusCode( createStatusCodes( "all (very late binding)" , isSuccess ) ); + countComplete(); + } , 100 ); + } + }).statusCode( createStatusCodes( "all (immediately with method)" , isSuccess ) ); + + var testString = ""; + + jQuery.ajax( url( uri ), { + success: function( a , b , jXHR ) { + ok( isSuccess , "success" ); + var statusCode = {}; + statusCode[ jXHR.status ] = function() { + testString += "B"; + }; + jXHR.statusCode( statusCode ); + testString += "A"; + }, + error: function( jXHR ) { + ok( ! isSuccess , "error" ); + var statusCode = {}; + statusCode[ jXHR.status ] = function() { + testString += "B"; + }; + jXHR.statusCode( statusCode ); + testString += "A"; + }, + complete: function() { + strictEqual( testString , "AB" , "Test statusCode callbacks are ordered like " + + ( isSuccess ? "success" : "error" ) + " callbacks" ); + countComplete(); + } + } ); + + }); +}); + +test("jQuery.ajax - transitive conversions", function() { + + expect( 8 ); + + stop(); + + jQuery.when( + + jQuery.ajax( url("data/json.php") , { + converters: { + "json myjson": function( data ) { + ok( true , "converter called" ); + return data; + } + }, + dataType: "myjson", + success: function() { + ok( true , "Transitive conversion worked" ); + strictEqual( this.dataTypes[0] , "text" , "response was retrieved as text" ); + strictEqual( this.dataTypes[1] , "myjson" , "request expected myjson dataType" ); + } + }), + + jQuery.ajax( url("data/json.php") , { + converters: { + "json myjson": function( data ) { + ok( true , "converter called (*)" ); + return data; + } + }, + contents: false, /* headers are wrong so we ignore them */ + dataType: "* myjson", + success: function() { + ok( true , "Transitive conversion worked (*)" ); + strictEqual( this.dataTypes[0] , "text" , "response was retrieved as text (*)" ); + strictEqual( this.dataTypes[1] , "myjson" , "request expected myjson dataType (*)" ); + } + }) + + ).then( start , start ); + +}); + +test("jQuery.ajax - active counter", function() { + ok( jQuery.active == 0, "ajax active counter should be zero: " + jQuery.active ); +}); + } //}
\ No newline at end of file diff --git a/test/unit/attributes.js b/test/unit/attributes.js index f9506b30b..c58111de1 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -1,16 +1,16 @@ -module("attributes"); +module("attributes", { teardown: moduleTeardown }); var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; test("jQuery.props: itegrity test", function() { - + expect(1); - + // This must be maintained and equal jQuery.props - // Ensure that accidental or erroneous property + // Ensure that accidental or erroneous property // overwrites don't occur - // This is simply for better code coverage and future proofing. + // This is simply for better code coverage and future proofing. var propsShouldBe = { "for": "htmlFor", "class": "className", @@ -23,7 +23,7 @@ test("jQuery.props: itegrity test", function() { usemap: "useMap", frameborder: "frameBorder" }; - + same(propsShouldBe, jQuery.props, "jQuery.props passes integrity check"); }); @@ -33,7 +33,7 @@ test("attr(String)", function() { // This one sometimes fails randomly ?! equals( jQuery('#text1').attr('value'), "Test", 'Check for value attribute' ); - + equals( jQuery('#text1').attr('value', "Test2").attr('defaultValue'), "Test", 'Check for defaultValue attribute' ); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -255,30 +255,30 @@ test("attr(String, Object)", function() { test("attr(jquery_method)", function(){ expect(7); - + var $elem = jQuery("<div />"), elem = $elem[0]; - - // one at a time + + // one at a time $elem.attr({'html': 'foo'}, true); equals( elem.innerHTML, 'foo', 'attr(html)'); - + $elem.attr({'text': 'bar'}, true); equals( elem.innerHTML, 'bar', 'attr(text)'); - + $elem.attr({'css': {color:'red'}}, true); ok( /^(#ff0000|red)$/i.test(elem.style.color), 'attr(css)'); - + $elem.attr({'height': 10}, true); equals( elem.style.height, '10px', 'attr(height)'); - + // Multiple attributes - + $elem.attr({ width:10, css:{ paddingLeft:1, paddingRight:1 } }, true); - + equals( elem.style.width, '10px', 'attr({...})'); equals( elem.style.paddingLeft, '1px', 'attr({...})'); equals( elem.style.paddingRight, '1px', 'attr({...})'); @@ -491,7 +491,7 @@ test( "val(Array of Numbers) (Bug #7123)", function() { ok( elements[1].checked, "Second element was checked" ); ok( !elements[2].checked, "Third element was unchecked" ); ok( !elements[3].checked, "Fourth element remained unchecked" ); - + elements.remove(); }); @@ -672,7 +672,7 @@ test("removeClass(Function) with incoming value", function() { ok( !$divs.is('.test'), "Remove Class" ); - QUnit.reset(); + QUnit.reset(); }); var testToggleClass = function(valueObj) { @@ -703,12 +703,12 @@ var testToggleClass = function(valueObj) { // toggleClass storage e.toggleClass(true); - ok( e.get(0).className === "", "Assert class is empty (data was empty)" ); + ok( e[0].className === "", "Assert class is empty (data was empty)" ); e.addClass("testD testE"); ok( e.is(".testD.testE"), "Assert class present" ); e.toggleClass(); ok( !e.is(".testD.testE"), "Assert class not present" ); - ok( e.data('__className__') === 'testD testE', "Assert data was stored" ); + ok( jQuery._data(e[0], '__className__') === 'testD testE', "Assert data was stored" ); e.toggleClass(); ok( e.is(".testD.testE"), "Assert class present (restored from data)" ); e.toggleClass(false); @@ -720,11 +720,9 @@ var testToggleClass = function(valueObj) { e.toggleClass(); ok( e.is(".testD.testE"), "Assert class present (restored from data)" ); - - // Cleanup e.removeClass("testD"); - e.removeData('__className__'); + jQuery.removeData(e[0], '__className__', true); }; test("toggleClass(String|boolean|undefined[, boolean])", function() { @@ -740,21 +738,21 @@ test("toggleClass(Fucntion[, boolean]) with incoming value", function() { var e = jQuery("#firstp"), old = e.attr("class"); ok( !e.is(".test"), "Assert class not present" ); - + e.toggleClass(function(i, val) { equals( val, old, "Make sure the incoming value is correct." ); return "test"; }); ok( e.is(".test"), "Assert class present" ); - + old = e.attr("class"); - + e.toggleClass(function(i, val) { equals( val, old, "Make sure the incoming value is correct." ); return "test"; }); ok( !e.is(".test"), "Assert class not present" ); - + old = e.attr("class"); // class name with a boolean @@ -764,18 +762,18 @@ test("toggleClass(Fucntion[, boolean]) with incoming value", function() { return "test"; }, false ); ok( !e.is(".test"), "Assert class not present" ); - + old = e.attr("class"); - + e.toggleClass(function(i, val, state) { equals( val, old, "Make sure the incoming value is correct." ); equals( state, true, "Make sure that the state is passed in." ); return "test"; }, true ); ok( e.is(".test"), "Assert class present" ); - + old = e.attr("class"); - + e.toggleClass(function(i, val, state) { equals( val, old, "Make sure the incoming value is correct." ); equals( state, false, "Make sure that the state is passed in." ); @@ -785,30 +783,30 @@ test("toggleClass(Fucntion[, boolean]) with incoming value", function() { // Cleanup e.removeClass("test"); - e.removeData('__className__'); + jQuery.removeData(e[0], '__className__', true); }); test("addClass, removeClass, hasClass", function() { expect(17); - + var jq = jQuery("<p>Hi</p>"), x = jq[0]; - + jq.addClass("hi"); equals( x.className, "hi", "Check single added class" ); - + jq.addClass("foo bar"); equals( x.className, "hi foo bar", "Check more added classes" ); - + jq.removeClass(); equals( x.className, "", "Remove all classes" ); - + jq.addClass("hi foo bar"); jq.removeClass("foo"); equals( x.className, "hi bar", "Check removal of one class" ); - + ok( jq.hasClass("hi"), "Check has1" ); ok( jq.hasClass("bar"), "Check has2" ); - + var jq = jQuery("<p class='class1\nclass2\tcla.ss3\n\rclass4'></p>"); ok( jq.hasClass("class1"), "Check hasClass with line feed" ); ok( jq.is(".class1"), "Check is with line feed" ); @@ -817,7 +815,7 @@ test("addClass, removeClass, hasClass", function() { ok( jq.hasClass("cla.ss3"), "Check hasClass with dot" ); ok( jq.hasClass("class4"), "Check hasClass with carriage return" ); ok( jq.is(".class4"), "Check is with carriage return" ); - + jq.removeClass("class2"); ok( jq.hasClass("class2")==false, "Check the class has been properly removed" ); jq.removeClass("cla"); diff --git a/test/unit/core.js b/test/unit/core.js index 9f9078a49..7638554ac 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1,4 +1,4 @@ -module("core"); +module("core", { teardown: moduleTeardown }); test("Basic requirements", function() { expect(7); @@ -12,7 +12,7 @@ test("Basic requirements", function() { }); test("jQuery()", function() { - expect(23); + expect(24); // Basic constructor's behavior @@ -21,7 +21,7 @@ test("jQuery()", function() { equals( jQuery(null).length, 0, "jQuery(null) === jQuery([])" ); equals( jQuery("").length, 0, "jQuery('') === jQuery([])" ); - var obj = jQuery("div") + var obj = jQuery("div"); equals( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); // can actually yield more than one, when iframes are included, the window is an array as well @@ -84,6 +84,17 @@ test("jQuery()", function() { exec = true; elem.click(); + + // manually clean up detached elements + elem.remove(); + + for ( var i = 0; i < 3; ++i ) { + elem = jQuery("<input type='text' value='TEST' />"); + } + equals( elem[0].defaultValue, "TEST", "Ensure cached nodes are cloned properly (Bug #6655)" ); + + // manually clean up detached elements + elem.remove(); }); test("selector state", function() { @@ -151,7 +162,7 @@ test("selector state", function() { test = jQuery("#main").eq(0); equals( test.selector, "#main.slice(0,1)", "#main eq Selector" ); equals( test.context, document, "#main eq Context" ); - + var d = "<div />"; equals( jQuery(d).appendTo(jQuery(d)).selector, @@ -253,38 +264,38 @@ test("isPlainObject", function() { // The use case that we want to match ok(jQuery.isPlainObject({}), "{}"); - + // Not objects shouldn't be matched ok(!jQuery.isPlainObject(""), "string"); ok(!jQuery.isPlainObject(0) && !jQuery.isPlainObject(1), "number"); ok(!jQuery.isPlainObject(true) && !jQuery.isPlainObject(false), "boolean"); ok(!jQuery.isPlainObject(null), "null"); ok(!jQuery.isPlainObject(undefined), "undefined"); - + // Arrays shouldn't be matched ok(!jQuery.isPlainObject([]), "array"); - + // Instantiated objects shouldn't be matched ok(!jQuery.isPlainObject(new Date), "new Date"); - + var fn = function(){}; - + // Functions shouldn't be matched ok(!jQuery.isPlainObject(fn), "fn"); - + // Again, instantiated objects shouldn't be matched ok(!jQuery.isPlainObject(new fn), "new fn (no methods)"); - + // Makes the function a little more realistic // (and harder to detect, incidentally) fn.prototype = {someMethod: function(){}}; - + // Again, instantiated objects shouldn't be matched ok(!jQuery.isPlainObject(new fn), "new fn"); // DOM Element ok(!jQuery.isPlainObject(document.createElement("div")), "DOM Element"); - + // Window ok(!jQuery.isPlainObject(window), "window"); @@ -298,7 +309,7 @@ test("isPlainObject", function() { document.body.removeChild( iframe ); start(); }; - + var doc = iframe.contentDocument || iframe.contentWindow.document; doc.open(); doc.write("<body onload='window.parent.iframeDone(Object);'>"); @@ -659,7 +670,7 @@ test("jQuery.merge()", function() { // Fixed at [5998], #3641 same( parse([-2,-1], [0,1,2]), [-2,-1,0,1,2], "Second array including a zero (falsy)"); - + // After fixing #5527 same( parse([], [null, undefined]), [null, undefined], "Second array including null and undefined values"); same( parse({length:0}, [1,2]), {length:2, 0:1, 1:2}, "First array like"); @@ -694,7 +705,7 @@ test("jQuery.extend(Object, Object)", function() { equals( deep1.foo2, document, "Make sure that a deep clone was not attempted on the document" ); ok( jQuery.extend(true, {}, nestedarray).arr !== arr, "Deep extend of object must clone child array" ); - + // #5991 ok( jQuery.isArray( jQuery.extend(true, { arr: {} }, nestedarray).arr ), "Cloned array heve to be an Array" ); ok( jQuery.isPlainObject( jQuery.extend(true, { arr: arr }, { arr: {} }).arr ), "Cloned object heve to be an plain object" ); @@ -715,13 +726,13 @@ test("jQuery.extend(Object, Object)", function() { empty = {}; jQuery.extend(true, empty, optionsWithCustomObject); ok( empty.foo && empty.foo.date === customObject, "Custom objects copy correctly (no methods)" ); - + // Makes the class a little more realistic myKlass.prototype = { someMethod: function(){} }; empty = {}; jQuery.extend(true, empty, optionsWithCustomObject); ok( empty.foo && empty.foo.date === customObject, "Custom objects copy correctly" ); - + var ret = jQuery.extend(true, { foo: 4 }, { foo: new Number(5) } ); ok( ret.foo == 5, "Wrapped numbers copy correctly" ); @@ -849,10 +860,10 @@ test("jQuery.makeArray", function(){ test("jQuery.isEmptyObject", function(){ expect(2); - + equals(true, jQuery.isEmptyObject({}), "isEmptyObject on empty object literal" ); equals(false, jQuery.isEmptyObject({a:1}), "isEmptyObject on non-empty object literal" ); - + // What about this ? // equals(true, jQuery.isEmptyObject(null), "isEmptyObject on null" ); }); @@ -883,23 +894,23 @@ test("jQuery.proxy", function(){ test("jQuery.parseJSON", function(){ expect(8); - + equals( jQuery.parseJSON(), null, "Nothing in, null out." ); equals( jQuery.parseJSON( null ), null, "Nothing in, null out." ); equals( jQuery.parseJSON( "" ), null, "Nothing in, null out." ); - + same( jQuery.parseJSON("{}"), {}, "Plain object parsing." ); same( jQuery.parseJSON('{"test":1}'), {"test":1}, "Plain object parsing." ); same( jQuery.parseJSON('\n{"test":1}'), {"test":1}, "Make sure leading whitespaces are handled." ); - + try { jQuery.parseJSON("{a:1}"); ok( false, "Test malformed JSON string." ); } catch( e ) { ok( true, "Test malformed JSON string." ); } - + try { jQuery.parseJSON("{'a':1}"); ok( false, "Test malformed JSON string." ); @@ -907,3 +918,290 @@ test("jQuery.parseJSON", function(){ ok( true, "Test malformed JSON string." ); } }); + +test("jQuery._Deferred()", function() { + + expect( 10 ); + + var deferred, + object, + test; + + deferred = jQuery._Deferred(); + + test = false; + + deferred.done( function( value ) { + equals( value , "value" , "Test pre-resolve callback" ); + test = true; + } ); + + deferred.resolve( "value" ); + + ok( test , "Test pre-resolve callbacks called right away" ); + + test = false; + + deferred.done( function( value ) { + equals( value , "value" , "Test post-resolve callback" ); + test = true; + } ); + + ok( test , "Test post-resolve callbacks called right away" ); + + deferred.cancel(); + + test = true; + + deferred.done( function() { + ok( false , "Cancel was ignored" ); + test = false; + } ); + + ok( test , "Test cancel" ); + + deferred = jQuery._Deferred().resolve(); + + try { + deferred.done( function() { + throw "Error"; + } , function() { + ok( true , "Test deferred do not cancel on exception" ); + } ); + } catch( e ) { + strictEqual( e , "Error" , "Test deferred propagates exceptions"); + deferred.done(); + } + + test = ""; + deferred = jQuery._Deferred().done( function() { + + test += "A"; + + }, function() { + + test += "B"; + + } ).resolve(); + + strictEqual( test , "AB" , "Test multiple done parameters" ); + + test = ""; + + deferred.done( function() { + + deferred.done( function() { + + test += "C"; + + } ); + + test += "A"; + + }, function() { + + test += "B"; + } ); + + strictEqual( test , "ABC" , "Test done callbacks order" ); + + deferred = jQuery._Deferred(); + + deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) { + ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" ); + }); +}); + +test("jQuery.Deferred()", function() { + + expect( 10 ); + + jQuery.Deferred( function( defer ) { + strictEqual( this , defer , "Defer passed as this & first argument" ); + this.resolve( "done" ); + }).then( function( value ) { + strictEqual( value , "done" , "Passed function executed" ); + }); + + jQuery.Deferred().resolve().then( function() { + ok( true , "Success on resolve" ); + }, function() { + ok( false , "Error on resolve" ); + }); + + jQuery.Deferred().reject().then( function() { + ok( false , "Success on reject" ); + }, function() { + ok( true , "Error on reject" ); + }); + + ( new jQuery.Deferred( function( defer ) { + strictEqual( this , defer , "Defer passed as this & first argument (new)" ); + this.resolve( "done" ); + }) ).then( function( value ) { + strictEqual( value , "done" , "Passed function executed (new)" ); + }); + + ( new jQuery.Deferred() ).resolve().then( function() { + ok( true , "Success on resolve (new)" ); + }, function() { + ok( false , "Error on resolve (new)" ); + }); + + ( new jQuery.Deferred() ).reject().then( function() { + ok( false , "Success on reject (new)" ); + }, function() { + ok( true , "Error on reject (new)" ); + }); + + var tmp = jQuery.Deferred(); + + strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" ); + strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" ); +}); + +test("jQuery.when()", function() { + + expect( 23 ); + + // Some other objects + jQuery.each( { + + "an empty string": "", + "a non-empty string": "some string", + "zero": 0, + "a number other than zero": 1, + "true": true, + "false": false, + "null": null, + "undefined": undefined, + "a plain object": {} + + } , function( message , value ) { + + ok( jQuery.isFunction( jQuery.when( value ).then( function( resolveValue ) { + strictEqual( resolveValue , value , "Test the promise was resolved with " + message ); + } ).promise ) , "Test " + message + " triggers the creation of a new Promise" ); + + } ); + + ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) { + strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" ); + } ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" ); + + var cache, i; + + for( i = 1 ; i < 4 ; i++ ) { + jQuery.when( cache || jQuery.Deferred( function() { + this.resolve( i ); + }) ).then( function( value ) { + strictEqual( value , 1 , "Function executed" + ( i > 1 ? " only once" : "" ) ); + cache = value; + }, function() { + ok( false , "Fail called" ); + }); + } +}); + +test("jQuery.when() - joined", function() { + + expect(8); + + jQuery.when( 1, 2, 3 ).done( function( a, b, c ) { + strictEqual( a , 1 , "Test first param is first resolved value - non-observables" ); + strictEqual( b , 2 , "Test second param is second resolved value - non-observables" ); + strictEqual( c , 3 , "Test third param is third resolved value - non-observables" ); + }).fail( function() { + ok( false , "Test the created deferred was resolved - non-observables"); + }); + + var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ), + errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" ); + + jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) { + strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" ); + same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" ); + strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" ); + }).fail( function() { + ok( false , "Test the created deferred was resolved - resolved observable"); + }); + + jQuery.when( 1 , errorDeferred , 3 ).done( function() { + ok( false , "Test the created deferred was rejected - rejected observable"); + }).fail( function( error , errorParam ) { + strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" ); + strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" ); + }); +}); + +test("jQuery.subclass", function(){ + expect(378); + + var Subclass = jQuery.subclass(), + SubclassSubclass = Subclass.subclass(), + jQueryDocument = jQuery(document), + selectors, contexts, methods, method, arg, description; + + jQueryDocument.toString = function(){ return 'jQueryDocument'; }; + + Subclass.fn.subclassMethod = function(){}; + SubclassSubclass.fn.subclassSubclassMethod = function(){}; + + selectors = [ + 'body', + 'html, body', + '<div></div>' + ]; + + methods = [ // all methods that return a new jQuery instance + ['eq', 1], + ['add', document], + ['end'], + ['has'], + ['closest', 'div'], + ['filter', document], + ['find', 'div'] + ]; + + contexts = [undefined, document, jQueryDocument]; + + jQuery.each(selectors, function(i, selector){ + + jQuery.each(methods, function(){ + method = this[0]; + arg = this[1]; + + jQuery.each(contexts, function(i, context){ + + description = '("'+selector+'", '+context+').'+method+'('+(arg||'')+')'; + + same( + jQuery(selector, context)[method](arg).subclassMethod, undefined, + 'jQuery'+description+' doesnt have Subclass methods' + ); + same( + jQuery(selector, context)[method](arg).subclassSubclassMethod, undefined, + 'jQuery'+description+' doesnt have SubclassSubclass methods' + ); + same( + Subclass(selector, context)[method](arg).subclassMethod, Subclass.fn.subclassMethod, + 'Subclass'+description+' has Subclass methods' + ); + same( + Subclass(selector, context)[method](arg).subclassSubclassMethod, undefined, + 'Subclass'+description+' doesnt have SubclassSubclass methods' + ); + same( + SubclassSubclass(selector, context)[method](arg).subclassMethod, Subclass.fn.subclassMethod, + 'SubclassSubclass'+description+' has Subclass methods' + ); + same( + SubclassSubclass(selector, context)[method](arg).subclassSubclassMethod, SubclassSubclass.fn.subclassSubclassMethod, + 'SubclassSubclass'+description+' has SubclassSubclass methods' + ); + + }); + }); + }); + +}); diff --git a/test/unit/css.js b/test/unit/css.js index cddd90256..555f13575 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1,4 +1,4 @@ -module("css"); +module("css", { teardown: moduleTeardown }); test("css(String|Hash)", function() { expect(41); @@ -178,24 +178,24 @@ if ( !jQuery.support.opacity ) { test("css(String, Function)", function() { expect(3); - + var sizes = ["10px", "20px", "30px"]; - - jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + - "<div class='cssFunction'></div>" + + + jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + + "<div class='cssFunction'></div>" + "<div class='cssFunction'></div></div>") .appendTo("body"); - + var index = 0; - + jQuery("#cssFunctionTest div").css("font-size", function() { var size = sizes[index]; index++; return size; }); - + index = 0; - + jQuery("#cssFunctionTest div").each(function() { var computedSize = jQuery(this).css("font-size") var expectedSize = sizes[index] @@ -208,24 +208,24 @@ test("css(String, Function)", function() { test("css(String, Function) with incoming value", function() { expect(3); - + var sizes = ["10px", "20px", "30px"]; - - jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + - "<div class='cssFunction'></div>" + + + jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + + "<div class='cssFunction'></div>" + "<div class='cssFunction'></div></div>") .appendTo("body"); - + var index = 0; - + jQuery("#cssFunctionTest div").css("font-size", function() { var size = sizes[index]; index++; return size; }); - + index = 0; - + jQuery("#cssFunctionTest div").css("font-size", function(i, computedSize) { var expectedSize = sizes[index] equals( computedSize, expectedSize, "Div #" + index + " should be " + expectedSize ); @@ -238,61 +238,61 @@ test("css(String, Function) with incoming value", function() { test("css(Object) where values are Functions", function() { expect(3); - + var sizes = ["10px", "20px", "30px"]; - - jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + - "<div class='cssFunction'></div>" + + + jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + + "<div class='cssFunction'></div>" + "<div class='cssFunction'></div></div>") .appendTo("body"); var index = 0; - + jQuery("#cssFunctionTest div").css({fontSize: function() { var size = sizes[index]; index++; return size; }}); - + index = 0; - + jQuery("#cssFunctionTest div").each(function() { var computedSize = jQuery(this).css("font-size") var expectedSize = sizes[index] equals( computedSize, expectedSize, "Div #" + index + " should be " + expectedSize ); index++; }); - + jQuery("#cssFunctionTest").remove(); }); test("css(Object) where values are Functions with incoming values", function() { expect(3); - + var sizes = ["10px", "20px", "30px"]; - - jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + - "<div class='cssFunction'></div>" + + + jQuery("<div id='cssFunctionTest'><div class='cssFunction'></div>" + + "<div class='cssFunction'></div>" + "<div class='cssFunction'></div></div>") .appendTo("body"); var index = 0; - + jQuery("#cssFunctionTest div").css({fontSize: function() { var size = sizes[index]; index++; return size; }}); - + index = 0; - + jQuery("#cssFunctionTest div").css({"font-size": function(i, computedSize) { var expectedSize = sizes[index] equals( computedSize, expectedSize, "Div #" + index + " should be " + expectedSize ); index++; return computedSize; }}); - + jQuery("#cssFunctionTest").remove(); }); @@ -320,3 +320,16 @@ test(":visible selector works properly on children with a hidden parent (bug #45 jQuery('#table').css('display', 'none').html('<tr><td>cell</td><td>cell</td></tr>'); equals(jQuery('#table td:visible').length, 0, "hidden cell children not perceived as visible"); }); + +test("internal ref to elem.runtimeStyle (bug #7608)", function () { + expect(1); + var result = true; + + try { + jQuery("#foo").css( { width: "0%" } ).css("width"); + } catch (e) { + result = false; + } + + ok( result, "elem.runtimeStyle does not throw exception" ); +}); diff --git a/test/unit/data.js b/test/unit/data.js index 1a0f84c1f..889fc2da3 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -1,22 +1,159 @@ -module("data"); +module("data", { teardown: moduleTeardown }); test("expando", function(){ - expect(6); + expect(1); equals("expando" in jQuery, true, "jQuery is exposing the expando"); +}); - var obj = {}; - equals( jQuery.data(obj), obj, "jQuery.data(obj) returns the object"); - equals( jQuery.expando in obj, false, "jQuery.data(obj) did not add an expando to the object" ); +function dataTests (elem) { + // expect(32) + + function getCacheLength() { + var cacheLength = 0; + for (var i in jQuery.cache) { + ++cacheLength; + } + + return cacheLength; + } + + equals( jQuery.data(elem, "foo"), undefined, "No data exists initially" ); + strictEqual( jQuery.hasData(elem), false, "jQuery.hasData agrees no data exists initially" ); + + var dataObj = jQuery.data(elem); + equals( typeof dataObj, "object", "Calling data with no args gives us a data object reference" ); + strictEqual( jQuery.data(elem), dataObj, "Calling jQuery.data returns the same data object when called multiple times" ); + + strictEqual( jQuery.hasData(elem), false, "jQuery.hasData agrees no data exists even when an empty data obj exists" ); + + dataObj.foo = "bar"; + equals( jQuery.data(elem, "foo"), "bar", "Data is readable by jQuery.data when set directly on a returned data object" ); + + strictEqual( jQuery.hasData(elem), true, "jQuery.hasData agrees data exists when data exists" ); + + jQuery.data(elem, "foo", "baz"); + equals( jQuery.data(elem, "foo"), "baz", "Data can be changed by jQuery.data" ); + equals( dataObj.foo, "baz", "Changes made through jQuery.data propagate to referenced data object" ); + + jQuery.data(elem, "foo", undefined); + equals( jQuery.data(elem, "foo"), "baz", "Data is not unset by passing undefined to jQuery.data" ); + + jQuery.data(elem, "foo", null); + strictEqual( jQuery.data(elem, "foo"), null, "Setting null using jQuery.data works OK" ); + + jQuery.data(elem, "foo", "foo1"); + + jQuery.data(elem, { "bar" : "baz", "boom" : "bloz" }); + strictEqual( jQuery.data(elem, "foo"), "foo1", "Passing an object extends the data object instead of replacing it" ); + equals( jQuery.data(elem, "boom"), "bloz", "Extending the data object works" ); + + jQuery._data(elem, "foo", "foo2"); + equals( jQuery._data(elem, "foo"), "foo2", "Setting internal data works" ); + equals( jQuery.data(elem, "foo"), "foo1", "Setting internal data does not override user data" ); + + var internalDataObj = jQuery.data(elem, jQuery.expando); + strictEqual( jQuery._data(elem), internalDataObj, "Internal data object is accessible via jQuery.expando property" ); + notStrictEqual( dataObj, internalDataObj, "Internal data object is not the same as user data object" ); + + strictEqual( elem.boom, undefined, "Data is never stored directly on the object" ); + + jQuery.removeData(elem, "foo"); + strictEqual( jQuery.data(elem, "foo"), undefined, "jQuery.removeData removes single properties" ); + + jQuery.removeData(elem); + strictEqual( jQuery.data(elem, jQuery.expando), internalDataObj, "jQuery.removeData does not remove internal data if it exists" ); + + jQuery.removeData(elem, undefined, true); - obj = {}; - jQuery.data(obj, 'test'); - equals( jQuery.expando in obj, false, "jQuery.data(obj,key) did not add an expando to the object" ); + strictEqual( jQuery.data(elem, jQuery.expando), undefined, "jQuery.removeData on internal data works" ); + strictEqual( jQuery.hasData(elem), false, "jQuery.hasData agrees all data has been removed from object" ); + + jQuery._data(elem, "foo", "foo2"); + strictEqual( jQuery.hasData(elem), true, "jQuery.hasData shows data exists even if it is only internal data" ); + + jQuery.data(elem, "foo", "foo1"); + equals( jQuery._data(elem, "foo"), "foo2", "Setting user data does not override internal data" ); + + jQuery.removeData(elem, undefined, true); + equals( jQuery.data(elem, "foo"), "foo1", "jQuery.removeData for internal data does not remove user data" ); + + if (elem.nodeType) { + var oldCacheLength = getCacheLength(); + jQuery.removeData(elem, "foo"); + + equals( getCacheLength(), oldCacheLength - 1, "Removing the last item in the data object destroys it" ); + } + else { + jQuery.removeData(elem, "foo"); + var expected, actual; + + if (jQuery.support.deleteExpando) { + expected = false; + actual = jQuery.expando in elem; + } + else { + expected = null; + actual = elem[ jQuery.expando ]; + } + + equals( actual, expected, "Removing the last item in the data object destroys it" ); + } + + jQuery.data(elem, "foo", "foo1"); + jQuery._data(elem, "foo", "foo2"); + + equals( jQuery.data(elem, "foo"), "foo1", "(sanity check) Ensure data is set in user data object" ); + equals( jQuery._data(elem, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" ); + + jQuery.removeData(elem, "foo", true); + + strictEqual( jQuery.data(elem, jQuery.expando), undefined, "Removing the last item in internal data destroys the internal data object" ); + + jQuery._data(elem, "foo", "foo2"); + equals( jQuery._data(elem, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" ); + + jQuery.removeData(elem, "foo"); + equals( jQuery._data(elem, "foo"), "foo2", "(sanity check) jQuery.removeData for user data does not remove internal data" ); + + if (elem.nodeType) { + oldCacheLength = getCacheLength(); + jQuery.removeData(elem, "foo", true); + equals( getCacheLength(), oldCacheLength - 1, "Removing the last item in the internal data object also destroys the user data object when it is empty" ); + } + else { + jQuery.removeData(elem, "foo", true); + + if (jQuery.support.deleteExpando) { + expected = false; + actual = jQuery.expando in elem; + } + else { + expected = null; + actual = elem[ jQuery.expando ]; + } - obj = {}; - jQuery.data(obj, "foo", "bar"); - equals( jQuery.expando in obj, false, "jQuery.data(obj,key,value) did not add an expando to the object" ); - equals( obj.foo, "bar", "jQuery.data(obj,key,value) sets fields directly on the object." ); + equals( actual, expected, "Removing the last item in the internal data object also destroys the user data object when it is empty" ); + } +} + +test("jQuery.data", function() { + expect(128); + + var div = document.createElement("div"); + + dataTests(div); + dataTests({}); + + // remove bound handlers from window object to stop potential false positives caused by fix for #5280 in + // transports/xhr.js + jQuery(window).unbind("unload"); + + dataTests(window); + dataTests(document); + + // clean up unattached element + jQuery(div).remove(); }); test("jQuery.acceptData", function() { @@ -37,53 +174,11 @@ test("jQuery.acceptData", function() { ok( !jQuery.acceptData( applet ), "applet" ); }); -test("jQuery.data", function() { - expect(15); - var div = document.createElement("div"); - - ok( jQuery.data(div, "test") === undefined, "Check for no data exists" ); - - jQuery.data(div, "test", "success"); - equals( jQuery.data(div, "test"), "success", "Check for added data" ); - - ok( jQuery.data(div, "notexist") === undefined, "Check for no data exists" ); - - var data = jQuery.data(div); - same( data, { "test": "success" }, "Return complete data set" ); - - jQuery.data(div, "test", "overwritten"); - equals( jQuery.data(div, "test"), "overwritten", "Check for overwritten data" ); - - jQuery.data(div, "test", undefined); - equals( jQuery.data(div, "test"), "overwritten", "Check that data wasn't removed"); - - jQuery.data(div, "test", null); - ok( jQuery.data(div, "test") === null, "Check for null data"); - - jQuery.data(div, "test3", "orig"); - jQuery.data(div, { "test": "in", "test2": "in2" }); - equals( jQuery.data(div, "test"), "in", "Verify setting an object in data" ); - equals( jQuery.data(div, "test2"), "in2", "Verify setting an object in data" ); - equals( jQuery.data(div, "test3"), "orig", "Verify original not overwritten" ); - - var obj = {}; - jQuery.data( obj, "prop", true ); - - ok( obj.prop, "Data is being stored on the object" ); - equals( jQuery.data( obj, "prop" ), true, "Make sure the right value is retrieved" ); - - jQuery.data( window, "BAD", true ); - ok( !window[ jQuery.expando ], "Make sure there is no expando on the window object." ); - ok( !window.BAD, "And make sure that the property wasn't set directly on the window." ); - ok( jQuery.data( window, "BAD" ), "Make sure that the value was set." ); -}); - test(".data()", function() { expect(5); var div = jQuery("#foo"); strictEqual( div.data("foo"), undefined, "Make sure that missing result is undefined" ); - div.data("test", "success"); same( div.data(), {test: "success"}, "data() get the entire data object" ); strictEqual( div.data("foo"), undefined, "Make sure that missing result is still undefined" ); @@ -92,7 +187,7 @@ test(".data()", function() { equals( nodiv.data(), null, "data() on empty set returns null" ); var obj = { foo: "bar" }; - equals( jQuery(obj).data(), obj, "Retrieve data object from a wrapped JS object (#7524)" ); + deepEqual( jQuery(obj).data(), {}, "Retrieve data object from a wrapped JS object (#7524)" ); }) test(".data(String) and .data(String, Object)", function() { @@ -179,11 +274,14 @@ test(".data(String) and .data(String, Object)", function() { equals( $elem.data('null',null).data('null'), null, "null's are preserved"); equals( $elem.data('emptyString','').data('emptyString'), '', "Empty strings are preserved"); equals( $elem.data('false',false).data('false'), false, "false's are preserved"); - equals( $elem.data('exists'), true, "Existing data is returned" ); - + equals( $elem.data('exists'), undefined, "Existing data is not returned" ); + // Clean up $elem.removeData(); - ok( jQuery.isEmptyObject( $elem[0] ), "removeData clears the object" ); + deepEqual( $elem[0], {exists:true}, "removeData does not clear the object" ); + + // manually clean up detached elements + parent.remove(); }); test("data-* attributes", function() { @@ -191,7 +289,7 @@ test("data-* attributes", function() { var div = jQuery("<div>"), child = jQuery("<div data-myobj='old data' data-ignored=\"DOM\" data-other='test'></div>"), dummy = jQuery("<div data-myobj='old data' data-ignored=\"DOM\" data-other='test'></div>"); - + equals( div.data("attr"), undefined, "Check for non-existing data-attr attribute" ); div.attr("data-attr", "exists"); @@ -199,10 +297,12 @@ test("data-* attributes", function() { div.attr("data-attr", "exists2"); equals( div.data("attr"), "exists", "Check that updates to data- don't update .data()" ); - + div.data("attr", "internal").attr("data-attr", "external"); equals( div.data("attr"), "internal", "Check for .data('attr') precedence (internal > external data-* attribute)" ); - + + div.remove(); + child.appendTo('#main'); equals( child.data("myobj"), "old data", "Value accessed from data-* attribute"); @@ -214,6 +314,8 @@ test("data-* attributes", function() { var obj = child.data(), obj2 = dummy.data(), check = [ "myobj", "ignored", "other" ], num = 0, num2 = 0; + dummy.remove(); + for ( var i = 0, l = check.length; i < l; i++ ) { ok( obj[ check[i] ], "Make sure data- property exists when calling data-." ); ok( obj2[ check[i] ], "Make sure data- property exists when calling data-." ); @@ -249,7 +351,7 @@ test("data-* attributes", function() { .attr("data-space", " ") .attr("data-null", "null") .attr("data-string", "test"); - + strictEqual( child.data('true'), true, "Primitive true read from attribute"); strictEqual( child.data('false'), false, "Primitive false read from attribute"); strictEqual( child.data('five'), 5, "Primitive number read from attribute"); @@ -265,7 +367,7 @@ test("data-* attributes", function() { strictEqual( child.data('string'), "test", "Typical string read from attribute"); child.remove(); - + // tests from metadata plugin function testData(index, elem) { switch (index) { @@ -289,10 +391,10 @@ test("data-* attributes", function() { ok(false, ["Assertion failed on index ", index, ", with data ", data].join('')); } } - + var metadata = '<ol><li class="test test2" data-foo="bar" data-bar="baz" data-arr="[1,2]">Some stuff</li><li class="test test2" data-test="bar" data-bar="baz">Some stuff</li><li class="test test2" data-zoooo="bar" data-bar=\'{"test":"baz"}\'>Some stuff</li><li class="test test2" data-number=true data-stuff="[2,8]">Some stuff</li></ol>', elem = jQuery(metadata).appendTo('#main'); - + elem.find("li").each(testData); elem.remove(); }); @@ -305,16 +407,20 @@ test(".data(Object)", function() { div.data({ "test": "in", "test2": "in2" }); equals( div.data("test"), "in", "Verify setting an object in data" ); equals( div.data("test2"), "in2", "Verify setting an object in data" ); - + var obj = {test:"unset"}, jqobj = jQuery(obj); + jqobj.data("test", "unset"); jqobj.data({ "test": "in", "test2": "in2" }); - equals( obj.test, "in", "Verify setting an object on an object extends the object" ); - equals( obj.test2, "in2", "Verify setting an object on an object extends the object" ); + equals( jQuery.data(obj).test, "in", "Verify setting an object on an object extends the data object" ); + equals( obj.test2, undefined, "Verify setting an object on an object does not extend the object" ); + + // manually clean up detached elements + div.remove(); }); test("jQuery.removeData", function() { - expect(7); + expect(6); var div = jQuery("#foo")[0]; jQuery.data(div, "test", "testing"); jQuery.removeData(div, "test"); @@ -324,13 +430,12 @@ test("jQuery.removeData", function() { jQuery.removeData( div ); ok( !jQuery.data(div, "test2"), "Make sure that the data property no longer exists." ); ok( !div[ jQuery.expando ], "Make sure the expando no longer exists, as well." ); - + var obj = {}; jQuery.data(obj, "test", "testing"); - equals( obj.test, "testing", "verify data on plain object"); + equals( jQuery(obj).data("test"), "testing", "verify data on plain object"); jQuery.removeData(obj, "test"); equals( jQuery.data(obj, "test"), undefined, "Check removal of data on plain object" ); - equals( obj.test, undefined, "Check removal of data directly from plain object" ); jQuery.data( window, "BAD", true ); jQuery.removeData( window, "BAD" ); @@ -356,4 +461,4 @@ test(".removeData()", function() { div.removeData("test.foo"); equals( div.data("test.foo"), undefined, "Make sure data is intact" ); -}); +});
\ No newline at end of file diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 8255bf325..fa59a9f77 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -1,4 +1,4 @@ -module("dimensions"); +module("dimensions", { teardown: moduleTeardown }); function pass( val ) { return val; @@ -33,6 +33,8 @@ function testWidth( val ) { var blah = jQuery("blah"); equals( blah.width( val(10) ), blah, "Make sure that setting a width on an empty set returns the set." ); equals( blah.width(), null, "Make sure 'null' is returned on an empty set"); + + jQuery.removeData($div[0], 'olddisplay', true); } test("width()", function() { @@ -45,13 +47,13 @@ test("width() with function", function() { test("width() with function args", function() { expect( 2 ); - + var $div = jQuery("#nothiddendiv"); $div.width( 30 ).width(function(i, width) { equals( width, 30, "Make sure previous value is corrrect." ); return width + 1; }); - + equals( $div.width(), 31, "Make sure value was modified correctly." ); }); @@ -80,6 +82,8 @@ function testHeight( val ) { var blah = jQuery("blah"); equals( blah.height( val(10) ), blah, "Make sure that setting a height on an empty set returns the set." ); equals( blah.height(), null, "Make sure 'null' is returned on an empty set"); + + jQuery.removeData($div[0], 'olddisplay', true); } test("height()", function() { @@ -92,13 +96,13 @@ test("height() with function", function() { test("height() with function args", function() { expect( 2 ); - + var $div = jQuery("#nothiddendiv"); $div.height( 30 ).height(function(i, height) { equals( height, 30, "Make sure previous value is corrrect." ); return height + 1; }); - + equals( $div.height(), 31, "Make sure value was modified correctly." ); }); @@ -112,13 +116,13 @@ test("innerWidth()", function() { border: "2px solid #fff", width: 30 }); - + equals($div.innerWidth(), 30, "Test with margin and border"); $div.css("padding", "20px"); equals($div.innerWidth(), 70, "Test with margin, border and padding"); $div.hide(); equals($div.innerWidth(), 70, "Test hidden div"); - + // reset styles $div.css({ display: "", border: "", padding: "", width: "", height: "" }); @@ -126,11 +130,14 @@ test("innerWidth()", function() { // Temporarily require 0 for backwards compat - should be auto equals( div.innerWidth(), 0, "Make sure that disconnected nodes are handled." ); + + div.remove(); + jQuery.removeData($div[0], 'olddisplay', true); }); test("innerHeight()", function() { expect(4); - + var $div = jQuery("#nothiddendiv"); // set styles $div.css({ @@ -138,13 +145,13 @@ test("innerHeight()", function() { border: "2px solid #fff", height: 30 }); - + equals($div.innerHeight(), 30, "Test with margin and border"); $div.css("padding", "20px"); equals($div.innerHeight(), 70, "Test with margin, border and padding"); $div.hide(); equals($div.innerHeight(), 70, "Test hidden div"); - + // reset styles $div.css({ display: "", border: "", padding: "", width: "", height: "" }); @@ -152,14 +159,17 @@ test("innerHeight()", function() { // Temporarily require 0 for backwards compat - should be auto equals( div.innerHeight(), 0, "Make sure that disconnected nodes are handled." ); + + div.remove(); + jQuery.removeData($div[0], 'olddisplay', true); }); test("outerWidth()", function() { expect(7); - + var $div = jQuery("#nothiddendiv"); $div.css("width", 30); - + equals($div.outerWidth(), 30, "Test with only width set"); $div.css("padding", "20px"); equals($div.outerWidth(), 70, "Test with padding"); @@ -171,7 +181,7 @@ test("outerWidth()", function() { equals($div.outerWidth(true), 94, "Test with padding, border and margin with margin option"); $div.hide(); equals($div.outerWidth(true), 94, "Test hidden div with padding, border and margin with margin option"); - + // reset styles $div.css({ position: "", display: "", border: "", padding: "", width: "", height: "" }); @@ -179,14 +189,17 @@ test("outerWidth()", function() { // Temporarily require 0 for backwards compat - should be auto equals( div.outerWidth(), 0, "Make sure that disconnected nodes are handled." ); + + div.remove(); + jQuery.removeData($div[0], 'olddisplay', true); }); test("outerHeight()", function() { expect(7); - + var $div = jQuery("#nothiddendiv"); $div.css("height", 30); - + equals($div.outerHeight(), 30, "Test with only width set"); $div.css("padding", "20px"); equals($div.outerHeight(), 70, "Test with padding"); @@ -197,7 +210,7 @@ test("outerHeight()", function() { equals($div.outerHeight(true), 94, "Test with padding, border and margin with margin option"); $div.hide(); equals($div.outerHeight(true), 94, "Test hidden div with padding, border and margin with margin option"); - + // reset styles $div.css({ display: "", border: "", padding: "", width: "", height: "" }); @@ -205,4 +218,7 @@ test("outerHeight()", function() { // Temporarily require 0 for backwards compat - should be auto equals( div.outerHeight(), 0, "Make sure that disconnected nodes are handled." ); + + div.remove(); + jQuery.removeData($div[0], 'olddisplay', true); }); diff --git a/test/unit/effects.js b/test/unit/effects.js index 74b336f1f..b1dd28840 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1,4 +1,4 @@ -module("effects"); +module("effects", { teardown: moduleTeardown }); test("sanity check", function() { expect(1); @@ -14,7 +14,7 @@ test("show()", function() { equals( hiddendiv.css("display"), "block", "Make sure a pre-hidden div is visible." ); - var div = jQuery("<div>").hide().appendTo("body").show(); + var div = jQuery("<div>").hide().appendTo("#main").show(); equal( div.css("display"), "block", "Make sure pre-hidden divs show" ); @@ -64,7 +64,7 @@ test("show()", function() { // #show-tests * is set display: none in CSS jQuery("#main").append('<div id="show-tests"><div><p><a href="#"></a></p><code></code><pre></pre><span></span></div><table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody></table><ul><li></li></ul></div><table id="test-table"></table>'); - + var old = jQuery("#test-table").show().css("display") !== "table"; jQuery("#test-table").remove(); @@ -130,6 +130,45 @@ test("show(Number) - other displays", function() { }); }); + + +// Supports #7397 +test("Persist correct display value", function() { + expect(3); + QUnit.reset(); + stop(); + + // #show-tests * is set display: none in CSS + jQuery("#main").append('<div id="show-tests"><span style="position:absolute;">foo</span></div>'); + + var $span = jQuery("#show-tests span"), + displayNone = $span.css("display"), + display = '', num = 0; + + $span.show(); + + display = $span.css("display"); + + $span.hide(); + + $span.fadeIn(100, function() { + + equals($span.css("display"), display, "Expecting display: " + display); + + $span.fadeOut(100, function () { + + equals($span.css("display"), displayNone, "Expecting display: " + displayNone); + + $span.fadeIn(100, function() { + + equals($span.css("display"), display, "Expecting display: " + display); + + start(); + }); + }); + }); +}); + test("animate(Hash, Object, Function)", function() { expect(1); stop(); @@ -155,7 +194,7 @@ test("animate block as inline width/height", function() { var span = jQuery("<span>").css("display", "inline-block").appendTo("body"), expected = span.css("display"); - + span.remove(); if ( jQuery.support.inlineBlockNeedsLayout || expected === "inline-block" ) { @@ -181,7 +220,7 @@ test("animate native inline width/height", function() { var span = jQuery("<span>").css("display", "inline-block").appendTo("body"), expected = span.css("display"); - + span.remove(); if ( jQuery.support.inlineBlockNeedsLayout || expected === "inline-block" ) { @@ -364,13 +403,16 @@ test("animate duration 0", function() { $elem.hide(0, function(){ ok(true, "Hide callback with no duration"); }); + + // manually clean up detached elements + $elem.remove(); }); test("animate hyphenated properties", function(){ expect(1); stop(); - jQuery("#nothiddendiv") + jQuery("#foo") .css("font-size", 10) .animate({"font-size": 20}, 200, function(){ equals( this.style.fontSize, "20px", "The font-size property was animated." ); @@ -394,7 +436,7 @@ test("stop()", function() { expect(3); stop(); - var $foo = jQuery("#nothiddendiv"); + var $foo = jQuery("#foo"); var w = 0; $foo.hide().width(200).width(); @@ -407,6 +449,8 @@ test("stop()", function() { nw = $foo.width(); notEqual( nw, w, "Stop didn't reset the animation " + nw + "px " + w + "px"); setTimeout(function(){ + $foo.removeData(); + $foo.removeData(undefined, true); equals( nw, $foo.width(), "The animation didn't continue" ); start(); }, 100); @@ -417,7 +461,7 @@ test("stop() - several in queue", function() { expect(3); stop(); - var $foo = jQuery("#nothiddendivchild"); + var $foo = jQuery("#foo"); var w = 0; $foo.hide().width(200).width(); @@ -442,7 +486,7 @@ test("stop(clearQueue)", function() { expect(4); stop(); - var $foo = jQuery("#nothiddendiv"); + var $foo = jQuery("#foo"); var w = 0; $foo.hide().width(200).width(); @@ -469,7 +513,7 @@ test("stop(clearQueue, gotoEnd)", function() { expect(1); stop(); - var $foo = jQuery("#nothiddendivchild"); + var $foo = jQuery("#foo"); var w = 0; $foo.hide().width(200).width(); @@ -497,7 +541,7 @@ test("stop(clearQueue, gotoEnd)", function() { test("toggle()", function() { expect(6); - var x = jQuery("#nothiddendiv"); + var x = jQuery("#foo"); ok( x.is(":visible"), "is visible" ); x.toggle(); ok( x.is(":hidden"), "is hidden" ); @@ -521,6 +565,23 @@ jQuery.checkOverflowDisplay = function(){ start(); } +test("support negative values < -10000 (bug #7193)", function () { + expect(1); + stop(); + + jQuery.extend(jQuery.fx.step, { + "marginBottom": function(fx) { + equals( fx.cur(), -11000, "Element has margin-bottom of -11000" ); + delete jQuery.fx.step.marginBottom; + } + }); + + jQuery("#main").css("marginBottom", "-11000px").animate({ marginBottom: "-11001px" }, { + duration: 1, + complete: start + }); +}); + test("JS Overflow and Display", function() { expect(2); stop(); @@ -681,6 +742,9 @@ jQuery.each( { } } + // manually remove generated element + jQuery(this).remove(); + start(); }); }); @@ -707,6 +771,10 @@ jQuery.checkState = function(){ var cur = self.style[ c ] || jQuery.css(self, c); equals( cur, v, "Make sure that " + c + " is reset (Old: " + v + " Cur: " + cur + ")"); }); + + // manually clean data on modified element + jQuery.removeData(this, 'olddisplay', true); + start(); } @@ -773,9 +841,6 @@ jQuery.makeTest = function( text ){ jQuery("<h4></h4>") .text( text ) .appendTo("#fx-tests") - .click(function(){ - jQuery(this).next().toggle(); - }) .after( elem ); return elem; @@ -839,7 +904,7 @@ test("hide hidden elements (bug #7141)", function() { var div = jQuery("<div style='display:none'></div>").appendTo("#main"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(); - ok( !div.data("olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); + ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); div.show(); equals( div.css("display"), "block", "Show a double-hidden element" ); @@ -850,11 +915,11 @@ test("hide hidden elements, with animation (bug #7141)", function() { expect(3); QUnit.reset(); stop(); - + var div = jQuery("<div style='display:none'></div>").appendTo("#main"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(1, function () { - ok( !div.data("olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); + ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); div.show(1, function () { equals( div.css("display"), "block", "Show a double-hidden element" ); start(); diff --git a/test/unit/event.js b/test/unit/event.js index a647e5f3b..e4caee82a 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -1,23 +1,23 @@ -module("event"); +module("event", { teardown: moduleTeardown }); test("null or undefined handler", function() { expect(2); // Supports Fixes bug #7229 try { - + jQuery("#firstp").click(null); - + ok(true, "Passing a null handler will not throw an exception"); - } catch (e) {} + } catch (e) {} try { - + jQuery("#firstp").click(undefined); - + ok(true, "Passing an undefined handler will not throw an exception"); - } catch (e) {} + } catch (e) {} }); test("bind(), with data", function() { @@ -28,7 +28,7 @@ test("bind(), with data", function() { }; jQuery("#firstp").bind("click", {foo: "bar"}, handler).click().unbind("click", handler); - ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." ); + ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." ); }); test("click(), with data", function() { @@ -39,7 +39,7 @@ test("click(), with data", function() { }; jQuery("#firstp").click({foo: "bar"}, handler).click().unbind("click", handler); - ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." ); + ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." ); }); test("bind(), with data, trigger with data", function() { @@ -80,6 +80,9 @@ test("bind(), multiple events at once and namespaces", function() { cur = "focusin"; div.trigger("focusin.a"); + // manually clean up detached elements + div.remove(); + div = jQuery("<div/>").bind("click mouseover", obj, function(e) { equals( e.type, cur, "Verify right multi event was fired." ); equals( e.data, obj, "Make sure the data came in correctly." ); @@ -91,6 +94,9 @@ test("bind(), multiple events at once and namespaces", function() { cur = "mouseover"; div.trigger("mouseover"); + // manually clean up detached elements + div.remove(); + div = jQuery("<div/>").bind("focusin.a focusout.b", function(e) { equals( e.type, cur, "Verify right multi event was fired." ); }); @@ -100,6 +106,9 @@ test("bind(), multiple events at once and namespaces", function() { cur = "focusout"; div.trigger("focusout.b"); + + // manually clean up detached elements + div.remove(); }); test("bind(), namespace with special add", function() { @@ -175,7 +184,7 @@ test("bind(), no data", function() { test("bind/one/unbind(Object)", function(){ expect(6); - + var clickCounter = 0, mouseoverCounter = 0; function handler(event) { if (event.type == "click") @@ -183,18 +192,18 @@ test("bind/one/unbind(Object)", function(){ else if (event.type == "mouseover") mouseoverCounter++; }; - + function handlerWithData(event) { if (event.type == "click") clickCounter += event.data; else if (event.type == "mouseover") mouseoverCounter += event.data; }; - + function trigger(){ $elem.trigger("click").trigger("mouseover"); } - + var $elem = jQuery("#firstp") // Regular bind .bind({ @@ -206,16 +215,16 @@ test("bind/one/unbind(Object)", function(){ click:handlerWithData, mouseover:handlerWithData }, 2 ); - + trigger(); - + equals( clickCounter, 3, "bind(Object)" ); equals( mouseoverCounter, 3, "bind(Object)" ); - + trigger(); equals( clickCounter, 4, "bind(Object)" ); equals( mouseoverCounter, 4, "bind(Object)" ); - + jQuery("#firstp").unbind({ click:handler, mouseover:handler @@ -228,10 +237,10 @@ test("bind/one/unbind(Object)", function(){ test("live/die(Object), delegate/undelegate(String, Object)", function() { expect(6); - + var clickCounter = 0, mouseoverCounter = 0, $p = jQuery("#firstp"), $a = $p.find("a:first"); - + var events = { click: function( event ) { clickCounter += ( event.data || 1 ); @@ -240,26 +249,26 @@ test("live/die(Object), delegate/undelegate(String, Object)", function() { mouseoverCounter += ( event.data || 1 ); } }; - + function trigger() { $a.trigger("click").trigger("mouseover"); } - + $a.live( events ); $p.delegate( "a", events, 2 ); - + trigger(); equals( clickCounter, 3, "live/delegate" ); equals( mouseoverCounter, 3, "live/delegate" ); - + $p.undelegate( "a", events ); - + trigger(); equals( clickCounter, 4, "undelegate" ); equals( mouseoverCounter, 4, "undelegate" ); - + $a.die( events ); - + trigger(); equals( clickCounter, 4, "die" ); equals( mouseoverCounter, 4, "die" ); @@ -267,12 +276,12 @@ test("live/die(Object), delegate/undelegate(String, Object)", function() { test("live/delegate immediate propagation", function() { expect(2); - + var $p = jQuery("#firstp"), $a = $p.find("a:first"), lastClick; - + lastClick = ""; - $a.live( "click", function(e) { - lastClick = "click1"; + $a.live( "click", function(e) { + lastClick = "click1"; e.stopImmediatePropagation(); }); $a.live( "click", function(e) { @@ -281,10 +290,10 @@ test("live/delegate immediate propagation", function() { $a.trigger( "click" ); equals( lastClick, "click1", "live stopImmediatePropagation" ); $a.die( "click" ); - + lastClick = ""; - $p.delegate( "a", "click", function(e) { - lastClick = "click1"; + $p.delegate( "a", "click", function(e) { + lastClick = "click1"; e.stopImmediatePropagation(); }); $p.delegate( "a", "click", function(e) { @@ -295,10 +304,53 @@ test("live/delegate immediate propagation", function() { $p.undelegate( "click" ); }); +test("bind/delegate bubbling, isDefaultPrevented", function() { + expect(2); + var $anchor2 = jQuery( "#anchor2" ), + $main = jQuery( "#main" ), + fakeClick = function($jq) { + // Use a native click so we don't get jQuery simulated bubbling + if ( document.createEvent ) { + var e = document.createEvent( 'MouseEvents' ); + e.initEvent( "click", true, true ); + $jq[0].dispatchEvent(e); + } + else if ( $jq[0].click ) { + $jq[0].click(); // IE + } + }; + $anchor2.click(function(e) { + e.preventDefault(); + }); + $main.delegate("#foo", "click", function(e) { + var orig = e.originalEvent; + + if ( typeof(orig.defaultPrevented) === "boolean" || typeof(orig.returnValue) === "boolean" || orig.getPreventDefault ) { + equals( e.isDefaultPrevented(), true, "isDefaultPrevented true passed to bubbled event" ); + + } else { + // Opera < 11 doesn't implement any interface we can use, so give it a pass + ok( true, "isDefaultPrevented not supported by this browser, test skipped" ); + } + }); + fakeClick( $anchor2 ); + $anchor2.unbind( "click" ); + $main.undelegate( "click" ); + $anchor2.click(function(e) { + // Let the default action occur + }); + $main.delegate("#foo", "click", function(e) { + equals( e.isDefaultPrevented(), false, "isDefaultPrevented false passed to bubbled event" ); + }); + fakeClick( $anchor2 ); + $anchor2.unbind( "click" ); + $main.undelegate( "click" ); +}); + test("bind(), iframes", function() { // events don't work with iframes, see #939 - this test fails in IE because of contentDocument var doc = jQuery("#loadediframe").contents(); - + jQuery("div", doc).bind("click", function() { ok( true, "Binding to element inside iframe" ); }).click().unbind('click'); @@ -360,7 +412,7 @@ test("bind(), namespaced events, cloned events", function() { test("bind(), multi-namespaced events", function() { expect(6); - + var order = [ "click.test.abc", "click.test.abc", @@ -369,7 +421,7 @@ test("bind(), multi-namespaced events", function() { "click.test", "custom.test2" ]; - + function check(name, msg){ same(name, order.shift(), msg); } @@ -389,7 +441,7 @@ test("bind(), multi-namespaced events", function() { jQuery("#firstp").bind("click.test.abc",function(e){ check("click.test.abc", "Namespaced click triggered"); }); - + // Those would not trigger/unbind (#5303) jQuery("#firstp").trigger("click.a.test"); jQuery("#firstp").unbind("click.a.test"); @@ -453,7 +505,7 @@ test("bind(), make sure order is maintained", function() { elem.unbind("click"); }); - + test("bind(), with different this object", function() { expect(4); var thisObject = { myThis: true }, @@ -465,12 +517,12 @@ test("bind(), with different this object", function() { equals( this, thisObject, "bind() with different this object and data" ); equals( event.data, data, "bind() with different this object and data" ); }; - + jQuery("#firstp") .bind("click", jQuery.proxy(handler1, thisObject)).click().unbind("click", handler1) .bind("click", data, jQuery.proxy(handler2, thisObject)).click().unbind("click", handler2); - ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using different this object and data." ); + ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using different this object and data." ); }); test("bind(name, false), unbind(name, false)", function() { @@ -490,6 +542,9 @@ test("bind(name, false), unbind(name, false)", function() { jQuery("#ap").unbind("click", false); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); + + // manually clean up events from elements outside the fixture + jQuery("#main").unbind("click"); }); test("bind()/trigger()/unbind() on plain object", function() { @@ -512,7 +567,7 @@ test("bind()/trigger()/unbind() on plain object", function() { } }); - var events = jQuery(obj).data("__events__"); + var events = jQuery._data(obj, "events"); ok( events, "Object has events bound." ); equals( obj.events, undefined, "Events object on plain objects is not events" ); equals( typeof events, "function", "'events' expando is a function on plain objects." ); @@ -531,29 +586,31 @@ test("bind()/trigger()/unbind() on plain object", function() { // Make sure it doesn't complain when no events are found jQuery(obj).unbind("test"); - - equals( obj.__events__, undefined, "Make sure events object is removed" ); + + equals( obj && obj[ jQuery.expando ] && + obj[ jQuery.expando ][ jQuery.expando ] && + obj[ jQuery.expando ][ jQuery.expando ].events, undefined, "Make sure events object is removed" ); }); test("unbind(type)", function() { expect( 0 ); - + var $elem = jQuery("#firstp"), message; function error(){ ok( false, message ); } - + message = "unbind passing function"; $elem.bind('error1', error).unbind('error1',error).triggerHandler('error1'); - + message = "unbind all from event"; $elem.bind('error1', error).unbind('error1').triggerHandler('error1'); - + message = "unbind all"; $elem.bind('error1', error).unbind().triggerHandler('error1'); - + message = "unbind many with function"; $elem.bind('error1 error2',error) .unbind('error1 error2', error ) @@ -563,7 +620,7 @@ test("unbind(type)", function() { $elem.bind('error1 error2',error) .unbind('error1 error2') .trigger('error1').triggerHandler('error2'); - + message = "unbind without a type or handler"; $elem.bind("error1 error2.test",error) .unbind() @@ -572,7 +629,7 @@ test("unbind(type)", function() { test("unbind(eventObject)", function() { expect(4); - + var $elem = jQuery("#firstp"), num; @@ -581,7 +638,7 @@ test("unbind(eventObject)", function() { $elem.trigger('foo').triggerHandler('bar'); equals( num, expected, "Check the right handlers are triggered" ); } - + $elem // This handler shouldn't be unbound .bind('foo', function(){ @@ -595,14 +652,14 @@ test("unbind(eventObject)", function() { .bind('bar', function(){ num += 4; }); - + assert( 7 ); assert( 5 ); - + $elem.unbind('bar'); assert( 1 ); - - $elem.unbind(); + + $elem.unbind(); assert( 0 ); }); @@ -626,34 +683,42 @@ test("hover()", function() { test("trigger() shortcuts", function() { expect(6); - jQuery('<li><a href="#">Change location</a></li>').prependTo('#firstUL').find('a').bind('click', function() { + + var elem = jQuery('<li><a href="#">Change location</a></li>').prependTo('#firstUL'); + elem.find('a').bind('click', function() { var close = jQuery('spanx', this); // same with jQuery(this).find('span'); equals( close.length, 0, "Context element does not exist, length must be zero" ); ok( !close[0], "Context element does not exist, direct access to element must return undefined" ); return false; }).click(); - + + // manually clean up detached elements + elem.remove(); + jQuery("#check1").click(function() { ok( true, "click event handler for checkbox gets fired twice, see #815" ); }).click(); - + var counter = 0; jQuery('#firstp')[0].onclick = function(event) { counter++; }; jQuery('#firstp').click(); equals( counter, 1, "Check that click, triggers onclick event handler also" ); - + var clickCounter = 0; jQuery('#simon1')[0].onclick = function(event) { clickCounter++; }; jQuery('#simon1').click(); equals( clickCounter, 1, "Check that click, triggers onclick event handler on an a tag also" ); - - jQuery('<img />').load(function(){ + + elem = jQuery('<img />').load(function(){ ok( true, "Trigger the load event, using the shortcut .load() (#2819)"); }).load(); + + // manually clean up detached elements + elem.remove(); }); test("trigger() bubbling", function() { @@ -688,6 +753,10 @@ test("trigger() bubbling", function() { equals( body, 2, "ap bubble" ); equals( main, 1, "ap bubble" ); equals( ap, 1, "ap bubble" ); + + // manually clean up events from elements outside the fixture + jQuery(document).unbind("click"); + jQuery("html, body, #main").unbind("click"); }); test("trigger(type, [data], [fn])", function() { @@ -728,10 +797,10 @@ test("trigger(type, [data], [fn])", function() { pass = false; } ok( pass, "Trigger focus on hidden element" ); - + pass = true; try { - jQuery('table:first').bind('test:test', function(){}).trigger('test:test'); + jQuery('#main table:first').bind('test:test', function(){}).trigger('test:test'); } catch (e) { pass = false; } @@ -768,28 +837,28 @@ test("jQuery.Event.currentTarget", function(){ test("trigger(eventObject, [data], [fn])", function() { expect(25); - + var $parent = jQuery('<div id="par" />').hide().appendTo('body'), $child = jQuery('<p id="child">foo</p>').appendTo( $parent ); - - var event = jQuery.Event("noNew"); + + var event = jQuery.Event("noNew"); ok( event != window, "Instantiate jQuery.Event without the 'new' keyword" ); equals( event.type, "noNew", "Verify its type" ); - + equals( event.isDefaultPrevented(), false, "Verify isDefaultPrevented" ); equals( event.isPropagationStopped(), false, "Verify isPropagationStopped" ); equals( event.isImmediatePropagationStopped(), false, "Verify isImmediatePropagationStopped" ); - + event.preventDefault(); equals( event.isDefaultPrevented(), true, "Verify isDefaultPrevented" ); event.stopPropagation(); equals( event.isPropagationStopped(), true, "Verify isPropagationStopped" ); - + event.isPropagationStopped = function(){ return false }; event.stopImmediatePropagation(); equals( event.isPropagationStopped(), true, "Verify isPropagationStopped" ); equals( event.isImmediatePropagationStopped(), true, "Verify isPropagationStopped" ); - + $parent.bind('foo',function(e){ // Tries bubbling equals( e.type, 'foo', 'Verify event type when passed passing an event object' ); @@ -797,72 +866,72 @@ test("trigger(eventObject, [data], [fn])", function() { equals( e.currentTarget.id, 'par', 'Verify event.target when passed passing an event object' ); equals( e.secret, 'boo!', 'Verify event object\'s custom attribute when passed passing an event object' ); }); - + // test with an event object event = new jQuery.Event("foo"); event.secret = 'boo!'; $child.trigger(event); - + // test with a literal object $child.trigger({type:'foo', secret:'boo!'}); - + $parent.unbind(); function error(){ ok( false, "This assertion shouldn't be reached"); } - + $parent.bind('foo', error ); - + $child.bind('foo',function(e, a, b, c ){ equals( arguments.length, 4, "Check arguments length"); equals( a, 1, "Check first custom argument"); equals( b, 2, "Check second custom argument"); equals( c, 3, "Check third custom argument"); - + equals( e.isDefaultPrevented(), false, "Verify isDefaultPrevented" ); equals( e.isPropagationStopped(), false, "Verify isPropagationStopped" ); equals( e.isImmediatePropagationStopped(), false, "Verify isImmediatePropagationStopped" ); - + // Skips both errors e.stopImmediatePropagation(); - + return "result"; }); - + // We should add this back in when we want to test the order // in which event handlers are iterated. //$child.bind('foo', error ); - + event = new jQuery.Event("foo"); $child.trigger( event, [1,2,3] ).unbind(); equals( event.result, "result", "Check event.result attribute"); - + // Will error if it bubbles $child.triggerHandler('foo'); - + $child.unbind(); $parent.unbind().remove(); }); test("jQuery.Event.currentTarget", function(){ expect(1); - + var counter = 0, $elem = jQuery('<button>a</button>').click(function(e){ equals( e.currentTarget, this, "Check currentTarget on "+(counter++?"native":"fake") +" event" ); }); - + // Fake event $elem.trigger('click'); - + // Cleanup $elem.unbind(); }); test("toggle(Function, Function, ...)", function() { expect(16); - + var count = 0, fn1 = function(e) { count++; }, fn2 = function(e) { count--; }, @@ -885,7 +954,7 @@ test("toggle(Function, Function, ...)", function() { }); return false; }).click().click().click(); - + var turn = 0; var fns = [ function(){ @@ -898,7 +967,7 @@ test("toggle(Function, Function, ...)", function() { turn = 3; } ]; - + var $div = jQuery("<div> </div>").toggle( fns[0], fns[1], fns[2] ); $div.click(); equals( turn, 1, "Trying toggle with 3 functions, attempt 1 yields 1"); @@ -910,11 +979,14 @@ test("toggle(Function, Function, ...)", function() { equals( turn, 1, "Trying toggle with 3 functions, attempt 4 yields 1"); $div.click(); equals( turn, 2, "Trying toggle with 3 functions, attempt 5 yields 2"); - + $div.unbind('click',fns[0]); - var data = jQuery.data( $div[0], 'events' ); + var data = jQuery._data( $div[0], 'events' ); ok( !data, "Unbinding one function from toggle unbinds them all"); + // manually clean up detached elements + $div.remove(); + // Test Multi-Toggles var a = [], b = []; $div = jQuery("<div/>"); @@ -930,6 +1002,9 @@ test("toggle(Function, Function, ...)", function() { $div.click(); same( a, [1,2,1], "Check that a click worked with a second toggle, second click." ); same( b, [1,2], "Check that a click worked with a second toggle, second click." ); + + // manually clean up detached elements + $div.remove(); }); test(".live()/.die()", function() { @@ -1030,7 +1105,7 @@ test(".live()/.die()", function() { equals( clicked, 2, "live with a context" ); // Make sure the event is actually stored on the context - ok( jQuery.data(container, "events").live, "live with a context" ); + ok( jQuery._data(container, "events").live, "live with a context" ); // Test unbinding with a different context jQuery("#foo", container).die("click"); @@ -1052,7 +1127,7 @@ test(".live()/.die()", function() { // Test binding with different this object, event data, and trigger data jQuery("#foo").live("click", true, jQuery.proxy(function(e, data){ equals( e.data, true, "live with with different this object, event data, and trigger data" ); - equals( this.foo, "bar", "live with with different this object, event data, and trigger data" ); + equals( this.foo, "bar", "live with with different this object, event data, and trigger data" ); equals( data, true, "live with with different this object, event data, and trigger data") }, { foo: "bar" })); jQuery("#foo").trigger("click", true).die("click"); @@ -1113,25 +1188,25 @@ test(".live()/.die()", function() { // Cleanup jQuery("#nothiddendiv").die("foo", callback); - + // Make sure we don't loose the target by DOM modifications // after the bubble already reached the liveHandler var livec = 0, elemDiv = jQuery("#nothiddendivchild").html('<span></span>').get(0); - + jQuery("#nothiddendivchild").live("click", function(e){ jQuery("#nothiddendivchild").html(''); }); jQuery("#nothiddendivchild").live("click", function(e){ if(e.target) {livec++;} }); - + jQuery("#nothiddendiv span").click(); equals( jQuery("#nothiddendiv span").length, 0, "Verify that first handler occurred and modified the DOM." ); equals( livec, 1, "Verify that second handler occurred even with nuked target." ); - + // Cleanup jQuery("#nothiddendivchild").die("click"); // Verify that .live() ocurs and cancel buble in the same order as // we would expect .bind() and .click() without delegation var lived = 0, livee = 0; - + // bind one pair in one order jQuery('span#liveSpan1 a').live('click', function(){ lived++; return false; }); jQuery('span#liveSpan1').live('click', function(){ livee++; }); @@ -1149,22 +1224,22 @@ test(".live()/.die()", function() { jQuery('span#liveSpan2 a').click(); equals( lived, 1, "Verify that only one first handler occurred." ); equals( livee, 0, "Verify that second handler doesn't." ); - + // Cleanup jQuery("span#liveSpan1 a").die("click") jQuery("span#liveSpan1").die("click"); jQuery("span#liveSpan2 a").die("click"); jQuery("span#liveSpan2").die("click"); - + // Test this, target and currentTarget are correct - jQuery('span#liveSpan1').live('click', function(e){ + jQuery('span#liveSpan1').live('click', function(e){ equals( this.id, 'liveSpan1', 'Check the this within a live handler' ); equals( e.currentTarget.id, 'liveSpan1', 'Check the event.currentTarget within a live handler' ); equals( e.target.nodeName.toUpperCase(), 'A', 'Check the event.target within a live handler' ); }); - + jQuery('span#liveSpan1 a').click(); - + jQuery('span#liveSpan1').die('click'); // Work with deep selectors @@ -1240,6 +1315,9 @@ test("live with multiple events", function(){ div.trigger("submit"); equals( count, 2, "Make sure both the click and submit were triggered." ); + + // manually clean up events from elements outside the fixture + div.die(); }); test("live with namespaces", function(){ @@ -1298,18 +1376,18 @@ test("live with change", function(){ expect(8); var selectChange = 0, checkboxChange = 0; - + var select = jQuery("select[name='S1']") select.live("change", function() { selectChange++; }); - - var checkbox = jQuery("#check2"), + + var checkbox = jQuery("#check2"), checkboxFunction = function(){ checkboxChange++; } checkbox.live("change", checkboxFunction); - + // test click on select // second click that changed it @@ -1317,17 +1395,17 @@ test("live with change", function(){ select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 1, "Change on click." ); - + // test keys on select selectChange = 0; select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 1, "Change on keyup." ); - + // test click on checkbox checkbox.trigger("change"); equals( checkboxChange, 1, "Change on checkbox." ); - + // test blur/focus on text var text = jQuery("#name"), textChange = 0, oldTextVal = text.val(); text.live("change", function() { @@ -1340,7 +1418,7 @@ test("live with change", function(){ text.val(oldTextVal); text.die("change"); - + // test blur/focus on password var password = jQuery("#name"), passwordChange = 0, oldPasswordVal = password.val(); password.live("change", function() { @@ -1353,9 +1431,9 @@ test("live with change", function(){ password.val(oldPasswordVal); password.die("change"); - + // make sure die works - + // die all changes selectChange = 0; select.die("change"); @@ -1367,7 +1445,7 @@ test("live with change", function(){ select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 0, "Die on keyup works." ); - + // die specific checkbox checkbox.die("change", checkboxFunction); checkbox.trigger("change"); @@ -1376,7 +1454,7 @@ test("live with change", function(){ test("live with submit", function() { var count1 = 0, count2 = 0; - + jQuery("#testForm").live("submit", function(ev) { count1++; ev.preventDefault(); @@ -1390,7 +1468,7 @@ test("live with submit", function() { jQuery("#testForm input[name=sub1]").submit(); equals( count1, 1, "Verify form submit." ); equals( count2, 1, "Verify body submit." ); - + jQuery("#testForm").die("submit"); jQuery("body").die("submit"); }); @@ -1543,7 +1621,7 @@ test(".delegate()/.undelegate()", function() { equals( clicked, 2, "delegate with a context" ); // Make sure the event is actually stored on the context - ok( jQuery.data(container, "events").live, "delegate with a context" ); + ok( jQuery._data(container, "events").live, "delegate with a context" ); // Test unbinding with a different context jQuery("#main").undelegate("#foo", "click"); @@ -1568,7 +1646,7 @@ test(".delegate()/.undelegate()", function() { // Test binding with different this object, event data, and trigger data jQuery("#body").delegate("#foo", "click", true, jQuery.proxy(function(e, data){ equals( e.data, true, "delegate with with different this object, event data, and trigger data" ); - equals( this.foo, "bar", "delegate with with different this object, event data, and trigger data" ); + equals( this.foo, "bar", "delegate with with different this object, event data, and trigger data" ); equals( data, true, "delegate with with different this object, event data, and trigger data") }, { foo: "bar" })); jQuery("#foo").trigger("click", true); @@ -1630,25 +1708,25 @@ test(".delegate()/.undelegate()", function() { // Cleanup jQuery("#body").undelegate("#nothiddendiv", "foo", callback); - + // Make sure we don't loose the target by DOM modifications // after the bubble already reached the liveHandler var livec = 0, elemDiv = jQuery("#nothiddendivchild").html('<span></span>').get(0); - + jQuery("#body").delegate("#nothiddendivchild", "click", function(e){ jQuery("#nothiddendivchild").html(''); }); jQuery("#body").delegate("#nothiddendivchild", "click", function(e){ if(e.target) {livec++;} }); - + jQuery("#nothiddendiv span").click(); equals( jQuery("#nothiddendiv span").length, 0, "Verify that first handler occurred and modified the DOM." ); equals( livec, 1, "Verify that second handler occurred even with nuked target." ); - + // Cleanup jQuery("#body").undelegate("#nothiddendivchild", "click"); // Verify that .live() ocurs and cancel buble in the same order as // we would expect .bind() and .click() without delegation var lived = 0, livee = 0; - + // bind one pair in one order jQuery("#body").delegate('span#liveSpan1 a', 'click', function(){ lived++; return false; }); jQuery("#body").delegate('span#liveSpan1', 'click', function(){ livee++; }); @@ -1666,19 +1744,19 @@ test(".delegate()/.undelegate()", function() { jQuery('span#liveSpan2 a').click(); equals( lived, 1, "Verify that only one first handler occurred." ); equals( livee, 0, "Verify that second handler doesn't." ); - + // Cleanup jQuery("#body").undelegate("click"); - + // Test this, target and currentTarget are correct - jQuery("#body").delegate('span#liveSpan1', 'click', function(e){ + jQuery("#body").delegate('span#liveSpan1', 'click', function(e){ equals( this.id, 'liveSpan1', 'Check the this within a delegate handler' ); equals( e.currentTarget.id, 'liveSpan1', 'Check the event.currentTarget within a delegate handler' ); equals( e.target.nodeName.toUpperCase(), 'A', 'Check the event.target within a delegate handler' ); }); - + jQuery('span#liveSpan1 a').click(); - + jQuery("#body").undelegate('span#liveSpan1', 'click'); // Work with deep selectors @@ -1754,18 +1832,18 @@ test("delegate with change", function(){ expect(8); var selectChange = 0, checkboxChange = 0; - + var select = jQuery("select[name='S1']"); jQuery("#body").delegate("select[name='S1']", "change", function() { selectChange++; }); - - var checkbox = jQuery("#check2"), + + var checkbox = jQuery("#check2"), checkboxFunction = function(){ checkboxChange++; } jQuery("#body").delegate("#check2", "change", checkboxFunction); - + // test click on select // second click that changed it @@ -1773,17 +1851,17 @@ test("delegate with change", function(){ select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 1, "Change on click." ); - + // test keys on select selectChange = 0; select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 1, "Change on keyup." ); - + // test click on checkbox checkbox.trigger("change"); equals( checkboxChange, 1, "Change on checkbox." ); - + // test blur/focus on text var text = jQuery("#name"), textChange = 0, oldTextVal = text.val(); jQuery("#body").delegate("#name", "change", function() { @@ -1796,7 +1874,7 @@ test("delegate with change", function(){ text.val(oldTextVal); jQuery("#body").die("change"); - + // test blur/focus on password var password = jQuery("#name"), passwordChange = 0, oldPasswordVal = password.val(); jQuery("#body").delegate("#name", "change", function() { @@ -1809,9 +1887,9 @@ test("delegate with change", function(){ password.val(oldPasswordVal); jQuery("#body").undelegate("#name", "change"); - + // make sure die works - + // die all changes selectChange = 0; jQuery("#body").undelegate("select[name='S1']", "change"); @@ -1823,7 +1901,7 @@ test("delegate with change", function(){ select[0].selectedIndex = select[0].selectedIndex ? 0 : 1; select.trigger("change"); equals( selectChange, 0, "Die on keyup works." ); - + // die specific checkbox jQuery("#body").undelegate("#check2", "change", checkboxFunction); checkbox.trigger("change"); @@ -1832,7 +1910,7 @@ test("delegate with change", function(){ test("delegate with submit", function() { var count1 = 0, count2 = 0; - + jQuery("#body").delegate("#testForm", "submit", function(ev) { count1++; ev.preventDefault(); @@ -1846,7 +1924,7 @@ test("delegate with submit", function() { jQuery("#testForm input[name=sub1]").submit(); equals( count1, 1, "Verify form submit." ); equals( count2, 1, "Verify body submit." ); - + jQuery("#body").undelegate(); jQuery(document).undelegate(); }); @@ -1872,27 +1950,7 @@ test("window resize", function() { ok( true, "Resize event fired." ); }).resize().unbind("resize"); - ok( !jQuery(window).data("__events__"), "Make sure all the events are gone." ); -}); - -test("focusin bubbles", function() { - //create an input and focusin on it - var input = jQuery("<input/>"), order = 0; - - input.prependTo("body"); - - jQuery("body").bind("focusin.focusinBubblesTest",function(){ - equals(1,order++,"focusin on the body second") - }); - - input.bind("focusin.focusinBubblesTest",function(){ - equals(0,order++,"focusin on the element first") - }); - - input[0].focus(); - input.remove(); - - jQuery("body").unbind("focusin.focusinBubblesTest"); + ok( !jQuery._data(window, "__events__"), "Make sure all the events are gone." ); }); /* diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index d49029eb8..37234d86d 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1,4 +1,7 @@ -module("manipulation"); +module("manipulation", { teardown: moduleTeardown }); + +// Ensure that an extended Array prototype doesn't break jQuery +Array.prototype.arrayProtoFn = function(arg) { throw("arrayProtoFn should not be called"); }; var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; @@ -51,7 +54,7 @@ test("text(Function) with incoming value", function() { }); var testWrap = function(val) { - expect(18); + expect(19); var defaultText = 'Try them out:' var result = jQuery('#first').wrap(val( '<div class="red"><span></span></div>' )).text(); equals( defaultText, result, 'Check for wrapping of on-the-fly html' ); @@ -80,10 +83,20 @@ var testWrap = function(val) { equals( jQuery("#nonnodes > i").text(), j.text(), "Check node,textnode,comment wraps doesn't hurt text" ); // Try wrapping a disconnected node + var cacheLength = 0; + for (var i in jQuery.cache) { + cacheLength++; + } + j = jQuery("<label/>").wrap(val( "<li/>" )); equals( j[0].nodeName.toUpperCase(), "LABEL", "Element is a label" ); equals( j[0].parentNode.nodeName.toUpperCase(), "LI", "Element has been wrapped" ); + for (i in jQuery.cache) { + cacheLength--; + } + equals(cacheLength, 0, "No memory leak in jQuery.cache (bug #7165)"); + // Wrap an element containing a text node j = jQuery("<span/>").wrap("<div>test</div>"); equals( j[0].previousSibling.nodeType, 3, "Make sure the previous node is a text element" ); @@ -102,12 +115,19 @@ var testWrap = function(val) { // Wrap an element with a jQuery set and event result = jQuery("<div></div>").click(function(){ ok(true, "Event triggered."); + + // Remove handlers on detached elements + result.unbind(); + jQuery(this).unbind(); }); j = jQuery("<span/>").wrap(result); equals( j[0].parentNode.nodeName.toLowerCase(), "div", "Wrapping works." ); j.parent().trigger("click"); + + // clean up attached elements + QUnit.reset(); } test("wrap(String|Element)", function() { @@ -382,7 +402,7 @@ test("append(Function) with incoming value", function() { }); test("append the same fragment with events (Bug #6997, 5566)", function () { - expect(4 + (document.fireEvent ? 1 : 0)); + expect(2 + (document.fireEvent ? 1 : 0)); stop(1000); var element; @@ -395,8 +415,12 @@ test("append the same fragment with events (Bug #6997, 5566)", function () { ok(true, "Event exists on original after being unbound on clone"); jQuery(this).unbind('click'); }); - element.clone(true).unbind('click')[0].fireEvent('onclick'); + var clone = element.clone(true).unbind('click'); + clone[0].fireEvent('onclick'); element[0].fireEvent('onclick'); + + // manually clean up detached elements + clone.remove(); } element = jQuery("<a class='test6997'></a>").click(function () { @@ -413,14 +437,6 @@ test("append the same fragment with events (Bug #6997, 5566)", function () { jQuery("#listWithTabIndex li").before(element); jQuery("#listWithTabIndex li.test6997").eq(1).click(); - - element = jQuery("<select><option>Foo</option><option selected>Bar</option></select>"); - - equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" ); - - element = jQuery("<input type='checkbox'>").attr('checked', 'checked'); - - equals( element.clone().is(":checked"), element.is(":checked"), "Checked input cloned correctly" ); }); test("appendTo(String|Element|Array<Element>|jQuery)", function() { @@ -856,7 +872,7 @@ test("replaceAll(String|Element|Array<Element>|jQuery)", function() { }); test("clone()", function() { - expect(36); + expect(37); equals( 'This is a normal link: Yahoo', jQuery('#en').text(), 'Assert text for #en' ); var clone = jQuery('#yahoo').clone(); equals( 'Try them out:Yahoo', jQuery('#first').append(clone).text(), 'Check for clone' ); @@ -881,20 +897,36 @@ test("clone()", function() { ok( true, "Bound event still exists." ); }); - div = div.clone(true).clone(true); + clone = div.clone(true); + + // manually clean up detached elements + div.remove(); + + div = clone.clone(true); + + // manually clean up detached elements + clone.remove(); + equals( div.length, 1, "One element cloned" ); equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); div.trigger("click"); + // manually clean up detached elements + div.remove(); + div = jQuery("<div/>").append([ document.createElement("table"), document.createElement("table") ]); div.find("table").click(function(){ ok( true, "Bound event still exists." ); }); - div = div.clone(true); - equals( div.length, 1, "One element cloned" ); - equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); - div.find("table:last").trigger("click"); + clone = div.clone(true); + equals( clone.length, 1, "One element cloned" ); + equals( clone[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); + clone.find("table:last").trigger("click"); + + // manually clean up detached elements + div.remove(); + clone.remove(); // this is technically an invalid object, but because of the special // classid instantiation it is the only kind that IE has trouble with, @@ -914,10 +946,16 @@ test("clone()", function() { equals( clone.html(), div.html(), "Element contents cloned" ); equals( clone[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" ); - div = jQuery("<div/>").data({ a: true, b: true }); - div = div.clone(true); - equals( div.data("a"), true, "Data cloned." ); - equals( div.data("b"), true, "Data cloned." ); + div = jQuery("<div/>").data({ a: true }); + clone = div.clone(true); + equals( clone.data("a"), true, "Data cloned." ); + clone.data("a", false); + equals( clone.data("a"), false, "Ensure cloned element data object was correctly modified" ); + equals( div.data("a"), true, "Ensure cloned element data object is copied, not referenced" ); + + // manually clean up detached elements + div.remove(); + clone.remove(); var form = document.createElement("form"); form.action = "/test/"; @@ -930,6 +968,28 @@ test("clone()", function() { equal( jQuery("body").clone().children()[0].id, "qunit-header", "Make sure cloning body works" ); }); +test("clone(form element) (Bug #3879, #6655)", function() { + expect(6); + element = jQuery("<select><option>Foo</option><option selected>Bar</option></select>"); + + equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" ); + + element = jQuery("<input type='checkbox' value='foo'>").attr('checked', 'checked'); + clone = element.clone(); + + equals( clone.is(":checked"), element.is(":checked"), "Checked input cloned correctly" ); + equals( clone[0].defaultValue, "foo", "Checked input defaultValue cloned correctly" ); + equals( clone[0].defaultChecked, !jQuery.support.noCloneEvent, "Checked input defaultChecked cloned correctly" ); + + element = jQuery("<input type='text' value='foo'>"); + clone = element.clone(); + equals( clone[0].defaultValue, "foo", "Text input defaultValue cloned correctly" ); + + element = jQuery("<textarea>foo</textarea>"); + clone = element.clone(); + equals( clone[0].defaultValue, "foo", "Textarea defaultValue cloned correctly" ); +}); + if (!isLocal) { test("clone() on XML nodes", function() { expect(2); @@ -1126,15 +1186,21 @@ var testRemove = function(method) { jQuery("#nonnodes").contents()[method](); equals( jQuery("#nonnodes").contents().length, 0, "Check node,textnode,comment remove works" ); + // manually clean up detached elements + if (method === "detach") { + first.remove(); + } + QUnit.reset(); var count = 0; var first = jQuery("#ap").children(":first"); - var cleanUp = first.click(function() { count++ })[method]().appendTo("body").click(); + var cleanUp = first.click(function() { count++ })[method]().appendTo("#main").click(); equals( method == "remove" ? 0 : 1, count ); - cleanUp.detach(); + // manually clean up detached elements + cleanUp.remove(); }; test("remove()", function() { @@ -1232,3 +1298,20 @@ test("jQuery.cleanData", function() { return div; } }); + +test("jQuery.buildFragment - no plain-text caching (Bug #6779)", function() { + expect(1); + + // DOM manipulation fails if added text matches an Object method + var $f = jQuery( "<div />" ).appendTo( "#main" ), + bad = [ "start-", "toString", "hasOwnProperty", "append", "here&there!", "-end" ]; + + for ( var i=0; i < bad.length; i++ ) { + try { + $f.append( bad[i] ); + } + catch(e) {} + } + equals($f.text(), bad.join(''), "Cached strings that match Object properties"); + $f.remove(); +}); diff --git a/test/unit/offset.js b/test/unit/offset.js index 879753181..329d69f95 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -1,4 +1,4 @@ -module("offset"); +module("offset", { teardown: moduleTeardown }); test("disconnected node", function() { expect(2); @@ -13,9 +13,9 @@ var supportsScroll = false; testoffset("absolute"/* in iframe */, function($, iframe) { expect(4); - + var doc = iframe.document, tests; - + // force a scroll value on the main window // this insures that the results will be wrong // if the offset method is using the scroll offset @@ -28,7 +28,7 @@ testoffset("absolute"/* in iframe */, function($, iframe) { } window.scrollTo(1, 1); - + // get offset tests = [ { id: '#absolute-1', top: 1, left: 1 } @@ -47,16 +47,16 @@ testoffset("absolute"/* in iframe */, function($, iframe) { equals( jQuery( this.id, doc ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); equals( jQuery( this.id, doc ).position().left, this.left, "jQuery('" + this.id + "').position().left" ); }); - + forceScroll.remove(); }); testoffset("absolute", function( jQuery ) { expect(178); - + // get offset tests var tests = [ - { id: '#absolute-1', top: 1, left: 1 }, + { id: '#absolute-1', top: 1, left: 1 }, { id: '#absolute-1-1', top: 5, left: 5 }, { id: '#absolute-1-1-1', top: 9, left: 9 }, { id: '#absolute-2', top: 20, left: 20 } @@ -65,8 +65,8 @@ testoffset("absolute", function( jQuery ) { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" ); }); - - + + // get position tests = [ { id: '#absolute-1', top: 0, left: 0 }, @@ -78,13 +78,13 @@ testoffset("absolute", function( jQuery ) { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" ); }); - + // test #5781 var offset = jQuery( '#positionTest' ).offset({ top: 10, left: 10 }).offset(); equals( offset.top, 10, "Setting offset on element with position absolute but 'auto' values." ) equals( offset.left, 10, "Setting offset on element with position absolute but 'auto' values." ) - - + + // set offset tests = [ { id: '#absolute-2', top: 30, left: 30 }, @@ -108,9 +108,9 @@ testoffset("absolute", function( jQuery ) { jQuery( this.id ).offset({ top: this.top, left: this.left }); equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" ); - + var top = this.top, left = this.left; - + jQuery( this.id ).offset(function(i, val){ equals( val.top, top, "Verify incoming top position." ); equals( val.left, left, "Verify incoming top position." ); @@ -118,13 +118,13 @@ testoffset("absolute", function( jQuery ) { }); equals( jQuery( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + (this.top + 1) + " })" ); equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + " })" ); - + jQuery( this.id ) .offset({ left: this.left + 2 }) .offset({ top: this.top + 2 }); equals( jQuery( this.id ).offset().top, this.top + 2, "Setting one property at a time." ); equals( jQuery( this.id ).offset().left, this.left + 2, "Setting one property at a time." ); - + jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) { jQuery( this ).css({ top: props.top + 1, @@ -138,10 +138,10 @@ testoffset("absolute", function( jQuery ) { testoffset("relative", function( jQuery ) { expect(60); - + // IE is collapsing the top margin of 1px var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; - + // get offset var tests = [ { id: '#relative-1', top: ie ? 6 : 7, left: 7 }, @@ -152,8 +152,8 @@ testoffset("relative", function( jQuery ) { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" ); }); - - + + // get position tests = [ { id: '#relative-1', top: ie ? 5 : 6, left: 6 }, @@ -164,8 +164,8 @@ testoffset("relative", function( jQuery ) { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" ); equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" ); }); - - + + // set offset tests = [ { id: '#relative-2', top: 200, left: 50 }, @@ -185,7 +185,7 @@ testoffset("relative", function( jQuery ) { jQuery( this.id ).offset({ top: this.top, left: this.left }); equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" ); - + jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) { jQuery( this ).css({ top: props.top + 1, @@ -199,10 +199,10 @@ testoffset("relative", function( jQuery ) { testoffset("static", function( jQuery ) { expect(80); - + // IE is collapsing the top margin of 1px var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; - + // get offset var tests = [ { id: '#static-1', top: ie ? 6 : 7, left: 7 }, @@ -214,8 +214,8 @@ testoffset("static", function( jQuery ) { equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" ); }); - - + + // get position tests = [ { id: '#static-1', top: ie ? 5 : 6, left: 6 }, @@ -227,8 +227,8 @@ testoffset("static", function( jQuery ) { equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.top + "').position().top" ); equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.left +"').position().left" ); }); - - + + // set offset tests = [ { id: '#static-2', top: 200, left: 200 }, @@ -252,7 +252,7 @@ testoffset("static", function( jQuery ) { jQuery( this.id ).offset({ top: this.top, left: this.left }); equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" ); - + jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) { jQuery( this ).css({ top: props.top + 1, @@ -266,9 +266,9 @@ testoffset("static", function( jQuery ) { testoffset("fixed", function( jQuery ) { expect(28); - + jQuery.offset.initialize(); - + var tests = [ { id: '#fixed-1', top: 1001, left: 1001 }, { id: '#fixed-2', top: 1021, left: 1021 } @@ -288,7 +288,7 @@ testoffset("fixed", function( jQuery ) { ok( true, 'Fixed position is not supported' ); } }); - + tests = [ { id: '#fixed-1', top: 100, left: 100 }, { id: '#fixed-1', top: 0, left: 0 }, @@ -297,13 +297,13 @@ testoffset("fixed", function( jQuery ) { { id: '#fixed-2', top: 0, left: 0 }, { id: '#fixed-2', top: -5, left: -5 } ]; - + jQuery.each( tests, function() { if ( jQuery.offset.supportsFixedPosition ) { jQuery( this.id ).offset({ top: this.top, left: this.left }); equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" ); - + jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) { jQuery( this ).css({ top: props.top + 1, @@ -324,38 +324,38 @@ testoffset("fixed", function( jQuery ) { testoffset("table", function( jQuery ) { expect(4); - + equals( jQuery('#table-1').offset().top, 6, "jQuery('#table-1').offset().top" ); equals( jQuery('#table-1').offset().left, 6, "jQuery('#table-1').offset().left" ); - + equals( jQuery('#th-1').offset().top, 10, "jQuery('#th-1').offset().top" ); equals( jQuery('#th-1').offset().left, 10, "jQuery('#th-1').offset().left" ); }); testoffset("scroll", function( jQuery, win ) { expect(16); - + var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; - + // IE is collapsing the top margin of 1px equals( jQuery('#scroll-1').offset().top, ie ? 6 : 7, "jQuery('#scroll-1').offset().top" ); equals( jQuery('#scroll-1').offset().left, 7, "jQuery('#scroll-1').offset().left" ); - + // IE is collapsing the top margin of 1px equals( jQuery('#scroll-1-1').offset().top, ie ? 9 : 11, "jQuery('#scroll-1-1').offset().top" ); equals( jQuery('#scroll-1-1').offset().left, 11, "jQuery('#scroll-1-1').offset().left" ); - - + + // scroll offset tests .scrollTop/Left equals( jQuery('#scroll-1').scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" ); equals( jQuery('#scroll-1').scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" ); - + equals( jQuery('#scroll-1-1').scrollTop(), 0, "jQuery('#scroll-1-1').scrollTop()" ); equals( jQuery('#scroll-1-1').scrollLeft(), 0, "jQuery('#scroll-1-1').scrollLeft()" ); - + // equals( jQuery('body').scrollTop(), 0, "jQuery('body').scrollTop()" ); // equals( jQuery('body').scrollLeft(), 0, "jQuery('body').scrollTop()" ); - + win.name = "test"; if ( !supportsScroll ) { @@ -367,11 +367,11 @@ testoffset("scroll", function( jQuery, win ) { } else { equals( jQuery(win).scrollTop(), 1000, "jQuery(window).scrollTop()" ); equals( jQuery(win).scrollLeft(), 1000, "jQuery(window).scrollLeft()" ); - + equals( jQuery(win.document).scrollTop(), 1000, "jQuery(document).scrollTop()" ); equals( jQuery(win.document).scrollLeft(), 1000, "jQuery(document).scrollLeft()" ); } - + // test jQuery using parent window/document // jQuery reference here is in the iframe window.scrollTo(0,0); @@ -383,7 +383,7 @@ testoffset("scroll", function( jQuery, win ) { testoffset("body", function( jQuery ) { expect(2); - + equals( jQuery('body').offset().top, 1, "jQuery('#body').offset().top" ); equals( jQuery('body').offset().left, 1, "jQuery('#body').offset().left" ); }); @@ -423,11 +423,11 @@ test("offsetParent", function(){ }); function testoffset(name, fn) { - + test(name, function() { // pause execution for now stop(); - + // load fixture in iframe var iframe = loadFixture(), win = iframe.contentWindow, @@ -443,7 +443,7 @@ function testoffset(name, fn) { } }, 15 ); }); - + function loadFixture() { var src = './data/offset/' + name + '.html?' + parseInt( Math.random()*1000, 10 ), iframe = jQuery('<iframe />').css({ diff --git a/test/unit/queue.js b/test/unit/queue.js index 79b753c11..31e587db2 100644 --- a/test/unit/queue.js +++ b/test/unit/queue.js @@ -1,11 +1,11 @@ -module("queue"); +module("queue", { teardown: moduleTeardown }); test("queue() with other types",function() { expect(9); var counter = 0; - + var $div = jQuery({}); - + $div .queue('foo',function(){ equals( ++counter, 1, "Dequeuing" ); @@ -21,26 +21,26 @@ test("queue() with other types",function() { .queue('foo',function(){ equals( ++counter, 4, "Dequeuing" ); }); - + equals( $div.queue('foo').length, 4, "Testing queue length" ); - + $div.dequeue('foo'); - + equals( counter, 3, "Testing previous call to dequeue" ); equals( $div.queue('foo').length, 1, "Testing queue length" ); - + $div.dequeue('foo'); - + equals( counter, 4, "Testing previous call to dequeue" ); equals( $div.queue('foo').length, 0, "Testing queue length" ); }); test("queue(name) passes in the next item in the queue as a parameter", function() { expect(2); - + var div = jQuery({}); var counter = 0; - + div.queue("foo", function(next) { equals(++counter, 1, "Dequeueing"); next(); @@ -50,16 +50,16 @@ test("queue(name) passes in the next item in the queue as a parameter", function }).queue("bar", function() { equals(++counter, 3, "Other queues are not triggered by next()") }); - + div.dequeue("foo"); }); test("queue(name) passes in the next item in the queue as a parameter", function() { expect(2); - + var div = jQuery({}); var counter = 0; - + div.queue("foo", function(next) { equals(++counter, 1, "Dequeueing"); next(); @@ -69,17 +69,17 @@ test("queue(name) passes in the next item in the queue as a parameter", function }).queue("bar", function() { equals(++counter, 3, "Other queues are not triggered by next()") }); - + div.dequeue("foo"); }); test("queue() passes in the next item in the queue as a parameter to fx queues", function() { expect(2); stop(); - + var div = jQuery({}); var counter = 0; - + div.queue(function(next) { equals(++counter, 1, "Dequeueing"); var self = this; @@ -111,10 +111,10 @@ test("delay()", function() { test("clearQueue(name) clears the queue", function() { expect(1); - + var div = jQuery({}); var counter = 0; - + div.queue("foo", function(next) { counter++; jQuery(this).clearQueue("foo"); @@ -122,18 +122,18 @@ test("clearQueue(name) clears the queue", function() { }).queue("foo", function(next) { counter++; }); - + div.dequeue("foo"); - + equals(counter, 1, "the queue was cleared"); }); test("clearQueue() clears the fx queue", function() { expect(1); - + var div = jQuery({}); var counter = 0; - + div.queue(function(next) { counter++; var self = this; @@ -141,8 +141,8 @@ test("clearQueue() clears the fx queue", function() { }).queue(function(next) { counter++; }); - + equals(counter, 1, "the queue was cleared"); - + div.removeData(); }); diff --git a/test/unit/selector.js b/test/unit/selector.js index 6ec20bc40..6a3832555 100644 --- a/test/unit/selector.js +++ b/test/unit/selector.js @@ -1,4 +1,4 @@ -module("selector"); +module("selector", { teardown: moduleTeardown }); test("element", function() { expect(21); @@ -22,7 +22,7 @@ test("element", function() { same( jQuery("div").find("p").get(), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." ); same( jQuery("#form").find("select").get(), q("select1","select2","select3","select4","select5"), "Finding selects with a context." ); - + ok( jQuery("#length").length, '<input name="length"> cannot be found under IE, see #945' ); ok( jQuery("#lengthtest input").length, '<input name="length"> cannot be found under IE, see #945' ); @@ -58,17 +58,18 @@ if ( location.protocol != "file:" ) { } test("broken", function() { - expect(8); + expect(19); + function broken(name, selector) { try { jQuery(selector); ok( false, name + ": " + selector ); } catch(e){ - ok( typeof e === "string" && e.indexOf("Syntax error") >= 0, + ok( typeof e === "string" && e.indexOf("Syntax error") >= 0, name + ": " + selector ); } } - + broken( "Broken Selector", "[", [] ); broken( "Broken Selector", "(", [] ); broken( "Broken Selector", "{", [] ); @@ -77,10 +78,31 @@ test("broken", function() { broken( "Broken Selector", "<>", [] ); broken( "Broken Selector", "{}", [] ); broken( "Doesn't exist", ":visble", [] ); + broken( "Nth-child", ":nth-child", [] ); + broken( "Nth-child", ":nth-child(-)", [] ); + // Sigh. WebKit thinks this is a real selector in qSA + // They've already fixed this and it'll be coming into + // current browsers soon. + //broken( "Nth-child", ":nth-child(asdf)", [] ); + broken( "Nth-child", ":nth-child(2n+-0)", [] ); + broken( "Nth-child", ":nth-child(2+0)", [] ); + broken( "Nth-child", ":nth-child(- 1n)", [] ); + broken( "Nth-child", ":nth-child(-1 n)", [] ); + broken( "First-child", ":first-child(n)", [] ); + broken( "Last-child", ":last-child(n)", [] ); + broken( "Only-child", ":only-child(n)", [] ); + + // Make sure attribute value quoting works correctly. See: #6093 + var attrbad = jQuery('<input type="hidden" value="2" name="foo.baz" id="attrbad1"/><input type="hidden" value="2" name="foo[baz]" id="attrbad2"/>').appendTo("body"); + + broken( "Attribute not escaped", "input[name=foo.baz]", [] ); + broken( "Attribute not escaped", "input[name=foo[baz]]", [] ); + + attrbad.remove(); }); test("id", function() { - expect(28); + expect(29); t( "ID Selector", "#body", ["body"] ); t( "ID Selector w/ Element", "body#body", ["body"] ); t( "ID Selector w/ Element", "ul#first", [] ); @@ -90,32 +112,35 @@ test("id", function() { t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", ["台北Táiběi","台北"] ); t( "Descendant ID selector using UTF8", "div #台北", ["台北"] ); t( "Child ID selector using UTF8", "form > #台北", ["台北"] ); - + t( "Escaped ID", "#foo\\:bar", ["foo:bar"] ); t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] ); t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] ); t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); - + t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] ); // bug #267 t( "ID Selector, not an ancestor ID", "#form #first", [] ); t( "ID Selector, not a child ID", "#form > #option1a", [] ); - + t( "All Children of ID", "#foo > *", ["sndp", "en", "sap"] ); t( "All Children of ID with no children", "#firstUL > *", [] ); - + var a = jQuery('<div><a name="tName1">tName1 A</a><a name="tName2">tName2 A</a><div id="tName1">tName1 Div</div></div>').appendTo('#main'); equals( jQuery("#tName1")[0].id, 'tName1', "ID selector with same value for a name attribute" ); equals( jQuery("#tName2").length, 0, "ID selector non-existing but name attribute on an A tag" ); a.remove(); t( "ID Selector on Form with an input that has a name of 'id'", "#lengthtest", ["lengthtest"] ); - + t( "ID selector with non-existant ancestor", "#asdfasdf #foobar", [] ); // bug #986 same( jQuery("body").find("div#form").get(), [], "ID selector within the context of another element" ); + //#7533 + equal( jQuery("<div id=\"A'B~C.D[E]\"><p>foo</p></div>").find("p").length, 1, "Find where context root is a node and has an ID with CSS3 meta characters" ); + t( "Underscore ID", "#types_all", ["types_all"] ); t( "Dash ID", "#fx-queue", ["fx-queue"] ); @@ -134,7 +159,7 @@ test("class", function() { same( jQuery(".blog", "p").get(), q("mark", "simon"), "Finding elements with a context." ); same( jQuery(".blog", jQuery("p")).get(), q("mark", "simon"), "Finding elements with a context." ); same( jQuery("p").find(".blog").get(), q("mark", "simon"), "Finding elements with a context." ); - + t( "Class selector using UTF8", ".台北Táiběi", ["utf8class1"] ); //t( "Class selector using UTF8", ".台北", ["utf8class1","utf8class2"] ); t( "Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"] ); @@ -150,7 +175,7 @@ test("class", function() { t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] ); var div = document.createElement("div"); - div.innerHTML = "<div class='test e'></div><div class='test'></div>"; + div.innerHTML = "<div class='test e'></div><div class='test'></div>"; same( jQuery(".e", div).get(), [ div.firstChild ], "Finding a second class." ); div.lastChild.className = "e"; @@ -194,7 +219,7 @@ test("name", function() { test("multiple", function() { expect(4); - + t( "Comma Support", "h2, p", ["qunit-banner","qunit-userAgent","firstp","ap","sndp","en","sap","first"]); t( "Comma Support", "h2 , p", ["qunit-banner","qunit-userAgent","firstp","ap","sndp","en","sap","first"]); t( "Comma Support", "h2 , p", ["qunit-banner","qunit-userAgent","firstp","ap","sndp","en","sap","first"]); @@ -202,7 +227,7 @@ test("multiple", function() { }); test("child and adjacent", function() { - expect(27); + expect(31); t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] ); t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] ); @@ -210,20 +235,25 @@ test("child and adjacent", function() { t( "Child w/ Class", "p > a.blog", ["mark","simon"] ); t( "All Children", "code > *", ["anchor1","anchor2"] ); t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] ); - t( "Adjacent", "#main a + a", ["groups"] ); - t( "Adjacent", "#main a +a", ["groups"] ); - t( "Adjacent", "#main a+ a", ["groups"] ); - t( "Adjacent", "#main a+a", ["groups"] ); + t( "Adjacent", "a + a", ["groups"] ); + t( "Adjacent", "a +a", ["groups"] ); + t( "Adjacent", "a+ a", ["groups"] ); + t( "Adjacent", "a+a", ["groups"] ); t( "Adjacent", "p + p", ["ap","en","sap"] ); t( "Adjacent", "p#firstp + p", ["ap"] ); t( "Adjacent", "p[lang=en] + p", ["sap"] ); t( "Adjacent", "a.GROUPS + code + a", ["mark"] ); - t( "Comma, Child, and Adjacent", "#main a + a, code > a", ["groups","anchor1","anchor2"] ); + t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] ); t( "Element Preceded By", "p ~ div", ["foo", "moretests","tabindex-tests", "liveHandlerOrder", "siblingTest"] ); t( "Element Preceded By", "#first ~ div", ["moretests","tabindex-tests", "liveHandlerOrder", "siblingTest"] ); t( "Element Preceded By", "#groups ~ a", ["mark"] ); t( "Element Preceded By", "#length ~ input", ["idTest"] ); t( "Element Preceded By", "#siblingfirst ~ em", ["siblingnext"] ); + same( jQuery("#siblingfirst").find("~ em").get(), q("siblingnext"), "Element Preceded By with a context." ); + same( jQuery("#siblingfirst").find("+ em").get(), q("siblingnext"), "Element Directly Preceded By with a context." ); + var a = jQuery("<div id='foo'></div><p id='bar'></p><p id='bar2'></p>"); + same( jQuery("~ p", a[0]).get(), [a[1], a[2]], "Detached Element Directly Preceded By with a context." ); + same( jQuery("+ p", a[0]).get(), [a[1]], "Detached Element Preceded By with a context." ); t( "Verify deep class selector", "div.blah > p > a", [] ); @@ -237,12 +267,13 @@ test("child and adjacent", function() { }); test("attributes", function() { - expect(39); + expect(41); + t( "Attribute Exists", "a[title]", ["google"] ); t( "Attribute Exists", "*[title]", ["google"] ); t( "Attribute Exists", "[title]", ["google"] ); t( "Attribute Exists", "a[ title ]", ["google"] ); - + t( "Attribute Equals", "a[rel='bookmark']", ["simon1"] ); t( "Attribute Equals", 'a[rel="bookmark"]', ["simon1"] ); t( "Attribute Equals", "a[rel=bookmark]", ["simon1"] ); @@ -263,13 +294,13 @@ test("attributes", function() { t( "Attribute containing []", "input[name$='[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name$='foo[bar]']", ["hidden2"] ); t( "Attribute containing []", "input[name*='foo[bar]']", ["hidden2"] ); - + t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type='hidden']", ["radio1", "radio2", "hidden1"] ); t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type=\"hidden\"]", ["radio1", "radio2", "hidden1"] ); t( "Multiple Attribute Equals", "#form input[type='radio'], #form input[type=hidden]", ["radio1", "radio2", "hidden1"] ); - + t( "Attribute selector using UTF8", "span[lang=中文]", ["台北"] ); - + t( "Attribute Begins With", "a[href ^= 'http://www']", ["google","yahoo"] ); t( "Attribute Ends With", "a[href $= 'org/']", ["mark"] ); t( "Attribute Contains", "a[href *= 'google']", ["google","groups"] ); @@ -288,16 +319,24 @@ test("attributes", function() { t("Empty values", "#select1 option[value='']", ["option1a"]); t("Empty values", "#select1 option[value!='']", ["option1b","option1c","option1d"]); - + t("Select options via :selected", "#select1 option:selected", ["option1a"] ); t("Select options via :selected", "#select2 option:selected", ["option2d"] ); t("Select options via :selected", "#select3 option:selected", ["option3b", "option3c"] ); - + t( "Grouped Form Elements", "input[name='foo[bar]']", ["hidden2"] ); + + // Make sure attribute value quoting works correctly. See: #6093 + var attrbad = jQuery('<input type="hidden" value="2" name="foo.baz" id="attrbad1"/><input type="hidden" value="2" name="foo[baz]" id="attrbad2"/>').appendTo("body"); + + t("Find escaped attribute value", "input[name=foo\\.baz]", ["attrbad1"]); + t("Find escaped attribute value", "input[name=foo\\[baz\\]]", ["attrbad2"]); + + attrbad.remove(); }); test("pseudo - child", function() { - expect(31); + expect(38); t( "First Child", "p:first-child", ["firstp","sndp"] ); t( "Last Child", "p:last-child", ["sap"] ); t( "Only Child", "#main a:only-child", ["simon1","anchor1","yahoo","anchor2","liveLink1","liveLink2"] ); @@ -306,6 +345,7 @@ test("pseudo - child", function() { t( "First Child", "p:first-child", ["firstp","sndp"] ); t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] ); + t( "Nth Child With Whitespace", "p:nth-child( 1 )", ["firstp","sndp"] ); t( "Not Nth Child", "p:not(:nth-child(1))", ["ap","en","sap","first"] ); // Verify that the child position isn't being cached improperly @@ -315,22 +355,26 @@ test("pseudo - child", function() { t( "First Child", "p:first-child", [] ); QUnit.reset(); - + t( "Last Child", "p:last-child", ["sap"] ); t( "Last Child", "#main a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon","liveLink1","liveLink2"] ); - + t( "Nth-child", "#main form#form > *:nth-child(2)", ["text1"] ); t( "Nth-child", "#main form#form > :nth-child(2)", ["text1"] ); + t( "Nth-child", "#form select:first option:nth-child(-1)", [] ); t( "Nth-child", "#form select:first option:nth-child(3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(0n+3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(1n+0)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(1n)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(n)", ["option1a", "option1b", "option1c", "option1d"] ); + t( "Nth-child", "#form select:first option:nth-child(+n)", ["option1a", "option1b", "option1c", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(even)", ["option1b", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(odd)", ["option1a", "option1c"] ); t( "Nth-child", "#form select:first option:nth-child(2n)", ["option1b", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(2n+1)", ["option1a", "option1c"] ); + t( "Nth-child", "#form select:first option:nth-child(2n + 1)", ["option1a", "option1c"] ); + t( "Nth-child", "#form select:first option:nth-child(+2n + 1)", ["option1a", "option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n+1)", ["option1a", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(3n+2)", ["option1b"] ); @@ -339,7 +383,9 @@ test("pseudo - child", function() { t( "Nth-child", "#form select:first option:nth-child(3n-2)", ["option1a", "option1d"] ); t( "Nth-child", "#form select:first option:nth-child(3n-3)", ["option1c"] ); t( "Nth-child", "#form select:first option:nth-child(3n+0)", ["option1c"] ); + t( "Nth-child", "#form select:first option:nth-child(-1n+3)", ["option1a", "option1b", "option1c"] ); t( "Nth-child", "#form select:first option:nth-child(-n+3)", ["option1a", "option1b", "option1c"] ); + t( "Nth-child", "#form select:first option:nth-child(-1n + 3)", ["option1a", "option1b", "option1c"] ); }); test("pseudo - misc", function() { @@ -347,7 +393,7 @@ test("pseudo - misc", function() { t( "Headers", ":header", ["qunit-header", "qunit-banner", "qunit-userAgent"] ); t( "Has Children - :has()", "p:has(a)", ["firstp","ap","en","sap"] ); - + var select = document.getElementById("select1"); ok( (window.Sizzle || window.jQuery.find).matchesSelector( select, ":has(option)" ), "Has Option Matches" ); @@ -393,7 +439,7 @@ test("pseudo - :not", function() { t( ":not() Multiple Class", "#foo a:not(.blog.link)", ["yahoo","anchor2"] ); }); -test("pseudo - position", function() { +test("pseudo - position", function() { expect(25); t( "nth Element", "p:nth(1)", ["ap"] ); t( "First Element", "p:first", ["firstp"] ); diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 0d079f19a..56fed2200 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -1,4 +1,4 @@ -module("traversing"); +module("traversing", { teardown: moduleTeardown }); test("find(String)", function() { expect(5); @@ -138,7 +138,7 @@ test("closest()", function() { same( jq.closest("html", document.body).get(), [], "Context limited." ); same( jq.closest("body", document.body).get(), [], "Context limited." ); same( jq.closest("#nothiddendiv", document.body).get(), q("nothiddendiv"), "Context not reached." ); - + //Test that .closest() returns unique'd set equals( jQuery('#main p').closest('#main').length, 1, "Closest should return a unique set" ); @@ -275,9 +275,9 @@ test("parents([String])", function() { test("parentsUntil([String])", function() { expect(9); - + var parents = jQuery("#groups").parents(); - + same( jQuery("#groups").parentsUntil().get(), parents.get(), "parentsUntil with no selector (nextAll)" ); same( jQuery("#groups").parentsUntil(".foo").get(), parents.get(), "parentsUntil with invalid selector (nextAll)" ); same( jQuery("#groups").parentsUntil("#html").get(), parents.not(':last').get(), "Simple parentsUntil check" ); @@ -307,9 +307,9 @@ test("prev([String])", function() { test("nextAll([String])", function() { expect(4); - + var elems = jQuery('#form').children(); - + same( jQuery("#label-for").nextAll().get(), elems.not(':first').get(), "Simple nextAll check" ); same( jQuery("#label-for").nextAll('input').get(), elems.not(':first').filter('input').get(), "Filtered nextAll check" ); same( jQuery("#label-for").nextAll('input,select').get(), elems.not(':first').filter('input,select').get(), "Multiple-filtered nextAll check" ); @@ -318,9 +318,9 @@ test("nextAll([String])", function() { test("prevAll([String])", function() { expect(4); - + var elems = jQuery( jQuery('#form').children().slice(0, 12).get().reverse() ); - + same( jQuery("#area1").prevAll().get(), elems.get(), "Simple prevAll check" ); same( jQuery("#area1").prevAll('input').get(), elems.filter('input').get(), "Filtered prevAll check" ); same( jQuery("#area1").prevAll('input,select').get(), elems.filter('input,select').get(), "Multiple-filtered prevAll check" ); @@ -329,9 +329,9 @@ test("prevAll([String])", function() { test("nextUntil([String])", function() { expect(11); - + var elems = jQuery('#form').children().slice( 2, 12 ); - + same( jQuery("#text1").nextUntil().get(), jQuery("#text1").nextAll().get(), "nextUntil with no selector (nextAll)" ); same( jQuery("#text1").nextUntil(".foo").get(), jQuery("#text1").nextAll().get(), "nextUntil with invalid selector (nextAll)" ); same( jQuery("#text1").nextUntil("#area1").get(), elems.get(), "Simple nextUntil check" ); @@ -342,15 +342,15 @@ test("nextUntil([String])", function() { same( jQuery("#text1").nextUntil("#area1", "button,input").get(), elems.get(), "Multiple-filtered nextUntil check" ); equals( jQuery("#text1").nextUntil("#area1", "div").length, 0, "Filtered nextUntil check, no match" ); same( jQuery("#text1, #hidden1").nextUntil("#area1", "button,input").get(), elems.get(), "Multi-source, multiple-filtered nextUntil check" ); - + same( jQuery("#text1").nextUntil("[class=foo]").get(), jQuery("#text1").nextAll().get(), "Non-element nodes must be skipped, since they have no attributes" ); }); test("prevUntil([String])", function() { expect(10); - + var elems = jQuery("#area1").prevAll(); - + same( jQuery("#area1").prevUntil().get(), elems.get(), "prevUntil with no selector (prevAll)" ); same( jQuery("#area1").prevUntil(".foo").get(), elems.get(), "prevUntil with invalid selector (prevAll)" ); same( jQuery("#area1").prevUntil("label").get(), elems.not(':last').get(), "Simple prevUntil check" ); @@ -440,12 +440,13 @@ test("add(String|Element|Array|undefined)", function() { test("add(String, Context)", function() { expect(6); - - equals( jQuery(document).add("#form").length, 2, "Make sure that using regular context document still works." ); - equals( jQuery(document.body).add("#form").length, 2, "Using a body context." ); - equals( jQuery(document.body).add("#html").length, 1, "Using a body context." ); - - equals( jQuery(document).add("#form", document).length, 2, "Use a passed in document context." ); - equals( jQuery(document).add("#form", document.body).length, 2, "Use a passed in body context." ); - equals( jQuery(document).add("#html", document.body).length, 1, "Use a passed in body context." ); + + deepEqual( jQuery( "#firstp" ).add( "#ap" ).get(), q( "firstp", "ap" ), "Add selector to selector " ); + deepEqual( jQuery( document.getElementById("firstp") ).add( "#ap" ).get(), q( "firstp", "ap" ), "Add gEBId to selector" ); + deepEqual( jQuery( document.getElementById("firstp") ).add( document.getElementById("ap") ).get(), q( "firstp", "ap" ), "Add gEBId to gEBId" ); + + var ctx = document.getElementById("firstp"); + deepEqual( jQuery( "#firstp" ).add( "#ap", ctx ).get(), q( "firstp" ), "Add selector to selector " ); + deepEqual( jQuery( document.getElementById("firstp") ).add( "#ap", ctx ).get(), q( "firstp" ), "Add gEBId to selector, not in context" ); + deepEqual( jQuery( document.getElementById("firstp") ).add( "#ap", document.getElementsByTagName("body")[0] ).get(), q( "firstp", "ap" ), "Add gEBId to selector, in context" ); }); |