diff options
Diffstat (limited to 'test')
38 files changed, 2857 insertions, 830 deletions
diff --git a/test/data/dashboard.xml b/test/data/dashboard.xml index 10f6b3347..5a6f56142 100644 --- a/test/data/dashboard.xml +++ b/test/data/dashboard.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <dashboard> <locations class="foo"> - <location for="bar"> + <location for="bar" checked="different"> <infowindowtab> <tab title="Location"><![CDATA[blabla]]></tab> <tab title="Users"><![CDATA[blublu]]></tab> diff --git a/test/data/offset/absolute.html b/test/data/offset/absolute.html index 9d7990a37..3868d6eb2 100644 --- a/test/data/offset/absolute.html +++ b/test/data/offset/absolute.html @@ -16,6 +16,7 @@ #positionTest { position: absolute; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/body.html b/test/data/offset/body.html index 8dbf282df..1678c2b25 100644 --- a/test/data/offset/body.html +++ b/test/data/offset/body.html @@ -9,6 +9,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/fixed.html b/test/data/offset/fixed.html index 81ba4ca7d..75e8b1f0a 100644 --- a/test/data/offset/fixed.html +++ b/test/data/offset/fixed.html @@ -13,6 +13,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/relative.html b/test/data/offset/relative.html index 280a2fc0e..6d0bb8d3e 100644 --- a/test/data/offset/relative.html +++ b/test/data/offset/relative.html @@ -11,6 +11,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/scroll.html b/test/data/offset/scroll.html index a0d1f4d18..c570e6c1a 100644 --- a/test/data/offset/scroll.html +++ b/test/data/offset/scroll.html @@ -14,6 +14,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/static.html b/test/data/offset/static.html index a61b6d10e..d78a2c4ea 100644 --- a/test/data/offset/static.html +++ b/test/data/offset/static.html @@ -11,6 +11,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/offset/table.html b/test/data/offset/table.html index 11fb0e795..83ef6c475 100644 --- a/test/data/offset/table.html +++ b/test/data/offset/table.html @@ -11,6 +11,7 @@ #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } </style> <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> <script src="../../../src/deferred.js"></script> <script src="../../../src/support.js"></script> <script src="../../../src/sizzle/sizzle.js"></script> diff --git a/test/data/selector.html b/test/data/selector.html new file mode 100644 index 000000000..8ffc6c6b3 --- /dev/null +++ b/test/data/selector.html @@ -0,0 +1,133 @@ +<!doctype html> +<html> +<head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <title>jQuery selector</title> + + <script src="../../src/core.js"></script> + <script src="../../src/callbacks.js"></script> + <script src="../../src/deferred.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> + + <script id="script1" + defer + async></script> + + <script type="text/javascript"> + document.createElement('video'); + document.createElement('audio'); + document.createElement('article'); + document.createElement('details'); + </script> +</head> +<body> + <img id="img1" + ismap> + + <hr id="hr1" + noshade> + + <form id="form1" + name="formName" + novalidate + formnovalidate> + <input type="text" id="text1" + tabindex="1" + name="name" + required + autofocus + readonly> + <textarea id="textarea1" + noresize></textarea> + </form> + + <table> + <tr><td id="td1" + nowrap></td></tr> + </table> + + <iframe id="iframe1" + src="iframe.html" + seamless></iframe> + + <style id="style1" + scoped></style> + + <ol id="ol1" + reversed></ol> + + <article id="article1" + pubdate></article> + + <details id="details1" + open></details> + + <div id="div1" + nowrap + hidden + itemscope + draggable="true" + contenteditable="true" + aria-disabled="true"> + <p>My name is <span id="span1" + spellcheck="true" + itemprop="name">Elizabeth</span>.</p> + </div> + + <audio id="audio1" + muted></audio> + + <video id="video1" + loop + controls + autoplay + autobuffer></video> + + <map id="map1"> + <area id="area1" + nohref + shape="default"> + </map> + + <input id="check1" + type="checkbox" + disabled + checked> + + <select id="select1" + multiple> + <option id="option1" + selected + value="blar">blar</option> + </select> + + <dl id="dl" + compact> + <dt>Term</dt><dd>This is the first definition in compact format.</dd> + <dt>Term</dt><dd>This is the second definition in compact format.</dd> + </dl> + + <object id="object1" + declare></object> + + <marquee id="marquee1" + direction="up" + truespeed>Scrolling text (non-standard)</marquee> +</body> +</html> diff --git a/test/data/statusText.php b/test/data/statusText.php new file mode 100644 index 000000000..daf58ce3f --- /dev/null +++ b/test/data/statusText.php @@ -0,0 +1,5 @@ +<?php + +header( "HTTP/1.0 $_GET[status] $_GET[text]" ); + +?>
\ No newline at end of file diff --git a/test/data/support/bodyBackground.html b/test/data/support/bodyBackground.html new file mode 100644 index 000000000..824fe65e4 --- /dev/null +++ b/test/data/support/bodyBackground.html @@ -0,0 +1,38 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr" id="html"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <style> + body { + background: #000000; + } + </style> +</head> +<body> + <div> + <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> + <script src="../../../src/deferred.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> + </div> + <script> + window.parent.supportCallback( jQuery( "body" ).css( "backgroundColor" ), jQuery.support ); + </script> +</body> +</html> diff --git a/test/data/support/boxModelIE.html b/test/data/support/boxModelIE.html new file mode 100644 index 000000000..59bd37b46 --- /dev/null +++ b/test/data/support/boxModelIE.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> + <script src="../../../src/deferred.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> + <script> + window.parent.supportCallback( document.compatMode, jQuery.support.boxModel ); + </script> +</body> +</html> diff --git a/test/data/support/hiddenIFrameFF.html b/test/data/support/hiddenIFrameFF.html new file mode 100644 index 000000000..a21708d57 --- /dev/null +++ b/test/data/support/hiddenIFrameFF.html @@ -0,0 +1,26 @@ +<html> + <head> + <script src="../../../src/core.js"></script> + <script src="../../../src/callbacks.js"></script> + <script src="../../../src/deferred.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> + </body> +</html> diff --git a/test/data/support/testElementCrash.html b/test/data/support/testElementCrash.html new file mode 100644 index 000000000..db2c45500 --- /dev/null +++ b/test/data/support/testElementCrash.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <style> + body { + background: url('http://s1.postimage.org/2d2r8xih0/body_background.png'); + } + </style> + <script src="../../../src/core.js"></script> + <script src="../../../src/deferred.js"></script> + <script src="../../../src/support.js"></script> +</head> +<body> + <script> + window.parent.supportCallback(); + </script> +</body> +</html> diff --git a/test/data/testinit.js b/test/data/testinit.js index 3b2da85fd..7d566faa5 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -32,8 +32,7 @@ function q() { /** * Asserts that a select matches the given IDs * @example t("Check for something", "//[a]", ["foo", "baar"]); - * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baa -r' + * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' */ function t(a,b,c) { var f = jQuery(b).get(), s = ""; diff --git a/test/data/testrunner.js b/test/data/testrunner.js index beb0fe2ab..6d44b460c 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -2,8 +2,9 @@ jQuery.noConflict(); // Allow the test to run with other libs or jQuery's. // jQuery-specific QUnit.reset (function() { - var reset = QUnit.reset; - var ajaxSettings = jQuery.ajaxSettings + var reset = QUnit.reset, + ajaxSettings = jQuery.ajaxSettings; + QUnit.reset = function() { reset.apply(this, arguments); jQuery.event.global = {}; @@ -24,3 +25,9 @@ jQuery.noConflict(); // Allow the test to run with other libs or jQuery's. document.write("<scr" + "ipt src='http://swarm.jquery.org/js/inject.js?" + (new Date).getTime() + "'></scr" + "ipt>"); })(); + +// QUnit Aliases +(function() { + window.equals = window.equal; + window.same = window.deepEqual; +})(); diff --git a/test/data/testsuite.css b/test/data/testsuite.css index 99851eaa5..8c88a9334 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -117,3 +117,9 @@ v\:oval { behavior:url(#default#VML); display:inline-block; } tt { display: none; } sup { display: none; } dfn { display: none; } + +/* #9239 Attach a background to the body( avoid crashes in removing the test element in support ) */ +body, div { background: url(http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif) no-repeat -1000px 0; } + +/* #6652 REMOVE FILTER:ALPHA(OPACITY=100) AFTER ANIMATION */ +#t6652 div { filter: alpha(opacity=50); } diff --git a/test/data/versioncheck.js b/test/data/versioncheck.js new file mode 100644 index 000000000..f4b7790da --- /dev/null +++ b/test/data/versioncheck.js @@ -0,0 +1,8 @@ +// Run minified source from dist (do make first) +// Should be loaded before QUnit but after src +(function() { + if ( /jquery\=min/.test( window.location.search ) ) { + jQuery.noConflict( true ); + document.write(unescape("%3Cscript%20src%3D%27../dist/jquery.min.js%27%3E%3C/script%3E")); + } +})();
\ No newline at end of file diff --git a/test/delegatetest.html b/test/delegatetest.html index c4f33aaea..ef8ea6158 100644 --- a/test/delegatetest.html +++ b/test/delegatetest.html @@ -1,157 +1,103 @@ +<!DOCTYPE html> <html> - <head> - <script src='../dist/jquery.js' type='text/javascript'></script> - <style> - .red { - background-color: red; - border: solid 3px red; - } - </style> - </head> - <body> - <h2>Change Tests</h2> - <table> - <tr> - <td> - Change each: - </td> - <td> - <select class='select_test'> - <option value='one'>change me 1</option> - <option value='two'>change me 2</option> - <option value='three'>change me 3</option> - </select> - <select class='select_test'> - <option value='one'>change me 1</option> - <option value='two' selected="selected">change me 2</option> - <option value='three'>change me 3</option> - </select> - </td> - <td> - <select class='mselect_test' multiple="multiple"> - <option value='one'>change me 1</option> - <option value='two'>change me 2</option> - <option value='three'>change me 3</option> - </select> - </td> - <td> - <input type="checkbox" class="checkbox_test" name="mycheckbox" id="checkbox1"/> - <label for="checkbox1">Checkbox 1</label><br/> - <input type="checkbox" class="checkbox_test" name="mycheckbox" id="checkbox2"/> - <label for="checkbox2">Checkbox 2</label><br /> - <input type="checkbox" class="checkbox_test" name="mycheckbox" id="checkbox3" disabled="disabled"/> - <label for="checkbox3">Checkbox 3</label> - </td> - <td> - <button class="button_test" name="mybutton1" id="button1">Button</button><br /> - <button class="button_test" name="mybutton1" id="button1"><span>Button w/ child</span></button><br /> - <button class="button_test" name="mybutton1" id="button1" disabled="disabled">Button Disabled</button><br /> - <button class="button_test" name="mybutton1" id="button1" disabled="disabled"><span disabled="disabled">Button w/ child Dis.</span></button><br /> - </td> - <td> - <input type="radio" class="radio_test" name="myradio" id="radio1"/> - <label for="radio1">Radio1</label><br/> - <input type="radio" class="radio_test" name="myradio" id="radio2"/> - <label for="radio2">Radio2</label><br /> - <input type="radio" class="radio_test" name="myradio" id="radio3" disabled="disabled"/> - <label for="radio3">Radio3</label> - </td> - <td> - <input class="file_test" id="file1" type="file"/> - <td> - <input class='test' value='' id='input' size='10' /> - <input class='test' value='test' id='input2' size='10' readonly="readonly" /> - </td> - <td> - <textarea rows='2'></textarea> - </td> - </td> - <td>$(document).bind('change')<br /> - $(document).bind('click') - </td> - </tr> - <tr> - <td>Live:</td> - <td id='select' class="red">SELECT</td> - <td id='mselect' class="red">MULTI</td> - <td id='checkbox' class="red">CHECKBOX</td> - <td id='button' class="red">BUTTON</td> - <td id='radio' class="red">RADIO</td> - <td id='file' class="red">FILE</td> - <td id='text' class="red">TEXT</td> - <td id='textarea' class="red">TEXTAREA</td> - <td id='boundChange' class="red">DOCUMENT</td> - </tr> - <tr> - <td>Bind:</td> - <td id='selectbind' class="red">SELECT</td> - <td id='mselectbind' class="red">MULTI</td> - <td id='checkboxbind' class="red">CHECKBOX</td> - <td id='buttonbind' class="red">BUTTON</td> - <td id='radiobind' class="red">RADIO</td> - <td id='filebind' class="red">FILE</td> - <td id='textbind' class="red">TEXT</td> - <td id='textareabind' class="red">TEXTAREA</td> - </tr> - <tr> - <td>Focusin:</td> - <td id='selectfocus' class="red">SELECT</td> - <td id='mselectfocus' class="red">MULTI</td> - <td id='checkboxfocus' class="red">CHECKBOX</td> - <td id='buttonfocus' class="red">BUTTON</td> - <td id='radiofocus' class="red">RADIO</td> - <td id='filefocus' class="red">FILE</td> - <td id='textfocus' class="red">TEXT</td> - <td id='textareafocus' class="red">TEXTAREA</td> - <td id='boundFocus' class="red">DOCUMENT</td> - </tr> - <tr> - <td>Focusout:</td> - <td id='selectblur' class="red">SELECT</td> - <td id='mselectblur' class="red">MULTI</td> - <td id='checkboxblur' class="red">CHECKBOX</td> - <td id='buttonblur' class="red">BUTTON</td> - <td id='radioblur' class="red">RADIO</td> - <td id='fileblur' class="red">FILE</td> - <td id='textblur' class="red">TEXT</td> - <td id='textareablur' class="red">TEXTAREA</td> - <td id='boundBlur' class="red">DOCUMENT</td> - </tr> - <tr> - <td>Live Focus:</td> - <td id='selectlfocus' class="red">SELECT</td> - <td id='mselectlfocus' class="red">MULTI</td> - <td id='checkboxlfocus' class="red">CHECKBOX</td> - <td id='buttonlfocus' class="red">BUTTON</td> - <td id='radiolfocus' class="red">RADIO</td> - <td id='filelfocus' class="red">FILE</td> - <td id='textlfocus' class="red">TEXT</td> - <td id='textarealfocus' class="red">TEXTAREA</td> - </tr> - <tr> - <td>Live Blur:</td> - <td id='selectlblur' class="red">SELECT</td> - <td id='mselectlblur' class="red">MULTI</td> - <td id='checkboxlblur' class="red">CHECKBOX</td> - <td id='buttonlblur' class="red">BUTTON</td> - <td id='radiolblur' class="red">RADIO</td> - <td id='filelblur' class="red">FILE</td> - <td id='textlblur' class="red">TEXT</td> - <td id='textarealblur' class="red">TEXTAREA</td> - </tr> - <tr> - <td>Live Click:</td> - <td id='selectlclick' class="red">SELECT</td> - <td id='mselectlclick' class="red">MULTI</td> - <td id='checkboxlclick' class="red">CHECKBOX</td> - <td id='buttonlclick' class="red">BUTTON</td> - <td id='radiolclick' class="red">RADIO</td> - <td id='filelclick' class="red">FILE</td> - <td id='textlclick' class="red">TEXT</td> - <td id='textarealclick' class="red">TEXTAREA</td> - <td id='boundClick' class="red">DOCUMENT</td> - </tr> - </table> +<head> +<title>Change Tests</title> +<script> +var version = location.search && location.search.substr(1); +if ( version ) { + version = "http://code.jquery.com/jquery-"+version+".js"; +} else { + version = "../dist/jquery.js"; +} +document.write('<script src="'+version+'"><'+'/script>'); +</script> +<style> +table { + border-collapse: collapse; + empty-cells: show; +} +th { + text-align: left; +} +thead td { + width: 11%; +} +tbody td { + background: #fed; +} +th, td { + border: 1px solid #bbb; +} +</style> +</head> +<body> +<h2>Delegate Tests (<span id="version">BAD FILE IN URL</span>, <span id="fileversion">x</span>)</h2> + +<table id="changes"> +<thead> + <tr> + <th> + Controls: + </th> + <td id="select-one"> + <select> + <option value='one1'>one1</option> + <option value='one2'>one2</option> + <option value='one3'>one3</option> + </select> + <select> + <option value='two1'>two1</option> + <option value='two2' selected="selected">two2</option> + <option value='two3'>two3</option> + </select> + </td> + <td id="select-mult"> + <select multiple="multiple"> + <option value='multi1'>multi1</option> + <option value='multi2'>multi2</option> + <option value='multi3'>multi3</option> + </select> + </td> + <td id="checkbox"> + <input type="checkbox" name="mycheckbox" id="check1"/> + <label for="check1">check1</label><br/> + <input type="checkbox" name="mycheckbox" id="check2"/> + <label for="check2">check2</label><br /> + <input type="checkbox" name="mycheckbox" id="check3" disabled="disabled"/> + <label for="check3">check3</label> + </td> + <td id="button"> + <button name="mybutton1" id="button1">Button</button><br /> + <button name="mybutton2" id="button2"><span>Button w/ child</span></button><br /> + <button name="mybutton3" id="button3" disabled="disabled">Button Disabled</button><br /> + <button name="mybutton4" id="button4" disabled="disabled"><span disabled="disabled">Button, child Disabled</span></button><br /> + </td> + <td id="radio"> + <input type="radio" name="myradio" id="radio1"/> + <label for="radio1">Radio1</label><br/> + <input type="radio" name="myradio" id="radio2"/> + <label for="radio2">Radio2</label><br /> + <input type="radio" name="myradio" id="radio3" disabled="disabled"/> + <label for="radio3">Radio3</label> + </td> + <td id="file"> + <input class="file_test" id="file1" type="file"/> + </td> + <td id="text"> + <input class='test' value='' id='input' size='10' /> + <input class='test' value='test' id='input2' size='10' readonly="readonly" /> + </td> + <td id="textarea"> + <textarea rows='2'></textarea> + </td> + + </tr> +</thead> +<tbody> +</tbody> +</table> +<p>NOTE: Only IE supports propertychange, beforeactivate, beforedeactivate; buttons do not support change events.</p> + <h2>Submit Tests</h2> <table> <tr> @@ -184,92 +130,78 @@ </tr> </table> - <ul id="log"></ul> - - <script type='text/javascript'> - jQuery.fn.addChangeClickTest = function( id, prevent ) { - this.bind("focusin", function(){ - jQuery(id + "focus").blink(); - }).bind("focusout", function(){ - jQuery(id + "blur").blink(); - }); - - this.bind("focus", function(){ - jQuery(id + "lfocus").blink(); - }).bind("blur", function(){ - jQuery(id + "lblur").blink(); - }); - - return this.bind("change", function(e){ - jQuery(id + "bind").blink(); - }).live("change", function(e){ - if ( prevent ) { - e.preventDefault(); - } - - jQuery(id).blink(); - }).live("click", function(e){ - jQuery(id + "lclick").blink(); - }); - }; +<script type='text/javascript'> +$("#version").text(version); +$("#fileversion").text($.fn.jquery); - jQuery.fn.addSubmitTest = function( id, prevent ) { - return this.live("submit", function(e){ - if ( prevent ) { - e.preventDefault(); - } - - jQuery(id).blink(); - }); - }; - - jQuery.fn.blink = function(){ - return this.css("backgroundColor","green").css("border","solid 3px green").delay(700).queue(function(next){ - jQuery(this).css("backgroundColor",""); - next(); - }); +// Events we want to track in row-order +var events = "bind-change live-change on-change bind-propertychange live-beforeactivate live-focusin bind-focus live-keydown live-beforedeactivate live-focusout bind-blur live-click".split(" "), + counter = 0; + blinker = function(event){ + if ( !counter ) { + $("#changes tbody td").text(""); + } + var $el = event.data, + prev = $el.text(); + prev = prev? prev +" | " : ""; + return $el + .text(prev + ++counter+" " + (this.value.replace(/^on$/,"") || this.id || this.checked || "")) + .css("backgroundColor","#0f0") + .delay(800) + .queue(function(next){ + $el.css("backgroundColor","#afa"); + --counter; + next(); + }); }; - $(document).bind("focusin", function() { - jQuery("#boundFocus").blink(); - }); - - $(document).bind("focusout", function() { - jQuery("#boundBlur").blink(); - }); +for ( var i=0; i < events.length; i++ ) { + var m = events[i].split("-"), + api = m[0], + type = m[1], + $row = $("<tr><th>"+type+" "+api+"</th></tr>"); - $(document).bind("click", function() { - jQuery("#boundClick").blink(); - }); - - $("td.red").live("hover", function(e) { - if ( e.type === "mouseenter" ) { - $(this).css("backgroundColor","green"); + $("#changes thead td").each(function(){ + var id = "#"+this.id, + $cell = $('<td></td>'); + if ( api == "on" ) { + $(this).find("input, button, select, textarea").each(function(){ + this["on"+type] = function(e){ e = $.event.fix(e||event); e.data = $cell; blinker.call(this, e); }; + }); + } else if ( api == "bind" ) { + $(this).find("input, button, select, textarea").bind(type, $cell, blinker); } else { - $(this).css("backgroundColor",""); + $(id+" input,"+id+" button,"+id+" select,"+id+" textarea").live(type, $cell, blinker); } + $row.append($cell); }); + $("#changes tbody").append($row); +} - $(".select_test").addChangeClickTest("#select"); - $(".mselect_test").addChangeClickTest("#mselect"); - $(".checkbox_test").addChangeClickTest("#checkbox"); - $(".radio_test").addChangeClickTest("#radio"); - $(".file_test").addChangeClickTest("#file"); - $('textarea').addChangeClickTest("#textarea"); - $('#input').addChangeClickTest("#text"); - $('button').addChangeClickTest("#button"); - $(document).bind("change", function(){ - jQuery("#boundChange").blink(); +jQuery.fn.blink = function(){ + return this.css("backgroundColor","green").css("border","solid 3px green").delay(700).queue(function(next){ + jQuery(this).css("backgroundColor",""); + next(); }); +}; - $("#text_submit").addSubmitTest("#textSubmit", true); - $("#password_submit").addSubmitTest("#passwordSubmit", true); - $("#submit_submit").addSubmitTest("#submitSubmit", true); - $(document).bind("submit", function(){ - jQuery("#boundSubmit").blink(); +jQuery.fn.addSubmitTest = function( id, prevent ) { + return this.live("submit", function(e){ + if ( prevent ) { + e.preventDefault(); + } + jQuery(id).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> +</script> +</body> </html> diff --git a/test/hovertest.html b/test/hovertest.html new file mode 100644 index 000000000..d6242091e --- /dev/null +++ b/test/hovertest.html @@ -0,0 +1,158 @@ +<html> +<head> +<title>Hover tests</title> +<script src="../dist/jquery.js" type='text/javascript'></script> +<style> +/* Remove body dimensions so we can test enter/leave to surrounding browser chrome */ +body, html { + border: 0; + margin: 0; + padding: 0; +} +p { + margin: 2px 0; +} +.hover-box { + background: #f33; + padding: 3px; + margin: 10px 40px 20px 0; +} +.hover-status { + background: #f66; + padding: 1px; +} +.hover-inside { + background: #6f6; + padding: 1px; + margin: 8px auto; + width: 40%; + text-align: center; +} +</style> + </head> + <body> + <h2>Hover (mouse{over,out,enter,leave}) Tests</h2> + <p>Be sure to try moving the mouse out of the browser via the left side on each test.</p> + <div id="wrapper"> + + <div id="hoverbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + .hover() in/out: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here should NOT trigger the counter. + </div> + </div> + <div id="liveenterbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + Live enter/leave: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here should NOT trigger the counter. + </div> + </div> + <div id="delegateenterbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + Delegated enter/leave: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here should NOT trigger the counter. + </div> + </div> + + <div id="overbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + Bind over/out: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here SHOULD trigger the counter. + </div> + </div> + <div id="liveoverbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + Live over/out: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here SHOULD trigger the counter. + </div> + </div> + <div id="delegateoverbox" class="hover-box"> + <div class="hover-status"> + <button>Activate</button> + Delegated over/out: <span class="ins">0</span> / <span class="outs">0</span> + </div> + <div class="hover-inside"> + Mouse over here SHOULD trigger the counter. + </div> + </div> + + </div> <!-- wrapper --> + +<script> + +$(function(){ + + var x, + countIns = function() { + var d = $(this).data(); + $("span.ins", this).text(++d.ins); + }, + countOuts = function() { + var d = $(this).data(); + $("span.outs", this).text(++d.outs); + }; + + // Tests can be activated separately or in combination to check for interference + + $("#hoverbox button").click(function(){ + $("#hoverbox") + .data({ ins: 0, outs: 0 }) + .hover( countIns, countOuts ); + $(this).remove(); + }); + $("#delegateenterbox button").click(function(){ + $("html") + .find("#delegateenterbox").data({ ins: 0, outs: 0 }).end() + .delegate("#delegateenterbox", "mouseenter", countIns ) + .delegate("#delegateenterbox", "mouseleave", countOuts ); + $(this).remove(); + }); + $("#liveenterbox button").click(function(){ + $("#liveenterbox") + .data({ ins: 0, outs: 0 }) + .live("mouseenter", countIns ) + .live("mouseleave", countOuts ); + $(this).remove(); + }); + + $("#overbox button").click(function(){ + $("#overbox") + .data({ ins: 0, outs: 0 }) + .bind("mouseover", countIns ) + .bind("mouseout", countOuts ); + $(this).remove(); + }); + $("#liveoverbox button").click(function(){ + $("#liveoverbox") + .data({ ins: 0, outs: 0 }) + .live("mouseover", countIns ) + .live("mouseout", countOuts ); + $(this).remove(); + }); + $("#delegateoverbox button").click(function(){ + $(document) + .find("#delegateoverbox").data({ ins: 0, outs: 0 }).end() + .delegate("#delegateoverbox", "mouseover", countIns ) + .delegate("#delegateoverbox", "mouseout", countOuts ); + $(this).remove(); + }); +}); + +</script> +</body> +</html> diff --git a/test/index.html b/test/index.html index a10655089..17baa4894 100644 --- a/test/index.html +++ b/test/index.html @@ -9,6 +9,7 @@ <script src="data/testinit.js"></script> <script src="../src/core.js"></script> + <script src="../src/callbacks.js"></script> <script src="../src/deferred.js"></script> <script src="../src/support.js"></script> <script src="../src/data.js"></script> @@ -28,16 +29,21 @@ <script src="../src/offset.js"></script> <script src="../src/dimensions.js"></script> + <script src="data/versioncheck.js"></script> + <script src="qunit/qunit/qunit.js"></script> <script src="data/testrunner.js"></script> <script src="unit/core.js"></script> + <script src="unit/support.js"></script> + <script src="unit/callbacks.js"></script> <script src="unit/deferred.js"></script> <script src="unit/data.js"></script> <script src="unit/queue.js"></script> <script src="unit/attributes.js"></script> <script src="unit/event.js"></script> <script src="../src/sizzle/test/unit/selector.js"></script> + <script src="unit/selector.js"></script> <script src="unit/traversing.js"></script> <script src="unit/manipulation.js"></script> <script src="unit/css.js"></script> @@ -48,7 +54,9 @@ </head> <body id="body"> - <h1 id="qunit-header">jQuery Test Suite</h1> + <h1 id="qunit-header"><a href="/jquery/test/index.html">jQuery Test Suite</a> + <a href="?jquery=min">(minified)</a> + </h1> <h2 id="qunit-banner"></h2> <div id="qunit-testrunner-toolbar"></div> <h2 id="qunit-userAgent"></h2> @@ -58,10 +66,10 @@ <div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv"> <div id="nothiddendivchild"></div> </div> - <!-- this iframe is outside the #main so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves --> + <!-- this iframe is outside the #qunit-fixture so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves --> <iframe id="loadediframe" name="loadediframe" style="display:none;" src="data/iframe.html"></iframe> - <dl id="dl" style="position:absolute;top:-32767px;left:-32767px;"> - <div id="main"> + <dl id="dl" style="position:absolute;top:-32767px;left:-32767px;width:1px"> + <div id="qunit-fixture"> <p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p> <p id="ap"> Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, @@ -131,7 +139,7 @@ <select name="select5" id="select5"> <option id="option5a" value="3">1</option> <option id="option5b" value="2">2</option> - <option id="option5c" value="1">3</option> + <option id="option5c" value="1" data-attr="">3</option> </select> <object id="object1" codebase="stupid"> @@ -221,6 +229,10 @@ Z</textarea> <div id="t2037"> <div><div class="hidden">hidden</div></div> </div> + <div id="t6652"> + <div></div> + </div> + <div id="no-clone-exception"><object><embed></embed></object></div> </div> <div id="tabindex-tests"> diff --git a/test/qunit b/test/qunit -Subproject d404faf8f587fcbe6b8907943022e6318dd51e0 +Subproject 7f292170fa1109f1355f3e96f8973c32fc55394 diff --git a/test/unit/ajax.js b/test/unit/ajax.js index a8a5fa0d7..f871da723 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -321,25 +321,40 @@ test("jQuery.ajax() - responseText on error", function() { test(".ajax() - retry with jQuery.ajax( this )", function() { - expect( 1 ); + expect( 2 ); stop(); - var firstTime = 1; + var firstTime = true, + previousUrl; jQuery.ajax({ url: url("data/errorWithText.php"), error: function() { if ( firstTime ) { - firstTime = 0; + firstTime = false; jQuery.ajax( this ); } else { ok( true , "Test retrying with jQuery.ajax(this) works" ); - start(); + jQuery.ajax({ + url: url("data/errorWithText.php"), + data: { x: 1 }, + beforeSend: function() { + if ( !previousUrl ) { + previousUrl = this.url; + } else { + strictEqual( this.url , previousUrl, "url parameters are not re-appended" ); + start(); + return false; + } + }, + error: function() { + jQuery.ajax( this ); + } + }); } } }); - }); test(".ajax() - headers" , function() { @@ -1782,7 +1797,7 @@ test("jQuery.ajaxSetup({timeout: Number}) - with global timeout", function() { passed++; if ( passed == 2 ) { ok( true, "Check local and global callbacks after timeout" ); - jQuery("#main").unbind("ajaxError"); + jQuery("#qunit-fixture").unbind("ajaxError"); start(); } }; @@ -1792,7 +1807,7 @@ test("jQuery.ajaxSetup({timeout: Number}) - with global timeout", function() { start(); }; - jQuery("#main").ajaxError(pass); + jQuery("#qunit-fixture").ajaxError(pass); jQuery.ajax({ type: "GET", @@ -2061,6 +2076,35 @@ test( "jQuery.ajax - Location object as url (#7531)", 1, function () { ok( success, "document.location did not generate exception" ); }); +test( "jQuery.ajax - Context with circular references (#9887)", 2, function () { + var success = false, + context = {}; + context.field = context; + try { + success = !jQuery.ajax( "non-existing", { + context: context, + beforeSend: function() { + ok( this === context, "context was not deep extended" ); + return false; + } + }); + } catch (e) { console.log( e ); } + ok( success, "context with circular reference did not generate an exception" ); +}); + +test( "jQuery.ajax - statusText" , 4, function() { + stop(); + jQuery.ajax( url( "data/statusText.php?status=200&text=Hello" ) ).done(function( _, statusText, jqXHR ) { + strictEqual( statusText, "success", "callback status text ok for success" ); + ok( jqXHR.statusText === "Hello" || jQuery.browser.safari && jqXHR.statusText === "OK", "jqXHR status text ok for success (" + jqXHR.statusText + ")" ); + jQuery.ajax( url( "data/statusText.php?status=404&text=World" ) ).fail(function( jqXHR, statusText ) { + strictEqual( statusText, "error", "callback status text ok for error" ); + ok( jqXHR.statusText === "World" || jQuery.browser.safari && jqXHR.statusText === "Not Found", "jqXHR status text ok for error (" + jqXHR.statusText + ")" ); + start(); + }); + }); +}); + test( "jQuery.ajax - statusCode" , function() { var count = 12; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 8ea27aa36..5945510de 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -4,16 +4,14 @@ var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; -test("jQuery.attrFix integrity test", function() { - expect(1); - +test("jQuery.attrFix/jQuery.propFix integrity test", function() { + expect(2); + // This must be maintained and equal jQuery.attrFix when appropriate // Ensure that accidental or erroneous property // overwrites don't occur // This is simply for better code coverage and future proofing. - var propsShouldBe; - if ( !jQuery.support.getSetAttribute ) { - propsShouldBe = { + var props = { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", @@ -24,60 +22,20 @@ test("jQuery.attrFix integrity test", function() { rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", - frameborder: "frameBorder" - }; - } else { - propsShouldBe = { - tabindex: "tabIndex", - readonly: "readOnly" + frameborder: "frameBorder", + contenteditable: "contentEditable" }; - } - same(propsShouldBe, jQuery.attrFix, "jQuery.attrFix passes integrity check"); -}); + var propsShouldBe = { + tabindex: "tabIndex" + }; -test("prop(String, Object)", function() { - expect(19); - equals( jQuery("#text1").prop("value"), "Test", "Check for value attribute" ); - equals( jQuery("#text1").prop("value", "Test2").prop("defaultValue"), "Test", "Check for defaultValue attribute" ); - equals( jQuery("#select2").prop("selectedIndex"), 3, "Check for selectedIndex attribute" ); - equals( jQuery("#foo").prop("nodeName").toUpperCase(), "DIV", "Check for nodeName attribute" ); - equals( jQuery("#foo").prop("tagName").toUpperCase(), "DIV", "Check for tagName attribute" ); - equals( jQuery("<option/>").prop("selected"), false, "Check selected attribute on disconnected element." ); - - var body = document.body, $body = jQuery( body ); - ok( $body.prop("nextSibling") === null, "Make sure a null expando returns null" ); - body.foo = "bar"; - equals( $body.prop("foo"), "bar", "Make sure the expando is preferred over the dom attribute" ); - body.foo = undefined; - ok( $body.prop("foo") === undefined, "Make sure the expando is preferred over the dom attribute, even if undefined" ); - - var select = document.createElement("select"), optgroup = document.createElement("optgroup"), option = document.createElement("option"); - optgroup.appendChild( option ); - select.appendChild( optgroup ); - - equals( jQuery(option).prop("selected"), true, "Make sure that a single option is selected, even when in an optgroup." ); - equals( jQuery(document).prop("nodeName"), "#document", "prop works correctly on document nodes (bug #7451)." ); - - var attributeNode = document.createAttribute("irrelevant"), - commentNode = document.createComment("some comment"), - textNode = document.createTextNode("some text"), - obj = {}; - jQuery.each( [document, attributeNode, commentNode, textNode, obj, "#firstp"], function( i, ele ) { - strictEqual( jQuery(ele).prop("nonexisting"), undefined, "prop works correctly for non existing attributes (bug #7500)." ); - }); - - var obj = {}; - jQuery.each( [document, obj], function( i, ele ) { - var $ele = jQuery( ele ); - $ele.prop( "nonexisting", "foo" ); - equal( $ele.prop("nonexisting"), "foo", "prop(name, value) works correctly for non existing attributes (bug #7500)." ); - }); - jQuery( document ).removeProp("nonexisting"); + deepEqual(propsShouldBe, jQuery.attrFix, "jQuery.attrFix passes integrity check"); + deepEqual(props, jQuery.propFix, "jQuery.propFix passes integrity check"); }); test("attr(String)", function() { - expect(32); + expect(45); equals( jQuery("#text1").attr("type"), "text", "Check for type attribute" ); equals( jQuery("#radio1").attr("type"), "radio", "Check for type attribute" ); @@ -90,25 +48,27 @@ test("attr(String)", function() { equals( jQuery("#name").attr("name"), "name", "Check for name attribute" ); equals( jQuery("#text1").attr("name"), "action", "Check for name attribute" ); ok( jQuery("#form").attr("action").indexOf("formaction") >= 0, "Check for action attribute" ); + equals( jQuery("#text1").attr("value", "t").attr("value"), "t", "Check setting the value attribute" ); + equals( jQuery("<div value='t'></div>").attr("value"), "t", "Check setting custom attr named 'value' on a div" ); equals( jQuery("#form").attr("blah", "blah").attr("blah"), "blah", "Set non-existant attribute on a form" ); equals( jQuery("#foo").attr("height"), undefined, "Non existent height attribute should return undefined" ); - + // [7472] & [3113] (form contains an input with name="action" or name="id") var extras = jQuery("<input name='id' name='name' /><input id='target' name='target' />").appendTo("#testForm"); - equals( jQuery("#form").attr("action","newformaction").attr("action"), "newformaction", "Check that action attribute was changed" ); - equals( jQuery("#testForm").attr("target"), undefined, "Retrieving target does not equal the input with name=target" ); - equals( jQuery("#testForm").attr("target", "newTarget").attr("target"), "newTarget", "Set target successfully on a form" ); - equals( jQuery("#testForm").removeAttr("id").attr("id"), undefined, "Retrieving id does not equal the input with name=id after id is removed [#7472]" ); + equal( jQuery("#form").attr("action","newformaction").attr("action"), "newformaction", "Check that action attribute was changed" ); + equal( jQuery("#testForm").attr("target"), undefined, "Retrieving target does not equal the input with name=target" ); + equal( jQuery("#testForm").attr("target", "newTarget").attr("target"), "newTarget", "Set target successfully on a form" ); + equal( jQuery("#testForm").removeAttr("id").attr("id"), undefined, "Retrieving id does not equal the input with name=id after id is removed [#7472]" ); // Bug #3685 (form contains input with name="name") equals( jQuery("#testForm").attr("name"), undefined, "Retrieving name does not retrieve input with name=name" ); extras.remove(); - + equals( jQuery("#text1").attr("maxlength"), "30", "Check for maxlength attribute" ); equals( jQuery("#text1").attr("maxLength"), "30", "Check for maxLength attribute" ); equals( jQuery("#area1").attr("maxLength"), "30", "Check for maxLength attribute" ); // using innerHTML in IE causes href attribute to be serialized to the full path - jQuery("<a/>").attr({ "id": "tAnchor5", "href": "#5" }).appendTo("#main"); + jQuery("<a/>").attr({ "id": "tAnchor5", "href": "#5" }).appendTo("#qunit-fixture"); equals( jQuery("#tAnchor5").attr("href"), "#5", "Check for non-absolute href (an anchor)" ); // list attribute is readonly by default in browsers that support it @@ -128,6 +88,12 @@ test("attr(String)", function() { body.removeAttribute("foo"); // Cleanup + var select = document.createElement("select"), optgroup = document.createElement("optgroup"), option = document.createElement("option"); + optgroup.appendChild( option ); + select.appendChild( optgroup ); + + equal( jQuery( option ).attr("selected"), "selected", "Make sure that a single option is selected, even when in an optgroup." ); + var $img = jQuery("<img style='display:none' width='215' height='53' src='http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif'/>").appendTo("body"); equals( $img.attr("width"), "215", "Retrieve width attribute an an element with display:none." ); equals( $img.attr("height"), "53", "Retrieve height attribute an an element with display:none." ); @@ -136,17 +102,37 @@ test("attr(String)", function() { ok( !!~jQuery("#dl").attr("style").indexOf("position"), "Check style attribute getter, also normalize css props to lowercase" ); ok( !!~jQuery("#foo").attr("style", "position:absolute;").attr("style").indexOf("position"), "Check style setter" ); + // Check value on button element (#1954) + var $button = jQuery("<button value='foobar'>text</button>").insertAfter("#button"); + equals( $button.attr("value"), "foobar", "Value retrieval on a button does not return innerHTML" ); + equals( $button.attr("value", "baz").html(), "text", "Setting the value does not change innerHTML" ); + + // Attributes with a colon on a table element (#1591) + equals( jQuery("#table").attr("test:attrib"), undefined, "Retrieving a non-existent attribute on a table with a colon does not throw an error." ); + equals( jQuery("#table").attr("test:attrib", "foobar").attr("test:attrib"), "foobar", "Setting an attribute on a table with a colon does not throw an error." ); + + var $form = jQuery("<form class='something'></form>").appendTo("#qunit-fixture"); + equal( $form.attr("class"), "something", "Retrieve the class attribute on a form." ); + + var $a = jQuery("<a href='#' onclick='something()'>Click</a>").appendTo("#qunit-fixture"); + equal( $a.attr("onclick"), "something()", "Retrieve ^on attribute without anonymous function wrapper." ); + ok( jQuery("<div/>").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); + ok( jQuery("<div/>").attr("title") === undefined, "Make sure undefined is returned when no attribute is found." ); + equal( jQuery("<div/>").attr("title", "something").attr("title"), "something", "Set the title attribute." ); ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); + equal( jQuery("<div/>").attr("value"), undefined, "An unset value on a div returns undefined." ); + equal( jQuery("<input/>").attr("value"), "", "An unset value on an input returns current value." ); }); if ( !isLocal ) { test("attr(String) in XML Files", function() { - expect(2); + expect(3); stop(); - jQuery.get("data/dashboard.xml", function(xml) { - equals( jQuery("locations", xml).attr("class"), "foo", "Check class attribute in XML document" ); - equals( jQuery("location", xml).attr("for"), "bar", "Check for attribute in XML document" ); + jQuery.get("data/dashboard.xml", function( xml ) { + equal( jQuery( "locations", xml ).attr("class"), "foo", "Check class attribute in XML document" ); + equal( jQuery( "location", xml ).attr("for"), "bar", "Check for attribute in XML document" ); + equal( jQuery( "location", xml ).attr("checked"), "different", "Check that hooks are not attached in XML document" ); start(); }); }); @@ -165,13 +151,12 @@ test("attr(Hash)", function() { if ( this.getAttribute("foo") != "baz" && this.getAttribute("zoo") != "ping" ) pass = false; }); ok( pass, "Set Multiple Attributes" ); - equals( jQuery("#text1").attr({value: function() { return this.id; }})[0].value, "text1", "Set attribute to computed value #1" ); - equals( jQuery("#text1").attr({title: function(i) { return i; }}).attr("title"), "0", "Set attribute to computed value #2"); - + equals( jQuery("#text1").attr({value: function() { return this.id; }})[0].value, "text1", "Set attribute to computed value #1" ); + equals( jQuery("#text1").attr({title: function(i) { return i; }}).attr("title"), "0", "Set attribute to computed value #2"); }); test("attr(String, Object)", function() { - expect(29); + expect(78); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -183,39 +168,111 @@ test("attr(String, Object)", function() { } } - equals( fail, false, "Set Attribute, the #"+fail+" element didn't get the attribute 'foo'" ); + equals( fail, false, "Set Attribute, the #" + fail + " element didn't get the attribute 'foo'" ); - // Fails on IE since recent changes to .attr() - // ok( jQuery("#foo").attr({"width": null}), "Try to set an attribute to nothing" ); + ok( jQuery("#foo").attr({ "width": null }), "Try to set an attribute to nothing" ); jQuery("#name").attr("name", "something"); equals( jQuery("#name").attr("name"), "something", "Set name attribute" ); jQuery("#name").attr("name", null); equals( jQuery("#name").attr("name"), undefined, "Remove name attribute" ); - jQuery("#check2").attr("checked", true); + var $input = jQuery("<input>", { name: "something", id: "specified" }); + equal( $input.attr("name"), "something", "Check element creation gets/sets the name attribute." ); + equal( $input.attr("id"), "specified", "Check element creation gets/sets the id attribute." ); + + jQuery("#check2").prop("checked", true).prop("checked", false).attr("checked", true); equals( document.getElementById("check2").checked, true, "Set checked attribute" ); + equals( jQuery("#check2").prop("checked"), true, "Set checked attribute" ); + equals( jQuery("#check2").attr("checked"), "checked", "Set checked attribute" ); jQuery("#check2").attr("checked", false); equals( document.getElementById("check2").checked, false, "Set checked attribute" ); + equals( jQuery("#check2").prop("checked"), false, "Set checked attribute" ); + equals( jQuery("#check2").attr("checked"), undefined, "Set checked attribute" ); jQuery("#text1").attr("readonly", true); equals( document.getElementById("text1").readOnly, true, "Set readonly attribute" ); + equals( jQuery("#text1").prop("readOnly"), true, "Set readonly attribute" ); + equals( jQuery("#text1").attr("readonly"), "readonly", "Set readonly attribute" ); jQuery("#text1").attr("readonly", false); equals( document.getElementById("text1").readOnly, false, "Set readonly attribute" ); + equals( jQuery("#text1").prop("readOnly"), false, "Set readonly attribute" ); + equals( jQuery("#text1").attr("readonly"), undefined, "Set readonly attribute" ); + + jQuery("#check2").prop("checked", true); + equals( document.getElementById("check2").checked, true, "Set checked attribute" ); + equals( jQuery("#check2").prop("checked"), true, "Set checked attribute" ); + equals( jQuery("#check2").attr("checked"), "checked", "Set checked attribute" ); + jQuery("#check2").prop("checked", false); + equals( document.getElementById("check2").checked, false, "Set checked attribute" ); + equals( jQuery("#check2").prop("checked"), false, "Set checked attribute" ); + equals( jQuery("#check2").attr("checked"), undefined, "Set checked attribute" ); + + jQuery("#check2").attr("checked", "checked"); + equal( document.getElementById("check2").checked, true, "Set checked attribute with 'checked'" ); + equal( jQuery("#check2").prop("checked"), true, "Set checked attribute" ); + equal( jQuery("#check2").attr("checked"), "checked", "Set checked attribute" ); + + QUnit.reset(); + + var $radios = jQuery("#checkedtest").find("input[type='radio']"); + $radios.eq(1).click(); + equal( $radios.eq(1).prop("checked"), true, "Second radio was checked when clicked"); + equal( $radios.attr("checked"), $radios[0].checked ? "checked" : undefined, "Known booleans do not fall back to attribute presence (#10278)"); + + jQuery("#text1").prop("readOnly", true); + equals( document.getElementById("text1").readOnly, true, "Set readonly attribute" ); + equals( jQuery("#text1").prop("readOnly"), true, "Set readonly attribute" ); + equals( jQuery("#text1").attr("readonly"), "readonly", "Set readonly attribute" ); + jQuery("#text1").prop("readOnly", false); + equals( document.getElementById("text1").readOnly, false, "Set readonly attribute" ); + equals( jQuery("#text1").prop("readOnly"), false, "Set readonly attribute" ); + equals( jQuery("#text1").attr("readonly"), undefined, "Set readonly attribute" ); + jQuery("#name").attr("maxlength", "5"); equals( document.getElementById("name").maxLength, 5, "Set maxlength attribute" ); jQuery("#name").attr("maxLength", "10"); equals( document.getElementById("name").maxLength, 10, "Set maxlength attribute" ); - var $p = jQuery("#firstp").attr("nonexisting", "foo"); - equals( $p.attr("nonexisting"), "foo", "attr(name, value) works correctly for non existing attributes (bug #7500)."); - $p.removeAttr("nonexisting"); - + + // HTML5 boolean attributes + var $text = jQuery("#text1").attr({ + "autofocus": true, + "required": true + }); + equal( $text.attr("autofocus"), "autofocus", "Set boolean attributes to the same name" ); + equal( $text.attr("autofocus", false).attr("autofocus"), undefined, "Setting autofocus attribute to false removes it" ); + equal( $text.attr("required"), "required", "Set boolean attributes to the same name" ); + equal( $text.attr("required", false).attr("required"), undefined, "Setting required attribute to false removes it" ); + + var $details = jQuery("<details open></details>").appendTo("#qunit-fixture"); + equal( $details.attr("open"), "open", "open attribute presense indicates true" ); + equal( $details.attr("open", false).attr("open"), undefined, "Setting open attribute to false removes it" ); + + $text.attr("data-something", true); + equal( $text.attr("data-something"), "true", "Set data attributes"); + equal( $text.data("something"), true, "Setting data attributes are not affected by boolean settings"); + $text.attr("data-another", false); + equal( $text.attr("data-another"), "false", "Set data attributes"); + equal( $text.data("another"), false, "Setting data attributes are not affected by boolean settings" ); + equal( $text.attr("aria-disabled", false).attr("aria-disabled"), "false", "Setting aria attributes are not affected by boolean settings"); + $text.removeData("something").removeData("another").removeAttr("aria-disabled"); + + jQuery("#foo").attr("contenteditable", true); + equals( jQuery("#foo").attr("contenteditable"), "true", "Enumerated attributes are set properly" ); + var attributeNode = document.createAttribute("irrelevant"), commentNode = document.createComment("some comment"), - textNode = document.createTextNode("some text"); - - jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { - var $ele = jQuery( ele ); - $ele.attr( "nonexisting", "foo" ); - strictEqual( $ele.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); + textNode = document.createTextNode("some text"), + obj = {}; + + jQuery.each( [commentNode, textNode, attributeNode], function( i, elem ) { + var $elem = jQuery( elem ); + $elem.attr( "nonexisting", "foo" ); + strictEqual( $elem.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); + }); + + jQuery.each( [window, document, obj, "#firstp"], function( i, elem ) { + var $elem = jQuery( elem ); + strictEqual( $elem.attr("nonexisting"), undefined, "attr works correctly for non existing attributes (bug #7500)." ); + equal( $elem.attr("something", "foo" ).attr("something"), "foo", "attr falls back to prop on unsupported arguments" ); }); var table = jQuery("#table").append("<tr><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr>"), @@ -227,6 +284,8 @@ test("attr(String, Object)", function() { table.attr("cellspacing", "2"); equals( table[0].cellSpacing, "2", "Check cellspacing is correctly set" ); + equals( jQuery("#area1").attr("value"), "foobar", "Value attribute retrieves the property for backwards compatibility." ); + // for #1070 jQuery("#name").attr("someAttr", "0"); equals( jQuery("#name").attr("someAttr"), "0", "Set attribute to a string of \"0\"" ); @@ -242,8 +301,6 @@ test("attr(String, Object)", function() { equals( j.attr("name"), "attrvalue", "Check node,textnode,comment for attr" ); j.removeAttr("name"); - QUnit.reset(); - // Type var type = jQuery("#check2").attr("type"); var thrown = false; @@ -256,7 +313,7 @@ test("attr(String, Object)", function() { equals( type, jQuery("#check2").attr("type"), "Verify that you can't change the type of an input element" ); var check = document.createElement("input"); - var thrown = true; + thrown = true; try { jQuery(check).attr("type", "checkbox"); } catch(e) { @@ -265,8 +322,8 @@ test("attr(String, Object)", function() { ok( thrown, "Exception thrown when trying to change type property" ); equals( "checkbox", jQuery(check).attr("type"), "Verify that you can change the type of an input element that isn't in the DOM" ); - var check = jQuery("<input />"); - var thrown = true; + check = jQuery("<input />"); + thrown = true; try { check.attr("type","checkbox"); } catch(e) { @@ -276,7 +333,7 @@ test("attr(String, Object)", function() { equals( "checkbox", check.attr("type"), "Verify that you can change the type of an input element that isn't in the DOM" ); var button = jQuery("#button"); - var thrown = false; + thrown = false; try { button.attr("type","submit"); } catch(e) { @@ -284,7 +341,10 @@ test("attr(String, Object)", function() { } ok( thrown, "Exception thrown when trying to change type property" ); equals( "button", button.attr("type"), "Verify that you can't change the type of a button element" ); - + + var $radio = jQuery("<input>", { "value": "sup", "type": "radio" }).appendTo("#testForm"); + equals( $radio.val(), "sup", "Value is not reset when type is set after value on a radio" ); + // Setting attributes on svg elements (bug #3116) var $svg = jQuery("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' baseProfile='full' width='200' height='200'>" + "<circle cx='200' cy='200' r='150' />" @@ -328,10 +388,10 @@ if ( !isLocal ) { test("attr(String, Object) - Loaded via XML document", function() { expect(2); stop(); - jQuery.get("data/dashboard.xml", function(xml) { + jQuery.get("data/dashboard.xml", function( xml ) { var titles = []; - jQuery("tab", xml).each(function() { - titles.push(jQuery(this).attr("title")); + jQuery( "tab", xml ).each(function() { + titles.push( jQuery(this).attr("title") ); }); equals( titles[0], "Location", "attr() in XML context: Check first title" ); equals( titles[1], "Users", "attr() in XML context: Check second title" ); @@ -396,12 +456,135 @@ test("attr('tabindex', value)", function() { }); test("removeAttr(String)", function() { - expect(5); - equals( jQuery("#mark").removeAttr( "class" )[0].className, "", "remove class" ); - equals( jQuery("#form").removeAttr("id").attr("id"), undefined, "Remove id" ); - equals( jQuery("#foo").attr("style", "position:absolute;").removeAttr("style").attr("style"), undefined, "Check removing style attribute" ); - equals( jQuery("#form").attr("style", "position:absolute;").removeAttr("style").attr("style"), undefined, "Check removing style attribute on a form" ); - equals( jQuery("#fx-test-group").attr("height", "3px").removeAttr("height").css("height"), "1px", "Removing height attribute has no effect on height set with style attribute" ); + expect(8); + equal( jQuery("#mark").removeAttr( "class" )[0].className, "", "remove class" ); + equal( jQuery("#form").removeAttr("id").attr("id"), undefined, "Remove id" ); + equal( jQuery("#foo").attr("style", "position:absolute;").removeAttr("style").attr("style"), undefined, "Check removing style attribute" ); + equal( jQuery("#form").attr("style", "position:absolute;").removeAttr("style").attr("style"), undefined, "Check removing style attribute on a form" ); + equal( jQuery("<div style='position: absolute'></div>").appendTo("#foo").removeAttr("style").prop("style").cssText, "", "Check removing style attribute (#9699 Webkit)" ); + equal( jQuery("#fx-test-group").attr("height", "3px").removeAttr("height").css("height"), "1px", "Removing height attribute has no effect on height set with style attribute" ); + + jQuery("#check1").removeAttr("checked").prop("checked", true).removeAttr("checked"); + equal( document.getElementById("check1").checked, false, "removeAttr sets boolean properties to false" ); + jQuery("#text1").prop("readOnly", true).removeAttr("readonly"); + equal( document.getElementById("text1").readOnly, false, "removeAttr sets boolean properties to false" ); +}); + +test("prop(String, Object)", function() { + expect(30); + + equals( jQuery("#text1").prop("value"), "Test", "Check for value attribute" ); + equals( jQuery("#text1").prop("value", "Test2").prop("defaultValue"), "Test", "Check for defaultValue attribute" ); + equals( jQuery("#select2").prop("selectedIndex"), 3, "Check for selectedIndex attribute" ); + equals( jQuery("#foo").prop("nodeName").toUpperCase(), "DIV", "Check for nodeName attribute" ); + equals( jQuery("#foo").prop("tagName").toUpperCase(), "DIV", "Check for tagName attribute" ); + equals( jQuery("<option/>").prop("selected"), false, "Check selected attribute on disconnected element." ); + + equals( jQuery("#listWithTabIndex").prop("tabindex"), 5, "Check retrieving tabindex" ); + jQuery("#text1").prop("readonly", true); + equals( document.getElementById("text1").readOnly, true, "Check setting readOnly property with 'readonly'" ); + equals( jQuery("#label-for").prop("for"), "action", "Check retrieving htmlFor" ); + jQuery("#text1").prop("class", "test"); + equals( document.getElementById("text1").className, "test", "Check setting className with 'class'" ); + equals( jQuery("#text1").prop("maxlength"), 30, "Check retrieving maxLength" ); + jQuery("#table").prop("cellspacing", 1); + equals( jQuery("#table").prop("cellSpacing"), "1", "Check setting and retrieving cellSpacing" ); + jQuery("#table").prop("cellpadding", 1); + equals( jQuery("#table").prop("cellPadding"), "1", "Check setting and retrieving cellPadding" ); + jQuery("#table").prop("rowspan", 1); + equals( jQuery("#table").prop("rowSpan"), 1, "Check setting and retrieving rowSpan" ); + jQuery("#table").prop("colspan", 1); + equals( jQuery("#table").prop("colSpan"), 1, "Check setting and retrieving colSpan" ); + jQuery("#table").prop("usemap", 1); + equals( jQuery("#table").prop("useMap"), 1, "Check setting and retrieving useMap" ); + jQuery("#table").prop("frameborder", 1); + equals( jQuery("#table").prop("frameBorder"), 1, "Check setting and retrieving frameBorder" ); + QUnit.reset(); + + var body = document.body, $body = jQuery( body ); + ok( $body.prop("nextSibling") === null, "Make sure a null expando returns null" ); + body.foo = "bar"; + equals( $body.prop("foo"), "bar", "Make sure the expando is preferred over the dom attribute" ); + body.foo = undefined; + ok( $body.prop("foo") === undefined, "Make sure the expando is preferred over the dom attribute, even if undefined" ); + + var select = document.createElement("select"), optgroup = document.createElement("optgroup"), option = document.createElement("option"); + optgroup.appendChild( option ); + select.appendChild( optgroup ); + + equals( jQuery(option).prop("selected"), true, "Make sure that a single option is selected, even when in an optgroup." ); + equals( jQuery(document).prop("nodeName"), "#document", "prop works correctly on document nodes (bug #7451)." ); + + var attributeNode = document.createAttribute("irrelevant"), + commentNode = document.createComment("some comment"), + textNode = document.createTextNode("some text"), + obj = {}; + jQuery.each( [document, attributeNode, commentNode, textNode, obj, "#firstp"], function( i, ele ) { + strictEqual( jQuery(ele).prop("nonexisting"), undefined, "prop works correctly for non existing attributes (bug #7500)." ); + }); + + var obj = {}; + jQuery.each( [document, obj], function( i, ele ) { + var $ele = jQuery( ele ); + $ele.prop( "nonexisting", "foo" ); + equal( $ele.prop("nonexisting"), "foo", "prop(name, value) works correctly for non existing attributes (bug #7500)." ); + }); + jQuery( document ).removeProp("nonexisting"); +}); + +test("prop('tabindex')", function() { + expect(8); + + // elements not natively tabbable + equals(jQuery("#listWithTabIndex").prop("tabindex"), 5, "not natively tabbable, with tabindex set to 0"); + equals(jQuery("#divWithNoTabIndex").prop("tabindex"), undefined, "not natively tabbable, no tabindex set"); + + // anchor with href + equals(jQuery("#linkWithNoTabIndex").prop("tabindex"), 0, "anchor with href, no tabindex set"); + equals(jQuery("#linkWithTabIndex").prop("tabindex"), 2, "anchor with href, tabindex set to 2"); + equals(jQuery("#linkWithNegativeTabIndex").prop("tabindex"), -1, "anchor with href, tabindex set to -1"); + + // anchor without href + equals(jQuery("#linkWithNoHrefWithNoTabIndex").prop("tabindex"), undefined, "anchor without href, no tabindex set"); + equals(jQuery("#linkWithNoHrefWithTabIndex").prop("tabindex"), 1, "anchor without href, tabindex set to 2"); + equals(jQuery("#linkWithNoHrefWithNegativeTabIndex").prop("tabindex"), -1, "anchor without href, no tabindex set"); +}); + +test("prop('tabindex', value)", function() { + expect(9); + + var element = jQuery("#divWithNoTabIndex"); + equals(element.prop("tabindex"), undefined, "start with no tabindex"); + + // set a positive string + element.prop("tabindex", "1"); + equals(element.prop("tabindex"), 1, "set tabindex to 1 (string)"); + + // set a zero string + element.prop("tabindex", "0"); + equals(element.prop("tabindex"), 0, "set tabindex to 0 (string)"); + + // set a negative string + element.prop("tabindex", "-1"); + equals(element.prop("tabindex"), -1, "set tabindex to -1 (string)"); + + // set a positive number + element.prop("tabindex", 1); + equals(element.prop("tabindex"), 1, "set tabindex to 1 (number)"); + + // set a zero number + element.prop("tabindex", 0); + equals(element.prop("tabindex"), 0, "set tabindex to 0 (number)"); + + // set a negative number + element.prop("tabindex", -1); + equals(element.prop("tabindex"), -1, "set tabindex to -1 (number)"); + + element = jQuery("#linkWithTabIndex"); + equals(element.prop("tabindex"), 2, "start with tabindex 2"); + + element.prop("tabindex", -1); + equals(element.prop("tabindex"), -1, "set negative tabindex"); }); test("removeProp(String)", function() { @@ -419,14 +602,14 @@ test("removeProp(String)", function() { strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { - $ele = jQuery( ele ); + var $ele = jQuery( ele ); $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); }); test("val()", function() { - expect(23); + expect(26); document.getElementById("text1").value = "bla"; equals( jQuery("#text1").val(), "bla", "Check for modified value of input element" ); @@ -488,8 +671,38 @@ test("val()", function() { same( checks.serialize(), "test=1&test=on", "Get multiple checked values." ); checks.remove(); + + var $button = jQuery("<button value='foobar'>text</button>").insertAfter("#button"); + equals( $button.val(), "foobar", "Value retrieval on a button does not return innerHTML" ); + equals( $button.val("baz").html(), "text", "Setting the value does not change innerHTML" ); + + equals( jQuery("<option/>").val("test").attr("value"), "test", "Setting value sets the value attribute" ); }); +if ( "value" in document.createElement("meter") && + "value" in document.createElement("progress") ) { + + test("val() respects numbers without exception (Bug #9319)", function() { + + expect(4); + + var $meter = jQuery("<meter min='0' max='10' value='5.6'></meter>"), + $progress = jQuery("<progress max='10' value='1.5'></progress>"); + + try { + equal( typeof $meter.val(), "number", "meter, returns a number and does not throw exception" ); + equal( $meter.val(), $meter[0].value, "meter, api matches host and does not throw exception" ); + + equal( typeof $progress.val(), "number", "progress, returns a number and does not throw exception" ); + equal( $progress.val(), $progress[0].value, "progress, api matches host and does not throw exception" ); + + } catch(e) {} + + $meter.remove(); + $progress.remove(); + }); +} + var testVal = function(valueObj) { expect(8); @@ -547,6 +760,7 @@ test( "val(Array of Numbers) (Bug #7123)", function() { test("val(Function) with incoming value", function() { expect(10); + QUnit.reset(); var oldVal = jQuery("#text1").val(); jQuery("#text1").val(function(i, val) { @@ -599,7 +813,7 @@ test("val(Function) with incoming value", function() { test("val(select) after form.reset() (Bug #2551)", function() { expect(3); - jQuery("<form id='kk' name='kk'><select id='kkk'><option value='cf'>cf</option><option value='gf'>gf</option></select></form>").appendTo("#main"); + jQuery("<form id='kk' name='kk'><select id='kkk'><option value='cf'>cf</option><option value='gf'>gf</option></select></form>").appendTo("#qunit-fixture"); jQuery("#kkk").val( "gf" ); @@ -612,15 +826,18 @@ test("val(select) after form.reset() (Bug #2551)", function() { same( jQuery("#select3").val(), ["1", "2"], "Call val() on a multiple=\"multiple\" select" ); jQuery("#kk").remove(); -}); +}); var testAddClass = function(valueObj) { - expect(5); + expect(9); + var div = jQuery("div"); div.addClass( valueObj("test") ); var pass = true; for ( var i = 0; i < div.size(); i++ ) { - if ( div.get(i).className.indexOf("test") == -1 ) pass = false; + if ( !~div.get(i).className.indexOf("test") ) { + pass = false; + } } ok( pass, "Add Class" ); @@ -641,6 +858,19 @@ var testAddClass = function(valueObj) { div.attr("class", "foo"); div.addClass( valueObj("bar baz") ); equals( div.attr("class"), "foo bar baz", "Make sure there isn't too much trimming." ); + + div.removeClass(); + div.addClass( valueObj("foo") ).addClass( valueObj("foo") ) + equal( div.attr("class"), "foo", "Do not add the same class twice in separate calls." ); + + div.addClass( valueObj("fo") ); + equal( div.attr("class"), "foo fo", "Adding a similar class does not get interrupted." ); + div.removeClass().addClass("wrap2"); + ok( div.addClass("wrap").hasClass("wrap"), "Can add similarly named classes"); + + div.removeClass(); + div.addClass( valueObj("bar bar") ); + equal( div.attr("class"), "bar", "Do not add the same class twice in the same call." ); }; test("addClass(String)", function() { @@ -652,11 +882,11 @@ test("addClass(Function)", function() { }); test("addClass(Function) with incoming value", function() { - expect(45); + expect(48); var div = jQuery("div"), old = div.map(function(){ return jQuery(this).attr("class") || ""; }); - + div.addClass(function(i, val) { if ( this.id !== "_firebugConsole") { equals( val, old[i], "Make sure the incoming value is correct." ); @@ -724,7 +954,7 @@ test("removeClass(Function) - simple", function() { }); test("removeClass(Function) with incoming value", function() { - expect(45); + expect(48); var $divs = jQuery("div").addClass("test"), old = $divs.map(function(){ return jQuery(this).attr("class"); @@ -803,11 +1033,11 @@ test("toggleClass(Function[, boolean])", function() { test("toggleClass(Fucntion[, boolean]) with incoming value", function() { expect(14); - var e = jQuery("#firstp"), old = e.attr("class"); + 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." ); + equal( old, val, "Make sure the incoming value is correct." ); return "test"; }); ok( e.is(".test"), "Assert class present" ); @@ -815,26 +1045,26 @@ test("toggleClass(Fucntion[, boolean]) with incoming value", function() { old = e.attr("class"); e.toggleClass(function(i, val) { - equals( val, old, "Make sure the incoming value is correct." ); + equal( old, val, "Make sure the incoming value is correct." ); return "test"; }); ok( !e.is(".test"), "Assert class not present" ); - old = e.attr("class"); + old = e.attr("class") || ""; // class name with a boolean 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." ); + equal( old, val, "Make sure the incoming value is correct." ); + equal( state, false, "Make sure that the state is passed in." ); return "test"; }, false ); ok( !e.is(".test"), "Assert class not present" ); - old = e.attr("class"); + 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." ); + equal( old, val, "Make sure the incoming value is correct." ); + equal( state, true, "Make sure that the state is passed in." ); return "test"; }, true ); ok( e.is(".test"), "Assert class present" ); @@ -842,8 +1072,8 @@ test("toggleClass(Fucntion[, boolean]) with incoming value", function() { 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." ); + equal( old, val, "Make sure the incoming value is correct." ); + equal( state, false, "Make sure that the state is passed in." ); return "test"; }, false ); ok( !e.is(".test"), "Assert class not present" ); @@ -891,4 +1121,14 @@ test("addClass, removeClass, hasClass", function() { ok( jq.hasClass("cla.ss3")==false, "Check the dotted class has been removed" ); jq.removeClass("class4"); ok( jq.hasClass("class4")==false, "Check the class has been properly removed" ); -});
\ No newline at end of file +}); + +test("contents().hasClass() returns correct values", function() { + expect(2); + + var $div = jQuery("<div><span class='foo'></span><!-- comment -->text</div>"), + $contents = $div.contents(); + + ok( $contents.hasClass("foo"), "Found 'foo' in $contents" ); + ok( !$contents.hasClass("undefined"), "Did not find 'undefined' in $contents (correctly)" ); +}); diff --git a/test/unit/callbacks.js b/test/unit/callbacks.js new file mode 100644 index 000000000..fcc3ee46b --- /dev/null +++ b/test/unit/callbacks.js @@ -0,0 +1,194 @@ +module("callbacks", { teardown: moduleTeardown }); + +(function() { + +var output, + addToOutput = function( string ) { + return function() { + output += string; + }; + }, + outputA = addToOutput( "A" ), + outputB = addToOutput( "B" ), + outputC = addToOutput( "C" ), + tests = { + "": "XABC X XABCABCC X XBB X XABA X", + "once": "XABC X X X X X XABA X", + "memory": "XABC XABC XABCABCCC XA XBB XB XABA XC", + "unique": "XABC X XABCA X XBB X XAB X", + "relocate": "XABC X XAABC X XBB X XBA X", + "stopOnFalse": "XABC X XABCABCC X XBB X XA X", + "addAfterFire": "XAB X XABCAB X XBB X XABA X", + "queue": "XA X XB X XB X XA X", + "once memory": "XABC XABC X XA X XA XABA XC", + "once unique": "XABC X X X X X XAB X", + "once relocate": "XABC X X X X X XBA X", + "once stopOnFalse": "XABC X X X X X XA X", + "once addAfterFire": "XAB X X X X X XABA X", + "memory unique": "XABC XA XABCA XA XBB XB XAB XC", + "memory relocate": "XABC XB XAABC XA XBB XB XBA XC", + "memory stopOnFalse": "XABC XABC XABCABCCC XA XBB XB XA X", + "memory addAfterFire": "XAB XAB XABCABC XA XBB XB XABA XC", + "unique relocate": "XABC X XAABC X XBB X XBA X", + "unique stopOnFalse": "XABC X XABCA X XBB X XA X", + "unique addAfterFire": "XAB X XABCA X XBB X XAB X", + "relocate stopOnFalse": "XABC X XAABC X XBB X X X", + "relocate addAfterFire": "XAB X XAA X XBB X XBA X", + "stopOnFalse addAfterFire": "XAB X XABCAB X XBB X XA X" + }, + filters = { + "no filter": undefined, + "filter": function( fn ) { + return function() { + return fn.apply( this, arguments ); + }; + } + }; + +jQuery.each( tests, function( flags, resultString ) { + + jQuery.each( filters, function( filterLabel, filter ) { + + test( "jQuery.Callbacks( \"" + flags + "\" ) - " + filterLabel, function() { + + expect( 19 ); + + // Give qunit a little breathing room + stop(); + setTimeout( start, 0 ); + + var cblist; + results = resultString.split( /\s+/ ); + + // Basic binding and firing + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add(function( str ) { + output += str; + }); + cblist.fire( "A" ); + strictEqual( output, "XA", "Basic binding and firing" ); + output = "X"; + cblist.disable(); + cblist.add(function( str ) { + output += str; + }); + strictEqual( output, "X", "Adding a callback after disabling" ); + cblist.fire( "A" ); + strictEqual( output, "X", "Firing after disabling" ); + + // Basic binding and firing (context, arguments) + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add(function() { + equals( this, window, "Basic binding and firing (context)" ); + output += Array.prototype.join.call( arguments, "" ); + }); + cblist.fireWith( window, [ "A", "B" ] ); + strictEqual( output, "XAB", "Basic binding and firing (arguments)" ); + + // fireWith with no arguments + output = ""; + cblist = jQuery.Callbacks( flags ); + cblist.add(function() { + equals( this, window, "fireWith with no arguments (context is window)" ); + strictEqual( arguments.length, 0, "fireWith with no arguments (no arguments)" ); + }); + cblist.fireWith(); + + // Basic binding, removing and firing + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( outputA, outputB, outputC ); + cblist.remove( outputB, outputC ); + cblist.fire(); + strictEqual( output, "XA", "Basic binding, removing and firing" ); + + // Empty + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( outputA ); + cblist.add( outputB ); + cblist.add( outputC ); + cblist.empty(); + cblist.fire(); + strictEqual( output, "X", "Empty" ); + + // Locking + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( function( str ) { + output += str; + }); + cblist.lock(); + cblist.add( function( str ) { + output += str; + }); + cblist.fire( "A" ); + cblist.add( function( str ) { + output += str; + }); + strictEqual( output, "X", "Lock early" ); + + // Ordering + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( function() { + cblist.add( outputC ); + outputA(); + }, outputB ); + cblist.fire(); + strictEqual( output, results.shift(), "Proper ordering" ); + + // Add and fire again + output = "X"; + cblist.add( function() { + cblist.add( outputC ); + outputA(); + }, outputB ); + strictEqual( output, results.shift(), "Add after fire" ); + + output = "X"; + cblist.fire(); + strictEqual( output, results.shift(), "Fire again" ); + + // Multiple fire + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( function( str ) { + output += str; + } ); + cblist.fire( "A" ); + strictEqual( output, "XA", "Multiple fire (first fire)" ); + output = "X"; + cblist.add( function( str ) { + output += str; + } ); + strictEqual( output, results.shift(), "Multiple fire (first new callback)" ); + output = "X"; + cblist.fire( "B" ); + strictEqual( output, results.shift(), "Multiple fire (second fire)" ); + output = "X"; + cblist.add( function( str ) { + output += str; + } ); + strictEqual( output, results.shift(), "Multiple fire (second new callback)" ); + + // Return false + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( outputA, function() { return false; }, outputB ); + cblist.add( outputA ); + cblist.fire(); + strictEqual( output, results.shift(), "Callback returning false" ); + + // Add another callback (to control lists with memory do not fire anymore) + output = "X"; + cblist.add( outputC ); + strictEqual( output, results.shift(), "Adding a callback after one returned false" ); + + }); + }); +}); + +})(); diff --git a/test/unit/core.js b/test/unit/core.js index 94771649e..0f4504a13 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -12,7 +12,7 @@ test("Basic requirements", function() { }); test("jQuery()", function() { - expect(25); + expect(29); // Basic constructor's behavior @@ -29,7 +29,7 @@ test("jQuery()", function() { equals( jQuery(window).length, 1, "Correct number of elements generated for jQuery(window)" ); - var main = jQuery("#main"); + var main = jQuery("#qunit-fixture"); same( jQuery("div p", main).get(), q("sndp", "en", "sap"), "Basic selector with jQuery object as context" ); /* @@ -96,6 +96,17 @@ test("jQuery()", function() { // manually clean up detached elements elem.remove(); + + equals( jQuery(" <div/> ").length, 1, "Make sure whitespace is trimmed." ); + equals( jQuery(" a<div/>b ").length, 1, "Make sure whitespace and other characters are trimmed." ); + + var long = ""; + for ( var i = 0; i < 128; i++ ) { + long += "12345678"; + } + + equals( jQuery(" <div>" + long + "</div> ").length, 1, "Make sure whitespace is trimmed on long strings." ); + equals( jQuery(" a<div>" + long + "</div>b ").length, 1, "Make sure whitespace and other characters are trimmed on long strings." ); }); test("selector state", function() { @@ -115,54 +126,54 @@ test("selector state", function() { equals( test.selector, "", "Body Selector" ); equals( test.context, document.body, "Body Context" ); - test = jQuery("#main"); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document, "#main Context" ); + test = jQuery("#qunit-fixture"); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document, "#qunit-fixture Context" ); test = jQuery("#notfoundnono"); equals( test.selector, "#notfoundnono", "#notfoundnono Selector" ); equals( test.context, document, "#notfoundnono Context" ); - test = jQuery("#main", document); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document, "#main Context" ); + test = jQuery("#qunit-fixture", document); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document, "#qunit-fixture Context" ); - test = jQuery("#main", document.body); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document.body, "#main Context" ); + test = jQuery("#qunit-fixture", document.body); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document.body, "#qunit-fixture Context" ); // Test cloning test = jQuery(test); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document.body, "#main Context" ); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document.body, "#qunit-fixture Context" ); - test = jQuery(document.body).find("#main"); - equals( test.selector, "#main", "#main find Selector" ); - equals( test.context, document.body, "#main find Context" ); + test = jQuery(document.body).find("#qunit-fixture"); + equals( test.selector, "#qunit-fixture", "#qunit-fixture find Selector" ); + equals( test.context, document.body, "#qunit-fixture find Context" ); - test = jQuery("#main").filter("div"); - equals( test.selector, "#main.filter(div)", "#main filter Selector" ); - equals( test.context, document, "#main filter Context" ); + test = jQuery("#qunit-fixture").filter("div"); + equals( test.selector, "#qunit-fixture.filter(div)", "#qunit-fixture filter Selector" ); + equals( test.context, document, "#qunit-fixture filter Context" ); - test = jQuery("#main").not("div"); - equals( test.selector, "#main.not(div)", "#main not Selector" ); - equals( test.context, document, "#main not Context" ); + test = jQuery("#qunit-fixture").not("div"); + equals( test.selector, "#qunit-fixture.not(div)", "#qunit-fixture not Selector" ); + equals( test.context, document, "#qunit-fixture not Context" ); - test = jQuery("#main").filter("div").not("div"); - equals( test.selector, "#main.filter(div).not(div)", "#main filter, not Selector" ); - equals( test.context, document, "#main filter, not Context" ); + test = jQuery("#qunit-fixture").filter("div").not("div"); + equals( test.selector, "#qunit-fixture.filter(div).not(div)", "#qunit-fixture filter, not Selector" ); + equals( test.context, document, "#qunit-fixture filter, not Context" ); - test = jQuery("#main").filter("div").not("div").end(); - equals( test.selector, "#main.filter(div)", "#main filter, not, end Selector" ); - equals( test.context, document, "#main filter, not, end Context" ); + test = jQuery("#qunit-fixture").filter("div").not("div").end(); + equals( test.selector, "#qunit-fixture.filter(div)", "#qunit-fixture filter, not, end Selector" ); + equals( test.context, document, "#qunit-fixture filter, not, end Context" ); - test = jQuery("#main").parent("body"); - equals( test.selector, "#main.parent(body)", "#main parent Selector" ); - equals( test.context, document, "#main parent Context" ); + test = jQuery("#qunit-fixture").parent("body"); + equals( test.selector, "#qunit-fixture.parent(body)", "#qunit-fixture parent Selector" ); + equals( test.context, document, "#qunit-fixture parent Context" ); - test = jQuery("#main").eq(0); - equals( test.selector, "#main.slice(0,1)", "#main eq Selector" ); - equals( test.context, document, "#main eq Context" ); + test = jQuery("#qunit-fixture").eq(0); + equals( test.selector, "#qunit-fixture.slice(0,1)", "#qunit-fixture eq Selector" ); + equals( test.context, document, "#qunit-fixture eq Context" ); var d = "<div />"; equals( @@ -234,7 +245,7 @@ test("noConflict", function() { equals( jQuery.noConflict(true), $$, "noConflict returned the jQuery object" ); equals( jQuery, originaljQuery, "Make sure jQuery was reverted." ); equals( $, original$, "Make sure $ was reverted." ); - ok( $$("#main").html("test"), "Make sure that jQuery still works." ); + ok( $$("#qunit-fixture").html("test"), "Make sure that jQuery still works." ); jQuery = $$; }); @@ -285,7 +296,7 @@ test("type", function() { }); test("isPlainObject", function() { - expect(14); + expect(15); stop(); @@ -327,6 +338,13 @@ test("isPlainObject", function() { ok(!jQuery.isPlainObject(window), "window"); try { + jQuery.isPlainObject( window.location ); + ok( true, "Does not throw exceptions on host objects"); + } catch ( e ) { + ok( false, "Does not throw exceptions on host objects -- FAIL"); + } + + try { var iframe = document.createElement("iframe"); document.body.appendChild(iframe); @@ -462,6 +480,24 @@ test("isXMLDoc - HTML", function() { document.body.removeChild( iframe ); }); +test("XSS via location.hash", function() { + expect(1); + + stop(); + jQuery._check9521 = function(x){ + ok( x, "script called from #id-like selector with inline handler" ); + jQuery("#check9521").remove(); + delete jQuery._check9521; + start(); + }; + try { + // This throws an error because it's processed like an id + jQuery( '#<img id="check9521" src="no-such-.gif" onerror="jQuery._check9521(false)">' ).appendTo("#qunit-fixture"); + } catch (err) { + jQuery._check9521(true); + }; +}); + if ( !isLocal ) { test("isXMLDoc - XML", function() { expect(3); @@ -577,29 +613,65 @@ test("end()", function() { test("length", function() { expect(1); - equals( jQuery("#main p").length, 6, "Get Number of Elements Found" ); + equals( jQuery("#qunit-fixture p").length, 6, "Get Number of Elements Found" ); }); test("size()", function() { expect(1); - equals( jQuery("#main p").size(), 6, "Get Number of Elements Found" ); + equals( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); }); test("get()", function() { expect(1); - same( jQuery("#main p").get(), q("firstp","ap","sndp","en","sap","first"), "Get All Elements" ); + same( jQuery("#qunit-fixture p").get(), q("firstp","ap","sndp","en","sap","first"), "Get All Elements" ); }); test("toArray()", function() { expect(1); - same( jQuery("#main p").toArray(), + same( jQuery("#qunit-fixture p").toArray(), q("firstp","ap","sndp","en","sap","first"), "Convert jQuery object to an Array" ) }) +test("inArray()", function() { + expect(19); + + var selections = { + p: q("firstp", "sap", "ap", "first"), + em: q("siblingnext", "siblingfirst"), + div: q("qunit-testrunner-toolbar", "nothiddendiv", "nothiddendivchild", "foo"), + a: q("mark", "groups", "google", "simon1"), + empty: [] + }, + tests = { + p: { elem: jQuery("#ap")[0], index: 2 }, + em: { elem: jQuery("#siblingfirst")[0], index: 1 }, + div: { elem: jQuery("#nothiddendiv")[0], index: 1 }, + a: { elem: jQuery("#simon1")[0], index: 3 } + }, + falseTests = { + p: jQuery("#liveSpan1")[0], + em: jQuery("#nothiddendiv")[0], + empty: "" + }; + + jQuery.each( tests, function( key, obj ) { + equal( jQuery.inArray( obj.elem, selections[ key ] ), obj.index, "elem is in the array of selections of its tag" ); + // Third argument (fromIndex) + equal( !!~jQuery.inArray( obj.elem, selections[ key ], 5 ), false, "elem is NOT in the array of selections given a starting index greater than its position" ); + equal( !!~jQuery.inArray( obj.elem, selections[ key ], 1 ), true, "elem is in the array of selections given a starting index less than or equal to its position" ); + equal( !!~jQuery.inArray( obj.elem, selections[ key ], -3 ), true, "elem is in the array of selections given a negative index" ); + }); + + jQuery.each( falseTests, function( key, elem ) { + equal( !!~jQuery.inArray( elem, selections[ key ] ), false, "elem is NOT in the array of selections" ); + }); + +}); + test("get(Number)", function() { expect(2); - equals( jQuery("#main p").get(0), document.getElementById("firstp"), "Get A Single Element" ); + equals( jQuery("#qunit-fixture p").get(0), document.getElementById("firstp"), "Get A Single Element" ); strictEqual( jQuery("#firstp").get(1), undefined, "Try get with index larger elements count" ); }); @@ -648,7 +720,7 @@ test("first()/last()", function() { }); test("map()", function() { - expect(7); + expect(8); same( jQuery("#ap").map(function(){ @@ -689,6 +761,12 @@ test("map()", function() { }); equals( mapped.length, scripts.length, "Map an array(-like) to a hash" ); + var nonsense = document.getElementsByTagName("asdf"); + var mapped = jQuery.map( nonsense, function( v, k ){ + return v; + }); + equals( mapped.length, nonsense.length, "Map an empty array(-like) to a hash" ); + var flat = jQuery.map( Array(4), function( v, k ){ return k % 2 ? k : [k,k,k];//try mixing array and regular returns }); @@ -905,6 +983,16 @@ test("jQuery.makeArray", function(){ same( jQuery.makeArray({length: "5"}), [], "Make sure object is coerced properly."); }); +test("jQuery.inArray", function(){ + expect(3); + + equals( jQuery.inArray( 0, false ), -1 , "Search in 'false' as array returns -1 and doesn't throw exception" ); + + equals( jQuery.inArray( 0, null ), -1 , "Search in 'null' as array returns -1 and doesn't throw exception" ); + + equals( jQuery.inArray( 0, undefined ), -1 , "Search in 'undefined' as array returns -1 and doesn't throw exception" ); +}); + test("jQuery.isEmptyObject", function(){ expect(2); @@ -916,7 +1004,7 @@ test("jQuery.isEmptyObject", function(){ }); test("jQuery.proxy", function(){ - expect(6); + expect(7); var test = function(){ equals( this, thisObject, "Make sure that scope is set properly." ); }; var thisObject = { foo: "bar", method: test }; @@ -927,6 +1015,9 @@ test("jQuery.proxy", function(){ // Basic scoping jQuery.proxy( test, thisObject )(); + // Another take on it + jQuery.proxy( thisObject, "method" )(); + // Make sure it doesn't freak out equals( jQuery.proxy( null, thisObject ), undefined, "Make sure no function was returned." ); @@ -970,6 +1061,26 @@ test("jQuery.parseJSON", function(){ } }); +test("jQuery.parseXML", 4, function(){ + var xml, tmp; + try { + xml = jQuery.parseXML( "<p>A <b>well-formed</b> xml string</p>" ); + tmp = xml.getElementsByTagName( "p" )[ 0 ]; + ok( !!tmp, "<p> present in document" ); + tmp = tmp.getElementsByTagName( "b" )[ 0 ]; + ok( !!tmp, "<b> present in document" ); + strictEqual( tmp.childNodes[ 0 ].nodeValue, "well-formed", "<b> text is as expected" ); + } catch (e) { + strictEqual( e, undefined, "unexpected error" ); + } + try { + xml = jQuery.parseXML( "<p>Not a <<b>well-formed</b> xml string</p>" ); + ok( false, "invalid xml not detected" ); + } catch( e ) { + strictEqual( e, "Invalid XML: <p>Not a <<b>well-formed</b> xml string</p>", "invalid xml detected" ); + } +}); + test("jQuery.sub() - Static Methods", function(){ expect(18); var Subclass = jQuery.sub(); @@ -1090,3 +1201,22 @@ test("jQuery.sub() - .fn Methods", function(){ }); }); + +test("jQuery.camelCase()", function() { + + var tests = { + "foo-bar": "fooBar", + "foo-bar-baz": "fooBarBaz", + "girl-u-want": "girlUWant", + "the-4th-dimension": "the4thDimension", + "-o-tannenbaum": "OTannenbaum", + "-moz-illa": "MozIlla", + "-ms-take": "msTake" + }; + + expect(7); + + jQuery.each( tests, function( key, val ) { + equal( jQuery.camelCase( key ), val, "Converts: " + key + " => " + val ); + }); +}); diff --git a/test/unit/css.js b/test/unit/css.js index 33bc1548d..78c6def61 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1,15 +1,17 @@ module("css", { teardown: moduleTeardown }); test("css(String|Hash)", function() { - expect( 42 ); + expect( 44 ); - equals( jQuery("#main").css("display"), "block", "Check for css property \"display\""); + equals( jQuery("#qunit-fixture").css("display"), "block", "Check for css property \"display\""); ok( jQuery("#nothiddendiv").is(":visible"), "Modifying CSS display: Assert element is visible"); jQuery("#nothiddendiv").css({display: "none"}); ok( !jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is hidden"); jQuery("#nothiddendiv").css({display: "block"}); ok( jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is visible"); + ok( jQuery(window).is(":visible"), "Calling is(':visible') on window does not throw an error in IE."); + ok( jQuery(document).is(":visible"), "Calling is(':visible') on document does not throw an error in IE."); var div = jQuery( "<div>" ); @@ -36,8 +38,8 @@ test("css(String|Hash)", function() { var width = parseFloat(jQuery("#nothiddendiv").css("width")), height = parseFloat(jQuery("#nothiddendiv").css("height")); jQuery("#nothiddendiv").css({ width: -1, height: -1 }); - equals( parseFloat(jQuery("#nothiddendiv").css("width")), width, "Test negative width ignored") - equals( parseFloat(jQuery("#nothiddendiv").css("height")), height, "Test negative height ignored") + equals( parseFloat(jQuery("#nothiddendiv").css("width")), width, "Test negative width ignored"); + equals( parseFloat(jQuery("#nothiddendiv").css("height")), height, "Test negative height ignored"); equals( jQuery("<div style='display: none;'>").css("display"), "none", "Styles on disconnected nodes"); @@ -45,9 +47,9 @@ test("css(String|Hash)", function() { equals( jQuery("#floatTest").css("float"), "right", "Modified CSS float using \"float\": Assert float is right"); jQuery("#floatTest").css({"font-size": "30px"}); equals( jQuery("#floatTest").css("font-size"), "30px", "Modified CSS font-size: Assert font-size is 30px"); - jQuery.each("0,0.25,0.5,0.75,1".split(","), function(i, n) { jQuery("#foo").css({opacity: n}); + equals( jQuery("#foo").css("opacity"), parseFloat(n), "Assert opacity is " + parseFloat(n) + " as a String" ); jQuery("#foo").css({opacity: parseFloat(n)}); equals( jQuery("#foo").css("opacity"), parseFloat(n), "Assert opacity is " + parseFloat(n) + " as a Number" ); @@ -62,7 +64,8 @@ test("css(String|Hash)", function() { ok(true, "Requires the same number of tests"): ok( ~jQuery("#empty")[0].currentStyle.filter.indexOf("gradient"), "Assert setting opacity doesn't overwrite other filters of the stylesheet in IE" ); - var div = jQuery("#nothiddendiv"), child = jQuery("#nothiddendivchild"); + div = jQuery("#nothiddendiv"); + var child = jQuery("#nothiddendivchild"); equals( parseInt(div.css("fontSize")), 16, "Verify fontSize px set." ); equals( parseInt(div.css("font-size")), 16, "Verify fontSize px set." ); @@ -109,11 +112,13 @@ test("css(String|Hash)", function() { }); test("css() explicit and relative values", function() { - expect(9); + expect(29); var $elem = jQuery("#nothiddendiv"); - $elem.css({ width: 1, height: 1 }); + $elem.css({ width: 1, height: 1, paddingLeft: "1px", opacity: 1 }); equals( $elem.width(), 1, "Initial css set or width/height works (hash)" ); + equals( $elem.css("paddingLeft"), "1px", "Initial css set of paddingLeft works (hash)" ); + equals( $elem.css("opacity"), "1", "Initial css set of opacity works (hash)" ); $elem.css({ width: "+=9" }); equals( $elem.width(), 10, "'+=9' on width (hash)" ); @@ -138,6 +143,60 @@ test("css() explicit and relative values", function() { $elem.css( "width", "-=9px" ); equals( $elem.width(), 1, "'-=9px' on width (params)" ); + + $elem.css( "width", "-=-9px" ); + equals( $elem.width(), 10, "'-=-9px' on width (params)" ); + + $elem.css( "width", "+=-9px" ); + equals( $elem.width(), 1, "'+=-9px' on width (params)" ); + + $elem.css({ paddingLeft: "+=4" }); + equals( $elem.css("paddingLeft"), "5px", "'+=4' on paddingLeft (hash)" ); + + $elem.css({ paddingLeft: "-=4" }); + equals( $elem.css("paddingLeft"), "1px", "'-=4' on paddingLeft (hash)" ); + + $elem.css({ paddingLeft: "+=4px" }); + equals( $elem.css("paddingLeft"), "5px", "'+=4px' on paddingLeft (hash)" ); + + $elem.css({ paddingLeft: "-=4px" }); + equals( $elem.css("paddingLeft"), "1px", "'-=4px' on paddingLeft (hash)" ); + + $elem.css({ "padding-left": "+=4" }); + equals( $elem.css("paddingLeft"), "5px", "'+=4' on padding-left (hash)" ); + + $elem.css({ "padding-left": "-=4" }); + equals( $elem.css("paddingLeft"), "1px", "'-=4' on padding-left (hash)" ); + + $elem.css({ "padding-left": "+=4px" }); + equals( $elem.css("paddingLeft"), "5px", "'+=4px' on padding-left (hash)" ); + + $elem.css({ "padding-left": "-=4px" }); + equals( $elem.css("paddingLeft"), "1px", "'-=4px' on padding-left (hash)" ); + + $elem.css( "paddingLeft", "+=4" ); + equals( $elem.css("paddingLeft"), "5px", "'+=4' on paddingLeft (params)" ); + + $elem.css( "paddingLeft", "-=4" ); + equals( $elem.css("paddingLeft"), "1px", "'-=4' on paddingLeft (params)" ); + + $elem.css( "padding-left", "+=4px" ); + equals( $elem.css("paddingLeft"), "5px", "'+=4px' on padding-left (params)" ); + + $elem.css( "padding-left", "-=4px" ); + equals( $elem.css("paddingLeft"), "1px", "'-=4px' on padding-left (params)" ); + + $elem.css({ opacity: "-=0.5" }); + equals( $elem.css("opacity"), "0.5", "'-=0.5' on opacity (hash)" ); + + $elem.css({ opacity: "+=0.5" }); + equals( $elem.css("opacity"), "1", "'+=0.5' on opacity (hash)" ); + + $elem.css( "opacity", "-=0.5" ); + equals( $elem.css("opacity"), "0.5", "'-=0.5' on opacity (params)" ); + + $elem.css( "opacity", "+=0.5" ); + equals( $elem.css("opacity"), "1", "'+=0.5' on opacity (params)" ); }); test("css(String, Object)", function() { @@ -171,7 +230,7 @@ test("css(String, Object)", function() { j.css("overflow", "visible"); equals( j.css("overflow"), "visible", "Check node,textnode,comment css works" ); // opera sometimes doesn't update 'display' correctly, see #2037 - jQuery("#t2037")[0].innerHTML = jQuery("#t2037")[0].innerHTML + jQuery("#t2037")[0].innerHTML = jQuery("#t2037")[0].innerHTML; equals( jQuery("#t2037 .hidden").css("display"), "none", "Make sure browser thinks it is hidden" ); var div = jQuery("#nothiddendiv"), @@ -209,6 +268,23 @@ if ( !jQuery.support.opacity ) { jQuery("#foo").css("filter", filterVal3).css("opacity", 1); ok( jQuery("#foo").css("filter").indexOf(filterVal3) !== -1, "Setting opacity in IE doesn't clobber other filters" ); }); + + test( "Setting opacity to 1 properly removes filter: style (#6652)", function() { + var rfilter = /filter:[^;]*/i, + test = jQuery( "#t6652" ).css( "opacity", 1 ), + test2 = test.find( "div" ).css( "opacity", 1 ); + + function hasFilter( elem ) { + var match = rfilter.exec( elem[0].style.cssText ); + if ( match ) { + return true; + } + return false; + } + expect( 2 ); + ok( !hasFilter( test ), "Removed filter attribute on element without filter in stylesheet" ); + ok( hasFilter( test2 ), "Filter attribute remains on element that had filter in stylesheet" ); + }); } test("css(String, Function)", function() { @@ -394,3 +470,44 @@ test("jQuery.cssProps behavior, (bug #8402)", function() { // cleanup jQuery.cssProps jQuery.cssProps.top = undefined; }); + +test("widows & orphans #8936", function () { + + var $p = jQuery("<p>").appendTo("#qunit-fixture"); + + if ( "widows" in $p[0].style ) { + expect(4); + $p.css({ + widows: 0, + orphans: 0 + }); + + equal( $p.css("widows") || jQuery.style( $p[0], "widows" ), 0, "widows correctly start with value 0"); + equal( $p.css("orphans") || jQuery.style( $p[0], "orphans" ), 0, "orphans correctly start with value 0"); + + $p.css({ + widows: 3, + orphans: 3 + }); + + equal( $p.css("widows") || jQuery.style( $p[0], "widows" ), 3, "widows correctly set to 3"); + equal( $p.css("orphans") || jQuery.style( $p[0], "orphans" ), 3, "orphans correctly set to 3"); + } else { + + expect(1); + ok( true, "jQuery does not attempt to test for style props that definitely don't exist in older versions of IE"); + } + + + $p.remove(); +}); + +test("Do not append px to 'fill-opacity' #9548", 1, function() { + + var $div = jQuery("<div>").appendTo("#qunit-fixture"); + + $div.css("fill-opacity", 0).animate({ "fill-opacity": 1.0 }, 0, function () { + equal( jQuery(this).css("fill-opacity"), 1, "Do not append px to 'fill-opacity'"); + }); + +}); diff --git a/test/unit/data.js b/test/unit/data.js index 888f71cbf..4feba32c0 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -7,7 +7,7 @@ test("expando", function(){ }); function dataTests (elem) { - // expect(32) + // expect(31) function getCacheLength() { var cacheLength = 0; @@ -52,8 +52,8 @@ function dataTests (elem) { 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" ); + var internalDataObj = jQuery._data( elem ); + ok( internalDataObj, "Internal data object exists" ); 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" ); @@ -62,7 +62,7 @@ function dataTests (elem) { 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" ); + strictEqual( jQuery._data(elem), internalDataObj, "jQuery.removeData does not remove internal data if it exists" ); jQuery.removeData(elem, undefined, true); @@ -75,8 +75,9 @@ function dataTests (elem) { 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" ); + // delete the last private data key so we can test removing public data + // will destroy the cache + jQuery.removeData( elem, "foo", true ); if (elem.nodeType) { var oldCacheLength = getCacheLength(); @@ -138,7 +139,7 @@ function dataTests (elem) { } test("jQuery.data", function() { - expect(128); + expect(124); var div = document.createElement("div"); @@ -316,7 +317,7 @@ test("data-* attributes", function() { div.remove(); - child.appendTo("#main"); + child.appendTo("#qunit-fixture"); equals( child.data("myobj"), "old data", "Value accessed from data-* attribute"); child.data("myobj", "replaced"); @@ -406,7 +407,7 @@ test("data-* attributes", function() { } 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 = jQuery(metadata).appendTo("#qunit-fixture"); elem.find("li").each(testData); elem.remove(); @@ -488,18 +489,134 @@ if (window.JSON && window.JSON.stringify) { } test("jQuery.data should follow html5 specification regarding camel casing", function() { - expect(6); + expect(10); - var div = jQuery("<div id='myObject' data-foo='a' data-foo-bar='b' data-foo-bar-baz='c'></div>") + var div = jQuery("<div id='myObject' data-w-t-f='ftw' data-big-a-little-a='bouncing-b' data-foo='a' data-foo-bar='b' data-foo-bar-baz='c'></div>") .prependTo("body"); - equals(div.data().foo, "a", "Verify single word data-* key"); - equals(div.data().fooBar, "b", "Verify multiple word data-* key"); - equals(div.data().fooBarBaz, "c", "Verify multiple word data-* key"); + equal( div.data().wTF, "ftw", "Verify single letter data-* key" ); + equal( div.data().bigALittleA, "bouncing-b", "Verify single letter mixed data-* key" ); + + equal( div.data().foo, "a", "Verify single word data-* key" ); + equal( div.data().fooBar, "b", "Verify multiple word data-* key" ); + equal( div.data().fooBarBaz, "c", "Verify multiple word data-* key" ); + + equal( div.data("foo"), "a", "Verify single word data-* key" ); + equal( div.data("fooBar"), "b", "Verify multiple word data-* key" ); + equal( div.data("fooBarBaz"), "c", "Verify multiple word data-* key" ); + + div.data("foo-bar", "d"); - equals(div.data("foo"), "a", "Verify single word data-* key"); - equals(div.data("fooBar"), "b", "Verify multiple word data-* key"); - equals(div.data("fooBarBaz"), "c", "Verify multiple word data-* key"); + equal( div.data("fooBar"), "d", "Verify updated data-* key" ); + equal( div.data("foo-bar"), "d", "Verify updated data-* key" ); div.remove(); -});
\ No newline at end of file +}); + +test("jQuery.data should not miss data with preset hyphenated property names", function() { + + expect(2); + + var div = jQuery("<div/>", { id: "hyphened" }).appendTo("#qunit-fixture"), + test = { + "camelBar": "camelBar", + "hyphen-foo": "hyphen-foo" + }; + + div.data( test ); + + jQuery.each( test , function(i, k) { + equal( div.data(k), k, "data with property '"+k+"' was correctly found"); + }); +}); + +test("jQuery.data supports interoperable hyphenated/camelCase get/set of properties with arbitrary non-null|NaN|undefined values", function() { + + var div = jQuery("<div/>", { id: "hyphened" }).appendTo("#qunit-fixture"), + datas = { + "non-empty": "a string", + "empty-string": "", + "one-value": 1, + "zero-value": 0, + "an-array": [], + "an-object": {}, + "bool-true": true, + "bool-false": false, + "some-json": '{ "foo": "bar" }', + "num-1-middle": true, + "num-end-2": true, + "2-num-start": true + }; + + expect( 24 ); + + jQuery.each( datas, function( key, val ) { + div.data( key, val ); + + deepEqual( div.data( key ), val, "get: " + key ); + deepEqual( div.data( jQuery.camelCase( key ) ), val, "get: " + jQuery.camelCase( key ) ); + }); +}); + +test("jQuery.data supports interoperable removal of hyphenated/camelCase properties", function() { + var div = jQuery("<div/>", { id: "hyphened" }).appendTo("#qunit-fixture"), + datas = { + "non-empty": "a string", + "empty-string": "", + "one-value": 1, + "zero-value": 0, + "an-array": [], + "an-object": {}, + "bool-true": true, + "bool-false": false, + "some-json": '{ "foo": "bar" }' + }; + + expect( 27 ); + + jQuery.each( datas, function( key, val ) { + div.data( key, val ); + + deepEqual( div.data( key ), val, "get: " + key ); + deepEqual( div.data( jQuery.camelCase( key ) ), val, "get: " + jQuery.camelCase( key ) ); + + div.removeData( key ); + + equal( div.data( key ), undefined, "get: " + key ); + + }); +}); + +// Test originally by Moschel +test("Triggering the removeData should not throw exceptions. (#10080)", function() { + expect(1); + stop(); + var frame = jQuery("#loadediframe"); + jQuery(frame[0].contentWindow).bind("unload", function() { + ok(true, "called unload"); + start(); + }); + // change the url to trigger unload + frame.attr("src", "data/iframe.html?param=true"); +}); + +test( "Only check element attributes once when calling .data() - #8909", function() { + expect( 2 ); + var testing = { + test: "testing", + test2: "testing" + }, + element = jQuery( "<div data-test='testing'>" ), + node = element[ 0 ]; + + // set an attribute using attr to ensure it + node.setAttribute( "data-test2", "testing" ); + deepEqual( element.data(), testing, "Sanity Check" ); + + node.setAttribute( "data-test3", "testing" ); + deepEqual( element.data(), testing, "The data didn't change even though the data-* attrs did" ); + + // clean up data cache + element.remove(); + +}); diff --git a/test/unit/deferred.js b/test/unit/deferred.js index c71fbdbe7..de74aeccd 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -2,119 +2,13 @@ module("deferred", { teardown: moduleTeardown }); jQuery.each( [ "", " - new operator" ], function( _, withNew ) { - function createDeferred() { - return withNew ? new jQuery._Deferred() : jQuery._Deferred(); - } - - test("jQuery._Deferred" + withNew, function() { - - expect( 11 ); - - var deferred, - object, - test; - - deferred = createDeferred(); - - 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 = createDeferred().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 = createDeferred().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 = createDeferred(); - - deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) { - ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" ); - }); - - // #8421 - deferred = createDeferred(); - deferred.resolveWith().done(function() { - ok( true, "Test resolveWith can be called with no argument" ); - }); - }); -} ); - -jQuery.each( [ "", " - new operator" ], function( _, withNew ) { - function createDeferred( fn ) { return withNew ? new jQuery.Deferred( fn ) : jQuery.Deferred( fn ); } test("jQuery.Deferred" + withNew, function() { - expect( 8 ); + expect( 14 ); createDeferred().resolve().then( function() { ok( true , "Success on resolve" ); @@ -140,12 +34,26 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) { }).then( function( value ) { strictEqual( value , "done" , "Passed function executed" ); }); + + jQuery.each( "resolve reject".split( " " ), function( _, change ) { + createDeferred( function( defer ) { + var checked = 0; + defer.progress(function( value ) { + strictEqual( value, checked, "Progress: right value (" + value + ") received" ); + }); + for( checked = 0; checked < 3 ; checked++ ) { + defer.notify( checked ); + } + defer[ change ](); + defer.notify(); + }); + }); }); } ); test( "jQuery.Deferred.pipe - filtering (done)", function() { - expect(3); + expect(4); var defer = jQuery.Deferred(), piped = defer.pipe(function( a, b ) { @@ -173,11 +81,15 @@ test( "jQuery.Deferred.pipe - filtering (done)", function() { jQuery.Deferred().reject().pipe(function() { ok( false, "pipe should not be called on reject" ); }); + + jQuery.Deferred().resolve().pipe( jQuery.noop ).done(function( value ) { + strictEqual( value, undefined, "pipe done callback can return undefined/null" ); + }); }); test( "jQuery.Deferred.pipe - filtering (fail)", function() { - expect(3); + expect(4); var defer = jQuery.Deferred(), piped = defer.pipe( null, function( a, b ) { @@ -205,6 +117,38 @@ test( "jQuery.Deferred.pipe - filtering (fail)", function() { jQuery.Deferred().resolve().pipe( null, function() { ok( false, "pipe should not be called on resolve" ); } ); + + jQuery.Deferred().reject().pipe( null, jQuery.noop ).fail(function( value ) { + strictEqual( value, undefined, "pipe fail callback can return undefined/null" ); + }); +}); + +test( "jQuery.Deferred.pipe - filtering (progress)", function() { + + expect(3); + + var defer = jQuery.Deferred(), + piped = defer.pipe( null, null, function( a, b ) { + return a * b; + } ), + value1, + value2, + value3; + + piped.progress(function( result ) { + value3 = result; + }); + + defer.progress(function( a, b ) { + value1 = a; + value2 = b; + }); + + defer.notify( 2, 3 ); + + strictEqual( value1, 2, "first progress value ok" ); + strictEqual( value2, 3, "second progress value ok" ); + strictEqual( value3, 6, "result of filter ok" ); }); test( "jQuery.Deferred.pipe - deferred (done)", function() { @@ -267,6 +211,62 @@ test( "jQuery.Deferred.pipe - deferred (fail)", function() { strictEqual( value3, 6, "result of filter ok" ); }); +test( "jQuery.Deferred.pipe - deferred (progress)", function() { + + expect(3); + + var defer = jQuery.Deferred(), + piped = defer.pipe( null, null, function( a, b ) { + return jQuery.Deferred(function( defer ) { + defer.resolve( a * b ); + }); + } ), + value1, + value2, + value3; + + piped.done(function( result ) { + value3 = result; + }); + + defer.progress(function( a, b ) { + value1 = a; + value2 = b; + }); + + defer.notify( 2, 3 ); + + strictEqual( value1, 2, "first progress value ok" ); + strictEqual( value2, 3, "second progress value ok" ); + strictEqual( value3, 6, "result of filter ok" ); +}); + +test( "jQuery.Deferred.pipe - context", function() { + + expect(4); + + var context = {}; + + jQuery.Deferred().resolveWith( context, [ 2 ] ).pipe(function( value ) { + return value * 3; + }).done(function( value ) { + strictEqual( this, context, "custom context correctly propagated" ); + strictEqual( value, 6, "proper value received" ); + }); + + var defer = jQuery.Deferred(), + piped = defer.pipe(function( value ) { + return value * 3; + }); + + defer.resolve( 2 ); + + piped.done(function( value ) { + strictEqual( this.promise(), piped, "default context gets updated to latest defer in the chain" ); + strictEqual( value, 6, "proper value received" ); + }); +}); + test( "jQuery.when" , function() { expect( 23 ); @@ -310,36 +310,54 @@ test( "jQuery.when" , function() { test("jQuery.when - joined", function() { - expect(25); + expect(53); var deferreds = { value: 1, success: jQuery.Deferred().resolve( 1 ), error: jQuery.Deferred().reject( 0 ), - futureSuccess: jQuery.Deferred(), - futureError: jQuery.Deferred() + futureSuccess: jQuery.Deferred().notify( true ), + futureError: jQuery.Deferred().notify( true ), + notify: jQuery.Deferred().notify( true ) }, willSucceed = { value: true, success: true, - error: false, + futureSuccess: true + }, + willError = { + error: true, + futureError: true + }, + willNotify = { futureSuccess: true, - futureError: false + futureError: true, + notify: true }; jQuery.each( deferreds, function( id1, defer1 ) { jQuery.each( deferreds, function( id2, defer2 ) { var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ], + shouldError = willError[ id1 ] || willError[ id2 ], + shouldNotify = willNotify[ id1 ] || willNotify[ id2 ], expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ], - code = id1 + "/" + id2; - jQuery.when( defer1, defer2 ).done(function( a, b ) { + expectedNotify = shouldNotify && [ willNotify[ id1 ], willNotify[ id2 ] ], + code = id1 + "/" + id2; + + var promise = jQuery.when( defer1, defer2 ).done(function( a, b ) { if ( shouldResolve ) { same( [ a, b ], expected, code + " => resolve" ); + } else { + ok( false , code + " => resolve" ); } }).fail(function( a, b ) { - if ( !shouldResolve ) { - same( [ a, b ], expected, code + " => resolve" ); + if ( shouldError ) { + same( [ a, b ], expected, code + " => reject" ); + } else { + ok( false , code + " => reject" ); } + }).progress(function progress( a, b ) { + same( [ a, b ], expectedNotify, code + " => progress" ); }); } ); } ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 641165f4f..57229199a 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -107,7 +107,13 @@ test("height() with function args", function() { }); test("innerWidth()", function() { - expect(4); + expect(8); + + equals(jQuery(window).innerWidth(), null, "Test on window without margin option"); + equals(jQuery(window).innerWidth(true), null, "Test on window with margin option"); + + equals(jQuery(document).innerWidth(), null, "Test on document without margin option"); + equals(jQuery(document).innerWidth(true), null, "Test on document with margin option"); var $div = jQuery("#nothiddendiv"); // set styles @@ -136,7 +142,13 @@ test("innerWidth()", function() { }); test("innerHeight()", function() { - expect(4); + expect(8); + + equals(jQuery(window).innerHeight(), null, "Test on window without margin option"); + equals(jQuery(window).innerHeight(true), null, "Test on window with margin option"); + + equals(jQuery(document).innerHeight(), null, "Test on document without margin option"); + equals(jQuery(document).innerHeight(true), null, "Test on document with margin option"); var $div = jQuery("#nothiddendiv"); // set styles @@ -165,7 +177,12 @@ test("innerHeight()", function() { }); test("outerWidth()", function() { - expect(7); + expect(11); + + equal( jQuery( window ).outerWidth(), null, "Test on window without margin option" ); + equal( jQuery( window ).outerWidth( true ), null, "Test on window with margin option" ); + equal( jQuery( document ).outerWidth(), null, "Test on document without margin option" ); + equal( jQuery( document ).outerWidth( true ), null, "Test on document with margin option" ); var $div = jQuery("#nothiddendiv"); $div.css("width", 30); @@ -194,8 +211,38 @@ test("outerWidth()", function() { jQuery.removeData($div[0], "olddisplay", true); }); +test("child of a hidden elem has accurate inner/outer/Width()/Height() see #9441 #9300", function() { + expect(8); + + // setup html + var $divNormal = jQuery("<div>").css({ width: "100px", height: "100px", border: "10px solid white", padding: "2px", margin: "3px" }), + $divChild = $divNormal.clone(), + $divHiddenParent = jQuery("<div>").css( "display", "none" ).append( $divChild ).appendTo("body"); + $divNormal.appendTo("body"); + + // tests that child div of a hidden div works the same as a normal div + equals( $divChild.width(), $divNormal.width(), "child of a hidden element width() is wrong see #9441" ); + equals( $divChild.innerWidth(), $divNormal.innerWidth(), "child of a hidden element innerWidth() is wrong see #9441" ); + equals( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #9441" ); + equals( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #9300" ); + + equals( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #9441" ); + equals( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #9441" ); + equals( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" ); + equals( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); + + // teardown html + $divHiddenParent.remove(); + $divNormal.remove(); +}); + test("outerHeight()", function() { - expect(7); + expect(11); + + equal( jQuery( window ).outerHeight(), null, "Test on window without margin option" ); + equal( jQuery( window ).outerHeight( true ), null, "Test on window with margin option" ); + equal( jQuery( document ).outerHeight(), null, "Test on document without margin option" ); + equal( jQuery( document ).outerHeight( true ), null, "Test on document with margin option" ); var $div = jQuery("#nothiddendiv"); $div.css("height", 30); diff --git a/test/unit/effects.js b/test/unit/effects.js index 8b7cf4679..d13bd587c 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -2,7 +2,7 @@ module("effects", { teardown: moduleTeardown }); test("sanity check", function() { expect(1); - ok( jQuery("#dl:visible, #main:visible, #foo:visible").length === 3, "QUnit state is correct for testing effects" ); + ok( jQuery("#dl:visible, #qunit-fixture:visible, #foo:visible").length === 3, "QUnit state is correct for testing effects" ); }); test("show()", function() { @@ -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("#main").show(); + var div = jQuery("<div>").hide().appendTo("#qunit-fixture").show(); equal( div.css("display"), "block", "Make sure pre-hidden divs show" ); @@ -32,7 +32,8 @@ test("show()", function() { hiddendiv.css("display",""); - var pass = true, div = jQuery("#main div"); + var pass = true; + div = jQuery("#qunit-fixture div"); div.show().each(function(){ if ( this.style.display == "none" ) pass = false; }); @@ -62,7 +63,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>"); + jQuery("#qunit-fixture").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(); @@ -88,6 +89,10 @@ test("show()", function() { var elem = jQuery(selector, "#show-tests").show(); equals( elem.css("display"), expected, "Show using correct display type for " + selector ); }); + + // Make sure that showing or hiding a text node doesn't cause an error + jQuery("<div>test</div> text <span>test</span>").show().remove(); + jQuery("<div>test</div> text <span>test</span>").hide().remove(); }); test("show(Number) - other displays", function() { @@ -96,7 +101,7 @@ test("show(Number) - other displays", function() { stop(); // #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>"); + jQuery("#qunit-fixture").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", num = 0; @@ -138,7 +143,7 @@ test("Persist correct display value", function() { stop(); // #show-tests * is set display: none in CSS - jQuery("#main").append("<div id='show-tests'><span style='position:absolute;'>foo</span></div>"); + jQuery("#qunit-fixture").append("<div id='show-tests'><span style='position:absolute;'>foo</span></div>"); var $span = jQuery("#show-tests span"), displayNone = $span.css("display"), @@ -164,7 +169,7 @@ test("Persist correct display value", function() { test("show() resolves correct default display #8099", function() { expect(7); - var tt8099 = jQuery("<tt/>").appendTo("body"), + var tt8099 = jQuery("<tt/>").appendTo("body"), dfn8099 = jQuery("<dfn/>", { html: "foo"}).appendTo("body"); equals( tt8099.css("display"), "none", "default display override for all tt" ); @@ -352,6 +357,41 @@ test("animate option (queue === false)", function () { }); */ +asyncTest( "animate option { queue: 'name' }", function() { + expect( 5 ); + + var foo = jQuery( "#foo" ), + origWidth = foo.width(), + order = []; + + foo.animate( { width: origWidth + 100 }, { + queue: 'name', + duration: 1, + complete: function() { + + // second callback function + order.push( 2 ); + equals( foo.width(), origWidth + 100, "Animation ended" ); + equals( foo.queue("name").length, 1, "Queue length of 'name' queue" ); + } + }).queue( "name", function( next ) { + + // last callback function + deepEqual( order, [ 1, 2 ], "Callbacks in expected order" ); + start(); + }); + + setTimeout( function() { + + // this is the first callback function that should be called + order.push( 1 ); + equals( foo.width(), origWidth, "Animation does not start on its own." ); + equals( foo.queue("name").length, 2, "Queue length of 'name' queue" ); + foo.dequeue( "name" ); + }, 100 ); + +}); + test("animate with no properties", function() { expect(2); @@ -423,19 +463,19 @@ test("animate duration 0", function() { $elem.remove(); }); -test("animate hyphenated properties", function(){ +test("animate hyphenated properties", function() { expect(1); stop(); jQuery("#foo") .css("font-size", 10) - .animate({"font-size": 20}, 200, function(){ + .animate({"font-size": 20}, 200, function() { equals( this.style.fontSize, "20px", "The font-size property was animated." ); start(); }); }); -test("animate non-element", function(){ +test("animate non-element", function() { expect(1); stop(); @@ -448,28 +488,42 @@ test("animate non-element", function(){ }); test("stop()", function() { - expect(3); + expect(4); stop(); var $foo = jQuery("#foo"); var w = 0; - $foo.hide().width(200).width(); - $foo.animate({ width: "show" }, 1000); - setTimeout(function(){ + $foo.hide().width(200) + .animate({ width: "show" }, 1000); + + setTimeout(function() { var nw = $foo.width(); notEqual( nw, w, "An animation occurred " + nw + "px " + w + "px"); $foo.stop(); nw = $foo.width(); notEqual( nw, w, "Stop didn't reset the animation " + nw + "px " + w + "px"); - setTimeout(function(){ + setTimeout(function() { $foo.removeData(); $foo.removeData(undefined, true); equals( nw, $foo.width(), "The animation didn't continue" ); start(); }, 100); }, 100); + + var $one = jQuery("#fadein"); + var $two = jQuery("#show"); + $one.fadeTo(100, 0, function() { + $one.stop(); + }); + setTimeout(function() { + $two.fadeTo(100, 0, function() { + equal( $two.css("opacity"), "0", "Stop does not interfere with animations on other elements (#6641)" ); + // Reset styles + $one.add( $two ).css("opacity", ""); + }); + }, 50); }); test("stop() - several in queue", function() { @@ -578,10 +632,10 @@ jQuery.checkOverflowDisplay = function(){ equals(jQuery.css( this, "display" ), "inline", "Display shouldn't be tampered with."); start(); -} +}; test( "jQuery.fx.prototype.cur()", 6, function() { - var div = jQuery( "<div></div>" ).appendTo( "#main" ).css({ + var div = jQuery( "<div></div>" ).appendTo( "#qunit-fixture" ).css({ color: "#ABC", border: "5px solid black", left: "auto", @@ -655,63 +709,63 @@ test("CSS Overflow and Display", function() { .animate({ opacity: 0.5 }, "slow", jQuery.checkOverflowDisplay); }); -jQuery.each( { - "CSS Auto": function(elem,prop){ - jQuery(elem).addClass("auto" + prop) - .text("This is a long string of text."); +jQuery.each({ + "CSS Auto": function( elem, prop ) { + jQuery( elem ).addClass( "auto" + prop ) + .text( "This is a long string of text." ); return ""; }, - "JS Auto": function(elem,prop){ - jQuery(elem).css(prop,"") - .text("This is a long string of text."); + "JS Auto": function( elem, prop ) { + jQuery( elem ).css( prop, "" ) + .text( "This is a long string of text." ); return ""; }, - "CSS 100": function(elem,prop){ - jQuery(elem).addClass("large" + prop); + "CSS 100": function( elem, prop ) { + jQuery( elem ).addClass( "large" + prop ); return ""; }, - "JS 100": function(elem,prop){ - jQuery(elem).css(prop,prop == "opacity" ? 1 : "100px"); - return prop == "opacity" ? 1 : 100; + "JS 100": function( elem, prop ) { + jQuery( elem ).css( prop, prop === "opacity" ? 1 : "100px" ); + return prop === "opacity" ? 1 : 100; }, - "CSS 50": function(elem,prop){ - jQuery(elem).addClass("med" + prop); + "CSS 50": function( elem, prop ) { + jQuery( elem ).addClass( "med" + prop ); return ""; }, - "JS 50": function(elem,prop){ - jQuery(elem).css(prop,prop == "opacity" ? 0.50 : "50px"); - return prop == "opacity" ? 0.5 : 50; + "JS 50": function( elem, prop ) { + jQuery( elem ).css( prop, prop === "opacity" ? 0.50 : "50px" ); + return prop === "opacity" ? 0.5 : 50; }, - "CSS 0": function(elem,prop){ - jQuery(elem).addClass("no" + prop); + "CSS 0": function( elem, prop ) { + jQuery( elem ).addClass( "no" + prop ); return ""; }, - "JS 0": function(elem,prop){ - jQuery(elem).css(prop,prop == "opacity" ? 0 : "0px"); + "JS 0": function( elem, prop ) { + jQuery( elem ).css( prop, prop === "opacity" ? 0 : "0px" ); return 0; } -}, function(fn, f){ - jQuery.each( { - "show": function(elem,prop){ - jQuery(elem).hide().addClass("wide"+prop); +}, function( fn, f ) { + jQuery.each({ + "show": function( elem, prop ) { + jQuery( elem ).hide( ).addClass( "wide" + prop ); return "show"; }, - "hide": function(elem,prop){ - jQuery(elem).addClass("wide"+prop); + "hide": function( elem, prop ) { + jQuery( elem ).addClass( "wide" + prop ); return "hide"; }, - "100": function(elem,prop){ - jQuery(elem).addClass("wide"+prop); + "100": function( elem, prop ) { + jQuery( elem ).addClass( "wide" + prop ); return prop == "opacity" ? 1 : 100; }, - "50": function(elem,prop){ + "50": function( elem, prop ) { return prop == "opacity" ? 0.50 : 50; }, - "0": function(elem,prop){ - jQuery(elem).addClass("noback"); + "0": function( elem, prop ) { + jQuery( elem ).addClass( "noback" ); return 0; } - }, function(tn, t){ + }, function( tn, t ) { test(fn + " to " + tn, function() { var elem = jQuery.makeTest( fn + " to " + tn ); @@ -722,81 +776,104 @@ jQuery.each( { var t_o = t( elem, "opacity" ); var f_o = f( elem, "opacity" ); + if ( f_o === "" ) { + f_o = 1; + } + var num = 0; if ( t_h == "show" ) num++; if ( t_w == "show" ) num++; - if ( t_w == "hide"||t_w == "show" ) num++; - if ( t_h == "hide"||t_h == "show" ) num++; - if ( t_o == "hide"||t_o == "show" ) num++; + if ( t_w == "hide" || t_w == "show" ) num++; + if ( t_h == "hide" || t_h == "show" ) num++; + if ( t_o == "hide" || t_o == "show" ) num++; if ( t_w == "hide" ) num++; if ( t_o.constructor == Number ) num += 2; if ( t_w.constructor == Number ) num += 2; if ( t_h.constructor == Number ) num +=2; - expect(num); + expect( num ); stop(); var anim = { width: t_w, height: t_h, opacity: t_o }; elem.animate(anim, 50); - jQuery.when( elem ).done(function( elem ){ + jQuery.when( elem ).done(function( elem ) { elem = elem[ 0 ]; - if ( t_w == "show" ) - equals( elem.style.display, "block", "Showing, display should block: " + elem.style.display); + if ( t_w == "show" ) { + equals( elem.style.display, "block", "Showing, display should block: " + elem.style.display ); + } - if ( t_w == "hide"||t_w == "show" ) - ok(f_w === "" ? elem.style.width === f_w : elem.style.width.indexOf(f_w) === 0, "Width must be reset to " + f_w + ": " + elem.style.width); + if ( t_w == "hide" || t_w == "show" ) { + ok( f_w === "" ? elem.style.width === f_w : elem.style.width.indexOf( f_w ) === 0, "Width must be reset to " + f_w + ": " + elem.style.width ); + } - if ( t_h == "hide"||t_h == "show" ) - ok(f_h === "" ? elem.style.height === f_h : elem.style.height.indexOf(f_h) === 0, "Height must be reset to " + f_h + ": " + elem.style.height); + if ( t_h == "hide" || t_h == "show" ) { + ok( f_h === "" ? elem.style.height === f_h : elem.style.height.indexOf( f_h ) === 0, "Height must be reset to " + f_h + ": " + elem.style.height ); + } var cur_o = jQuery.style(elem, "opacity"); - if ( t_o == "hide" || t_o == "show" ) - equals(cur_o, f_o, "Opacity must be reset to " + f_o + ": " + cur_o); + if ( f_o !== jQuery.css(elem, "opacity") ) { + f_o = f( elem, "opacity" ); + } + + // The only time an _empty_string_ will be matched is in IE + // otherwise, the correct values will be tested as usual + if ( f_o === "" ) { + f_o = 1; + } + // See above + if ( cur_o === "" ) { + cur_o = 1; + } - if ( t_w == "hide" ) - equals(elem.style.display, "none", "Hiding, display should be none: " + elem.style.display); + if ( t_o == "hide" || t_o == "show" ) { + equals( cur_o, f_o, "Opacity must be reset to " + f_o + ": " + cur_o ); + } + + if ( t_w == "hide" ) { + equals( elem.style.display, "none", "Hiding, display should be none: " + elem.style.display ); + } if ( t_o.constructor == Number ) { - equals(cur_o, t_o, "Final opacity should be " + t_o + ": " + cur_o); + equals( cur_o, t_o, "Final opacity should be " + t_o + ": " + cur_o ); - ok(jQuery.css(elem, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o); + ok( jQuery.css(elem, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o ); } if ( t_w.constructor == Number ) { - equals(elem.style.width, t_w + "px", "Final width should be " + t_w + ": " + elem.style.width); + equals( elem.style.width, t_w + "px", "Final width should be " + t_w + ": " + elem.style.width ); - var cur_w = jQuery.css(elem,"width"); + var cur_w = jQuery.css( elem,"width" ); - ok(elem.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w); + ok( elem.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w ); } if ( t_h.constructor == Number ) { - equals(elem.style.height, t_h + "px", "Final height should be " + t_h + ": " + elem.style.height); + equals( elem.style.height, t_h + "px", "Final height should be " + t_h + ": " + elem.style.height ); - var cur_h = jQuery.css(elem,"height"); + var cur_h = jQuery.css( elem,"height" ); - ok(elem.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w); + ok( elem.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w ); } if ( t_h == "show" ) { - var old_h = jQuery.css(elem, "height"); - jQuery(elem).append("<br/>Some more text<br/>and some more..."); + var old_h = jQuery.css( elem, "height" ); + jQuery( elem ).append("<br/>Some more text<br/>and some more..."); if ( /Auto/.test( fn ) ) { - notEqual(jQuery.css(elem, "height"), old_h, "Make sure height is auto."); + notEqual( jQuery.css( elem, "height" ), old_h, "Make sure height is auto." ); } else { - equals(jQuery.css(elem, "height"), old_h, "Make sure height is not auto."); + equals( jQuery.css( elem, "height" ), old_h, "Make sure height is not auto." ); } } // manually remove generated element - jQuery(elem).remove(); + jQuery( elem ).remove(); start(); }); @@ -804,7 +881,7 @@ jQuery.each( { }); }); -jQuery.fn.saveState = function(hiddenOverflow){ +jQuery.fn.saveState = function( hiddenOverflow ) { var check = ["opacity", "height", "width", "display", "overflow"]; expect(check.length); @@ -812,83 +889,83 @@ jQuery.fn.saveState = function(hiddenOverflow){ return this.each(function(){ var self = this; self.save = {}; - jQuery.each(check, function(i,c){ - self.save[c] = c === "overflow" && hiddenOverflow ? "hidden" : self.style[ c ] || jQuery.css(self,c); + jQuery.each(check, function( i, c ) { + self.save[ c ] = c === "overflow" && hiddenOverflow ? "hidden" : self.style[ c ] || jQuery.css( self, c ); }); }); }; -jQuery.checkState = function(){ +jQuery.checkState = function() { var self = this; - jQuery.each(this.save, function(c,v){ - var cur = self.style[ c ] || jQuery.css(self, c); + jQuery.each(this.save, function( c, v ) { + 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); + jQuery.removeData( this, "olddisplay", true ); start(); }; // Chaining Tests test("Chain fadeOut fadeIn", function() { - jQuery("#fadein div").saveState().fadeOut("fast").fadeIn("fast",jQuery.checkState); + jQuery("#fadein div").saveState().fadeOut("fast").fadeIn("fast", jQuery.checkState ); }); test("Chain fadeIn fadeOut", function() { - jQuery("#fadeout div").saveState().fadeIn("fast").fadeOut("fast",jQuery.checkState); + jQuery("#fadeout div").saveState().fadeIn("fast").fadeOut("fast", jQuery.checkState ); }); test("Chain hide show", function() { - jQuery("#show div").saveState(jQuery.support.shrinkWrapBlocks).hide("fast").show("fast",jQuery.checkState); + jQuery("#show div").saveState( jQuery.support.shrinkWrapBlocks ).hide("fast").show("fast", jQuery.checkState ); }); test("Chain show hide", function() { - jQuery("#hide div").saveState(jQuery.support.shrinkWrapBlocks).show("fast").hide("fast",jQuery.checkState); + jQuery("#hide div").saveState( jQuery.support.shrinkWrapBlocks ).show("fast").hide("fast", jQuery.checkState ); }); test("Chain show hide with easing and callback", function() { - jQuery("#hide div").saveState().show("fast").hide("fast","linear",jQuery.checkState); + jQuery("#hide div").saveState().show("fast").hide("fast","linear", jQuery.checkState ); }); test("Chain toggle in", function() { - jQuery("#togglein div").saveState(jQuery.support.shrinkWrapBlocks).toggle("fast").toggle("fast",jQuery.checkState); + jQuery("#togglein div").saveState( jQuery.support.shrinkWrapBlocks ).toggle("fast").toggle("fast", jQuery.checkState ); }); test("Chain toggle out", function() { - jQuery("#toggleout div").saveState(jQuery.support.shrinkWrapBlocks).toggle("fast").toggle("fast",jQuery.checkState); + jQuery("#toggleout div").saveState( jQuery.support.shrinkWrapBlocks ).toggle("fast").toggle("fast", jQuery.checkState ); }); test("Chain toggle out with easing and callback", function() { - jQuery("#toggleout div").saveState(jQuery.support.shrinkWrapBlocks).toggle("fast").toggle("fast","linear",jQuery.checkState); + jQuery("#toggleout div").saveState( jQuery.support.shrinkWrapBlocks ).toggle("fast").toggle("fast","linear", jQuery.checkState ); }); test("Chain slideDown slideUp", function() { - jQuery("#slidedown div").saveState(jQuery.support.shrinkWrapBlocks).slideDown("fast").slideUp("fast",jQuery.checkState); + jQuery("#slidedown div").saveState( jQuery.support.shrinkWrapBlocks ).slideDown("fast").slideUp("fast", jQuery.checkState ); }); test("Chain slideUp slideDown", function() { - jQuery("#slideup div").saveState(jQuery.support.shrinkWrapBlocks).slideUp("fast").slideDown("fast",jQuery.checkState); + jQuery("#slideup div").saveState( jQuery.support.shrinkWrapBlocks ).slideUp("fast").slideDown("fast", jQuery.checkState ); }); test("Chain slideUp slideDown with easing and callback", function() { - jQuery("#slideup div").saveState(jQuery.support.shrinkWrapBlocks).slideUp("fast").slideDown("fast","linear",jQuery.checkState); + jQuery("#slideup div").saveState( jQuery.support.shrinkWrapBlocks ).slideUp("fast").slideDown("fast","linear", jQuery.checkState ); }); test("Chain slideToggle in", function() { - jQuery("#slidetogglein div").saveState(jQuery.support.shrinkWrapBlocks).slideToggle("fast").slideToggle("fast",jQuery.checkState); + jQuery("#slidetogglein div").saveState( jQuery.support.shrinkWrapBlocks ).slideToggle("fast").slideToggle("fast", jQuery.checkState ); }); test("Chain slideToggle out", function() { - jQuery("#slidetoggleout div").saveState(jQuery.support.shrinkWrapBlocks).slideToggle("fast").slideToggle("fast",jQuery.checkState); + jQuery("#slidetoggleout div").saveState( jQuery.support.shrinkWrapBlocks ).slideToggle("fast").slideToggle("fast", jQuery.checkState ); }); test("Chain fadeToggle in", function() { - jQuery("#fadetogglein div").saveState().fadeToggle("fast").fadeToggle("fast",jQuery.checkState); + jQuery("#fadetogglein div").saveState().fadeToggle("fast").fadeToggle("fast", jQuery.checkState ); }); test("Chain fadeToggle out", function() { - jQuery("#fadetoggleout div").saveState().fadeToggle("fast").fadeToggle("fast",jQuery.checkState); + jQuery("#fadetoggleout div").saveState().fadeToggle("fast").fadeToggle("fast", jQuery.checkState ); }); test("Chain fadeTo 0.5 1.0 with easing and callback)", function() { - jQuery("#fadeto div").saveState().fadeTo("fast",0.5).fadeTo("fast",1.0,"linear",jQuery.checkState); + jQuery("#fadeto div").saveState().fadeTo("fast",0.5).fadeTo("fast",1.0,"linear", jQuery.checkState ); }); jQuery.makeTest = function( text ){ var elem = jQuery("<div></div>") - .attr("id", "test" + jQuery.makeTest.id++) + .attr( "id", "test" + jQuery.makeTest.id++ ) .addClass("box"); jQuery("<h4></h4>") @@ -897,7 +974,7 @@ jQuery.makeTest = function( text ){ .after( elem ); return elem; -} +}; jQuery.makeTest.id = 1; @@ -916,36 +993,80 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function () }); }); +jQuery.each({ + "slideToggle": function( $elem ) { + return $elem.height(); + }, + "fadeToggle": function( $elem ) { + return $elem.css("opacity"); + }, + "toggle": function( $elem ) { + return $elem.width(); + } +}, +function( method, defProp ) { + test( method + "().stop()." + method + "()", function() { + expect( 4 ); + + jQuery.each([ "in", "out" ], function( i, type ) { + var $elem = jQuery( "#" + method.toLowerCase() + type ), + startVal = defProp( $elem ); + + $elem[ method ]("fast"); + stop(); + + setTimeout( function() { + $elem.stop(); + + notEqual( defProp( $elem ), startVal, ".stop() is called about halfway through animation." ); + + $elem[ method ]("fast", function() { + equal( defProp( jQuery(this) ), startVal, "After doing .stop() halfway, check that state has been saved for returning to original property value." ); + start(); + }); + }, 100); + }); + }); +}); + test("animate with per-property easing", function(){ - expect(3); + expect(5); stop(); - var _test1_called = false; - var _test2_called = false; - var _default_test_called = false; - - jQuery.easing["_test1"] = function() { + var data = { a:0, b:0, c:0 }, + _test1_called = false, + _test2_called = false, + _default_test_called = false, + props = { + a: [ 100, "_test1" ], + b: [ 100, "_test2" ], + c: 100 + }; + + jQuery.easing["_test1"] = function(p) { _test1_called = true; + return p; }; - jQuery.easing["_test2"] = function() { + jQuery.easing["_test2"] = function(p) { _test2_called = true; + return p; }; - jQuery.easing["_default_test"] = function() { + jQuery.easing["_default_test"] = function(p) { _default_test_called = true; + return p; }; - jQuery({a:0,b:0,c:0}).animate({ - a: [100, "_test1"], - b: [100, "_test2"], - c: 100 - }, 400, "_default_test", function(){ + jQuery(data).animate( props, 400, "_default_test", function(){ start(); - ok(_test1_called, "Easing function (1) called"); - ok(_test2_called, "Easing function (2) called"); - ok(_default_test_called, "Easing function (_default) called"); + + ok( _test1_called, "Easing function (_test1) called" ); + ok( _test2_called, "Easing function (_test2) called" ); + ok( _default_test_called, "Easing function (_default) called" ); + equal( props.a[ 1 ], "_test1", "animate does not change original props (per-property easing would be lost)"); + equal( props.b[ 1 ], "_test2", "animate does not change original props (per-property easing would be lost)"); }); }); @@ -954,7 +1075,7 @@ test("hide hidden elements (bug #7141)", function() { expect(3); QUnit.reset(); - var div = jQuery("<div style='display:none'></div>").appendTo("#main"); + var div = jQuery("<div style='display:none'></div>").appendTo("#qunit-fixture"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(); ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); @@ -969,7 +1090,7 @@ test("hide hidden elements, with animation (bug #7141)", function() { QUnit.reset(); stop(); - var div = jQuery("<div style='display:none'></div>").appendTo("#main"); + var div = jQuery("<div style='display:none'></div>").appendTo("#qunit-fixture"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(1, function () { ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); @@ -982,10 +1103,53 @@ test("hide hidden elements, with animation (bug #7141)", function() { test("animate unit-less properties (#4966)", 2, function() { stop(); - var div = jQuery( "<div style='z-index: 0; position: absolute;'></div>" ).appendTo( "#main" ); + var div = jQuery( "<div style='z-index: 0; position: absolute;'></div>" ).appendTo( "#qunit-fixture" ); equal( div.css( "z-index" ), "0", "z-index is 0" ); div.animate({ zIndex: 2 }, function() { equal( div.css( "z-index" ), "2", "z-index is 2" ); start(); }); }); + +test( "animate properties missing px w/ opacity as last (#9074)", 2, function() { + expect( 6 ); + stop(); + var div = jQuery( "<div style='position: absolute; margin-left: 0; left: 0px;'></div>" ) + .appendTo( "#qunit-fixture" ); + function cssInt( prop ) { + return parseInt( div.css( prop ), 10 ); + } + equal( cssInt( "marginLeft" ), 0, "Margin left is 0" ); + equal( cssInt( "left" ), 0, "Left is 0" ); + div.animate({ + left: 200, + marginLeft: 200, + opacity: 0 + }, 1000); + setTimeout(function() { + var ml = cssInt( "marginLeft" ), + l = cssInt( "left" ); + notEqual( ml, 0, "Margin left is not 0 after partial animate" ); + notEqual( ml, 200, "Margin left is not 200 after partial animate" ); + notEqual( l, 0, "Left is not 0 after partial animate" ); + notEqual( l, 200, "Left is not 200 after partial animate" ); + div.stop().remove(); + start(); + }, 100); +}); + +test("callbacks should fire in correct order (#9100)", function() { + stop(); + var a = 1, + cb = 0, + $lis = jQuery("<p data-operation='*2'></p><p data-operation='^2'></p>").appendTo("#qunit-fixture") + // The test will always pass if no properties are animated or if the duration is 0 + .animate({fontSize: 12}, 13, function() { + a *= jQuery(this).data("operation") === "*2" ? 2 : a; + cb++; + if ( cb === 2 ) { + equal( a, 4, "test value has been *2 and _then_ ^2"); + start(); + } + }); +}); diff --git a/test/unit/event.js b/test/unit/event.js index a1aee191f..c00eb202c 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -14,6 +14,51 @@ test("null or undefined handler", function() { } catch (e) {} }); +test("bind(),live(),delegate() with non-null,defined data", function() { + + expect(3); + + var handler = function( event, data ) { + equal( data, 0, "non-null, defined data (zero) is correctly passed" ); + }; + + jQuery("#foo").bind("foo", handler); + jQuery("#foo").live("foo", handler); + jQuery("div").delegate("#foo", "foo", handler); + + jQuery("#foo").trigger("foo", 0); + + jQuery("#foo").unbind("foo", handler); + jQuery("#foo").die("foo", handler); + jQuery("div").undelegate("#foo", "foo"); + +}); + +/* +Removed because Chrome 13 snaps/crashes on this 2011-09-07 + +test("Handler changes and .trigger() order", function() { + expect(1); + + var markup = jQuery( + '<div><p><b class="a">b</b></p></div>' + ).appendTo( "body" ); + + var path = ""; + jQuery( "b" ).parents().bind( "click", function(e){ + path += this.nodeName.toLowerCase() + " "; + // Should not change the event triggering order + $(this).parent().remove(); + }); + + markup.find( "b" ).trigger( "click" ); + + equals( path, "p div body html ", "Delivered all events" ) + + markup.remove(); +}); +*/ + test("bind(), with data", function() { expect(4); var handler = function(event) { @@ -68,6 +113,22 @@ test("bind(), multiple events at once", function() { equals( mouseoverCounter, 1, "bind() with multiple events at once" ); }); +test("bind(), five events at once", function() { + expect(1); + + var count = 0, + handler = function(event) { + count++; + }; + + jQuery("#firstp").bind("click mouseover foo bar baz", handler) + .trigger("click").trigger("mouseover") + .trigger("foo").trigger("bar") + .trigger("baz"); + + equals( count, 5, "bind() five events at once" ); +}); + test("bind(), multiple events at once and namespaces", function() { expect(7); @@ -112,7 +173,7 @@ test("bind(), multiple events at once and namespaces", function() { }); test("bind(), namespace with special add", function() { - expect(24); + expect(27); var div = jQuery("<div/>").bind("test", function(e) { ok( true, "Test event fired." ); @@ -121,10 +182,11 @@ test("bind(), namespace with special add", function() { var i = 0; jQuery.event.special.test = { - _default: function(e) { + _default: function(e, data) { equals( this, document, "Make sure we're at the top of the chain." ); equals( e.type, "test", "And that we're still dealing with a test event." ); equals( e.target, div[0], "And that the target is correct." ); + ok( data !== undefined , "And that trigger data was passed." ); }, setup: function(){}, teardown: function(){ @@ -153,13 +215,13 @@ test("bind(), namespace with special add", function() { }); // Should trigger 5 - div.trigger("test"); + div.trigger("test", 33.33); // Should trigger 2 - div.trigger("test.a"); + div.trigger("test.a", "George Harrison"); // Should trigger 2 - div.trigger("test.b"); + div.trigger("test.b", { year: 1982 }); // Should trigger 4 div.unbind("test"); @@ -169,7 +231,7 @@ test("bind(), namespace with special add", function() { }); // Should trigger 2 - div.appendTo("#main").remove(); + div.appendTo("#qunit-fixture").remove(); delete jQuery.event.special.test; }); @@ -307,7 +369,7 @@ test("live/delegate immediate propagation", function() { test("bind/delegate bubbling, isDefaultPrevented", function() { expect(2); var $anchor2 = jQuery( "#anchor2" ), - $main = jQuery( "#main" ), + $main = jQuery( "#qunit-fixture" ), fakeClick = function($jq) { // Use a native click so we don't get jQuery simulated bubbling if ( document.createEvent ) { @@ -415,7 +477,7 @@ test("bind(), namespaced events, cloned events", 18, function() { }).trigger("tester"); // Make sure events stick with appendTo'd elements (which are cloned) #2027 - jQuery("<a href='#fail' class='test'>test</a>").click(function(){ return false; }).appendTo("#main"); + jQuery("<a href='#fail' class='test'>test</a>").click(function(){ return false; }).appendTo("#qunit-fixture"); ok( jQuery("a.test:first").triggerHandler("click") === false, "Handler is bound to appendTo'd elements" ); }); @@ -538,7 +600,7 @@ test("bind(name, false), unbind(name, false)", function() { expect(3); var main = 0; - jQuery("#main").bind("click", function(e){ main++; }); + jQuery("#qunit-fixture").bind("click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -553,14 +615,14 @@ test("bind(name, false), unbind(name, false)", function() { equals( main, 1, "Verify that the trigger happened correctly." ); // manually clean up events from elements outside the fixture - jQuery("#main").unbind("click"); + jQuery("#qunit-fixture").unbind("click"); }); test("live(name, false), die(name, false)", function() { expect(3); var main = 0; - jQuery("#main").live("click", function(e){ main++; }); + jQuery("#qunit-fixture").live("click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -573,7 +635,7 @@ test("live(name, false), die(name, false)", function() { jQuery("#ap").die("click", false); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); - jQuery("#main").die("click"); + jQuery("#qunit-fixture").die("click"); }); test("delegate(selector, name, false), undelegate(selector, name, false)", function() { @@ -581,7 +643,7 @@ test("delegate(selector, name, false), undelegate(selector, name, false)", funct var main = 0; - jQuery("#main").delegate("#ap", "click", function(e){ main++; }); + jQuery("#qunit-fixture").delegate("#ap", "click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -594,7 +656,7 @@ test("delegate(selector, name, false), undelegate(selector, name, false)", funct jQuery("#ap").undelegate("#groups", "click", false); jQuery("#groups").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); - jQuery("#main").undelegate("#ap", "click"); + jQuery("#qunit-fixture").undelegate("#ap", "click"); }); test("bind()/trigger()/unbind() on plain object", function() { @@ -744,6 +806,43 @@ test("mouseover triggers mouseenter", function() { elem.remove(); }); +test("withinElement implemented with jQuery.contains()", function() { + + expect(1); + + jQuery("#qunit-fixture").append('<div id="jc-outer"><div id="jc-inner"></div></div>'); + + jQuery("#jc-outer").bind("mouseenter mouseleave", function( event ) { + + equal( this.id, "jc-outer", this.id + " " + event.type ); + + }).trigger("mouseenter"); + + jQuery("#jc-inner").trigger("mousenter"); + + jQuery("#jc-outer").unbind("mouseenter mouseleave").remove(); + jQuery("#jc-inner").remove(); + +}); + +test("mouseenter, mouseleave don't catch exceptions", function() { + expect(2); + + var elem = jQuery("#firstp").hover(function() { throw "an Exception"; }); + + try { + elem.mouseenter(); + } catch (e) { + equals( e, "an Exception", "mouseenter doesn't catch exceptions" ); + } + + try { + elem.mouseleave(); + } catch (e) { + equals( e, "an Exception", "mouseleave doesn't catch exceptions" ); + } +}); + test("trigger() shortcuts", function() { expect(6); @@ -798,7 +897,7 @@ test("trigger() bubbling", function() { jQuery(document).bind("click", function(e){ if ( e.target !== document) { doc++; } }); jQuery("html").bind("click", function(e){ html++; }); jQuery("body").bind("click", function(e){ body++; }); - jQuery("#main").bind("click", function(e){ main++; }); + jQuery("#qunit-fixture").bind("click", function(e){ main++; }); jQuery("#ap").bind("click", function(){ ap++; return false; }); jQuery("html").trigger("click"); @@ -812,7 +911,7 @@ test("trigger() bubbling", function() { equals( html, 2, "Body bubble" ); equals( body, 1, "Body bubble" ); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); equals( win, 3, "Main bubble" ); equals( doc, 3, "Main bubble" ); equals( html, 3, "Main bubble" ); @@ -828,11 +927,11 @@ test("trigger() bubbling", function() { // manually clean up events from elements outside the fixture jQuery(document).unbind("click"); - jQuery("html, body, #main").unbind("click"); + jQuery("html, body, #qunit-fixture").unbind("click"); }); test("trigger(type, [data], [fn])", function() { - expect(14); + expect(16); var handler = function(event, a, b, c) { equals( event.type, "click", "check passed data" ); @@ -849,7 +948,24 @@ test("trigger(type, [data], [fn])", function() { ok( true, "Native call was triggered" ); }; - // Triggers handlrs and native + + $elem.live('mouseenter', function(){ + ok( true, 'Trigger mouseenter bound by live' ); + }); + + $elem.live('mouseleave', function(){ + ok( true, 'Trigger mouseleave bound by live' ); + }); + + $elem.trigger('mouseenter'); + + $elem.trigger('mouseleave'); + + $elem.die('mouseenter'); + + $elem.die('mouseleave'); + + // Triggers handlrs and native // Trigger 5 $elem.bind("click", handler).trigger("click", [1, "2", "abc"]); @@ -872,7 +988,7 @@ test("trigger(type, [data], [fn])", function() { pass = true; try { - jQuery("#main table:first").bind("test:test", function(){}).trigger("test:test"); + jQuery("#qunit-fixture table:first").bind("test:test", function(){}).trigger("test:test"); } catch (e) { pass = false; } @@ -904,9 +1020,6 @@ test("trigger(type, [data], [fn])", function() { form.remove(); }); -test("jQuery.Event.currentTarget", function(){ -}); - test("trigger(eventObject, [data], [fn])", function() { expect(25); @@ -1101,7 +1214,7 @@ test("toggle(Function, Function, ...)", function() { }); test(".live()/.die()", function() { - expect(66); + expect(65); var submit = 0, div = 0, livea = 0, liveb = 0; @@ -1189,17 +1302,14 @@ test(".live()/.die()", function() { jQuery("div").die("submit"); // Test binding with a different context - var clicked = 0, container = jQuery("#main")[0]; + var clicked = 0, container = jQuery("#qunit-fixture")[0]; jQuery("#foo", container).live("click", function(e){ clicked++; }); jQuery("div").trigger("click"); jQuery("#foo").trigger("click"); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); jQuery("body").trigger("click"); 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" ); - // Test unbinding with a different context jQuery("#foo", container).die("click"); jQuery("#foo").trigger("click"); @@ -1372,6 +1482,9 @@ test(".live()/.die()", function() { jQuery("#nothiddendiv div").die("click"); + // div must have a tabindex to be focusable + jQuery("#nothiddendiv div").attr("tabindex", "0")[0].focus(); + jQuery("#nothiddendiv div").live("blur", function(){ ok( true, "Live div trigger blur." ); }); @@ -1546,7 +1659,7 @@ test("live with change", function(){ }); test("live with submit", function() { - expect(5); + expect(7); var count1 = 0, count2 = 0; @@ -1572,6 +1685,10 @@ test("live with submit", function() { equals( count1, 2, "Verify form submit." ); equals( count2, 2, "Verify body submit." ); + jQuery("#testForm button[name=sub4]")[0].click(); + equals( count1, 3, "Verify form submit." ); + equals( count2, 3, "Verify body submit." ); + jQuery("#testForm").die("submit"); jQuery("#testForm input[name=sub1]").die("click"); jQuery("body").die("submit"); @@ -1612,7 +1729,6 @@ test("live with special events", function() { jQuery("#liveSpan1").trigger("foo"); // Run: Handler 1, Default - // TODO: Namespace doesn't trigger default (?) jQuery("#liveSpan1").trigger("foo.a"); // Run: remove @@ -1628,7 +1744,7 @@ test("live with special events", function() { }); test(".delegate()/.undelegate()", function() { - expect(65); + expect(64); var submit = 0, div = 0, livea = 0, liveb = 0; @@ -1716,19 +1832,16 @@ test(".delegate()/.undelegate()", function() { jQuery("#body").undelegate("div", "submit"); // Test binding with a different context - var clicked = 0, container = jQuery("#main")[0]; - jQuery("#main").delegate("#foo", "click", function(e){ clicked++; }); + var clicked = 0, container = jQuery("#qunit-fixture")[0]; + jQuery("#qunit-fixture").delegate("#foo", "click", function(e){ clicked++; }); jQuery("div").trigger("click"); jQuery("#foo").trigger("click"); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); jQuery("body").trigger("click"); 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" ); - // Test unbinding with a different context - jQuery("#main").undelegate("#foo", "click"); + jQuery("#qunit-fixture").undelegate("#foo", "click"); jQuery("#foo").trigger("click"); equals( clicked, 2, "undelegate with a context"); @@ -2122,6 +2235,156 @@ test("custom events with colons (#3533, #8272)", function() { }); +test(".on and .off", function() { + expect(9); + var counter, mixfn; + + jQuery( '<div id="onandoff"><p>on<b>and</b>off</p><div>worked<em>or</em>borked?</div></div>' ).appendTo( 'body' ); + + // Simple case + jQuery( "#onandoff" ) + .on( "whip", function() { + ok( true, "whipped it good" ); + }) + .trigger( "whip" ) + .off(); + + // Direct events only + counter = 0; + jQuery( "#onandoff b" ) + .on( "click", 5, function( e, trig ) { + counter += e.data + (trig || 9); // twice, 5+9+5+17=36 + }) + .one( "click", 7, function( e, trig ) { + counter += e.data + (trig || 11); // once, 7+11=18 + }) + .click() + .trigger( "click", 17 ) + .off( "click" ); + equals( counter, 54, "direct event bindings with data" ); + + // Delegated events only + counter = 0; + jQuery( "#onandoff" ) + .on( "click", "em", 5, function( e, trig ) { + counter += e.data + (trig || 9); // twice, 5+9+5+17=36 + }) + .one( "click", "em", 7, function( e, trig ) { + counter += e.data + (trig || 11); // once, 7+11=18 + }) + .find("em") + .click() + .trigger( "click", 17 ) + .end() + .off( "click", "em" ); + equals( counter, 54, "delegated event bindings with data" ); + + + // Mixed event bindings and types + counter = 0; + mixfn = function(e, trig) { + counter += (e.data || 0) + (trig || 1); + }; + jQuery( "#onandoff" ) + .on( "click clack cluck", "em", 2, mixfn ) + .on( "cluck", "b", 7, mixfn ) + .on( "cluck", mixfn ) + .trigger( "what!" ) + .each( function() { + equals( counter, 0, "nothing triggered yet" ); + }) + .find( "em" ) + .one( "cluck", 3, mixfn ) + .trigger( "cluck", 8 ) // 3+8 2+8 + 0+8 = 29 + .off() + .trigger( "cluck", 9 ) // 2+9 + 0+9 = 20 + .end() + .each( function() { + equals( counter, 49, "after triggering em element" ); + }) + .off( "cluck", function(){} ) // shouldn't remove anything + .trigger( "cluck", 2 ) // 0+2 = 2 + .each( function() { + equals( counter, 51, "after triggering #onandoff cluck" ); + }) + .find( "b" ) + .on( "click", 95, mixfn ) + .on( "clack", "p", 97, mixfn ) + .one( "cluck", 3, mixfn ) + .trigger( "quack", 19 ) // 0 + .off( "click clack cluck" ) + .end() + .each( function() { + equals( counter, 51, "after triggering b" ); + }) + .trigger( "cluck", 3 ) // 0+3 = 3 + .off( "clack", "em", mixfn ) + .find( "em" ) + .trigger( "clack" ) // 0 + .end() + .each( function() { + equals( counter, 54, "final triggers" ); + }) + .off( "click cluck" ); + + // We should have removed all the event handlers ... kinda hacky way to check this + var data = jQuery.data[ jQuery( "#onandoff" )[0].expando ] || {}; + equals( data.events, undefined, "no events left" ); + + jQuery("#onandoff").remove(); +}); + +test("delegated events quickIs", function() { + expect(23); + var markup = jQuery( + '<div>'+ + '<p class="D">'+ + 'dead<b devo="cool">beat</b>club'+ + '</p>'+ + '<q id="famous">'+ + 'worked<em>or</em>borked?<em></em>'+ + '</q>'+ + '</div>' + ), + str, + check = function(el, expect){ + str = ""; + markup.find( el ).trigger( "blink" ); + equals( str, expect, "On " + el ); + }, + func = function(e){ + var tag = this.nodeName.toLowerCase(); + str += (str && " ") + tag + "|" + e.handleObj.selector; + ok( e.handleObj.quick, "Selector "+ e.handleObj.selector + " on " + tag + " is a quickIs case" ); + }; + + // tag#id.class[name=value] + markup + .appendTo( "body" ) + .on( "blink", "em", func ) + .on( "blink", ".D", func ) + .on( "blink", ".d", func ) + .on( "blink", "p.d", func ) + .on( "blink", "[devo=cool]", func ) + .on( "blink", "[devo='NO']", func ) + .on( "blink", "#famous", func ) + .on( "blink", "em:empty", func ) + .on( "blink", ":first-child", func ) + .on( "blink", "em:last-child", func ); + + check( "[devo=cool]", "b|[devo=cool] p|.D p|:first-child" ); + check( "[devo='']", "" ); + check( "p", "p|.D p|:first-child" ); + check( "b", "b|[devo=cool] p|.D p|:first-child" ); + check( "em", "em|em q|#famous em|em em|em:empty em|em:last-child q|#famous" ); + + markup.find( "b" ).attr( "devo", "NO" ); + check( "b", "b|[devo='NO'] p|.D p|:first-child" ); + + markup.remove(); +}); + + (function(){ // This code must be run before DOM ready! var notYetReady, noEarlyExecution, diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index de65daa13..4017cf196 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -227,7 +227,7 @@ test("unwrap()", function() { }); var testAppend = function(valueObj) { - expect(37); + expect(41); var defaultText = "Try them out:" var result = jQuery("#first").append(valueObj("<b>buga</b>")); equals( result.text(), defaultText + "buga", "Check if text appending works" ); @@ -330,6 +330,31 @@ var testAppend = function(valueObj) { d.contents().appendTo("#nonnodes"); d.remove(); ok( jQuery("#nonnodes").contents().length >= 2, "Check node,textnode,comment append cleanup worked" ); + + QUnit.reset(); + var $input = jQuery("<input />").attr({ "type": "checkbox", "checked": true }).appendTo('#testForm'); + equals( $input[0].checked, true, "A checked checkbox that is appended stays checked" ); + + QUnit.reset(); + var $radios = jQuery("input:radio[name='R1']"), + $radioNot = jQuery("<input type='radio' name='R1' checked='checked'/>").insertAfter( $radios ), + $radio = $radios.eq(1).click(); + $radioNot[0].checked = false; + $radios.parent().wrap("<div></div>"); + equals( $radio[0].checked, true, "Reappending radios uphold which radio is checked" ); + equals( $radioNot[0].checked, false, "Reappending radios uphold not being checked" ); + QUnit.reset(); + + var prev = jQuery("#sap").children().length; + + jQuery("#sap").append( + "<span></span>", + "<span></span>", + "<span></span>" + ); + + equals( jQuery("#sap").children().length, prev + 3, "Make sure that multiple arguments works." ); + QUnit.reset(); } test("append(String|Element|Array<Element>|jQuery)", function() { @@ -440,6 +465,40 @@ test("append the same fragment with events (Bug #6997, 5566)", function () { jQuery("#listWithTabIndex li.test6997").eq(1).click(); }); +test("append(xml)", function() { + expect( 1 ); + + function createXMLDoc() { + // Initialize DOM based upon latest installed MSXML or Netscape + var elem, + aActiveX = + [ "MSXML6.DomDocument", + "MSXML3.DomDocument", + "MSXML2.DomDocument", + "MSXML.DomDocument", + "Microsoft.XmlDom" ]; + + if ( document.implementation && "createDocument" in document.implementation ) { + return document.implementation.createDocument( "", "", null ); + } else { + // IE + for ( var n = 0, len = aActiveX.length; n < len; n++ ) { + try { + elem = new ActiveXObject( aActiveX[ n ] ); + return elem; + } catch(_){}; + } + } + } + + var xmlDoc = createXMLDoc(), + xml1 = xmlDoc.createElement("head"), + xml2 = xmlDoc.createElement("test"); + + ok( jQuery( xml1 ).append( xml2 ), "Append an xml element to another without raising an exception." ); + +}); + test("appendTo(String|Element|Array<Element>|jQuery)", function() { expect(16); @@ -483,19 +542,19 @@ test("appendTo(String|Element|Array<Element>|jQuery)", function() { var div = jQuery("<div/>").click(function(){ ok(true, "Running a cloned click."); }); - div.appendTo("#main, #moretests"); + div.appendTo("#qunit-fixture, #moretests"); - jQuery("#main div:last").click(); + jQuery("#qunit-fixture div:last").click(); jQuery("#moretests div:last").click(); QUnit.reset(); - var div = jQuery("<div/>").appendTo("#main, #moretests"); + var div = jQuery("<div/>").appendTo("#qunit-fixture, #moretests"); equals( div.length, 2, "appendTo returns the inserted elements" ); div.addClass("test"); - ok( jQuery("#main div:last").hasClass("test"), "appendTo element was modified after the insertion" ); + ok( jQuery("#qunit-fixture div:last").hasClass("test"), "appendTo element was modified after the insertion" ); ok( jQuery("#moretests div:last").hasClass("test"), "appendTo element was modified after the insertion" ); QUnit.reset(); @@ -507,10 +566,10 @@ test("appendTo(String|Element|Array<Element>|jQuery)", function() { div = jQuery("#moretests div"); - var num = jQuery("#main div").length; - div.remove().appendTo("#main"); + var num = jQuery("#qunit-fixture div").length; + div.remove().appendTo("#qunit-fixture"); - equals( jQuery("#main div").length, num, "Make sure all the removed divs were inserted." ); + equals( jQuery("#qunit-fixture div").length, num, "Make sure all the removed divs were inserted." ); QUnit.reset(); }); @@ -750,7 +809,7 @@ var testReplaceWith = function(val) { ok( !jQuery("#yahoo")[0], "Verify that original element is gone, after element" ); QUnit.reset(); - jQuery("#main").append("<div id='bar'><div id='baz'</div></div>"); + jQuery("#qunit-fixture").append("<div id='bar'><div id='baz'</div></div>"); jQuery("#baz").replaceWith("Baz"); equals( jQuery("#bar").text(),"Baz", "Replace element with text" ); ok( !jQuery("#baz")[0], "Verify that original element is gone, after element" ); @@ -813,14 +872,14 @@ var testReplaceWith = function(val) { QUnit.reset(); - jQuery("#main").append("<div id='replaceWith'></div>"); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + jQuery("#qunit-fixture").append("<div id='replaceWith'></div>"); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); jQuery("#replaceWith").replaceWith( val("<div id='replaceWith'></div>") ); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); jQuery("#replaceWith").replaceWith( val("<div id='replaceWith'></div>") ); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); } test("replaceWith(String|Element|Array<Element>|jQuery)", function() { @@ -881,7 +940,7 @@ test("jQuery.clone() (#8017)", function() { ok( jQuery.clone && jQuery.isFunction( jQuery.clone ) , "jQuery.clone() utility exists and is a function."); - var main = jQuery("#main")[0], + var main = jQuery("#qunit-fixture")[0], clone = jQuery.clone( main ); equals( main.childNodes.length, clone.childNodes.length, "Simple child length to ensure a large dom tree copies correctly" ); @@ -890,7 +949,7 @@ test("jQuery.clone() (#8017)", function() { test("clone() (#8070)", function () { expect(2); - jQuery("<select class='test8070'></select><select class='test8070'></select>").appendTo("#main"); + jQuery("<select class='test8070'></select><select class='test8070'></select>").appendTo("#qunit-fixture"); var selects = jQuery(".test8070"); selects.append("<OPTION>1</OPTION><OPTION>2</OPTION>"); @@ -1019,7 +1078,7 @@ test("clone(form element) (Bug #3879, #6655)", function() { equals( clone.is(":checked"), element.is(":checked"), "Checked input cloned correctly" ); equals( clone[0].defaultValue, "foo", "Checked input defaultValue cloned correctly" ); - + // defaultChecked also gets set now due to setAttribute in attr, is this check still valid? // equals( clone[0].defaultChecked, !jQuery.support.noCloneChecked, "Checked input defaultChecked cloned correctly" ); @@ -1062,7 +1121,7 @@ var testHtml = function(valueObj) { jQuery.scriptorder = 0; - var div = jQuery("#main > div"); + var div = jQuery("#qunit-fixture > div"); div.html(valueObj("<b>test</b>")); var pass = true; for ( var i = 0; i < div.size(); i++ ) { @@ -1079,10 +1138,10 @@ var testHtml = function(valueObj) { ok( /^\xA0$|^ $/.test( space ), "Make sure entities are passed through correctly." ); equals( jQuery("<div/>").html(valueObj("&"))[0].innerHTML, "&", "Make sure entities are passed through correctly." ); - jQuery("#main").html(valueObj("<style>.foobar{color:green;}</style>")); + jQuery("#qunit-fixture").html(valueObj("<style>.foobar{color:green;}</style>")); - equals( jQuery("#main").children().length, 1, "Make sure there is a child element." ); - equals( jQuery("#main").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); + equals( jQuery("#qunit-fixture").children().length, 1, "Make sure there is a child element." ); + equals( jQuery("#qunit-fixture").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); QUnit.reset(); // using contents will get comments regular, text, and comment nodes @@ -1093,9 +1152,9 @@ var testHtml = function(valueObj) { j.find("b").removeData(); equals( j.html().replace(/ xmlns="[^"]+"/g, "").toLowerCase(), "<b>bold</b>", "Check node,textnode,comment with html()" ); - jQuery("#main").html(valueObj("<select/>")); - jQuery("#main select").html(valueObj("<option>O1</option><option selected='selected'>O2</option><option>O3</option>")); - equals( jQuery("#main select").val(), "O2", "Selected option correct" ); + jQuery("#qunit-fixture").html(valueObj("<select/>")); + jQuery("#qunit-fixture select").html(valueObj("<option>O1</option><option selected='selected'>O2</option><option>O3</option>")); + equals( jQuery("#qunit-fixture select").val(), "O2", "Selected option correct" ); var $div = jQuery("<div />"); equals( $div.html(valueObj( 5 )).html(), "5", "Setting a number as html" ); @@ -1113,23 +1172,23 @@ var testHtml = function(valueObj) { QUnit.reset(); - jQuery("#main").html(valueObj("<script type='something/else'>ok( false, 'Non-script evaluated.' );</script><script type='text/javascript'>ok( true, 'text/javascript is evaluated.' );</script><script>ok( true, 'No type is evaluated.' );</script><div><script type='text/javascript'>ok( true, 'Inner text/javascript is evaluated.' );</script><script>ok( true, 'Inner No type is evaluated.' );</script><script type='something/else'>ok( false, 'Non-script evaluated.' );</script></div>")); + jQuery("#qunit-fixture").html(valueObj("<script type='something/else'>ok( false, 'Non-script evaluated.' );</script><script type='text/javascript'>ok( true, 'text/javascript is evaluated.' );</script><script>ok( true, 'No type is evaluated.' );</script><div><script type='text/javascript'>ok( true, 'Inner text/javascript is evaluated.' );</script><script>ok( true, 'Inner No type is evaluated.' );</script><script type='something/else'>ok( false, 'Non-script evaluated.' );</script></div>")); - var child = jQuery("#main").find("script"); + var child = jQuery("#qunit-fixture").find("script"); equals( child.length, 2, "Make sure that two non-JavaScript script tags are left." ); equals( child[0].type, "something/else", "Verify type of script tag." ); equals( child[1].type, "something/else", "Verify type of script tag." ); - jQuery("#main").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); - jQuery("#main").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); - jQuery("#main").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); + jQuery("#qunit-fixture").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); + jQuery("#qunit-fixture").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); + jQuery("#qunit-fixture").html(valueObj("<script>ok( true, 'Test repeated injection of script.' );</script>")); - jQuery("#main").html(valueObj("<script type='text/javascript'>ok( true, 'jQuery().html().evalScripts() Evals Scripts Twice in Firefox, see #975 (1)' );</script>")); + jQuery("#qunit-fixture").html(valueObj("<script type='text/javascript'>ok( true, 'jQuery().html().evalScripts() Evals Scripts Twice in Firefox, see #975 (1)' );</script>")); - jQuery("#main").html(valueObj("foo <form><script type='text/javascript'>ok( true, 'jQuery().html().evalScripts() Evals Scripts Twice in Firefox, see #975 (2)' );</script></form>")); + jQuery("#qunit-fixture").html(valueObj("foo <form><script type='text/javascript'>ok( true, 'jQuery().html().evalScripts() Evals Scripts Twice in Firefox, see #975 (2)' );</script></form>")); - jQuery("#main").html(valueObj("<script>equals(jQuery.scriptorder++, 0, 'Script is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html (even though appears before)')<\/script><span id='scriptorder'><script>equals(jQuery.scriptorder++, 1, 'Script (nested) is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html')<\/script></span><script>equals(jQuery.scriptorder++, 2, 'Script (unnested) is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html')<\/script>")); + jQuery("#qunit-fixture").html(valueObj("<script>equals(jQuery.scriptorder++, 0, 'Script is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html (even though appears before)')<\/script><span id='scriptorder'><script>equals(jQuery.scriptorder++, 1, 'Script (nested) is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html')<\/script></span><script>equals(jQuery.scriptorder++, 2, 'Script (unnested) is executed in order');equals(jQuery('#scriptorder').length, 1,'Execute after html')<\/script>")); } test("html(String)", function() { @@ -1143,18 +1202,18 @@ test("html(Function)", function() { QUnit.reset(); - jQuery("#main").html(function(){ + jQuery("#qunit-fixture").html(function(){ return jQuery(this).text(); }); - ok( !/</.test( jQuery("#main").html() ), "Replace html with text." ); - ok( jQuery("#main").html().length > 0, "Make sure text exists." ); + ok( !/</.test( jQuery("#qunit-fixture").html() ), "Replace html with text." ); + ok( jQuery("#qunit-fixture").html().length > 0, "Make sure text exists." ); }); test("html(Function) with incoming value", function() { expect(20); - var div = jQuery("#main > div"), old = div.map(function(){ return jQuery(this).html() }); + var div = jQuery("#qunit-fixture > div"), old = div.map(function(){ return jQuery(this).html() }); div.html(function(i, val) { equals( val, old[i], "Make sure the incoming value is correct." ); @@ -1251,7 +1310,7 @@ var testRemove = function(method) { var count = 0; var first = jQuery("#ap").children(":first"); - var cleanUp = first.click(function() { count++ })[method]().appendTo("#main").click(); + var cleanUp = first.click(function() { count++ })[method]().appendTo("#qunit-fixture").click(); equals( method == "remove" ? 0 : 1, count ); @@ -1359,7 +1418,7 @@ 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" ), + var $f = jQuery( "<div />" ).appendTo( "#qunit-fixture" ), bad = [ "start-", "toString", "hasOwnProperty", "append", "here&there!", "-end" ]; for ( var i=0; i < bad.length; i++ ) { @@ -1368,6 +1427,52 @@ test("jQuery.buildFragment - no plain-text caching (Bug #6779)", function() { } catch(e) {} } - equals($f.text(), bad.join(""), "Cached strings that match Object properties"); + equals($f.text(), bad.join(""), "Cached strings that match Object properties"); $f.remove(); }); + +test( "jQuery.html - execute scripts escaped with html comment or CDATA (#9221)", function() { + expect( 3 ); + jQuery( [ + '<script type="text/javascript">', + '<!--', + 'ok( true, "<!-- handled" );', + '//-->', + '</script>' + ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); + jQuery( [ + '<script type="text/javascript">', + '<![CDATA[', + 'ok( true, "<![CDATA[ handled" );', + '//]]>', + '</script>' + ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); + jQuery( [ + '<script type="text/javascript">', + '<!--//--><![CDATA[//><!--', + 'ok( true, "<!--//--><![CDATA[//><!-- (Drupal case) handled" );', + '//--><!]]>', + '</script>' + ].join ( "\n" ) ).appendTo( "#qunit-fixture" ); +}); + +test("jQuery.buildFragment - plain objects are not a document #8950", function() { + expect(1); + + try { + jQuery('<input type="hidden">', {}); + ok( true, "Does not allow attribute object to be treated like a doc object"); + } catch (e) {} + +}); + +test("jQuery.clone - no exceptions for object elements #9587", function() { + expect(1); + + try { + jQuery("#no-clone-exception").clone(); + ok( true, "cloned with no exceptions" ); + } catch( e ) { + ok( false, e.message ); + } +}); diff --git a/test/unit/offset.js b/test/unit/offset.js index ea1a49332..79a0f3606 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -11,7 +11,7 @@ test("disconnected node", function() { var supportsScroll = false; -testoffset("absolute"/* in iframe */, function($, iframe) { +testoffset("absolute", function($, iframe) { expect(4); var doc = iframe.document, tests; @@ -390,7 +390,7 @@ testoffset("scroll", function( jQuery, win ) { equals( jQuery(window).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" ); equals( jQuery(document).scrollTop(), 0, "jQuery(window).scrollTop() other document" ); equals( jQuery(document).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" ); - + // Tests scrollTop/Left with empty jquery objects notEqual( jQuery().scrollTop(100), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); notEqual( jQuery().scrollLeft(100), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); @@ -443,12 +443,12 @@ test("offsetParent", function(){ test("fractions (see #7730 and #7885)", function() { expect(2); - + jQuery('body').append('<div id="fractions"/>'); - + var expected = { top: 1000, left: 1000 }; var div = jQuery('#fractions'); - + div.css({ position: 'absolute', left: '1000.7432222px', @@ -456,14 +456,14 @@ test("fractions (see #7730 and #7885)", function() { width: 100, height: 100 }); - + div.offset(expected); - + var result = div.offset(); equals( result.top, expected.top, "Check top" ); equals( result.left, expected.left, "Check left" ); - + div.remove(); }); diff --git a/test/unit/queue.js b/test/unit/queue.js index 9b612ce37..b5c058caa 100644 --- a/test/unit/queue.js +++ b/test/unit/queue.js @@ -66,25 +66,6 @@ test("queue(name) passes in the next item in the queue as a parameter", function 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(); - }).queue("foo", function(next) { - equals(++counter, 2, "Next was called"); - next(); - }).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(3); stop(); @@ -107,7 +88,31 @@ test("queue() passes in the next item in the queue as a parameter to fx queues", equals(counter, 2, "Deferreds resolved"); start(); }); +}); +test("callbacks keep their place in the queue", function() { + expect(5); + stop(); + var div = jQuery("<div>"), + counter = 0; + + div.queue(function( next ) { + equal( ++counter, 1, "Queue/callback order: first called" ); + setTimeout( next, 200 ); + }).show(100, function() { + equal( ++counter, 2, "Queue/callback order: second called" ); + jQuery(this).hide(100, function() { + equal( ++counter, 4, "Queue/callback order: fourth called" ); + }); + }).queue(function( next ) { + equal( ++counter, 3, "Queue/callback order: third called" ); + next(); + }); + + div.promise("fx").done(function() { + equals(counter, 4, "Deferreds resolved"); + start(); + }); }); test("delay()", function() { diff --git a/test/unit/selector.js b/test/unit/selector.js new file mode 100644 index 000000000..441258008 --- /dev/null +++ b/test/unit/selector.js @@ -0,0 +1,133 @@ +/** + * This test page is for selector tests that address selector issues that have already been addressed in jQuery functions + * and which only work because jQuery has hooked into Sizzle. + * These tests may or may not fail in an independent Sizzle. + */ + +module("selector - jQuery only", { teardown: moduleTeardown }); + +/** + * Loads an iframe for the selector context + * @param {String} fileName - Name of the html file to load + * @param {String} name - Test name + * @param {Function} fn - Test callback containing the tests to run + */ +var testIframe = function( fileName, name, fn ) { + + var loadFixture = function() { + + // Creates iframe with cache disabled + var src = "./data/" + fileName + ".html?" + parseInt( Math.random()*1000, 10 ), + iframe = jQuery("<iframe />").css({ + width: 500, height: 500, position: "absolute", top: -600, left: -600, visibility: "hidden" + }).appendTo("body")[0]; + iframe.contentWindow.location = src; + return iframe; + }; + + test(name, function() { + // pause execution for now + stop(); + + // load fixture in iframe + var iframe = loadFixture(), + win = iframe.contentWindow, + interval = setInterval( function() { + if ( win && win.jQuery && win.jQuery.isReady ) { + clearInterval( interval ); + // continue + start(); + // call actual tests passing the correct jQuery instance to use + fn.call( this, win.jQuery, win ); + document.body.removeChild( iframe ); + iframe = null; + } + }, 15 ); + }); +}; + +testIframe("selector", "attributes - jQuery.attr", function( jQuery, window ) { + expect(34); + + var document = window.document; + + /** + * Returns an array of elements with the given IDs, eg. + */ + var q = function() { + var r = []; + + for ( var i = 0; i < arguments.length; i++ ) { + r.push( document.getElementById( arguments[i] ) ); + } + + return r; + }; + + /** + * Asserts that a select matches the given IDs * @example t("Check for something", "//[a]", ["foo", "baar"]); + * @param {String} a - Assertion name + * @param {String} b - Sizzle selector + * @param {String} c - Array of ids to construct what is expected + */ + var t = function( a, b, c ) { + var f = jQuery(b).get(), s = ""; + + for ( var i = 0; i < f.length; i++ ) { + s += (s && ",") + '"' + f[i].id + '"'; + } + + deepEqual(f, q.apply( q, c ), a + " (" + b + ")"); + }; + + // ====== All known boolean attributes, including html5 booleans ====== + // autobuffer, autofocus, autoplay, async, checked, + // compact, controls, declare, defer, disabled, + // formnovalidate, hidden, indeterminate (property only), + // ismap, itemscope, loop, multiple, muted, nohref, noresize, + // noshade, nowrap, novalidate, open, pubdate, readonly, required, + // reversed, scoped, seamless, selected, truespeed, visible (skipping visible attribute, which is on a barprop object) + + t( "Attribute Exists", "[autobuffer]", ["video1"]); + t( "Attribute Exists", "[autofocus]", ["text1"]); + t( "Attribute Exists", "[autoplay]", ["video1"]); + t( "Attribute Exists", "[async]", ["script1"]); + t( "Attribute Exists", "[checked]", ["check1"]); + t( "Attribute Exists", "[compact]", ["dl"]); + t( "Attribute Exists", "[controls]", ["video1"]); + t( "Attribute Exists", "[declare]", ["object1"]); + t( "Attribute Exists", "[defer]", ["script1"]); + t( "Attribute Exists", "[disabled]", ["check1"]); + t( "Attribute Exists", "[formnovalidate]", ["form1"]); + t( "Attribute Exists", "[hidden]", ["div1"]); + t( "Attribute Exists", "[indeterminate]", []); + t( "Attribute Exists", "[ismap]", ["img1"]); + t( "Attribute Exists", "[itemscope]", ["div1"]); + // t( "Attribute Exists", "[loop]", ["video1"]); // IE 6/7 cannot differentiate here. loop is also used on img, input, and marquee tags as well as video/audio. getAttributeNode unfortunately only retrieves the property value. + t( "Attribute Exists", "[multiple]", ["select1"]); + t( "Attribute Exists", "[muted]", ["audio1"]); + // t( "Attribute Exists", "[nohref]", ["area1"]); // IE 6/7 keep this set to false regardless of presence. The attribute node is not retrievable. + t( "Attribute Exists", "[noresize]", ["textarea1"]); + t( "Attribute Exists", "[noshade]", ["hr1"]); + t( "Attribute Exists", "[nowrap]", ["td1", "div1"]); + t( "Attribute Exists", "[novalidate]", ["form1"]); + t( "Attribute Exists", "[open]", ["details1"]); + t( "Attribute Exists", "[pubdate]", ["article1"]); + t( "Attribute Exists", "[readonly]", ["text1"]); + t( "Attribute Exists", "[required]", ["text1"]); + t( "Attribute Exists", "[reversed]", ["ol1"]); + t( "Attribute Exists", "[scoped]", ["style1"]); + t( "Attribute Exists", "[seamless]", ["iframe1"]); + // t( "Attribute Exists", "[selected]", ["option1"]); // IE8's querySelectorAll fails here. Redirecting to oldSizzle would work, but it would require an additional support test as well as a check for the selected attribute within the qsa logic + t( "Attribute Exists", "[truespeed]", ["marquee1"]); + + // Enumerated attributes (these are not boolean content attributes) + jQuery.each([ "draggable", "contenteditable", "aria-disabled" ], function( i, val ) { + t( "Enumerated attribute", "[" + val + "]", ["div1"]); + }); + t( "Enumerated attribute", "[spellcheck]", ["span1"]); + + // t( "tabindex selector does not retrieve all elements in IE6/7(#8473)", "form, [tabindex]", ["form1", "text1"]); // Uncomment this when the tabindex attrHook is deprecated + + t( "Improperly named form elements do not interfere with form selections (#9570)", "form[name='formName']", ["form1"]); +}); diff --git a/test/unit/support.js b/test/unit/support.js new file mode 100644 index 000000000..4733b2529 --- /dev/null +++ b/test/unit/support.js @@ -0,0 +1,60 @@ +module("support", { teardown: moduleTeardown }); + +function supportIFrameTest( title, url, noDisplay, func ) { + + if ( noDisplay !== true ) { + func = noDisplay; + noDisplay = false; + } + + test( title, function() { + var iframe; + + stop(); + window.supportCallback = function() { + var self = this, + args = arguments; + setTimeout( function() { + window.supportCallback = undefined; + iframe.remove(); + func.apply( self, args ); + start(); + }, 0 ); + }; + iframe = jQuery( "<div/>" ).css( "display", noDisplay ? "none" : "block" ).append( + jQuery( "<iframe/>" ).attr( "src", "data/support/" + url + ".html" ) + ).appendTo( "body" ); + }); +} + +supportIFrameTest( "proper boxModel in compatMode CSS1Compat (IE6 and IE7)", "boxModelIE", function( compatMode, boxModel ) { + ok( compatMode !== "CSS1Compat" || boxModel, "boxModel properly detected" ); +}); + +supportIFrameTest( "body background is not lost if set prior to loading jQuery (#9238)", "bodyBackground", function( color, support ) { + expect( 2 ); + var okValue = { + "#000000": true, + "rgb(0, 0, 0)": true + }; + ok( okValue[ color ], "color was not reset (" + color + ")" ); + var i, passed = true; + for ( i in jQuery.support ) { + if ( jQuery.support[ i ] !== support[ i ] ) { + passed = false; + strictEqual( jQuery.support[ i ], support[ i ], "Support property " + i + " is different" ); + } + } + for ( i in support ) { + if ( !( i in jQuery.support ) ) { + ok = false; + strictEqual( src[ i ], dest[ i ], "Unexpected property: " + i ); + } + } + ok( passed, "Same support properties" ); +}); + +supportIFrameTest( "A background on the testElement does not cause IE8 to crash (#9823)", "testElementCrash", function() { + expect(1); + ok( true, "IE8 does not crash" ); +}); diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 109a9aa6d..4cbcee912 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -8,14 +8,14 @@ test("find(String)", function() { var j = jQuery("#nonnodes").contents(); equals( j.find("div").length, 0, "Check node,textnode,comment to find zero divs" ); - same( jQuery("#main").find("> div").get(), q("foo", "moretests", "tabindex-tests", "liveHandlerOrder", "siblingTest"), "find child elements" ); - same( jQuery("#main").find("> #foo, > #moretests").get(), q("foo", "moretests"), "find child elements" ); - same( jQuery("#main").find("> #foo > p").get(), q("sndp", "en", "sap"), "find child elements" ); + same( jQuery("#qunit-fixture").find("> div").get(), q("foo", "moretests", "tabindex-tests", "liveHandlerOrder", "siblingTest"), "find child elements" ); + same( jQuery("#qunit-fixture").find("> #foo, > #moretests").get(), q("foo", "moretests"), "find child elements" ); + same( jQuery("#qunit-fixture").find("> #foo > p").get(), q("sndp", "en", "sap"), "find child elements" ); }); test("find(node|jQuery object)", function() { expect( 11 ); - + var $foo = jQuery("#foo"), $blog = jQuery(".blogTest"), $first = jQuery("#first"), @@ -29,16 +29,16 @@ test("find(node|jQuery object)", function() { ok( $foo.find( $two ).is(".blogTest"), "Find returns only nodes within #foo" ); ok( $fooTwo.find( $blog ).is(".blogTest"), "Blog is part of the collection, but also within foo" ); ok( $fooTwo.find( $blog[0] ).is(".blogTest"), "Blog is part of the collection, but also within foo(node)" ); - + equals( $two.find( $foo ).length, 0, "Foo is not in two elements" ); equals( $two.find( $foo[0] ).length, 0, "Foo is not in two elements(node)" ); equals( $two.find( $first ).length, 0, "first is in the collection and not within two" ); equals( $two.find( $first ).length, 0, "first is in the collection and not within two(node)" ); - + }); test("is(String|undefined)", function() { - expect(27); + expect(29); ok( jQuery("#form").is("form"), "Check for element: A form must be a form" ); ok( !jQuery("#form").is("div"), "Check for element: A form is not a div" ); ok( jQuery("#mark").is(".blog"), "Check for class: Expected class 'blog'" ); @@ -63,12 +63,15 @@ test("is(String|undefined)", function() { ok( !jQuery("#foo").is(""), "Expected false for an invalid expression - \"\"" ); ok( !jQuery("#foo").is(undefined), "Expected false for an invalid expression - undefined" ); ok( !jQuery("#foo").is({ plain: "object" }), "Check passing invalid object" ); - + // test is() with comma-seperated expressions ok( jQuery("#en").is("[lang=\"en\"],[lang=\"de\"]"), "Comma-seperated; Check for lang attribute: Expect en or de" ); ok( jQuery("#en").is("[lang=\"de\"],[lang=\"en\"]"), "Comma-seperated; Check for lang attribute: Expect en or de" ); ok( jQuery("#en").is("[lang=\"en\"] , [lang=\"de\"]"), "Comma-seperated; Check for lang attribute: Expect en or de" ); ok( jQuery("#en").is("[lang=\"de\"] , [lang=\"en\"]"), "Comma-seperated; Check for lang attribute: Expect en or de" ); + + ok( !jQuery(window).is('a'), "Checking is on a window does not throw an exception(#10178)" ); + ok( !jQuery(document).is('a'), "Checking is on a document does not throw an exception(#10178)" ); }); test("is(jQuery)", function() { @@ -88,7 +91,7 @@ test("is(jQuery)", function() { ok( !jQuery("#radio1").is( jQuery("input:checked") ), "Check for pseudoclass: Expected not checked" ); ok( jQuery("#foo").is( jQuery("div:has(p)") ), "Check for child: Expected a child 'p' element" ); ok( !jQuery("#foo").is( jQuery("div:has(ul)") ), "Check for child: Did not expect 'ul' element" ); - + // Some raw elements ok( jQuery("#form").is( jQuery("form")[0] ), "Check for element: A form is a form" ); ok( !jQuery("#form").is( jQuery("div")[0] ), "Check for element: A form is not a div" ); @@ -99,9 +102,11 @@ test("is(jQuery)", function() { }); test("index()", function() { - expect(1); + expect( 2 ); - equals( jQuery("#text2").index(), 2, "Returns the index of a child amongst its siblings" ) + equal( jQuery("#text2").index(), 2, "Returns the index of a child amongst its siblings" ); + + equal( jQuery("<div/>").index(), -1, "Node without parent returns -1" ); }); test("index(Object|String|undefined)", function() { @@ -140,7 +145,7 @@ test("filter(Selector|undefined)", function() { same( jQuery("#form input").filter(":checked").get(), q("radio2", "check1"), "filter(String)" ); same( jQuery("p").filter("#ap, #sndp").get(), q("ap", "sndp"), "filter('String, String')" ); same( jQuery("p").filter("#ap,#sndp").get(), q("ap", "sndp"), "filter('String,String')" ); - + same( jQuery("p").filter(null).get(), [], "filter(null) should return an empty jQuery object"); same( jQuery("p").filter(undefined).get(), [], "filter(undefined) should return an empty jQuery object"); same( jQuery("p").filter(0).get(), [], "filter(0) should return an empty jQuery object"); @@ -155,9 +160,9 @@ test("filter(Selector|undefined)", function() { test("filter(Function)", function() { expect(2); - same( jQuery("#main p").filter(function() { return !jQuery("a", this).length }).get(), q("sndp", "first"), "filter(Function)" ); + same( jQuery("#qunit-fixture p").filter(function() { return !jQuery("a", this).length }).get(), q("sndp", "first"), "filter(Function)" ); - same( jQuery("#main p").filter(function(i, elem) { return !jQuery("a", elem).length }).get(), q("sndp", "first"), "filter(Function) using arg" ); + same( jQuery("#qunit-fixture p").filter(function(i, elem) { return !jQuery("a", elem).length }).get(), q("sndp", "first"), "filter(Function) using arg" ); }); test("filter(Element)", function() { @@ -186,7 +191,7 @@ test("closest()", function() { same( jQuery("body").closest("body").get(), q("body"), "closest(body)" ); same( jQuery("body").closest("html").get(), q("html"), "closest(html)" ); same( jQuery("body").closest("div").get(), [], "closest(div)" ); - same( jQuery("#main").closest("span,#html").get(), q("html"), "closest(span,#html)" ); + same( jQuery("#qunit-fixture").closest("span,#html").get(), q("html"), "closest(span,#html)" ); same( jQuery("div:eq(1)").closest("div:first").get(), [], "closest(div:first)" ); same( jQuery("div").closest("body:first div:last").get(), q("fx-tests"), "closest(body:first div:last)" ); @@ -198,7 +203,7 @@ test("closest()", function() { 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" ); + equals( jQuery("#qunit-fixture p").closest("#qunit-fixture").length, 1, "Closest should return a unique set" ); // Test on disconnected node equals( jQuery("<div><p></p></div>").find("p").closest("table").length, 0, "Make sure disconnected closest work." ); @@ -213,8 +218,8 @@ test("closest(Array)", function() { same( jQuery("body").closest(["body"]), [{selector:"body", elem:document.body, level:1}], "closest([body])" ); same( jQuery("body").closest(["html"]), [{selector:"html", elem:document.documentElement, level:2}], "closest([html])" ); same( jQuery("body").closest(["div"]), [], "closest([div])" ); - same( jQuery("#yahoo").closest(["div"]), [{"selector":"div", "elem": document.getElementById("foo"), "level": 3}, { "selector": "div", "elem": document.getElementById("main"), "level": 4 }], "closest([div])" ); - same( jQuery("#main").closest(["span,#html"]), [{selector:"span,#html", elem:document.documentElement, level:4}], "closest([span,#html])" ); + same( jQuery("#yahoo").closest(["div"]), [{"selector":"div", "elem": document.getElementById("foo"), "level": 3}, { "selector": "div", "elem": document.getElementById("qunit-fixture"), "level": 4 }], "closest([div])" ); + same( jQuery("#qunit-fixture").closest(["span,#html"]), [{selector:"span,#html", elem:document.documentElement, level:4}], "closest([span,#html])" ); same( jQuery("body").closest(["body","html"]), [{selector:"body", elem:document.body, level:1}, {selector:"html", elem:document.documentElement, level:2}], "closest([body, html])" ); same( jQuery("body").closest(["span","html"]), [{selector:"html", elem:document.documentElement, level:2}], "closest([body, html])" ); @@ -224,7 +229,7 @@ test("closest(jQuery)", function() { expect(8); var $child = jQuery("#nothiddendivchild"), $parent = jQuery("#nothiddendiv"), - $main = jQuery("#main"), + $main = jQuery("#qunit-fixture"), $body = jQuery("body"); ok( $child.closest( $parent ).is("#nothiddendiv"), "closest( jQuery('#nothiddendiv') )" ); ok( $child.closest( $parent[0] ).is("#nothiddendiv"), "closest( jQuery('#nothiddendiv') ) :: node" ); @@ -238,7 +243,7 @@ test("closest(jQuery)", function() { test("not(Selector|undefined)", function() { expect(11); - equals( jQuery("#main > p#ap > a").not("#google").length, 2, "not('selector')" ); + equals( jQuery("#qunit-fixture > p#ap > a").not("#google").length, 2, "not('selector')" ); same( jQuery("p").not(".result").get(), q("firstp", "ap", "sndp", "en", "sap", "first"), "not('.class')" ); same( jQuery("p").not("#ap, #sndp, .result").get(), q("firstp", "en", "sap", "first"), "not('selector, selector')" ); same( jQuery("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e", "option4e","option5b"), "not('complex selector')"); @@ -262,13 +267,13 @@ test("not(Element)", function() { }); test("not(Function)", function() { - same( jQuery("#main p").not(function() { return jQuery("a", this).length }).get(), q("sndp", "first"), "not(Function)" ); + same( jQuery("#qunit-fixture p").not(function() { return jQuery("a", this).length }).get(), q("sndp", "first"), "not(Function)" ); }); test("not(Array)", function() { expect(2); - equals( jQuery("#main > p#ap > a").not(document.getElementById("google")).length, 2, "not(DOMElement)" ); + equals( jQuery("#qunit-fixture > p#ap > a").not(document.getElementById("google")).length, 2, "not(DOMElement)" ); equals( jQuery("p").not(document.getElementsByTagName("p")).length, 0, "not(Array-like DOM collection)" ); }); @@ -281,37 +286,37 @@ test("not(jQuery)", function() { test("has(Element)", function() { expect(2); - var obj = jQuery("#main").has(jQuery("#sndp")[0]); - same( obj.get(), q("main"), "Keeps elements that have the element as a descendant" ); + var obj = jQuery("#qunit-fixture").has(jQuery("#sndp")[0]); + same( obj.get(), q("qunit-fixture"), "Keeps elements that have the element as a descendant" ); - var multipleParent = jQuery("#main, #header").has(jQuery("#sndp")[0]); - same( obj.get(), q("main"), "Does not include elements that do not have the element as a descendant" ); + var multipleParent = jQuery("#qunit-fixture, #header").has(jQuery("#sndp")[0]); + same( obj.get(), q("qunit-fixture"), "Does not include elements that do not have the element as a descendant" ); }); test("has(Selector)", function() { expect(3); - var obj = jQuery("#main").has("#sndp"); - same( obj.get(), q("main"), "Keeps elements that have any element matching the selector as a descendant" ); + var obj = jQuery("#qunit-fixture").has("#sndp"); + same( obj.get(), q("qunit-fixture"), "Keeps elements that have any element matching the selector as a descendant" ); - var multipleParent = jQuery("#main, #header").has("#sndp"); - same( obj.get(), q("main"), "Does not include elements that do not have the element as a descendant" ); + var multipleParent = jQuery("#qunit-fixture, #header").has("#sndp"); + same( obj.get(), q("qunit-fixture"), "Does not include elements that do not have the element as a descendant" ); - var multipleHas = jQuery("#main").has("#sndp, #first"); - same( multipleHas.get(), q("main"), "Only adds elements once" ); + var multipleHas = jQuery("#qunit-fixture").has("#sndp, #first"); + same( multipleHas.get(), q("qunit-fixture"), "Only adds elements once" ); }); test("has(Arrayish)", function() { expect(3); - var simple = jQuery("#main").has(jQuery("#sndp")); - same( simple.get(), q("main"), "Keeps elements that have any element in the jQuery list as a descendant" ); + var simple = jQuery("#qunit-fixture").has(jQuery("#sndp")); + same( simple.get(), q("qunit-fixture"), "Keeps elements that have any element in the jQuery list as a descendant" ); - var multipleParent = jQuery("#main, #header").has(jQuery("#sndp")); - same( multipleParent.get(), q("main"), "Does not include elements that do not have an element in the jQuery list as a descendant" ); + var multipleParent = jQuery("#qunit-fixture, #header").has(jQuery("#sndp")); + same( multipleParent.get(), q("qunit-fixture"), "Does not include elements that do not have an element in the jQuery list as a descendant" ); - var multipleHas = jQuery("#main").has(jQuery("#sndp, #first")); - same( simple.get(), q("main"), "Only adds elements once" ); + var multipleHas = jQuery("#qunit-fixture").has(jQuery("#sndp, #first")); + same( simple.get(), q("qunit-fixture"), "Only adds elements once" ); }); test("andSelf()", function() { @@ -319,17 +324,18 @@ test("andSelf()", function() { same( jQuery("#en").siblings().andSelf().get(), q("sndp", "en", "sap"), "Check for siblings and self" ); same( jQuery("#foo").children().andSelf().get(), q("foo", "sndp", "en", "sap"), "Check for children and self" ); same( jQuery("#sndp, #en").parent().andSelf().get(), q("foo","sndp","en"), "Check for parent and self" ); - same( jQuery("#groups").parents("p, div").andSelf().get(), q("main", "ap", "groups"), "Check for parents and self" ); + same( jQuery("#groups").parents("p, div").andSelf().get(), q("qunit-fixture", "ap", "groups"), "Check for parents and self" ); }); test("siblings([String])", function() { - expect(5); + expect(6); same( jQuery("#en").siblings().get(), q("sndp", "sap"), "Check for siblings" ); same( jQuery("#sndp").siblings(":has(code)").get(), q("sap"), "Check for filtered siblings (has code child element)" ); same( jQuery("#sndp").siblings(":has(a)").get(), q("en", "sap"), "Check for filtered siblings (has anchor child element)" ); same( jQuery("#foo").siblings("form, b").get(), q("form", "floatTest", "lengthtest", "name-tests", "testForm"), "Check for multiple filters" ); var set = q("sndp", "en", "sap"); same( jQuery("#en, #sndp").siblings().get(), set, "Check for unique results from siblings" ); + deepEqual( jQuery("#option5a").siblings("option[data-attr]").get(), q("option5c"), "Has attribute selector in siblings (#9261)" ); }); test("children([String])", function() { @@ -352,9 +358,9 @@ test("parents([String])", function() { expect(5); equals( jQuery("#groups").parents()[0].id, "ap", "Simple parents check" ); equals( jQuery("#groups").parents("p")[0].id, "ap", "Filtered parents check" ); - equals( jQuery("#groups").parents("div")[0].id, "main", "Filtered parents check2" ); - same( jQuery("#groups").parents("p, div").get(), q("ap", "main"), "Check for multiple filters" ); - same( jQuery("#en, #sndp").parents().get(), q("foo", "main", "dl", "body", "html"), "Check for unique results from parents" ); + equals( jQuery("#groups").parents("div")[0].id, "qunit-fixture", "Filtered parents check2" ); + same( jQuery("#groups").parents("p, div").get(), q("ap", "qunit-fixture"), "Check for multiple filters" ); + same( jQuery("#en, #sndp").parents().get(), q("foo", "qunit-fixture", "dl", "body", "html"), "Check for unique results from parents" ); }); test("parentsUntil([String])", function() { @@ -367,7 +373,7 @@ test("parentsUntil([String])", function() { same( jQuery("#groups").parentsUntil("#html").get(), parents.not(":last").get(), "Simple parentsUntil check" ); equals( jQuery("#groups").parentsUntil("#ap").length, 0, "Simple parentsUntil check" ); same( jQuery("#groups").parentsUntil("#html, #body").get(), parents.slice( 0, 3 ).get(), "Less simple parentsUntil check" ); - same( jQuery("#groups").parentsUntil("#html", "div").get(), jQuery("#main").get(), "Filtered parentsUntil check" ); + same( jQuery("#groups").parentsUntil("#html", "div").get(), jQuery("#qunit-fixture").get(), "Filtered parentsUntil check" ); same( jQuery("#groups").parentsUntil("#html", "p,div,dl").get(), parents.slice( 0, 3 ).get(), "Multiple-filtered parentsUntil check" ); equals( jQuery("#groups").parentsUntil("#html", "span").length, 0, "Filtered parentsUntil check, no match" ); same( jQuery("#groups, #ap").parentsUntil("#html", "p,div,dl").get(), parents.slice( 0, 3 ).get(), "Multi-source, multiple-filtered parentsUntil check" ); @@ -483,7 +489,12 @@ test("add(String|Element|Array|undefined)", function() { expect(16); same( jQuery("#sndp").add("#en").add("#sap").get(), q("sndp", "en", "sap"), "Check elements from document" ); same( jQuery("#sndp").add( jQuery("#en")[0] ).add( jQuery("#sap") ).get(), q("sndp", "en", "sap"), "Check elements from document" ); - ok( jQuery([]).add(jQuery("#form")[0].elements).length >= 13, "Check elements from array" ); + + // We no longer support .add(form.elements), unfortunately. + // There is no way, in browsers, to reliably determine the difference + // between form.elements and form - and doing .add(form) and having it + // add the form elements is way to unexpected, so this gets the boot. + // ok( jQuery([]).add(jQuery("#form")[0].elements).length >= 13, "Check elements from array" ); // For the time being, we're discontinuing support for jQuery(form.elements) since it's ambiguous in IE // use jQuery([]).add(form.elements) instead. @@ -519,12 +530,13 @@ test("add(String|Element|Array|undefined)", function() { var notDefined; equals( jQuery([]).add(notDefined).length, 0, "Check that undefined adds nothing" ); - ok( jQuery([]).add( document.getElementById("form") ).length >= 13, "Add a form (adds the elements)" ); + equals( jQuery([]).add( document.getElementById("form") ).length, 1, "Add a form" ); + equals( jQuery([]).add( document.getElementById("select1") ).length, 1, "Add a select" ); }); test("add(String, Context)", function() { expect(6); - + 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" ); |