Selector: Port Sizzle tests to jQuery

Apart from porting most Sizzle tests to jQuery (mostly to its selector module),
this commit fixes selector-native so that a jQuery custom compilation that
excludes Sizzle passes all tests as well.

Closes gh-4406
This commit is contained in:
Michał Gołębiowski-Owczarek 2019-06-26 21:39:10 +02:00 committed by GitHub
parent 438b1a3e8a
commit 79b74e043a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1899 additions and 175 deletions

View File

@ -34,6 +34,7 @@ define( [
*/
var hasDuplicate, sortInput,
rhtmlSuffix = /HTML$/i,
sortStable = jQuery.expando.split( "" ).sort( sortOrder ).join( "" ) === jQuery.expando,
// Support: IE 9 - 11+
@ -199,11 +200,14 @@ jQuery.extend( {
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains( bup ) );
},
isXMLDoc: function( elem ) {
var namespace = elem.namespaceURI,
documentElement = ( elem.ownerDocument || elem ).documentElement;
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = elem && ( elem.ownerDocument || elem ).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
// Assume HTML when documentElement doesn't yet exist, such as inside
// document fragments.
return !rhtmlSuffix.test( namespace ||
documentElement && documentElement.nodeName ||
"HTML" );
},
expr: {
attrHandle: {},

View File

@ -18,6 +18,7 @@
"ajaxTest": false,
"testIframe": false,
"createDashboardXML": false,
"createWithFriesXML": false,
"createXMLFragment": false,
"moduleTeardown": false,
"url": false,

View File

@ -1,8 +1,8 @@
<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>,
Here are some [links] in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>,
<a id="groups" href="http://groups.google.com/" class="GROUPS">Google Groups (Link)</a>.
This link has <code><a href="http://smin" id="anchor1">class="blog"</a></code>:
This link has <code id="code1"><a href="http://smin" id="anchor1">class="blog"</a></code>:
<a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a>
</p>
@ -78,11 +78,11 @@
<param name="p2" value="x2" />
</object>
<span id="台北Táiběi"></span>
<span id="台北Táiběi"><span id="台北Táiběi-child"></span></span>
<span id="台北" lang="中文"></span>
<span id="utf8class1" class="台北Táiběi 台北"></span>
<span id="utf8class1" class="台北Táiběi 台北">"'台北Táiběi"'</span>
<span id="utf8class2" class="台北"></span>
<span id="foo:bar" class="foo:bar"></span>
<span id="foo:bar" class="foo:bar"><span id="foo_descendant"></span></span>
<span id="test.foo[5]bar" class="test.foo[5]bar"></span>
<foo_bar id="foobar">test element</foo_bar>
@ -163,7 +163,26 @@ Z</textarea>
<div id="t6652">
<div></div>
</div>
<div id="t12087">
<input type="hidden" id="el12087" data-comma="0,1"/>
</div>
<div id="no-clone-exception"><object><embed></embed></object></div>
<div id="names-group">
<span id="name-is-example" name="example"></span>
<span id="name-is-div" name="div"></span>
</div>
<div id="id-name-tests">
<a id="tName1ID" name="tName1"><span></span></a>
<a id="tName2ID" name="tName2"><span></span></a>
<div id="tName1"><span id="tName1-span">C</span></div>
</div>
<div id="whitespace-lists">
<input id="t15233-single" data-15233="foo"/>
<input id="t15233-double" data-15233="foo bar"/>
<input id="t15233-double-tab" data-15233="foo bar"/>
<input id="t15233-double-nl" data-15233="foo&#xA;bar"/>
<input id="t15233-triple" data-15233="foo bar baz"/>
</div>
</div>
<div id="tabindex-tests">
@ -194,6 +213,53 @@ Z</textarea>
<span id="liveSpan2"><a href="#" id="liveLink2"></a></span>
</div>
<form id="disabled-tests">
<fieldset id="disabled-fieldset" disabled="disabled">
<a id="disabled-fieldset-a" href="#"></a>
<input id="disabled-fieldset-input" name="disabled-fieldset-input" type="text" />
<textarea id="disabled-fieldset-textarea" name="disabled-fieldset-textarea" ></textarea>
<button id="disabled-fieldset-button" name="disabled-fieldset-button">Go</button>
<!-- exclude <select> because IE6 is bugged and fails
<select id="disabled-fieldset-select" name="disabled-fieldset-select"></select>
-->
<span id="disabled-fieldset-span">Neither enabled nor disabled</span>
</fieldset>
<fieldset id="enabled-fieldset">
<a id="disabled-a" href="#" disabled="disabled"></a>
<input id="disabled-input" name="disabled-input" type="text" disabled="disabled"/>
<textarea id="disabled-textarea" name="disabled-textarea" disabled="disabled"></textarea>
<button id="disabled-button" name="disabled-button" disabled="disabled">Go</button>
<select id="disabled-select" name="disabled-select" disabled="disabled">
<optgroup id="disabled-optgroup" label="and" disabled="disabled">
<option id="disabled-option" disabled="disabled">Black</option>
</optgroup>
</select>
<input id="enabled-input" name="enabled-input" type="text"/>
<textarea id="enabled-textarea" name="enabled-textarea"></textarea>
<button id="enabled-button" name="enabled-button">Go</button>
<select id="enabled-select" name="enabled-select">
<optgroup id="enabled-optgroup" label="and">
<option id="enabled-option">Gold</option>
</optgroup>
</select>
<span id="enabled-fieldset-span">Neither enabled nor disabled</span>
</fieldset>
<select id="disabled-select-inherit" name="disabled-select-inherit" disabled="disabled">
<optgroup id="disabled-optgroup-inherit" label="and" disabled="disabled">
<option id="disabled-optgroup-option">Black</option>
</optgroup>
<optgroup id="enabled-optgroup-inherit" label="and">
<option id="enabled-optgroup-option">Gold</option>
</optgroup>
</select>
<select id="enabled-select-inherit" name="enabled-select-inherit">
<optgroup id="en_disabled-optgroup-inherit" label="and" disabled="disabled">
<option id="en_disabled-optgroup-option">Black</option>
</optgroup>
<option id="enabled-select-option">Black</option>
</select>
</form>
<div id="siblingTest">
<em id="siblingfirst">1</em>
<em id="siblingnext">2</em>
@ -208,7 +274,7 @@ Z</textarea>
</div>
<div id="fx-test-group" style="position: absolute; width: 1px; height: 1px; overflow: hidden;">
<div id="fx-queue" name="test">
<div id="fadein" class='chain-test' name='div'>fadeIn<div>fadeIn</div></div>
<div id="fadein" class='chain-test'>fadeIn<div>fadeIn</div></div>
<div id="fadeout" class='chain-test chain-test-out'>fadeOut<div>fadeOut</div></div>
<div id="show" class='chain-test'>show<div>show</div></div>
@ -235,3 +301,4 @@ Z</textarea>
<div id="fx-tests"></div>
<span id="display"></span>
</div>
<br id="last"/>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jQuery selector - cross-window uniqueSort</title>
<script src="../../jquery.js"></script>
<script src="../iframeTest.js"></script>
</head>
<body>
<script>
var doc = parent.document,
unframed = [ doc.getElementById( "qunit-fixture" ), doc.body, doc.documentElement ],
framed = jQuery.find( "*" );
parent.console.log( unframed );
startIframeTest(
jQuery.uniqueSort( unframed.concat( framed ) ),
framed.concat( unframed.slice(0).reverse() )
);
</script>
</body>
</html>

View File

@ -51,15 +51,9 @@ this.q = function() {
* @example match("Check for something", "p", ["foo", "bar"]);
*/
function match( message, selector, expectedIds, context, assert ) {
var f = jQuery( selector, context ).get(),
s = "",
i = 0;
var elems = jQuery( selector, context ).get();
for ( ; i < f.length; i++ ) {
s += ( s && "," ) + "\"" + f[ i ].id + "\"";
}
assert.deepEqual( f, q.apply( q, expectedIds ), message + " (" + selector + ")" );
assert.deepEqual( elems, q.apply( q, expectedIds ), message + " (" + selector + ")" );
}
/**
@ -102,6 +96,36 @@ this.createDashboardXML = function() {
return jQuery.parseXML( string );
};
this.createWithFriesXML = function() {
var string = "<?xml version='1.0' encoding='UTF-8'?> \
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' \
xmlns:xsd='http://www.w3.org/2001/XMLSchema' \
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> \
<soap:Body> \
<jsconf xmlns='http://www.example.com/ns1'> \
<response xmlns:ab='http://www.example.com/ns2'> \
<meta> \
<component id='seite1' class='component'> \
<properties xmlns:cd='http://www.example.com/ns3'> \
<property name='prop1'> \
<thing /> \
<value>1</value> \
</property> \
<property name='prop2'> \
<thing att='something' /> \
</property> \
<foo_bar>foo</foo_bar> \
</properties> \
</component> \
</meta> \
</response> \
</jsconf> \
</soap:Body> \
</soap:Envelope>";
return jQuery.parseXML( string );
};
this.createXMLFragment = function() {
var frag,
xml = document.implementation.createDocument( "", "", null );

View File

@ -1278,7 +1278,7 @@ QUnit.test( "addClass(Array)", function( assert ) {
} );
QUnit.test( "addClass(Function) with incoming value", function( assert ) {
assert.expect( 52 );
assert.expect( 57 );
var pass, i,
div = jQuery( "#qunit-fixture div" ),
old = div.map( function() {
@ -1286,10 +1286,8 @@ QUnit.test( "addClass(Function) with incoming value", function( assert ) {
} );
div.addClass( function( i, val ) {
if ( this.id !== "_firebugConsole" ) {
assert.equal( val, old[ i ], "Make sure the incoming value is correct." );
return "test";
}
} );
pass = true;
@ -1355,17 +1353,15 @@ QUnit.test( "removeClass(Array) - simple", function( assert ) {
} );
QUnit.test( "removeClass(Function) with incoming value", function( assert ) {
assert.expect( 52 );
assert.expect( 57 );
var $divs = jQuery( "#qunit-fixture div" ).addClass( "test" ), old = $divs.map( function() {
return jQuery( this ).attr( "class" );
} );
$divs.removeClass( function( i, val ) {
if ( this.id !== "_firebugConsole" ) {
assert.equal( val, old[ i ], "Make sure the incoming value is correct." );
return "test";
}
} );
assert.ok( !$divs.is( ".test" ), "Remove Class" );

View File

@ -380,6 +380,52 @@ QUnit.test( "isXMLDoc - HTML", function( assert ) {
document.body.removeChild( iframe );
} );
QUnit.test( "isXMLDoc - embedded SVG", function( assert ) {
assert.expect( 6 );
var htmlTree = jQuery( "<div>" +
"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1' width='1'>" +
"<desc></desc>" +
"</svg>" +
"</div>"
)[ 0 ];
assert.strictEqual( jQuery.isXMLDoc( htmlTree ), false, "disconnected div element" );
assert.strictEqual( jQuery.isXMLDoc( htmlTree.firstChild ), true,
"disconnected HTML-embedded SVG root element" );
assert.strictEqual( jQuery.isXMLDoc( htmlTree.firstChild.firstChild ), true,
"disconnected HTML-embedded SVG child element" );
document.getElementById( "qunit-fixture" ).appendChild( htmlTree );
assert.strictEqual( jQuery.isXMLDoc( htmlTree ), false, "connected div element" );
assert.strictEqual( jQuery.isXMLDoc( htmlTree.firstChild ), true,
"connected HTML-embedded SVG root element" );
assert.strictEqual( jQuery.isXMLDoc( htmlTree.firstChild.firstChild ), true,
"disconnected HTML-embedded SVG child element" );
} );
QUnit.test( "isXMLDoc - XML", function( assert ) {
assert.expect( 8 );
var xml = createDashboardXML();
var svg = jQuery.parseXML(
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " +
"\"http://www.w3.org/Gaphics/SVG/1.1/DTD/svg11.dtd\">" +
"<svg version='1.1' xmlns='http://www.w3.org/2000/svg'><desc/></svg>"
);
assert.ok( jQuery.isXMLDoc( xml ), "XML document" );
assert.ok( jQuery.isXMLDoc( xml.documentElement ), "XML documentElement" );
assert.ok( jQuery.isXMLDoc( xml.documentElement.firstChild ), "XML child element" );
assert.ok( jQuery.isXMLDoc( jQuery( "tab", xml )[ 0 ] ), "XML tab Element" );
assert.ok( jQuery.isXMLDoc( svg ), "SVG document" );
assert.ok( jQuery.isXMLDoc( svg.documentElement ), "SVG documentElement" );
assert.ok( jQuery.isXMLDoc( svg.documentElement.firstChild ), "SVG child element" );
assert.ok( jQuery.isXMLDoc( jQuery( "desc", svg )[ 0 ] ), "XML desc Element" );
} );
QUnit.test( "XSS via location.hash", function( assert ) {
var done = assert.async();
assert.expect( 1 );
@ -399,14 +445,6 @@ QUnit.test( "XSS via location.hash", function( assert ) {
}
} );
QUnit.test( "isXMLDoc - XML", function( assert ) {
assert.expect( 3 );
var xml = createDashboardXML();
assert.ok( jQuery.isXMLDoc( xml ), "XML document" );
assert.ok( jQuery.isXMLDoc( xml.documentElement ), "XML documentElement" );
assert.ok( jQuery.isXMLDoc( jQuery( "tab", xml )[ 0 ] ), "XML Tab Element" );
} );
QUnit.test( "jQuery('html')", function( assert ) {
assert.expect( 18 );

View File

@ -193,7 +193,7 @@ function testAppendForObject( valueObj, isFragment, assert ) {
function testAppend( valueObj, assert ) {
assert.expect( 78 );
assert.expect( 82 );
testAppendForObject( valueObj, false, assert );
testAppendForObject( valueObj, true, assert );

File diff suppressed because it is too large Load Diff

View File

@ -50,8 +50,24 @@ QUnit.test( "find(node|jQuery object)", function( assert ) {
assert.equal( $two.find( $foo[ 0 ] ).addBack().length, 2, "find preserves the pushStack, see #12009" );
} );
QUnit.test( "is(String|undefined)", function( assert ) {
assert.expect( 23 );
QUnit.test( "is(falsy|invalid)", function( assert ) {
assert.expect( 5 );
assert.ok( !jQuery( "#foo" ).is( 0 ), "Expected false for an invalid expression - 0" );
assert.ok( !jQuery( "#foo" ).is( null ), "Expected false for an invalid expression - null" );
assert.ok( !jQuery( "#foo" ).is( "" ), "Expected false for an invalid expression - \"\"" );
assert.ok( !jQuery( "#foo" ).is( undefined ), "Expected false for an invalid expression - undefined" );
assert.ok( !jQuery( "#foo" ).is( { plain: "object" } ), "Check passing invalid object" );
} );
QUnit.test( "is(String)", function( assert ) {
assert.expect( 33 );
var link = document.getElementById( "simon1" ),
input = document.getElementById( "text1" ),
option = document.getElementById( "option1a" ),
disconnected = document.createElement( "div" );
assert.ok( jQuery( "#form" ).is( "form" ), "Check for element: A form must be a form" );
assert.ok( !jQuery( "#form" ).is( "div" ), "Check for element: A form is not a div" );
assert.ok( jQuery( "#mark" ).is( ".blog" ), "Check for class: Expected class 'blog'" );
@ -67,17 +83,56 @@ QUnit.test( "is(String|undefined)", function( assert ) {
assert.ok( jQuery( "#radio2" ).is( ":checked" ), "Check for pseudoclass: Expected to be checked" );
assert.ok( !jQuery( "#radio1" ).is( ":checked" ), "Check for pseudoclass: Expected not checked" );
assert.ok( !jQuery( "#foo" ).is( 0 ), "Expected false for an invalid expression - 0" );
assert.ok( !jQuery( "#foo" ).is( null ), "Expected false for an invalid expression - null" );
assert.ok( !jQuery( "#foo" ).is( "" ), "Expected false for an invalid expression - \"\"" );
assert.ok( !jQuery( "#foo" ).is( undefined ), "Expected false for an invalid expression - undefined" );
assert.ok( !jQuery( "#foo" ).is( { plain: "object" } ), "Check passing invalid object" );
// test is() with comma-separated expressions
assert.ok( jQuery( "#en" ).is( "[lang=\"en\"],[lang=\"de\"]" ), "Comma-separated; Check for lang attribute: Expect en or de" );
assert.ok( jQuery( "#en" ).is( "[lang=\"de\"],[lang=\"en\"]" ), "Comma-separated; Check for lang attribute: Expect en or de" );
assert.ok( jQuery( "#en" ).is( "[lang=\"en\"] , [lang=\"de\"]" ), "Comma-separated; Check for lang attribute: Expect en or de" );
assert.ok( jQuery( "#en" ).is( "[lang=\"de\"] , [lang=\"en\"]" ), "Comma-separated; Check for lang attribute: Expect en or de" );
link.title = "Don't click me";
assert.ok( jQuery( link ).is( "[rel='bookmark']" ), "attribute-equals string (delimited via apostrophes)" );
assert.ok( jQuery( link ).is( "[rel=bookmark]" ), "attribute-equals identifier" );
assert.ok( jQuery( link ).is( "[\nrel = bookmark\t]" ),
"attribute-equals identifier (whitespace ignored)" );
assert.ok( jQuery( link ).is( "a[title=\"Don't click me\"]" ),
"attribute-equals string containing single quote" );
// jQuery trac-12303
input.setAttribute( "data-pos", ":first" );
assert.ok( jQuery( input ).is( "input[data-pos=\\:first]" ),
"attribute-equals POS in identifier" );
assert.ok( jQuery( input ).is( "input[data-pos=':first']" ),
"attribute-equals POS in string" );
if ( jQuery.find.compile ) {
assert.ok( jQuery( input ).is( ":input[data-pos=':first']" ),
"attribute-equals POS in string after pseudo" );
} else {
assert.ok( "skip", ":input not supported in selector-native" );
}
option.setAttribute( "test", "" );
assert.ok( jQuery( option ).is( "[id=option1a]" ),
"id attribute-equals identifier" );
if ( jQuery.find.compile ) {
assert.ok( jQuery( option ).is( "[id*=option1][type!=checkbox]" ),
"attribute-not-equals identifier" );
} else {
assert.ok( "skip", "attribute-not-equals not supported in selector-native" );
}
assert.ok( jQuery( option ).is( "[id*=option1]" ), "attribute-contains identifier" );
assert.ok( !jQuery( option ).is( "[test^='']" ),
"attribute-starts-with empty string (negative)" );
option.className = "=]";
assert.ok( jQuery( option ).is( ".\\=\\]" ),
"class selector with attribute-equals confusable" );
assert.ok( jQuery( disconnected ).is( "div" ), "disconnected element" );
assert.ok( jQuery( link ).is( "* > *" ), "child combinator matches in document" );
assert.ok( !jQuery( disconnected ).is( "* > *" ), "child combinator fails in fragment" );
} );
QUnit.test( "is() against non-elements (#10178)", function( assert ) {
@ -561,7 +616,11 @@ QUnit.test( "siblings([String])", function( assert ) {
assert.expect( 6 );
assert.deepEqual( jQuery( "#en" ).siblings().get(), q( "sndp", "sap" ), "Check for siblings" );
assert.deepEqual( jQuery( "#nonnodes" ).contents().eq( 1 ).siblings().get(), q( "nonnodesElement" ), "Check for text node siblings" );
assert.deepEqual( jQuery( "#foo" ).siblings( "form, b" ).get(), q( "form", "floatTest", "lengthtest", "name-tests", "testForm" ), "Check for multiple filters" );
assert.deepEqual(
jQuery( "#foo" ).siblings( "form, b" ).get(),
q( "form", "floatTest", "lengthtest", "name-tests", "testForm", "disabled-tests" ),
"Check for multiple filters"
);
var set = q( "sndp", "en", "sap" );
assert.deepEqual( jQuery( "#en, #sndp" ).siblings().get(), set, "Check for unique results from siblings" );