Attributes: Make `.attr( name, false )` remove for all non-ARIA attrs
[jquery.git] / test / unit / selector.js
blob419120e7d7e19b3f77901b4cd1df71c148701550
1 QUnit.module( "selector", {
2         beforeEach: function() {
4                 // Playwright WebKit on macOS doesn't expose `Safari` in its user agent
5                 // string; use the "AppleWebKit" token. This token is also present
6                 // in the Chromium UA, but it is locked to an older version there.
7                 // Modern WebKit (Safari 13+) locks it to `605.1.15`.
8                 this.safari = /\bapplewebkit\/605\.1\.15\b/i.test( navigator.userAgent );
9         },
10         afterEach: moduleTeardown
11 } );
13 QUnit.test( "empty", function( assert ) {
14         assert.expect( 5 );
16         var form;
18         assert.strictEqual( jQuery( "" ).length, 0,
19                 "Empty selector returns an empty array" );
21         assert.deepEqual( jQuery( "div", document.createTextNode( "" ) ).get(), [],
22                 "Text element as context fails silently" );
23         form = document.getElementById( "form" );
24         assert.ok( !jQuery( form ).is( "" ), "Empty string passed to .is() does not match" );
26         if ( QUnit.jQuerySelectors ) {
27                 assert.equal( jQuery( " " ).length, 0, "Empty selector returns an empty array" );
28                 assert.equal( jQuery( "\t" ).length, 0, "Empty selector returns an empty array" );
29         } else {
30                 assert.ok( "skip", "whitespace-only selector not supported in selector-native" );
31                 assert.ok( "skip", "whitespace-only selector not supported in selector-native" );
32         }
33 } );
35 QUnit.test( "star", function( assert ) {
36         assert.expect( 2 );
38         var good, i,
39                 all = jQuery( "*" );
41         assert.ok( all.length >= 30, "Select all" );
42         good = true;
43         for ( i = 0; i < all.length; i++ ) {
44                 if ( all[ i ].nodeType === 8 ) {
45                         good = false;
46                 }
47         }
48         assert.ok( good, "Select all elements, no comment nodes" );
49 } );
51 QUnit.test( "element", function( assert ) {
52         assert.expect( 37 );
54         var i, lengthtest, siblingTest, html,
55                 fixture = document.getElementById( "qunit-fixture" );
57         assert.deepEqual( jQuery( "p", fixture ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a Node context." );
58         assert.deepEqual( jQuery( "p", "#qunit-fixture" ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a selector context." );
59         assert.deepEqual( jQuery( "p", jQuery( "#qunit-fixture" ) ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a jQuery object context." );
60         assert.deepEqual( jQuery( "#qunit-fixture" ).find( "p" ).get(), q( "firstp", "ap", "sndp", "en", "sap", "first" ), "Finding elements with a context via .find()." );
62         assert.ok( jQuery( "#length" ).length, "<input name=\"length\"> cannot be found under IE, see trac-945" );
63         assert.ok( jQuery( "#lengthtest input" ).length, "<input name=\"length\"> cannot be found under IE, see trac-945" );
65         // trac-7533
66         assert.equal( jQuery( "<div id=\"A'B~C.D[E]\"><p>foo</p></div>" ).find( "p" ).length, 1, "Find where context root is a node and has an ID with CSS3 meta characters" );
68         assert.equal( jQuery( "" ).length, 0, "Empty selector returns an empty array" );
69         assert.deepEqual( jQuery( "div", document.createTextNode( "" ) ).get(), [],
70                 "Text element as context fails silently" );
72         assert.t( "Element Selector", "html", [ "html" ] );
73         assert.t( "Element Selector", "body", [ "body" ] );
74         assert.t( "Element Selector", "#qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
76         assert.t( "Leading space", " #qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
77         assert.t( "Leading tab", "\t#qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
78         assert.t( "Leading carriage return", "\r#qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
79         assert.t( "Leading line feed", "\n#qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
80         assert.t( "Leading form feed", "\f#qunit-fixture p", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
81         assert.t( "Trailing space", "#qunit-fixture p ", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
82         assert.t( "Trailing tab", "#qunit-fixture p\t", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
83         assert.t( "Trailing carriage return", "#qunit-fixture p\r",
84                 [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
85         assert.t( "Trailing line feed", "#qunit-fixture p\n", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
86         assert.t( "Trailing form feed", "#qunit-fixture p\f", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
88         assert.deepEqual(
89                 jQuery( jQuery( "div ol" ) ).filter( "#qunit-fixture *" ).get(),
90                 q( "empty", "listWithTabIndex" ),
91                 "Parent Element"
92         );
93         assert.deepEqual(
94                 jQuery( jQuery( "div\tol" ) ).filter( "#qunit-fixture *" ).get(),
95                 q( "empty", "listWithTabIndex" ),
96                 "Parent Element (non-space descendant combinator)"
97         );
99         // Check for unique-ness and sort order
100         assert.deepEqual( jQuery( "p, div p" ), jQuery( "p" ), "Check for duplicates: p, div p" );
102         jQuery( "<h1 id='h1'></h1><h2 id='h2'></h2><h2 id='h2-2'></h2>" ).prependTo( "#qunit-fixture" );
103         assert.t( "Checking sort order", "#qunit-fixture h2, #qunit-fixture h1", [ "h1", "h2", "h2-2" ] );
105         if ( QUnit.jQuerySelectorsPos ) {
106                 assert.t( "Checking sort order", "#qunit-fixture h2:first, #qunit-fixture h1:first", [ "h1", "h2" ] );
107         } else {
108                 assert.ok( "skip", "Positional selectors are not supported" );
109         }
111         assert.t( "Checking sort order", "#qunit-fixture p, #qunit-fixture p a",
112                 [ "firstp", "simon1", "ap", "google", "groups", "anchor1", "mark", "sndp", "en", "yahoo",
113                         "sap", "anchor2", "simon", "first" ] );
115         // Test Conflict ID
116         lengthtest = document.getElementById( "lengthtest" );
117         assert.deepEqual( jQuery( "#idTest", lengthtest ).get(), q( "idTest" ),
118                 "Finding element with id of ID." );
119         assert.deepEqual( jQuery( "[name='id']", lengthtest ).get(), q( "idTest" ),
120                 "Finding element with id of ID." );
121         assert.deepEqual( jQuery( "input[id='idTest']", lengthtest ).get(), q( "idTest" ),
122                 "Finding elements with id of ID." );
124         siblingTest = document.getElementById( "siblingTest" );
125         assert.deepEqual( jQuery( "div em", siblingTest ).get(), [],
126                 "Element-rooted QSA does not select based on document context" );
127         assert.deepEqual( jQuery( "div em, div em, div em:not(div em)", siblingTest ).get(), [],
128                 "Element-rooted QSA does not select based on document context" );
129         assert.deepEqual( jQuery( "div em, em\\,", siblingTest ).get(), [],
130                 "Escaped commas do not get treated with an id in element-rooted QSA" );
132         html = "";
133         for ( i = 0; i < 100; i++ ) {
134                 html = "<div>" + html + "</div>";
135         }
136         html = jQuery( html ).appendTo( document.body );
137         assert.ok( !!jQuery( "body div div div" ).length,
138                 "No stack or performance problems with large amounts of descendants" );
139         assert.ok( !!jQuery( "body>div div div" ).length,
140                 "No stack or performance problems with large amounts of descendants" );
141         html.remove();
143         // Real use case would be using .watch in browsers with window.watch
144         // (see https://github.com/jquery/sizzle/pull/157)
145         q( "qunit-fixture" )[ 0 ].appendChild( document.createElement( "toString" ) ).id = "toString";
146         assert.t( "Element name matches Object.prototype property", "toString#toString", [ "toString" ] );
147 } );
149 QUnit.test( "XML Document Selectors", function( assert ) {
150         assert.expect( 11 );
152         var xml = createWithFriesXML();
154         assert.equal( jQuery( "foo_bar", xml ).length, 1, "Element Selector with underscore" );
155         assert.equal( jQuery( ".component", xml ).length, 1, "Class selector" );
156         assert.equal( jQuery( "[class*=component]", xml ).length, 1, "Attribute selector for class" );
157         assert.equal( jQuery( "property[name=prop2]", xml ).length, 1, "Attribute selector with name" );
158         assert.equal( jQuery( "[name=prop2]", xml ).length, 1, "Attribute selector with name" );
159         assert.equal( jQuery( "#seite1", xml ).length, 1, "Attribute selector with ID" );
160         assert.equal( jQuery( "component#seite1", xml ).length, 1, "Attribute selector with ID" );
161         assert.equal( jQuery( "component", xml ).filter( "#seite1" ).length, 1,
162                 "Attribute selector filter with ID" );
163         assert.equal( jQuery( "meta property thing", xml ).length, 2,
164                 "Descendent selector and dir caching" );
165         if ( QUnit.jQuerySelectors ) {
166                 assert.ok( jQuery( xml.lastChild ).is( "soap\\:Envelope" ), "Check for namespaced element" );
168                 xml = jQuery.parseXML( "<?xml version='1.0' encoding='UTF-8'?><root><elem id='1'/></root>" );
170                 assert.equal( jQuery( "elem:not(:has(*))", xml ).length, 1,
171                         "Non-qSA path correctly handles numeric ids (jQuery trac-14142)" );
172         } else {
173                 assert.ok( "skip", "namespaced elements not matching correctly in selector-native" );
174                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
175         }
176 } );
178 QUnit.test( "broken selectors throw", function( assert ) {
179         assert.expect( 33 );
181         function broken( name, selector ) {
182                 assert.throws( function() {
183                         jQuery( selector );
184                 }, name + ": " + selector );
185         }
187         broken( "Broken Selector", "[" );
188         broken( "Broken Selector", "(" );
189         broken( "Broken Selector", "{" );
190         broken( "Broken Selector", "<" );
191         broken( "Broken Selector", "()" );
192         broken( "Broken Selector", "<>" );
193         broken( "Broken Selector", "{}" );
194         broken( "Broken Selector", "," );
195         broken( "Broken Selector", ",a" );
196         broken( "Broken Selector", "a," );
197         broken( "Post-comma invalid selector", "*,:x" );
198         broken( "Identifier with bad escape", "foo\\\fbaz" );
199         broken( "Broken Selector", "[id=012345678901234567890123456789" );
200         broken( "Doesn't exist", ":visble" );
201         broken( "Nth-child", ":nth-child" );
202         broken( "Nth-child", ":nth-child(-)" );
203         broken( "Nth-child", ":nth-child(asdf)", [] );
204         broken( "Nth-child", ":nth-child(2n+-0)" );
205         broken( "Nth-child", ":nth-child(2+0)" );
206         broken( "Nth-child", ":nth-child(- 1n)" );
207         broken( "Nth-child", ":nth-child(-1 n)" );
208         broken( "First-child", ":first-child(n)" );
209         broken( "Last-child", ":last-child(n)" );
210         broken( "Only-child", ":only-child(n)" );
211         broken( "Nth-last-last-child", ":nth-last-last-child(1)" );
212         broken( "First-last-child", ":first-last-child" );
213         broken( "Last-last-child", ":last-last-child" );
214         broken( "Only-last-child", ":only-last-child" );
216         // Make sure attribute value quoting works correctly. See: trac-6093
217         jQuery( "<input type='hidden' value='2' name='foo.baz' id='attrbad1'/>" +
218                 "<input type='hidden' value='2' name='foo[baz]' id='attrbad2'/>" )
219                 .appendTo( "#qunit-fixture" );
221         broken( "Attribute equals non-value", "input[name=]" );
222         broken( "Attribute equals unquoted non-identifier", "input[name=foo.baz]" );
223         broken( "Attribute equals unquoted non-identifier", "input[name=foo[baz]]" );
224         broken( "Attribute equals bad string", "input[name=''double-quoted'']" );
225         broken( "Attribute equals bad string", "input[name='apostrophe'd']" );
226 } );
228 QUnit.test( "id", function( assert ) {
229         assert.expect( 35 );
231         var fiddle, a, lengthtest;
233         assert.t( "ID Selector", "#body", [ "body" ] );
234         assert.t( "ID Selector w/ Element", "body#body", [ "body" ] );
235         assert.t( "ID Selector w/ Element", "ul#first", [] );
236         assert.t( "ID selector with existing ID descendant", "#firstp #simon1", [ "simon1" ] );
237         assert.t( "ID selector with non-existent descendant", "#firstp #foobar", [] );
238         assert.t( "ID selector using UTF8", "#台北Táiběi", [ "台北Táiběi" ] );
239         assert.t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", [ "台北Táiběi", "台北" ] );
240         assert.t( "Descendant ID selector using UTF8", "div #台北", [ "台北" ] );
241         assert.t( "Child ID selector using UTF8", "form > #台北", [ "台北" ] );
243         assert.t( "Escaped ID", "#foo\\:bar", [ "foo:bar" ] );
245         if ( QUnit.jQuerySelectors ) {
246                 assert.t( "Escaped ID with descendant", "#foo\\:bar span:not(:input)", [ "foo_descendant" ] );
247         } else {
248                 assert.ok( "skip", ":input not supported in selector-native" );
249         }
251         assert.t( "Escaped ID", "#test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
252         assert.t( "Descendant escaped ID", "div #foo\\:bar", [ "foo:bar" ] );
253         assert.t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
254         assert.t( "Child escaped ID", "form > #foo\\:bar", [ "foo:bar" ] );
255         assert.t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
257         fiddle = jQuery( "<div id='fiddle\\Foo'><span id='fiddleSpan'></span></div>" )
258                 .appendTo( "#qunit-fixture" );
260         assert.deepEqual( jQuery( "> span", jQuery( "#fiddle\\\\Foo" )[ 0 ] ).get(),
261                 q( [ "fiddleSpan" ] ), "Escaped ID as context" );
263         fiddle.remove();
265         assert.t( "ID Selector, child ID present", "#form > #radio1", [ "radio1" ] ); // bug trac-267
266         assert.t( "ID Selector, not an ancestor ID", "#form #first", [] );
267         assert.t( "ID Selector, not a child ID", "#form > #option1a", [] );
269         assert.t( "All Children of ID", "#foo > *", [ "sndp", "en", "sap" ] );
270         assert.t( "All Children of ID with no children", "#firstUL > *", [] );
272         assert.equal( jQuery( "#tName1" )[ 0 ].id, "tName1",
273                 "ID selector with same value for a name attribute" );
274         assert.t( "ID selector non-existing but name attribute on an A tag", "#tName2", [] );
275         assert.t( "Leading ID selector non-existing but name attribute on an A tag", "#tName2 span", [] );
276         assert.t( "Leading ID selector existing, retrieving the child", "#tName1 span", [ "tName1-span" ] );
277         assert.equal( jQuery( "div > div #tName1" )[ 0 ].id, jQuery( "#tName1-span" )[ 0 ].parentNode.id,
278                 "Ending with ID" );
280         a = jQuery( "<a id='backslash\\foo'></a>" ).appendTo( "#qunit-fixture" );
281         assert.t( "ID Selector contains backslash", "#backslash\\\\foo", [ "backslash\\foo" ] );
282         a.remove();
284         assert.t( "ID Selector on Form with an input that has a name of 'id'", "#lengthtest", [ "lengthtest" ] );
286         // Run the above test again but with `jQuery.find` directly to avoid the jQuery
287         // quick path that avoids running the selector engine.
288         lengthtest = jQuery.find( "#lengthtest" );
289         assert.strictEqual(
290                 lengthtest && lengthtest[ 0 ],
291                 document.getElementById( "lengthtest" ),
292                 "ID Selector on Form with an input that has a name of 'id' - no quick path (#lengthtest)"
293         );
295         assert.t( "ID selector with non-existent ancestor", "#asdfasdf #foobar", [] ); // bug trac-986
297         assert.deepEqual( jQuery( "div#form", document.body ).get(), [],
298                 "ID selector within the context of another element" );
300         assert.t( "Underscore ID", "#types_all", [ "types_all" ] );
301         assert.t( "Dash ID", "#qunit-fixture", [ "qunit-fixture" ] );
303         assert.t( "ID with weird characters in it", "#name\\+value", [ "name+value" ] );
304 } );
306 QUnit.test( "class", function( assert ) {
307         assert.expect( 32 );
309         assert.deepEqual( jQuery( ".blog", document.getElementsByTagName( "p" ) ).get(),
310                 q( "mark", "simon" ), "Finding elements with a context." );
311         assert.deepEqual( jQuery( ".blog", "p" ).get(),
312                 q( "mark", "simon" ), "Finding elements with a context." );
313         assert.deepEqual( jQuery( ".blog", jQuery( "p" ) ).get(),
314                 q( "mark", "simon" ), "Finding elements with a context." );
315         assert.deepEqual( jQuery( "p" ).find( ".blog" ).get(),
316                 q( "mark", "simon" ), "Finding elements with a context." );
318         assert.t( "Class Selector", ".blog", [ "mark", "simon" ] );
319         assert.t( "Class Selector", ".GROUPS", [ "groups" ] );
320         assert.t( "Class Selector", ".blog.link", [ "simon" ] );
321         assert.t( "Class Selector w/ Element", "a.blog", [ "mark", "simon" ] );
322         assert.t( "Parent Class Selector", "p .blog", [ "mark", "simon" ] );
324         assert.t( "Class selector using UTF8", ".台北Táiběi", [ "utf8class1" ] );
325         assert.t( "Class selector using UTF8", ".台北", [ "utf8class1", "utf8class2" ] );
326         assert.t( "Class selector using UTF8", ".台北Táiběi.台北", [ "utf8class1" ] );
327         assert.t( "Class selector using UTF8", ".台北Táiběi, .台北", [ "utf8class1", "utf8class2" ] );
328         assert.t( "Descendant class selector using UTF8", "div .台北Táiběi", [ "utf8class1" ] );
329         assert.t( "Child class selector using UTF8", "form > .台北Táiběi", [ "utf8class1" ] );
331         assert.t( "Escaped Class", ".foo\\:bar", [ "foo:bar" ] );
332         assert.t( "Escaped Class", ".test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
333         assert.t( "Descendant escaped Class", "div .foo\\:bar", [ "foo:bar" ] );
334         assert.t( "Descendant escaped Class", "div .test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
335         assert.t( "Child escaped Class", "form > .foo\\:bar", [ "foo:bar" ] );
336         assert.t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", [ "test.foo[5]bar" ] );
338         var div = document.createElement( "div" );
339         div.innerHTML = "<div class='test e'></div><div class='test'></div>";
340         assert.deepEqual( jQuery( ".e", div ).get(), [ div.firstChild ], "Finding a second class." );
342         div.lastChild.className = "e";
344         assert.ok( !jQuery( div ).is( ".null" ),
345                 ".null does not match an element with no class" );
346         assert.ok( !jQuery( div.firstChild ).is( ".null div" ),
347                 ".null does not match an element with no class" );
348         div.className = "null";
349         assert.ok( jQuery( div ).is( ".null" ), ".null matches element with class 'null'" );
350         assert.ok( jQuery( div.firstChild ).is( ".null div" ),
351                 "caching system respects DOM changes" );
352         assert.ok( !jQuery( document ).is( ".foo" ),
353                 "testing class on document doesn't error" );
354         assert.ok( !jQuery( window ).is( ".foo" ), "testing class on window doesn't error" );
356         assert.deepEqual( jQuery( ".e", div ).get(), [ div.firstChild, div.lastChild ],
357                 "Finding a modified class." );
359         div.lastChild.className += " hasOwnProperty toString";
360         assert.deepEqual( jQuery( ".e.hasOwnProperty.toString", div ).get(), [ div.lastChild ],
361                 "Classes match Object.prototype properties" );
363         div = jQuery( "<div><svg width='200' height='250' version='1.1'" +
364                 " xmlns='http://www.w3.org/2000/svg'><rect x='10' y='10' width='30' height='30'" +
365                 "class='foo'></rect></svg></div>" )[ 0 ];
366         assert.equal( jQuery( ".foo", div ).length, 1, "Class selector against SVG container" );
367         assert.equal( jQuery( ".foo", div.firstChild ).length, 1,
368                 "Class selector directly against SVG" );
369 } );
371 QUnit.test( "name", function( assert ) {
372         assert.expect( 14 );
374         var form;
376         assert.t( "Name selector", "input[name=action]", [ "text1" ] );
377         assert.t( "Name selector with single quotes", "input[name='action']", [ "text1" ] );
378         assert.t( "Name selector with double quotes", "input[name=\"action\"]", [ "text1" ] );
380         assert.t( "Name selector non-input", "[name=example]", [ "name-is-example" ] );
381         assert.t( "Name selector non-input", "[name=div]", [ "name-is-div" ] );
382         assert.t( "Name selector non-input", "*[name=iframe]", [ "iframe" ] );
384         assert.t( "Name selector for grouped input", "input[name='types[]']", [ "types_all", "types_anime", "types_movie" ] );
386         form = document.getElementById( "form" );
387         assert.deepEqual( jQuery( "input[name=action]", form ).get(), q( "text1" ),
388                 "Name selector within the context of another element" );
389         assert.deepEqual( jQuery( "input[name='foo[bar]']", form ).get(), q( "hidden2" ),
390                 "Name selector for grouped form element within the context of another element" );
392         form = jQuery( "<form><input name='id'/></form>" ).appendTo( "body" );
393         assert.equal( jQuery( "input", form[ 0 ] ).length, 1,
394                 "Make sure that rooted queries on forms (with possible expandos) work." );
396         form.remove();
398         assert.t( "Find elements that have similar IDs", "[name=tName1]", [ "tName1ID" ] );
399         assert.t( "Find elements that have similar IDs", "[name=tName2]", [ "tName2ID" ] );
400         assert.t( "Find elements that have similar IDs", "#tName2ID", [ "tName2ID" ] );
402         assert.t( "Case-sensitivity", "[name=tname1]", [] );
403 } );
405 QUnit.test( "comma-separated", function( assert ) {
406         assert.expect( 10 );
408         var fixture = jQuery( "<div><h2><span></span></h2><div><p><span></span></p><p></p></div></div>" );
410         assert.equal( fixture.find( "h2, div p" ).filter( "p" ).length, 2, "has to find two <p>" );
411         assert.equal( fixture.find( "h2, div p" ).filter( "h2" ).length, 1, "has to find one <h2>" );
412         assert.equal( fixture.find( "h2 , div p" ).filter( "p" ).length, 2, "has to find two <p>" );
413         assert.equal( fixture.find( "h2 , div p" ).filter( "h2" ).length, 1, "has to find one <h2>" );
414         assert.equal( fixture.find( "h2 ,div p" ).filter( "p" ).length, 2, "has to find two <p>" );
415         assert.equal( fixture.find( "h2 ,div p" ).filter( "h2" ).length, 1, "has to find one <h2>" );
416         assert.equal( fixture.find( "h2,div p" ).filter( "p" ).length, 2, "has to find two <p>" );
417         assert.equal( fixture.find( "h2,div p" ).filter( "h2" ).length, 1, "has to find one <h2>" );
418         assert.equal( fixture.find( "h2\t,\rdiv p" ).filter( "p" ).length, 2, "has to find two <p>" );
419         assert.equal( fixture.find( "h2\t,\rdiv p" ).filter( "h2" ).length, 1, "has to find one <h2>" );
420 } );
422 QUnit.test( "comma-separated, only supported natively (gh-5177)", function( assert ) {
423         assert.expect( 5 );
425         var fixture = jQuery( "<div><input/><span></span></div>" );
427         fixture.appendTo( "#qunit-fixture" );
429         assert.equal( fixture.find( "input:valid, span" ).length, 2, "has to find two elements" );
430         assert.equal( fixture.find( "input:valid , span" ).length, 2, "has to find two elements" );
431         assert.equal( fixture.find( "input:valid ,span" ).length, 2, "has to find two elements" );
432         assert.equal( fixture.find( "input:valid,span" ).length, 2, "has to find two elements" );
433         assert.equal( fixture.find( "input:valid\t,\rspan" ).length, 2, "has to find two elements" );
434 } );
436 QUnit.test( "child and adjacent", function( assert ) {
437         assert.expect( 43 );
439         var siblingFirst, en, nothiddendiv;
441         assert.t( "Child", "p > a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] );
442         assert.t( "Child minus leading whitespace", "p> a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] );
443         assert.t( "Child minus trailing whitespace", "p >a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] );
444         assert.t( "Child minus whitespace", "p>a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] );
445         assert.t( "Child w/ Class", "p > a.blog", [ "mark", "simon" ] );
446         assert.t( "All Children", "code > *", [ "anchor1", "anchor2" ] );
447         assert.selectInFixture( "All Grandchildren", "p > * > *", [ "anchor1", "anchor2" ] );
449         assert.t( "Rooted tag adjacent", "#qunit-fixture a + a", [ "groups", "tName2ID" ] );
450         assert.t( "Rooted tag adjacent minus whitespace", "#qunit-fixture a+a", [ "groups", "tName2ID" ] );
451         assert.t( "Rooted tag adjacent minus leading whitespace", "#qunit-fixture a +a",
452                 [ "groups", "tName2ID" ] );
453         assert.t( "Rooted tag adjacent minus trailing whitespace", "#qunit-fixture a+ a",
454                 [ "groups", "tName2ID" ] );
456         assert.t( "Tag adjacent", "p + p", [ "ap", "en", "sap" ] );
457         assert.t( "#id adjacent", "#firstp + p", [ "ap" ] );
458         assert.t( "Tag#id adjacent", "p#firstp + p", [ "ap" ] );
459         assert.t( "Tag[attr] adjacent", "p[lang=en] + p", [ "sap" ] );
460         assert.t( "Tag.class adjacent", "a.GROUPS + code + a", [ "mark" ] );
461         assert.t( "Comma, Child, and Adjacent", "#qunit-fixture a + a, code > a",
462                 [ "groups", "anchor1", "anchor2", "tName2ID" ] );
464         assert.t( "Element Preceded By", "#qunit-fixture p ~ div",
465                 [ "foo", "nothiddendiv", "moretests", "tabindex-tests", "liveHandlerOrder", "siblingTest", "fx-test-group" ] );
466         assert.t( "Element Preceded By", "#first ~ div",
467                 [ "moretests", "tabindex-tests", "liveHandlerOrder", "siblingTest", "fx-test-group" ] );
468         assert.t( "Element Preceded By", "#groups ~ a", [ "mark" ] );
469         assert.t( "Element Preceded By", "#length ~ input", [ "idTest" ] );
470         assert.t( "Element Preceded By", "#siblingfirst ~ em", [ "siblingnext", "siblingthird" ] );
471         assert.t( "Element Preceded By (multiple)", "#siblingTest em ~ em ~ em ~ span", [ "siblingspan" ] );
473         siblingFirst = document.getElementById( "siblingfirst" );
475         assert.deepEqual( jQuery( "+ em", siblingFirst ).get(), q( "siblingnext" ),
476                 "Element Directly Preceded By with a context." );
477         assert.deepEqual( jQuery( "~ em", siblingFirst ).get(), q( "siblingnext", "siblingthird" ),
478                 "Element Preceded By with a context." );
480         if ( QUnit.jQuerySelectorsPos ) {
481                 assert.deepEqual( jQuery( "~ em:first", siblingFirst ).get(), q( "siblingnext" ),
482                         "Element Preceded By positional with a context." );
483         } else {
484                 assert.ok( "skip", "Positional selectors are not supported" );
485         }
487         en = document.getElementById( "en" );
488         assert.deepEqual( jQuery( "+ p, a", en ).get(), q( "yahoo", "sap" ),
489                 "Compound selector with context, beginning with sibling test." );
490         assert.deepEqual( jQuery( "a, + p", en ).get(), q( "yahoo", "sap" ),
491                 "Compound selector with context, containing sibling test." );
493         if ( QUnit.jQuerySelectors ) {
494                 assert.t( "Element Preceded By, Containing", "#liveHandlerOrder ~ div em:contains('1')", [ "siblingfirst" ] );
495                 assert.t( "Combinators are not skipped when mixing general and specific", "#siblingTest > em:contains('x') + em ~ span", [] );
496         } else {
497                 assert.ok( "skip", ":contains not supported in selector-native" );
498                 assert.ok( "skip", ":contains not supported in selector-native" );
499         }
501         if ( QUnit.jQuerySelectorsPos ) {
502                 assert.equal( jQuery( "#listWithTabIndex li:eq(2) ~ li" ).length, 1, "Find by general sibling combinator (trac-8310)" );
504                 nothiddendiv = document.getElementById( "nothiddendiv" );
505                 assert.deepEqual( jQuery( "> :first", nothiddendiv ).get(), q( "nothiddendivchild" ),
506                         "Verify child context positional selector" );
507                 assert.deepEqual( jQuery( "> :eq(0)", nothiddendiv ).get(), q( "nothiddendivchild" ),
508                         "Verify child context positional selector" );
509                 assert.deepEqual( jQuery( "> *:first", nothiddendiv ).get(), q( "nothiddendivchild" ),
510                         "Verify child context positional selector" );
511         } else {
512                 assert.ok( "skip", "Positional selectors are not supported" );
513                 assert.ok( "skip", "Positional selectors are not supported" );
514                 assert.ok( "skip", "Positional selectors are not supported" );
515                 assert.ok( "skip", "Positional selectors are not supported" );
516         }
518         assert.t( "Multiple combinators selects all levels", "#siblingTest em *", [ "siblingchild", "siblinggrandchild", "siblinggreatgrandchild" ] );
519         assert.t( "Multiple combinators selects all levels", "#siblingTest > em *", [ "siblingchild", "siblinggrandchild", "siblinggreatgrandchild" ] );
520         assert.t( "Multiple sibling combinators doesn't miss general siblings", "#siblingTest > em:first-child + em ~ span", [ "siblingspan" ] );
522         assert.equal( jQuery( "#listWithTabIndex" ).length, 1, "Parent div for next test is found via ID (trac-8310)" );
523         assert.equal( jQuery( "#__sizzle__" ).length, 0, "Make sure the temporary id assigned by sizzle is cleared out (trac-8310)" );
524         assert.equal( jQuery( "#listWithTabIndex" ).length, 1, "Parent div for previous test is still found via ID (trac-8310)" );
526         assert.t( "Verify deep class selector", "div.blah > p > a", [] );
527         assert.t( "No element deep selector", "div.foo > span > a", [] );
528         assert.t( "Non-existent ancestors", ".fototab > .thumbnails > a", [] );
529 } );
531 QUnit.test( "attributes - existence", function( assert ) {
532         assert.expect( 7 );
534         assert.t( "On element", "#qunit-fixture a[title]", [ "google" ] );
535         assert.t( "On element (whitespace ignored)", "#qunit-fixture a[ title ]", [ "google" ] );
536         assert.t( "On element (case-insensitive)", "#qunit-fixture a[TITLE]", [ "google" ] );
537         assert.t( "On any element", "#qunit-fixture *[title]", [ "google" ] );
538         assert.t( "On implicit element", "#qunit-fixture [title]", [ "google" ] );
539         assert.t( "Boolean", "#select2 option[selected]", [ "option2d" ] );
540         assert.t( "For attribute on label", "#qunit-fixture form label[for]", [ "label-for" ] );
541 } );
543 QUnit.test( "attributes - equals", function( assert ) {
544         assert.expect( 20 );
546         var withScript;
548         assert.t( "Identifier", "#qunit-fixture a[rel=bookmark]", [ "simon1" ] );
549         assert.t( "Identifier with underscore", "input[id=types_all]", [ "types_all" ] );
550         assert.t( "String", "#qunit-fixture a[rel='bookmark']", [ "simon1" ] );
551         assert.t( "String (whitespace ignored)", "#qunit-fixture a[ rel = 'bookmark' ]", [ "simon1" ] );
552         assert.t( "Non-identifier string", "#qunit-fixture a[href='https://www.google.com/']", [ "google" ] );
553         assert.t( "Empty string", "#select1 option[value='']", [ "option1a" ] );
555         if ( QUnit.jQuerySelectors ) {
556                 assert.t( "Number",
557                         "#qunit-fixture option[value=1]",
558                         [ "option1b", "option2b", "option3b", "option4b", "option5c" ] );
559                 assert.t( "negative number",
560                         "#qunit-fixture li[tabIndex=-1]", [ "foodWithNegativeTabIndex" ] );
561         } else {
562                 assert.ok( "skip", "Number value not supported in selector-native" );
563                 assert.ok( "skip", "Negative number value not supported in selector-native" );
564         }
566         assert.t( "Non-ASCII identifier", "span[lang=中文]", [ "台北" ] );
568         assert.t( "input[type=text]", "#form input[type=text]", [ "text1", "text2", "hidden2", "name" ] );
569         assert.t( "input[type=search]", "#form input[type=search]", [ "search" ] );
571         withScript = supportjQuery( "<div><span><script src=''></script></span></div>" );
572         assert.ok( withScript.find( "#moretests script[src]" ).has( "script" ), "script[src] (jQuery trac-13777)" );
574         assert.t( "Boolean attribute equals name", "#select2 option[selected='selected']", [ "option2d" ] );
575         assert.t( "for Attribute in form", "#form [for=action]", [ "label-for" ] );
576         assert.t( "Grouped Form Elements - name", "input[name='foo[bar]']", [ "hidden2" ] );
577         assert.t( "Value", "input[value=Test]", [ "text1", "text2" ] );
579         assert.deepEqual(
580                 jQuery( "input[data-comma='0,1']" ).get(),
581                 q( "el12087" ),
582                 "Without context, single-quoted attribute containing ','" );
583         assert.deepEqual(
584                 jQuery( "input[data-comma=\"0,1\"]" ).get(),
585                 q( "el12087" ),
586                 "Without context, double-quoted attribute containing ','" );
587         assert.deepEqual(
588                 jQuery( "input[data-comma='0,1']", document.getElementById( "t12087" ) ).get(),
589                 q( "el12087" ),
590                 "With context, single-quoted attribute containing ','" );
591         assert.deepEqual(
592                 jQuery( "input[data-comma=\"0,1\"]", document.getElementById( "t12087" ) ).get(),
593                 q( "el12087" ),
594                 "With context, double-quoted attribute containing ','" );
595 } );
597 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "attributes - does not equal", function( assert ) {
598         assert.expect( 2 );
600         assert.t( "string", "#ap a[hreflang!='en']", [ "google", "groups", "anchor1" ] );
601         assert.t( "Empty values", "#select1 option[value!='']", [ "option1b", "option1c", "option1d" ] );
602 } );
604 QUnit.test( "attributes - starts with", function( assert ) {
605         assert.expect( 4 );
607         assert.t( "string (whitespace ignored)", "a[href ^= 'https://www']", [ "google", "yahoo" ] );
608         assert.t( "href starts with hash", "p a[href^='#']", [ "anchor2" ] );
609         assert.t( "string containing '['", "input[name^='foo[']", [ "hidden2" ] );
610         assert.t( "string containing '[' ... ']'", "input[name^='foo[bar]']", [ "hidden2" ] );
611 } );
613 QUnit.test( "attributes - contains", function( assert ) {
614         assert.expect( 4 );
616         assert.t( "string (whitespace ignored)", "a[href *= 'google']", [ "google", "groups" ] );
617         assert.t( "string like '[' ... ']']", "input[name*='[bar]']", [ "hidden2" ] );
618         assert.t( "string containing '['...']", "input[name*='foo[bar]']", [ "hidden2" ] );
619         assert.t( "href contains hash", "p a[href*='#']", [ "simon1", "anchor2" ] );
620 } );
622 QUnit.test( "attributes - ends with", function( assert ) {
623         assert.expect( 4 );
625         assert.t( "string (whitespace ignored)", "a[href $= 'org/']", [ "mark" ] );
626         assert.t( "string ending with ']'", "input[name$='bar]']", [ "hidden2" ] );
627         assert.t( "string like '[' ... ']'", "input[name$='[bar]']", [ "hidden2" ] );
628         assert.t( "Attribute containing []", "input[name$='foo[bar]']", [ "hidden2" ] );
629 } );
631 QUnit.test( "attributes - whitespace list includes", function( assert ) {
632         assert.expect( 3 );
634         assert.t( "string found at the beginning",
635                 "input[data-15233~='foo']",
636                 [ "t15233-single", "t15233-double", "t15233-double-tab", "t15233-double-nl", "t15233-triple" ] );
637         assert.t( "string found in the middle",
638                 "input[data-15233~='bar']",
639                 [ "t15233-double", "t15233-double-tab", "t15233-double-nl", "t15233-triple" ] );
640         assert.t( "string found at the end", "input[data-15233~='baz']", [ "t15233-triple" ] );
641 } );
643 QUnit.test( "attributes - hyphen-prefix matches", function( assert ) {
644         assert.expect( 3 );
646         assert.t( "string", "#names-group span[id|='name']", [ "name-is-example", "name-is-div" ] );
647         assert.t( "string containing hyphen",
648                 "#names-group span[id|='name-is']",
649                 [ "name-is-example", "name-is-div" ] );
650         assert.t( "string ending with hyphen", "#names-group span[id|='name-is-']", [] );
651 } );
653 QUnit.test( "attributes - special characters", function( assert ) {
654         assert.expect( 16 );
656         var attrbad;
657         var div = document.createElement( "div" );
659         // trac-3729
660         div.innerHTML = "<div id='foo' xml:test='something'></div>";
661         assert.deepEqual( jQuery( "[xml\\:test]", div ).get(),
662                 [ div.firstChild ],
663                 "attribute name containing colon" );
665         // Make sure attribute value quoting works correctly.
666         // See jQuery trac-6093; trac-6428; trac-13894.
667         // Use seeded results to bypass querySelectorAll optimizations.
668         attrbad = jQuery(
669                 "<input type='hidden' id='attrbad_space' name='foo bar'/>" +
670                 "<input type='hidden' id='attrbad_dot' value='2' name='foo.baz'/>" +
671                 "<input type='hidden' id='attrbad_brackets' value='2' name='foo[baz]'/>" +
672                 "<input type='hidden' id='attrbad_leading_digits' name='agent' value='007'/>" +
673                 "<input type='hidden' id='attrbad_injection' data-attr='foo_baz&#39;]'/>" +
674                 "<input type='hidden' id='attrbad_quote' data-attr='&#39;'/>" +
675                 "<input type='hidden' id='attrbad_backslash' data-attr='&#92;'/>" +
676                 "<input type='hidden' id='attrbad_backslash_quote' data-attr='&#92;&#39;'/>" +
677                 "<input type='hidden' id='attrbad_backslash_backslash' data-attr='&#92;&#92;'/>" +
678                 "<input type='hidden' id='attrbad_unicode' data-attr='&#x4e00;'/>"
679         ).appendTo( "#qunit-fixture" ).get();
682         assert.deepEqual( jQuery( attrbad ).filter( "input[name=foo\\ bar]" ).get(),
683                 q( "attrbad_space" ),
684                 "identifier containing space" );
685         assert.deepEqual( jQuery( attrbad ).filter( "input[name=foo\\.baz]" ).get(),
686                 q( "attrbad_dot" ),
687                 "identifier containing dot" );
688         assert.deepEqual( jQuery( attrbad ).filter( "input[name=foo\\[baz\\]]" ).get(),
689                 q( "attrbad_brackets" ),
690                 "identifier containing brackets" );
691         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='foo_baz\\']']" ).get(),
692                 q( "attrbad_injection" ),
693                 "string containing quote and right bracket" );
695         assert.deepEqual( jQuery( attrbad ).filter( "input[value=\\30 \\30\\37 ]" ).get(),
696                 q( "attrbad_leading_digits" ),
697                 "identifier containing escaped leading digits with whitespace termination" );
698         assert.deepEqual( jQuery( attrbad ).filter( "input[value=\\00003007]" ).get(),
699                 q( "attrbad_leading_digits" ),
700                 "identifier containing escaped leading digits without whitespace termination" );
702         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\'']" ).get(),
703                 q( "attrbad_quote" ),
704                 "string containing quote" );
705         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\\\']" ).get(),
706                 q( "attrbad_backslash" ),
707                 "string containing backslash" );
708         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\\\\\'']" ).get(),
709                 q( "attrbad_backslash_quote" ),
710                 "string containing backslash and quote" );
711         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\\\\\\\']" ).get(),
712                 q( "attrbad_backslash_backslash" ),
713                 "string containing adjacent backslashes" );
715         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\5C\\\\']" ).get(),
716                 q( "attrbad_backslash_backslash" ),
717                 "string containing numeric-escape backslash and backslash" );
718         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\5C \\\\']" ).get(),
719                 q( "attrbad_backslash_backslash" ),
720                 "string containing numeric-escape-with-trailing-space backslash and backslash" );
721         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\5C\t\\\\']" ).get(),
722                 q( "attrbad_backslash_backslash" ),
723                 "string containing numeric-escape-with-trailing-tab backslash and backslash" );
724         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\04e00']" ).get(),
725                 q( "attrbad_unicode" ),
726                 "Long numeric escape (BMP)" );
728         document.getElementById( "attrbad_unicode" ).setAttribute( "data-attr", "\uD834\uDF06A" );
729         assert.deepEqual( jQuery( attrbad ).filter( "input[data-attr='\\01D306A']" ).get(),
730                 q( "attrbad_unicode" ),
731                 "Long numeric escape (non-BMP)" );
732 } );
734 QUnit.test( "attributes - others", function( assert ) {
735         assert.expect( 14 );
737         var div = document.getElementById( "foo" );
739         assert.t( "Find elements with a tabindex attribute", "[tabindex]", [ "listWithTabIndex", "foodWithNegativeTabIndex", "linkWithTabIndex", "linkWithNegativeTabIndex", "linkWithNoHrefWithTabIndex", "linkWithNoHrefWithNegativeTabIndex" ] );
741         assert.t( "Selector list with multiple quoted attribute-equals",
742                 "#form input[type='radio'], #form input[type='hidden']",
743                 [ "radio1", "radio2", "hidden1" ] );
744         assert.t( "Selector list with differently-quoted attribute-equals",
745                 "#form input[type='radio'], #form input[type=\"hidden\"]",
746                 [ "radio1", "radio2", "hidden1" ] );
747         assert.t( "Selector list with quoted and unquoted attribute-equals",
748                 "#form input[type='radio'], #form input[type=hidden]",
749                 [ "radio1", "radio2", "hidden1" ] );
751         assert.t( "Object.prototype property \"constructor\" (negative)", "[constructor]", [] );
752         assert.t( "Gecko Object.prototype property \"watch\" (negative)", "[watch]", [] );
753         div.setAttribute( "constructor", "foo" );
754         div.setAttribute( "watch", "bar" );
755         assert.t( "Object.prototype property \"constructor\"", "[constructor='foo']", [ "foo" ] );
756         assert.t( "Gecko Object.prototype property \"watch\"", "[watch='bar']", [ "foo" ] );
758         // trac-11115
759         assert.ok( jQuery( "<input type='checkbox' checked='checked'/>" ).prop( "checked", false ).is( "[checked]" ),
760                 "[checked] selects by attribute (positive)"
761         );
762         assert.ok( !jQuery( "<input type='checkbox'/>" ).prop( "checked", true ).is( "[checked]" ),
763                 "[checked] selects by attribute (negative)"
764         );
766         assert.t( "empty name", "[name='']", [ "name-empty" ] );
767         assert.t( "prefixed empty name", "#empty-name-parent [name='']", [ "name-empty" ] );
769         var emptyNameContainer = jQuery( ".empty-name-container" );
770         assert.deepEqual( emptyNameContainer.find( "[name='']" ).get(),
771                 q( "name-empty" ),
772                 "empty name with context" );
773         assert.deepEqual( emptyNameContainer.find( "#empty-name-parent [name='']" ).get(),
774                 q( "name-empty" ),
775                 "prefixed empty name with context" );
776 } );
778 QUnit.test( "pseudo - (parent|empty)", function( assert ) {
779         assert.expect( 3 );
780         assert.t( "Empty", "#qunit-fixture ul:empty", [ "firstUL" ] );
781         assert.t( "Empty with comment node", "#qunit-fixture ol:empty", [ "empty" ] );
783         if ( QUnit.jQuerySelectors ) {
784                 assert.t( "Is A Parent", "#qunit-fixture p:parent",
785                         [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
786         } else {
787                 assert.ok( "skip", ":parent not supported in selector-native" );
788         }
789 } );
791 QUnit.test( "pseudo - (first|last|only)-(child|of-type)", function( assert ) {
792         assert.expect( 12 );
794         assert.t( "First Child", "#qunit-fixture p:first-child", [ "firstp", "sndp" ] );
795         assert.t( "First Child (leading id)", "#qunit-fixture p:first-child", [ "firstp", "sndp" ] );
796         assert.t( "First Child (leading class)", ".nothiddendiv div:first-child", [ "nothiddendivchild" ] );
797         assert.t( "First Child (case-insensitive)", "#qunit-fixture p:FIRST-CHILD", [ "firstp", "sndp" ] );
799         assert.t( "Last Child", "#qunit-fixture p:last-child", [ "sap" ] );
800         assert.t( "Last Child (leading id)", "#qunit-fixture a:last-child", [ "simon1", "anchor1", "mark", "yahoo", "anchor2", "simon", "liveLink1", "liveLink2" ] );
802         assert.t( "Only Child", "#qunit-fixture a:only-child", [ "simon1", "anchor1", "yahoo", "anchor2", "liveLink1", "liveLink2" ] );
804         assert.t( "First-of-type", "#qunit-fixture > p:first-of-type", [ "firstp" ] );
805         assert.t( "Last-of-type", "#qunit-fixture > p:last-of-type", [ "first" ] );
806         assert.t( "Only-of-type", "#qunit-fixture > :only-of-type", [ "name+value", "firstUL", "empty", "floatTest", "iframe", "table", "last" ] );
808         // Verify that the child position isn't being cached improperly
809         var secondChildren = jQuery( "p:nth-child(2)" ).before( "<div></div>" );
811         assert.t( "No longer second child", "p:nth-child(2)", [] );
812         secondChildren.prev().remove();
813         assert.t( "Restored second child", "p:nth-child(2)", [ "ap", "en" ] );
814 } );
816 QUnit.test( "pseudo - nth-child", function( assert ) {
817         assert.expect( 30 );
819         assert.t( "Nth-child", "p:nth-child(1)", [ "firstp", "sndp" ] );
820         assert.t( "Nth-child (with whitespace)", "p:nth-child( 1 )", [ "firstp", "sndp" ] );
821         assert.t( "Nth-child (case-insensitive)", "#form #select1 option:NTH-child(3)", [ "option1c" ] );
822         assert.t( "Not nth-child", "#qunit-fixture p:not(:nth-child(1))", [ "ap", "en", "sap", "first" ] );
824         assert.t( "Nth-child(2)", "#qunit-fixture form#form > *:nth-child(2)", [ "text1" ] );
825         assert.t( "Nth-child(2)", "#qunit-fixture form#form > :nth-child(2)", [ "text1" ] );
827         assert.t( "Nth-child(-1)", "#form #select1 option:nth-child(-1)", [] );
828         assert.t( "Nth-child(3)", "#form #select1 option:nth-child(3)", [ "option1c" ] );
829         assert.t( "Nth-child(0n+3)", "#form #select1 option:nth-child(0n+3)", [ "option1c" ] );
830         assert.t( "Nth-child(1n+0)", "#form #select1 option:nth-child(1n+0)", [ "option1a", "option1b", "option1c", "option1d" ] );
831         assert.t( "Nth-child(1n)", "#form #select1 option:nth-child(1n)", [ "option1a", "option1b", "option1c", "option1d" ] );
832         assert.t( "Nth-child(n)", "#form #select1 option:nth-child(n)", [ "option1a", "option1b", "option1c", "option1d" ] );
833         assert.t( "Nth-child(even)", "#form #select1 option:nth-child(even)", [ "option1b", "option1d" ] );
834         assert.t( "Nth-child(odd)", "#form #select1 option:nth-child(odd)", [ "option1a", "option1c" ] );
835         assert.t( "Nth-child(2n)", "#form #select1 option:nth-child(2n)", [ "option1b", "option1d" ] );
836         assert.t( "Nth-child(2n+1)", "#form #select1 option:nth-child(2n+1)", [ "option1a", "option1c" ] );
837         assert.t( "Nth-child(2n + 1)", "#form #select1 option:nth-child(2n + 1)", [ "option1a", "option1c" ] );
838         assert.t( "Nth-child(+2n + 1)", "#form #select1 option:nth-child(+2n + 1)", [ "option1a", "option1c" ] );
839         assert.t( "Nth-child(3n)", "#form #select1 option:nth-child(3n)", [ "option1c" ] );
840         assert.t( "Nth-child(3n+1)", "#form #select1 option:nth-child(3n+1)", [ "option1a", "option1d" ] );
841         assert.t( "Nth-child(3n+2)", "#form #select1 option:nth-child(3n+2)", [ "option1b" ] );
842         assert.t( "Nth-child(3n+3)", "#form #select1 option:nth-child(3n+3)", [ "option1c" ] );
843         assert.t( "Nth-child(3n-1)", "#form #select1 option:nth-child(3n-1)", [ "option1b" ] );
844         assert.t( "Nth-child(3n-2)", "#form #select1 option:nth-child(3n-2)", [ "option1a", "option1d" ] );
845         assert.t( "Nth-child(3n-3)", "#form #select1 option:nth-child(3n-3)", [ "option1c" ] );
846         assert.t( "Nth-child(3n+0)", "#form #select1 option:nth-child(3n+0)", [ "option1c" ] );
847         assert.t( "Nth-child(-1n+3)", "#form #select1 option:nth-child(-1n+3)", [ "option1a", "option1b", "option1c" ] );
848         assert.t( "Nth-child(-n+3)", "#form #select1 option:nth-child(-n+3)", [ "option1a", "option1b", "option1c" ] );
849         assert.t( "Nth-child(-1n + 3)", "#form #select1 option:nth-child(-1n + 3)", [ "option1a", "option1b", "option1c" ] );
851         if ( QUnit.jQuerySelectors || this.safari ) {
852                 assert.deepEqual(
853                         jQuery( [ document.createElement( "a" ) ].concat( q( "ap" ) ) )
854                                 .filter( ":nth-child(n)" )
855                                 .get(),
856                         q( "ap" ),
857                         "Seeded nth-child"
858                 );
859         } else {
861                 // Support: Chrome 75+, Firefox 67+
862                 // Some browsers mark disconnected elements as matching `:nth-child(n)`
863                 // so let's skip the test.
864                 assert.ok( "skip", "disconnected elements match ':nth-child(n)' in Chrome/Firefox" );
865         }
866 } );
868 QUnit.test( "pseudo - nth-last-child", function( assert ) {
869         assert.expect( 30 );
871         jQuery( "#qunit-fixture" ).append( "<form id='nth-last-child-form'></form><i></i><i></i><i></i><i></i>" );
872         assert.t( "Nth-last-child", "form:nth-last-child(5)", [ "nth-last-child-form" ] );
873         assert.t( "Nth-last-child (with whitespace)", "form:nth-last-child( 5 )", [ "nth-last-child-form" ] );
876         assert.t( "Nth-last-child (case-insensitive)", "#form #select1 option:NTH-last-child(3)", [ "option1b" ] );
877         assert.t( "Not nth-last-child", "#qunit-fixture p:not(:nth-last-child(1))", [ "firstp", "ap", "sndp", "en", "first" ] );
879         assert.t( "Nth-last-child(-1)", "#form #select1 option:nth-last-child(-1)", [] );
880         assert.t( "Nth-last-child(3)", "#form #select1 :nth-last-child(3)", [ "option1b" ] );
881         assert.t( "Nth-last-child(3)", "#form #select1 *:nth-last-child(3)", [ "option1b" ] );
882         assert.t( "Nth-last-child(3)", "#form #select1 option:nth-last-child(3)", [ "option1b" ] );
883         assert.t( "Nth-last-child(0n+3)", "#form #select1 option:nth-last-child(0n+3)", [ "option1b" ] );
884         assert.t( "Nth-last-child(1n+0)", "#form #select1 option:nth-last-child(1n+0)", [ "option1a", "option1b", "option1c", "option1d" ] );
885         assert.t( "Nth-last-child(1n)", "#form #select1 option:nth-last-child(1n)", [ "option1a", "option1b", "option1c", "option1d" ] );
886         assert.t( "Nth-last-child(n)", "#form #select1 option:nth-last-child(n)", [ "option1a", "option1b", "option1c", "option1d" ] );
887         assert.t( "Nth-last-child(even)", "#form #select1 option:nth-last-child(even)", [ "option1a", "option1c" ] );
888         assert.t( "Nth-last-child(odd)", "#form #select1 option:nth-last-child(odd)", [ "option1b", "option1d" ] );
889         assert.t( "Nth-last-child(2n)", "#form #select1 option:nth-last-child(2n)", [ "option1a", "option1c" ] );
890         assert.t( "Nth-last-child(2n+1)", "#form #select1 option:nth-last-child(2n+1)", [ "option1b", "option1d" ] );
891         assert.t( "Nth-last-child(2n + 1)", "#form #select1 option:nth-last-child(2n + 1)", [ "option1b", "option1d" ] );
892         assert.t( "Nth-last-child(+2n + 1)", "#form #select1 option:nth-last-child(+2n + 1)", [ "option1b", "option1d" ] );
893         assert.t( "Nth-last-child(3n)", "#form #select1 option:nth-last-child(3n)", [ "option1b" ] );
894         assert.t( "Nth-last-child(3n+1)", "#form #select1 option:nth-last-child(3n+1)", [ "option1a", "option1d" ] );
895         assert.t( "Nth-last-child(3n+2)", "#form #select1 option:nth-last-child(3n+2)", [ "option1c" ] );
896         assert.t( "Nth-last-child(3n+3)", "#form #select1 option:nth-last-child(3n+3)", [ "option1b" ] );
897         assert.t( "Nth-last-child(3n-1)", "#form #select1 option:nth-last-child(3n-1)", [ "option1c" ] );
898         assert.t( "Nth-last-child(3n-2)", "#form #select1 option:nth-last-child(3n-2)", [ "option1a", "option1d" ] );
899         assert.t( "Nth-last-child(3n-3)", "#form #select1 option:nth-last-child(3n-3)", [ "option1b" ] );
900         assert.t( "Nth-last-child(3n+0)", "#form #select1 option:nth-last-child(3n+0)", [ "option1b" ] );
901         assert.t( "Nth-last-child(-1n+3)", "#form #select1 option:nth-last-child(-1n+3)", [ "option1b", "option1c", "option1d" ] );
902         assert.t( "Nth-last-child(-n+3)", "#form #select1 option:nth-last-child(-n+3)", [ "option1b", "option1c", "option1d" ] );
903         assert.t( "Nth-last-child(-1n + 3)", "#form #select1 option:nth-last-child(-1n + 3)", [ "option1b", "option1c", "option1d" ] );
905         if ( QUnit.jQuerySelectors || this.safari ) {
906                 assert.deepEqual(
907                         jQuery( [ document.createElement( "a" ) ].concat( q( "ap" ) ) )
908                                 .filter( ":nth-last-child(n)" )
909                                 .get(),
910                         q( "ap" ),
911                         "Seeded nth-last-child"
912                 );
913         } else {
915                 // Support: Chrome 75+, Firefox 67+
916                 // Some browsers mark disconnected elements as matching `:nth-last-child(n)`
917                 // so let's skip the test.
918                 assert.ok( "skip", "disconnected elements match ':nth-last-child(n)' in Chrome/Firefox" );
919         }
920 } );
922 QUnit.test( "pseudo - nth-of-type", function( assert ) {
923         assert.expect( 9 );
924         assert.t( "Nth-of-type(-1)", ":nth-of-type(-1)", [] );
925         assert.t( "Nth-of-type(3)", "#ap :nth-of-type(3)", [ "mark" ] );
926         assert.t( "Nth-of-type(n)", "#ap :nth-of-type(n)", [ "google", "groups", "code1", "anchor1", "mark" ] );
927         assert.t( "Nth-of-type(0n+3)", "#ap :nth-of-type(0n+3)", [ "mark" ] );
928         assert.t( "Nth-of-type(2n)", "#ap :nth-of-type(2n)", [ "groups" ] );
929         assert.t( "Nth-of-type(even)", "#ap :nth-of-type(even)", [ "groups" ] );
930         assert.t( "Nth-of-type(2n+1)", "#ap :nth-of-type(2n+1)", [ "google", "code1", "anchor1", "mark" ] );
931         assert.t( "Nth-of-type(odd)", "#ap :nth-of-type(odd)", [ "google", "code1", "anchor1", "mark" ] );
932         assert.t( "Nth-of-type(-n+2)", "#qunit-fixture > :nth-of-type(-n+2)", [ "firstp", "ap", "foo", "nothiddendiv", "name+value", "firstUL", "empty", "form", "floatTest", "iframe", "lengthtest", "table", "last" ] );
933 } );
935 QUnit.test( "pseudo - nth-last-of-type", function( assert ) {
936         assert.expect( 9 );
937         assert.t( "Nth-last-of-type(-1)", ":nth-last-of-type(-1)", [] );
938         assert.t( "Nth-last-of-type(3)", "#ap :nth-last-of-type(3)", [ "google" ] );
939         assert.t( "Nth-last-of-type(n)", "#ap :nth-last-of-type(n)", [ "google", "groups", "code1", "anchor1", "mark" ] );
940         assert.t( "Nth-last-of-type(0n+3)", "#ap :nth-last-of-type(0n+3)", [ "google" ] );
941         assert.t( "Nth-last-of-type(2n)", "#ap :nth-last-of-type(2n)", [ "groups" ] );
942         assert.t( "Nth-last-of-type(even)", "#ap :nth-last-of-type(even)", [ "groups" ] );
943         assert.t( "Nth-last-of-type(2n+1)", "#ap :nth-last-of-type(2n+1)", [ "google", "code1", "anchor1", "mark" ] );
944         assert.t( "Nth-last-of-type(odd)", "#ap :nth-last-of-type(odd)", [ "google", "code1", "anchor1", "mark" ] );
945         assert.t( "Nth-last-of-type(-n+2)", "#qunit-fixture > :nth-last-of-type(-n+2)", [ "ap", "name+value", "first", "firstUL", "empty", "floatTest", "iframe", "table", "testForm", "disabled-tests", "siblingTest", "fx-test-group", "last" ] );
946 } );
948 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "pseudo - has", function( assert ) {
949         assert.expect( 4 );
951         assert.selectInFixture( "Basic test", "p:has(a)", [ "firstp", "ap", "en", "sap" ] );
952         assert.selectInFixture( "Basic test (irrelevant whitespace)", "p:has( a )", [ "firstp", "ap", "en", "sap" ] );
953         assert.selectInFixture( "Nested with overlapping candidates",
954                 "div:has(div:has(div:not([id])))",
955                 [ "moretests", "t2037", "fx-test-group", "fx-queue" ] );
957         // Support: Safari 15.4+, Chrome 105+
958         // `qSA` in Safari/Chrome throws for `:has()` with only unsupported arguments
959         // but if you add a supported arg to the list, it will run and just potentially
960         // return no results. Make sure this is accounted for. (gh-5098)
961         // Note: Chrome 105 has this behavior only in 105.0.5195.125 or newer;
962         // initially it shipped with a fully forgiving parsing in `:has()`.
963         assert.t( "Nested with list arguments",
964                 "#qunit-fixture div:has(faketag, div:has(faketag, div:not([id])))",
965                 [ "moretests", "t2037", "fx-test-group", "fx-queue" ] );
966 } );
968 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "pseudo - contains", function( assert ) {
969         assert.expect( 9 );
971         var gh335 = document.getElementById( "qunit-fixture" ).appendChild(
972                 document.createElement( "mark" ) );
973         gh335.id = "gh-335";
974         gh335.appendChild( document.createTextNode( "raw line 1\nline 2" ) );
976         assert.ok( jQuery( "a:contains('')" ).length, "empty string" );
977         assert.t( "unquoted argument", "a:contains(Google)", [ "google", "groups" ] );
978         assert.t( "unquoted argument with whitespace", "a:contains(Google Groups)", [ "groups" ] );
979         assert.t( "quoted argument with whitespace and parentheses",
980                 "a:contains('Google Groups (Link)')", [ "groups" ] );
981         assert.t( "quoted argument with double quotes and parentheses",
982                 "a:contains(\"(Link)\")", [ "groups" ] );
983         assert.t( "unquoted argument with whitespace and paired parentheses",
984                 "a:contains(Google Groups (Link))", [ "groups" ] );
985         assert.t( "unquoted argument with paired parentheses", "a:contains((Link))", [ "groups" ] );
986         assert.t( "quoted argument with CSS escapes",
987                 "span:contains(\"\\\"'\\53F0 \\5317 Ta\\301 ibe\\30C i\")",
988                 [ "utf8class1" ] );
990         assert.t( "collapsed whitespace", "mark:contains('line 1\\A line')", [ "gh-335" ] );
991 } );
993 QUnit.test( "pseudo - misc", function( assert ) {
994         assert.expect( 32 );
996         var select, tmp, input;
998         jQuery( "<h1 id='h1'></h1><h2 id='h2'></h2><h2 id='h2-2'></h2>" ).prependTo( "#qunit-fixture" );
1000         if ( QUnit.jQuerySelectors ) {
1001                 assert.t( "Headers", "#qunit-fixture :header", [ "h1", "h2", "h2-2" ] );
1002                 assert.t( "Headers(case-insensitive)", "#qunit-fixture :Header", [ "h1", "h2", "h2-2" ] );
1003         } else {
1004                 assert.ok( "skip", ":header not supported in selector-native" );
1005                 assert.ok( "skip", ":header not supported in selector-native" );
1006         }
1008         if ( QUnit.jQuerySelectors ) {
1009                 assert.t( "Multiple matches with the same context (cache check)",
1010                         "#form select:has(option:first-child:contains('o'))",
1011                         [ "select1", "select2", "select3", "select4" ]
1012                 );
1013                 assert.ok( jQuery( "#qunit-fixture :not(:has(:has(*)))" ).length, "All not grandparents" );
1015                 select = document.getElementById( "select1" );
1016                 assert.ok( jQuery( select ).is( ":has(option)" ), "Has Option Matches" );
1017         } else {
1018                 assert.ok( "skip", ":has not supported in selector-native" );
1019                 assert.ok( "skip", ":has not supported in selector-native" );
1020                 assert.ok( "skip", ":has not supported in selector-native" );
1021         }
1023         tmp = document.createElement( "div" );
1024         tmp.id = "tmp_input";
1025         document.body.appendChild( tmp );
1027         jQuery.each( [ "button", "submit", "reset" ], function( i, type ) {
1028                 var els = jQuery(
1029                         "<input id='input_%' type='%'/><button id='button_%' type='%'>test</button>"
1030                                 .replace( /%/g, type )
1031                 ).appendTo( tmp );
1033                 if ( QUnit.jQuerySelectors ) {
1034                         assert.t( "Input Buttons :" + type, "#tmp_input :" + type, [ "input_" + type, "button_" + type ] );
1036                         assert.ok( jQuery( els[ 0 ] ).is( ":" + type ), "Input Matches :" + type );
1037                         assert.ok( jQuery( els[ 1 ] ).is( ":" + type ), "Button Matches :" + type );
1038                 } else {
1039                         assert.ok( "skip", ":" + type + " not supported in selector-native" );
1040                         assert.ok( "skip", ":" + type + " not supported in selector-native" );
1041                         assert.ok( "skip", ":" + type + " not supported in selector-native" );
1042                 }
1043         } );
1045         document.body.removeChild( tmp );
1047         // Recreate tmp
1048         tmp = document.createElement( "div" );
1049         tmp.id = "tmp_input";
1050         tmp.innerHTML = "<span>Hello I am focusable.</span>";
1052         // Setting tabIndex should make the element focusable
1053         // https://html.spec.whatwg.org/#the-tabindex-attribute
1054         document.body.appendChild( tmp );
1055         tmp.tabIndex = 0;
1056         tmp.focus();
1057         if ( document.activeElement !== tmp || ( document.hasFocus && !document.hasFocus() ) ||
1058                 ( document.querySelectorAll && !document.querySelectorAll( "div:focus" ).length ) ) {
1059                 assert.ok( true, "The div was not focused. Skip checking the :focus match." );
1060                 assert.ok( true, "The div was not focused. Skip checking the :focus match." );
1061         } else {
1062                 assert.t( "tabIndex element focused", ":focus", [ "tmp_input" ] );
1063                 assert.ok( jQuery( tmp ).is( ":focus" ), ":focus matches tabIndex div" );
1064         }
1066         // Blur tmp
1067         tmp.blur();
1068         document.body.focus();
1069         assert.ok( !jQuery( tmp ).is( ":focus" ), ":focus doesn't match tabIndex div" );
1070         document.body.removeChild( tmp );
1072         // Input focus/active
1073         input = document.createElement( "input" );
1074         input.type = "text";
1075         input.id = "focus-input";
1077         document.body.appendChild( input );
1078         input.focus();
1080         // Inputs can't be focused unless the document has focus
1081         if ( document.activeElement !== input || ( document.hasFocus && !document.hasFocus() ) ||
1082                 ( document.querySelectorAll && !document.querySelectorAll( "input:focus" ).length ) ) {
1083                 assert.ok( true, "The input was not focused. Skip checking the :focus match." );
1084                 assert.ok( true, "The input was not focused. Skip checking the :focus match." );
1085         } else {
1086                 assert.t( "Element focused", "input:focus", [ "focus-input" ] );
1087                 assert.ok( jQuery( input ).is( ":focus" ), ":focus matches" );
1088         }
1090         input.blur();
1092         // When IE is out of focus, blur does not work. Force it here.
1093         if ( document.activeElement === input ) {
1094                 document.body.focus();
1095         }
1097         assert.ok( !jQuery( input ).is( ":focus" ), ":focus doesn't match" );
1098         document.body.removeChild( input );
1101         assert.deepEqual(
1102                 jQuery( "[id='select1'] *:not(:last-child), [id='select2'] *:not(:last-child)", q( "qunit-fixture" )[ 0 ] ).get(),
1103                 q( "option1a", "option1b", "option1c", "option2a", "option2b", "option2c" ),
1104                 "caching system tolerates recursive selection"
1105         );
1107         if ( QUnit.jQuerySelectors ) {
1109                 // Tokenization edge cases
1110                 assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code)", [ "ap" ] );
1111                 assert.t( "Sequential pseudos", "#qunit-fixture p:has(:contains(mark)):has(code):contains(This link)", [ "ap" ] );
1113                 assert.t( "Pseudo argument containing ')'", "p:has(>a.GROUPS[src!=')'])", [ "ap" ] );
1114                 assert.t( "Pseudo argument containing ')'", "p:has(>a.GROUPS[src!=')'])", [ "ap" ] );
1115                 assert.t( "Pseudo followed by token containing ')'", "p:contains(id=\"foo\")[id!=\\)]", [ "sndp" ] );
1116                 assert.t( "Pseudo followed by token containing ')'", "p:contains(id=\"foo\")[id!=')']", [ "sndp" ] );
1118                 assert.t( "Multi-pseudo", "#ap:has(*), #ap:has(*)", [ "ap" ] );
1119                 assert.t( "Multi-pseudo with leading nonexistent id", "#nonexistent:has(*), #ap:has(*)", [ "ap" ] );
1121                 assert.t( "Tokenization stressor", "a[class*=blog]:not(:has(*, :contains(!)), :contains(!)), br:contains(]), p:contains(]):not(.qunit-source), :not(:empty):not(:parent):not(.qunit-source)", [ "ap", "mark", "yahoo", "simon" ] );
1122         } else {
1123                 assert.ok( "skip", ":has not supported in selector-native" );
1124                 assert.ok( "skip", ":has not supported in selector-native" );
1126                 assert.ok( "skip", ":has not supported in selector-native" );
1127                 assert.ok( "skip", ":has not supported in selector-native" );
1128                 assert.ok( "skip", ":contains not supported in selector-native" );
1129                 assert.ok( "skip", ":contains not supported in selector-native" );
1131                 assert.ok( "skip", ":has not supported in selector-native" );
1132                 assert.ok( "skip", ":has supported in selector-native" );
1134                 assert.ok( "skip", ":has not supported in selector-native" );
1135         }
1137         if ( QUnit.jQuerySelectorsPos ) {
1138                 assert.t( "Multi-positional", "#ap:gt(0), #ap:lt(1)", [ "ap" ] );
1139                 assert.t( "Multi-positional with leading nonexistent id", "#nonexistent:gt(0), #ap:lt(1)", [ "ap" ] );
1140         } else {
1141                 assert.ok( "skip", "Positional selectors are not supported" );
1142                 assert.ok( "skip", "Positional selectors are not supported" );
1143         }
1144 } );
1146 QUnit.test( "pseudo - :not", function( assert ) {
1147         assert.expect( 43 );
1149         assert.t( "Not", "a.blog:not(.link)", [ "mark" ] );
1151         if ( QUnit.jQuerySelectors ) {
1152                 assert.t( "Not - multiple", "#form option:not(:contains(Nothing),#option1b,:selected)", [ "option1c", "option1d", "option2b", "option2c", "option3d", "option3e", "option4e", "option5b", "option5c" ] );
1153                 assert.t( "Not - recursive", "#form option:not(:not(:selected))[id^='option3']", [ "option3b", "option3c" ] );
1154         } else {
1155                 assert.ok( "skip", ":contains not supported in selector-native" );
1156                 assert.ok( "skip", ":selected not supported in selector-native" );
1157         }
1159         if ( QUnit.jQuerySelectorsPos ) {
1160                 assert.t( ":not() with :first", "#foo p:not(:first) .link", [ "simon" ] );
1161         } else {
1162                 assert.ok( "skip", "Positional selectors are not supported" );
1163         }
1165         assert.t( ":not() failing interior", "#qunit-fixture p:not(.foo)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1166         assert.t( ":not() failing interior", "#qunit-fixture p:not(#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1168         if ( QUnit.jQuerySelectors || !QUnit.isIE ) {
1169                 assert.t( ":not() failing interior", "#qunit-fixture p:not(div.foo)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1170                 assert.t( ":not() failing interior", "#qunit-fixture p:not(p.foo)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1171                 assert.t( ":not() failing interior", "#qunit-fixture p:not(div#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1172                 assert.t( ":not() failing interior", "#qunit-fixture p:not(p#blargh)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1173         } else {
1175                 // Support: IE 11+
1176                 // IE doesn't support `:not(complex selector)`.
1177                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1178                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1179                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1180                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1181         }
1183         assert.t( ":not Multiple", "#qunit-fixture p:not(a)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1184         assert.t( ":not Multiple", "#qunit-fixture p:not( a )", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1185         assert.t( ":not Multiple", "#qunit-fixture p:not( p )", [] );
1186         assert.t( ":not Multiple", "p:not(p)", [] );
1188         if ( QUnit.jQuerySelectors || !QUnit.isIE ) {
1189                 assert.t( ":not Multiple", "#qunit-fixture p:not(a, b)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1190                 assert.t( ":not Multiple", "#qunit-fixture p:not(a, b, div)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1191                 assert.t( ":not Multiple", "p:not(a,p)", [] );
1192                 assert.t( ":not Multiple", "p:not(p,a)", [] );
1193                 assert.t( ":not Multiple", "p:not(a,p,b)", [] );
1194         } else {
1196                 // Support: IE 11+
1197                 // IE doesn't support `:not(complex selector)`.
1198                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1199                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1200                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1201                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1202                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1203         }
1205         if ( QUnit.jQuerySelectors ) {
1206                 assert.t( ":not Multiple", ":input:not(:image,:input,:submit)", [] );
1207                 assert.t( ":not Multiple", "#qunit-fixture p:not(:has(a), :nth-child(1))", [ "first" ] );
1208         } else {
1209                 assert.ok( "skip", ":image, :input, :submit not supported in selector-native" );
1210                 assert.ok( "skip", ":has not supported in selector-native" );
1211         }
1213         assert.t( "No element not selector", ".container div:not(.excluded) div", [] );
1215         assert.t( ":not() Existing attribute", "#form select:not([multiple])", [ "select1", "select2", "select5" ] );
1216         assert.t( ":not() Equals attribute", "#form select:not([name=select1])", [ "select2", "select3", "select4", "select5" ] );
1217         assert.t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", [ "select2", "select3", "select4", "select5" ] );
1219         assert.t( ":not() Multiple Class", "#foo a:not(.blog)", [ "yahoo", "anchor2" ] );
1220         assert.t( ":not() Multiple Class", "#foo a:not(.link)", [ "yahoo", "anchor2" ] );
1222         if ( QUnit.jQuerySelectors || !QUnit.isIE ) {
1223                 assert.t( ":not() Multiple Class", "#foo a:not(.blog.link)", [ "yahoo", "anchor2" ] );
1224         } else {
1226                 // Support: IE 11+
1227                 // IE doesn't support `:not(complex selector)`.
1228                 assert.ok( "skip", ":not(complex selector) not supported in selector-native" );
1229         }
1231         if ( QUnit.jQuerySelectors ) {
1232                 assert.t( ":not chaining (compound)", "#qunit-fixture div[id]:not(:has(div, span)):not(:has(*))", [ "nothiddendivchild", "divWithNoTabIndex", "fx-tests" ] );
1233                 assert.t( ":not chaining (with attribute)", "#qunit-fixture form[id]:not([action$='formaction']):not(:button)", [ "lengthtest", "name-tests", "testForm", "disabled-tests" ] );
1234                 assert.t( ":not chaining (colon in attribute)", "#qunit-fixture form[id]:not([action='form:action']):not(:button)", [ "form", "lengthtest", "name-tests", "testForm", "disabled-tests" ] );
1235                 assert.t( ":not chaining (colon in attribute and nested chaining)", "#qunit-fixture form[id]:not([action='form:action']:button):not(:input)", [ "form", "lengthtest", "name-tests", "testForm", "disabled-tests" ] );
1236                 assert.t( ":not chaining", "#form select:not(.select1):contains(Nothing) > option:not(option)", [] );
1237         } else {
1238                 assert.ok( "skip", ":has not supported in selector-native" );
1239                 assert.ok( "skip", ":button not supported in selector-native" );
1240                 assert.ok( "skip", ":button not supported in selector-native" );
1241                 assert.ok( "skip", ":button not supported in selector-native" );
1242                 assert.ok( "skip", ":contains not supported in selector-native" );
1243         }
1245         if ( QUnit.jQuerySelectorsPos ) {
1246                 assert.t( "positional :not()", "#foo p:not(:last)", [ "sndp", "en" ] );
1247                 assert.t( "positional :not() prefix", "#foo p:not(:last) a", [ "yahoo" ] );
1248                 assert.t( "compound positional :not()", "#foo p:not(:first, :last)", [ "en" ] );
1249                 assert.t( "compound positional :not()", "#foo p:not(:first, :even)", [ "en" ] );
1250                 assert.t( "compound positional :not()", "#foo p:not(:first, :odd)", [ "sap" ] );
1251                 assert.t( "reordered compound positional :not()", "#foo p:not(:odd, :first)", [ "sap" ] );
1253                 assert.t( "positional :not() with pre-filter", "#foo p:not([id]:first)", [ "en", "sap" ] );
1254                 assert.t( "positional :not() with post-filter", "#foo p:not(:first[id])", [ "en", "sap" ] );
1255                 assert.t( "positional :not() with pre-filter", "#foo p:not([lang]:first)", [ "sndp", "sap" ] );
1256                 assert.t( "positional :not() with post-filter", "#foo p:not(:first[lang])", [ "sndp", "en", "sap" ] );
1257         } else {
1258                 assert.ok( "skip", "Positional selectors are not supported" );
1259                 assert.ok( "skip", "Positional selectors are not supported" );
1260                 assert.ok( "skip", "Positional selectors are not supported" );
1261                 assert.ok( "skip", "Positional selectors are not supported" );
1262                 assert.ok( "skip", "Positional selectors are not supported" );
1263                 assert.ok( "skip", "Positional selectors are not supported" );
1265                 assert.ok( "skip", "Positional selectors are not supported" );
1266                 assert.ok( "skip", "Positional selectors are not supported" );
1267                 assert.ok( "skip", "Positional selectors are not supported" );
1268                 assert.ok( "skip", "Positional selectors are not supported" );
1269         }
1270 } );
1272 QUnit[ QUnit.jQuerySelectorsPos ? "test" : "skip" ]( "pseudo - position", function( assert ) {
1273         assert.expect( 34 );
1275         assert.t( "First element", "#qunit-fixture p:first", [ "firstp" ] );
1276         assert.t( "First element(case-insensitive)", "#qunit-fixture p:fiRst", [ "firstp" ] );
1277         assert.t( "nth Element", "#qunit-fixture p:nth(1)", [ "ap" ] );
1278         assert.t( "First Element", "#qunit-fixture p:first", [ "firstp" ] );
1279         assert.t( "Last Element", "p:last", [ "first" ] );
1280         assert.t( "Even Elements", "#qunit-fixture p:even", [ "firstp", "sndp", "sap" ] );
1281         assert.t( "Odd Elements", "#qunit-fixture p:odd", [ "ap", "en", "first" ] );
1282         assert.t( "Position Equals", "#qunit-fixture p:eq(1)", [ "ap" ] );
1283         assert.t( "Position Equals (negative)", "#qunit-fixture p:eq(-1)", [ "first" ] );
1284         assert.t( "Position Greater Than", "#qunit-fixture p:gt(0)", [ "ap", "sndp", "en", "sap", "first" ] );
1285         assert.t( "Position Less Than", "#qunit-fixture p:lt(3)", [ "firstp", "ap", "sndp" ] );
1286         assert.t( "Position Less Than Big Number", "#qunit-fixture p:lt(9007199254740991)", [ "firstp", "ap", "sndp", "en", "sap", "first" ] );
1288         assert.t( "Check position filtering", "div#nothiddendiv:eq(0)", [ "nothiddendiv" ] );
1289         assert.t( "Check position filtering", "div#nothiddendiv:last", [ "nothiddendiv" ] );
1290         assert.t( "Check position filtering", "div#nothiddendiv:not(:gt(0))", [ "nothiddendiv" ] );
1291         assert.t( "Check position filtering", "#foo > :not(:first)", [ "en", "sap" ] );
1292         assert.t( "Check position filtering", "#qunit-fixture select > :not(:gt(2))", [ "option1a", "option1b", "option1c" ] );
1293         assert.t( "Check position filtering", "#qunit-fixture select:lt(2) :not(:first)", [ "option1b", "option1c", "option1d", "option2a", "option2b", "option2c", "option2d" ] );
1294         assert.t( "Check position filtering", "div.nothiddendiv:eq(0)", [ "nothiddendiv" ] );
1295         assert.t( "Check position filtering", "div.nothiddendiv:last", [ "nothiddendiv" ] );
1296         assert.t( "Check position filtering", "div.nothiddendiv:not(:lt(0))", [ "nothiddendiv" ] );
1298         assert.t( "Check element position", "#qunit-fixture div div:eq(0)", [ "nothiddendivchild" ] );
1299         assert.t( "Check element position", "#select1 option:eq(3)", [ "option1d" ] );
1300         assert.t( "Check element position", "#qunit-fixture div div:eq(10)", [ "no-clone-exception" ] );
1301         assert.t( "Check element position", "#qunit-fixture div div:first", [ "nothiddendivchild" ] );
1302         assert.t( "Check element position", "#qunit-fixture div > div:first", [ "nothiddendivchild" ] );
1303         assert.t( "Check element position", "#qunit-fixture div:first a:first", [ "yahoo" ] );
1304         assert.t( "Check element position", "#qunit-fixture div:first > p:first", [ "sndp" ] );
1305         assert.t( "Check element position", "div#nothiddendiv:first > div:first", [ "nothiddendivchild" ] );
1306         assert.t( "Chained pseudo after a pos pseudo", "#listWithTabIndex li:eq(0):contains(Rice)", [ "foodWithNegativeTabIndex" ] );
1308         assert.t( "Check sort order with POS and comma", "#qunit-fixture em>em>em>em:first-child,div>em:first", [ "siblingfirst", "siblinggreatgrandchild" ] );
1310         assert.t( "Isolated position", "#qunit-fixture :last", [ "last" ] );
1312         assert.deepEqual(
1313                 jQuery( "#qunit-fixture > p" ).filter( "*:lt(2) + *" ).get(),
1314                 q( "ap" ),
1315                 "Seeded pos with trailing relative" );
1317         // jQuery trac-12526
1318         var context = jQuery( "#qunit-fixture" ).append( "<div id='jquery12526'></div>" )[ 0 ];
1319         assert.deepEqual( jQuery( ":last", context ).get(), q( "jquery12526" ),
1320                 "Post-manipulation positional" );
1321 } );
1323 QUnit.test( "pseudo - form", function( assert ) {
1324         assert.expect( 16 );
1326         var extraTexts = jQuery( "<input id=\"impliedText\"/><input id=\"capitalText\" type=\"TEXT\">" ).appendTo( "#form" );
1328         if ( QUnit.jQuerySelectors ) {
1329                 assert.t( "Form element :radio", "#form :radio", [ "radio1", "radio2" ] );
1330                 assert.t( "Form element :checkbox", "#form :checkbox", [ "check1", "check2" ] );
1331                 assert.t( "Form element :text", "#form :text", [ "text1", "text2", "hidden2", "name", "impliedText", "capitalText" ] );
1332                 assert.t( "Form element :radio:checked", "#form :radio:checked", [ "radio2" ] );
1333                 assert.t( "Form element :checkbox:checked", "#form :checkbox:checked", [ "check1" ] );
1334                 assert.t( "Form element :radio:checked, :checkbox:checked", "#form :radio:checked, #form :checkbox:checked", [ "radio2", "check1" ] );
1335         } else {
1336                 assert.ok( "skip", ":radio not supported in selector-native" );
1337                 assert.ok( "skip", ":checkbox not supported in selector-native" );
1338                 assert.ok( "skip", ":text not supported in selector-native" );
1339                 assert.ok( "skip", ":radio not supported in selector-native" );
1340                 assert.ok( "skip", ":checkbox not supported in selector-native" );
1341                 assert.ok( "skip", ":radio not supported in selector-native" );
1342         }
1344         if ( QUnit.jQuerySelectors ) {
1345                 assert.t( "Selected option element",
1346                         "#form option:selected",
1347                         [ "option1a", "option2d", "option3b", "option3c", "option4b", "option4c", "option4d",
1348                                 "option5a" ] );
1349                 assert.t( "Select options via :selected", "#select1 option:selected", [ "option1a" ] );
1350                 assert.t( "Select options via :selected", "#select2 option:selected", [ "option2d" ] );
1351                 assert.t( "Select options via :selected", "#select3 option:selected", [ "option3b", "option3c" ] );
1352                 assert.t( "Select options via :selected", "select[name='select2'] option:selected", [ "option2d" ] );
1353         } else {
1354                 assert.ok( "skip", ":selected not supported in selector-native" );
1355                 assert.ok( "skip", ":selected not supported in selector-native" );
1356                 assert.ok( "skip", ":selected not supported in selector-native" );
1357                 assert.ok( "skip", ":selected not supported in selector-native" );
1358                 assert.ok( "skip", ":selected not supported in selector-native" );
1359         }
1361         if ( QUnit.jQuerySelectors ) {
1362                 assert.t( "Form element :input", "#form :input", [ "text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3", "select4", "select5", "impliedText", "capitalText" ] );
1364                 // trac-12600
1365                 assert.ok(
1366                         jQuery( "<select value='12600'><option value='option' selected='selected'></option><option value=''></option></select>" )
1367                                 .prop( "value", "option" )
1368                                 .is( ":input[value='12600']" ),
1370                         ":input[value=foo] selects select by attribute"
1371                 );
1372                 assert.ok( jQuery( "<input type='text' value='12600'/>" ).prop( "value", "option" ).is( ":input[value='12600']" ),
1373                         ":input[value=foo] selects text input by attribute"
1374                 );
1375         } else {
1376                 assert.ok( "skip", ":input not supported in selector-native" );
1377                 assert.ok( "skip", ":input not supported in selector-native" );
1378                 assert.ok( "skip", ":input not supported in selector-native" );
1379         }
1381         assert.t( "Selected option elements are also :checked", "#form option:checked",
1382                 [ "option1a", "option2d", "option3b", "option3c", "option4b", "option4c", "option4d",
1383                         "option5a" ] );
1384         assert.t( "Hidden inputs are still :enabled",
1385                 "#hidden1:enabled",
1386                 [ "hidden1" ] );
1388         extraTexts.remove();
1389 } );
1391 QUnit.test( "pseudo - :(dis|en)abled, explicitly disabled", function( assert ) {
1392         assert.expect( 2 );
1394         // Set a meaningless disabled property on a common ancestor
1395         var container = document.getElementById( "disabled-tests" );
1396         container.disabled = true;
1398         // Support: IE 6 - 11
1399         // Unset the property where it is not meaningless
1400         if ( document.getElementById( "enabled-input" ).isDisabled ) {
1401                 container.disabled = undefined;
1402         }
1404         assert.t(
1405                 "Explicitly disabled elements",
1406                 "#enabled-fieldset :disabled",
1407                 [ "disabled-input", "disabled-textarea", "disabled-button",
1408                         "disabled-select", "disabled-optgroup", "disabled-option" ]
1409         );
1411         assert.t(
1412                 "Enabled elements",
1413                 "#enabled-fieldset :enabled",
1414                 [ "enabled-input", "enabled-textarea", "enabled-button",
1415                         "enabled-select", "enabled-optgroup", "enabled-option" ]
1416         );
1417 } );
1419 QUnit.test( "pseudo - :(dis|en)abled, optgroup and option", function( assert ) {
1420         assert.expect( 2 );
1422         assert.t(
1423                 ":disabled",
1424                 "#disabled-select-inherit :disabled, #enabled-select-inherit :disabled",
1425                 [ "disabled-optgroup-inherit", "disabled-optgroup-option", "en_disabled-optgroup-inherit",
1426                         "en_disabled-optgroup-option" ]
1427         );
1429         assert.t(
1430                 ":enabled",
1431                 "#disabled-select-inherit :enabled, #enabled-select-inherit :enabled",
1432                 [ "enabled-optgroup-inherit", "enabled-optgroup-option", "enabled-select-option" ]
1433         );
1434 } );
1436 QUnit.test( "pseudo - fieldset:(dis|en)abled", function( assert ) {
1437         assert.expect( 2 );
1439         assert.t( "Disabled fieldset", "fieldset:disabled", [ "disabled-fieldset" ] );
1440         assert.t( "Enabled fieldset", "fieldset:enabled", [ "enabled-fieldset" ] );
1441 } );
1443 QUnit.test( "pseudo - :disabled by ancestry", function( assert ) {
1444         assert.expect( 1 );
1446         assert.t(
1447                 "Inputs inherit disabled from fieldset",
1448                 "#disabled-fieldset :disabled",
1449                 [ "disabled-fieldset-input", "disabled-fieldset-textarea",
1450                         "disabled-fieldset-button" ]
1451         );
1452 } );
1454 QUnit.test( "pseudo - a:(dis|en)abled", function( assert ) {
1455         assert.expect( 2 );
1457         var enabled, disabled,
1458                 container = jQuery( "<div></div>" );
1460         container.appendTo( "#qunit-fixture" );
1462         enabled = container.find( "a:enabled" );
1463         disabled = container.find( "a:disabled" );
1465         assert.strictEqual( enabled.length, 0, ":enabled doesn't match anchor elements" );
1466         assert.strictEqual( disabled.length, 0, ":disabled doesn't match anchor elements" );
1467 } );
1469 QUnit.test( "pseudo - :target and :root", function( assert ) {
1470         assert.expect( 2 );
1472         // Target
1473         var oldHash,
1474                 $link = jQuery( "<a></a>" ).attr( {
1475                         href: "#",
1476                         id: "new-link"
1477                 } ).appendTo( "#qunit-fixture" );
1479         oldHash = window.location.hash;
1480         window.location.hash = "new-link";
1482         assert.t( ":target", ":target", [ "new-link" ] );
1484         $link.remove();
1485         window.location.hash = oldHash;
1487         // Root
1488         assert.equal( jQuery( ":root" )[ 0 ], document.documentElement, ":root selector" );
1489 } );
1491 QUnit.test( "pseudo - :lang", function( assert ) {
1492         assert.expect( QUnit.jQuerySelectors ? 104 : 54 );
1494         var docElem = document.documentElement,
1495                 docXmlLang = docElem.getAttribute( "xml:lang" ),
1496                 docLang = docElem.lang,
1497                 foo = document.getElementById( "foo" ),
1498                 anchor = document.getElementById( "anchor2" ),
1499                 xml = createWithFriesXML(),
1500                 testLang = function( text, elem, container, lang, extra ) {
1501                         var message,
1502                                 full = lang + "-" + extra;
1504                         message = "lang=" + lang + " " + text;
1505                         container.setAttribute( container.ownerDocument.documentElement.nodeName === "HTML" ? "lang" : "xml:lang", lang );
1506                         assertMatch( message, elem, ":lang(" + lang + ")" );
1507                         assertMatch( message, elem, ":lang(" + mixCase( lang ) + ")" );
1508                         assertNoMatch( message, elem, ":lang(" + full + ")" );
1509                         assertNoMatch( message, elem, ":lang(" + mixCase( full ) + ")" );
1510                         assertNoMatch( message, elem, ":lang(" + lang + "-)" );
1511                         assertNoMatch( message, elem, ":lang(" + full + "-)" );
1512                         assertNoMatch( message, elem, ":lang(" + lang + "glish)" );
1513                         assertNoMatch( message, elem, ":lang(" + full + "glish)" );
1515                         message = "lang=" + full + " " + text;
1516                         container.setAttribute( container.ownerDocument.documentElement.nodeName === "HTML" ? "lang" : "xml:lang", full );
1517                         assertMatch( message, elem, ":lang(" + lang + ")" );
1518                         assertMatch( message, elem, ":lang(" + mixCase( lang ) + ")" );
1519                         assertMatch( message, elem, ":lang(" + full + ")" );
1520                         assertMatch( message, elem, ":lang(" + mixCase( full ) + ")" );
1521                         assertNoMatch( message, elem, ":lang(" + lang + "-)" );
1522                         assertNoMatch( message, elem, ":lang(" + full + "-)" );
1523                         assertNoMatch( message, elem, ":lang(" + lang + "glish)" );
1524                         assertNoMatch( message, elem, ":lang(" + full + "glish)" );
1525                 },
1526                 mixCase = function( str ) {
1527                         var ret = str.split( "" ),
1528                                 i = ret.length;
1529                         while ( i-- ) {
1530                                 if ( i & 1 ) {
1531                                         ret[ i ] = ret[ i ].toUpperCase();
1532                                 }
1533                         }
1534                         return ret.join( "" );
1535                 },
1536                 assertMatch = function( text, elem, selector ) {
1537                         assert.ok( jQuery( elem ).is( selector ), text + " match " + selector );
1538                 },
1539                 assertNoMatch = function( text, elem, selector ) {
1540                         assert.ok( !jQuery( elem ).is( selector ), text + " fail " + selector );
1541                 };
1543         // Prefixing and inheritance
1544         assert.ok( jQuery( docElem ).is( ":lang(" + docElem.lang + ")" ), "starting :lang" );
1545         testLang( "document", anchor, docElem, "en", "us" );
1546         testLang( "grandparent", anchor, anchor.parentNode.parentNode, "yue", "hk" );
1547         assert.ok( !jQuery( anchor ).is( ":lang(en), :lang(en-us)" ),
1548                 ":lang does not look above an ancestor with specified lang" );
1549         testLang( "self", anchor, anchor, "es", "419" );
1550         assert.ok(
1551                 !jQuery( anchor ).is( ":lang(en), :lang(en-us), :lang(yue), :lang(yue-hk)" ),
1552                 ":lang does not look above self with specified lang"
1553         );
1555         // Searching by language tag
1556         anchor.parentNode.parentNode.lang = "arab";
1557         anchor.parentNode.lang = anchor.parentNode.id = "ara-sa";
1558         anchor.lang = "ara";
1559         assert.deepEqual( jQuery( ":lang(ara)", foo ).get(), [ anchor.parentNode, anchor ], "Find by :lang" );
1561         // Selector validity
1562         anchor.parentNode.lang = "ara";
1563         anchor.lang = "ara\\b";
1564         assert.deepEqual( jQuery( ":lang(ara\\b)", foo ).get(), [], ":lang respects backslashes" );
1566         // Support: Firefox 114+
1567         // Firefox 114+ no longer match on backslashes in `:lang()`, even when escaped.
1568         // It is an intentional change as `:lang()` parameters are supposed to be valid
1569         // BCP 47 strings. Therefore, we won't attempt to patch it.
1570         // We'll keep this test here until other browsers match the behavior.
1571         // See https://bugzilla.mozilla.org/show_bug.cgi?id=1839747#c1
1572         // See https://github.com/w3c/csswg-drafts/issues/8720#issuecomment-1509242961
1573         //
1574         // assert.deepEqual( jQuery( ":lang(ara\\\\b)", foo ).get(), [ anchor ],
1575         //      ":lang respects escaped backslashes" );
1577         assert.throws( function() {
1578                 jQuery( "#qunit-fixture:lang(c++)" );
1579         }, ":lang value must be a valid identifier" );
1581         if ( QUnit.jQuerySelectors ) {
1583                 // XML
1584                 foo = jQuery( "response", xml )[ 0 ];
1585                 anchor = jQuery( "#seite1", xml )[ 0 ];
1586                 testLang( "XML document", anchor, xml.documentElement, "en", "us" );
1587                 testLang( "XML grandparent", anchor, foo, "yue", "hk" );
1588                 assert.ok( !jQuery( anchor ).is( ":lang(en), :lang(en-us)" ),
1589                         "XML :lang does not look above an ancestor with specified lang" );
1590                 testLang( "XML self", anchor, anchor, "es", "419" );
1591                 assert.ok(
1592                         !jQuery( anchor ).is( ":lang(en), :lang(en-us), :lang(yue), :lang(yue-hk)" ),
1593                         "XML :lang does not look above self with specified lang" );
1594         }
1596         // Cleanup
1597         if ( docXmlLang == null ) {
1598                 docElem.removeAttribute( "xml:lang" );
1599         } else {
1600                 docElem.setAttribute( "xml:lang", docXmlLang );
1601         }
1602         docElem.lang = docLang;
1603 } );
1605 QUnit.test( "context", function( assert ) {
1606         assert.expect( 21 );
1608         var context,
1609                 selector = ".blog",
1610                 expected = q( "mark", "simon" ),
1611                 iframe = document.getElementById( "iframe" ),
1612                 iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
1614         assert.deepEqual( jQuery( selector, document ).get(), expected, "explicit document context" );
1615         assert.deepEqual( jQuery( selector ).get(), expected, "unspecified context becomes document" );
1616         assert.deepEqual( jQuery( selector, undefined ).get(), expected,
1617                 "undefined context becomes document" );
1618         assert.deepEqual( jQuery( selector, null ).get(), expected, "null context becomes document" );
1620         iframeDoc.open();
1621         iframeDoc.write( "<body><p id='foo'>bar</p></body>" );
1622         iframeDoc.close();
1623         expected = [ iframeDoc.getElementById( "foo" ) ];
1624         assert.deepEqual( jQuery( "p", iframeDoc ).get(), expected, "Other document context (simple)" );
1626         if ( QUnit.jQuerySelectors ) {
1627                 assert.deepEqual( jQuery( "p:contains(ar)", iframeDoc ).get(), expected,
1628                         "Other document context (complex)" );
1629         } else {
1630                 assert.ok( "skip", ":contains not supported in selector-native" );
1631         }
1633         assert.deepEqual( jQuery( "span", iframeDoc ).get(), [],
1634                 "Other document context (simple, no results)" );
1635         assert.deepEqual( jQuery( "* span", iframeDoc ).get(), [],
1636                 "Other document context (complex, no results)" );
1638         context = document.getElementById( "nothiddendiv" );
1639         assert.deepEqual( jQuery( "*", context ).get(), q( "nothiddendivchild" ), "<div> context" );
1641         assert.deepEqual( jQuery( "* > *", context ).get(), [], "<div> context (no results)" );
1643         context.removeAttribute( "id" );
1644         assert.deepEqual( jQuery( "*", context ).get(), q( "nothiddendivchild" ), "no-id element context" );
1646         if ( QUnit.jQuerySelectors ) {
1647                 assert.deepEqual( jQuery( "* > *", context ).get(), [], "no-id element context (no results)" );
1648         } else {
1649                 assert.ok( "skip", ":contains not supported in selector-native" );
1650         }
1652         assert.strictEqual( context.getAttribute( "id" ) || "", "", "id not added by no-id selection" );
1654         context = document.getElementById( "lengthtest" );
1655         assert.deepEqual( jQuery( "input", context ).get(), q( "length", "idTest" ), "<form> context" );
1656         assert.deepEqual( jQuery( "select", context ).get(), [], "<form> context (no results)" );
1658         context = document.getElementById( "台北Táiběi" );
1659         expected = q( "台北Táiběi-child" );
1660         assert.deepEqual( jQuery( "span[id]", context ).get(), expected, "context with non-ASCII id" );
1661         assert.deepEqual( jQuery( "#台北Táiběi span[id]", context.parentNode ).get(), expected,
1662                 "context with non-ASCII id selector prefix" );
1664         context = document.createDocumentFragment();
1666         // Capture *independent* expected nodes before they're detached from the page
1667         expected = q( "siblingnext", "siblingspan" );
1668         context.appendChild( document.getElementById( "siblingTest" ) );
1670         assert.deepEqual(
1671                 jQuery( "em:nth-child(2)", context ).get(),
1672                 expected.slice( 0, 1 ),
1673                 "DocumentFragment context"
1674         );
1675         assert.deepEqual( jQuery( "span", context ).get(), expected.slice( 1 ),
1676                 "DocumentFragment context by tag name" );
1677         assert.deepEqual( jQuery( "p", context ).get(), [], "DocumentFragment context (no results)" );
1679         if ( QUnit.jQuerySelectors ) {
1680                 assert.deepEqual(
1681                         jQuery( "em + :not(:has(*)):not(:empty), foo", context.firstChild ).get(),
1682                         expected.slice( 0, 1 ),
1683                         "Non-qSA path correctly sets detached context for sibling selectors (jQuery trac-14351)"
1684                 );
1685         } else {
1686                 assert.ok( "skip", ":has not supported in selector-native" );
1687         }
1688 } );
1690 // Support: IE 11+
1691 // IE doesn't support the :scope pseudo-class so it will trigger MutationObservers.
1692 // The test is skipped there.
1693 QUnit.testUnlessIE( "selectors maintaining context don't trigger mutation observers", function( assert ) {
1694         assert.expect( 1 );
1696         var timeout,
1697                 done = assert.async(),
1698                 container = jQuery( "<div></div>" ),
1699                 child = jQuery( "<div></div>" );
1701         child.appendTo( container );
1702         container.appendTo( "#qunit-fixture" );
1704         var observer = new MutationObserver(  function() {
1705                 clearTimeout( timeout );
1706                 observer.disconnect();
1707                 assert.ok( false, "Mutation observer fired during selection" );
1708                 done();
1709         } );
1710         observer.observe( container[ 0 ], { attributes: true } );
1712         container.find( "div div" );
1714         timeout = setTimeout( function() {
1715                 observer.disconnect();
1716                 assert.ok( true, "Mutation observer didn't fire during selection" );
1717                 done();
1718         } );
1719 } );
1721 QUnit.test( "caching does not introduce bugs", function( assert ) {
1722         assert.expect( 3 );
1724         var sap = document.getElementById( "sap" );
1726         jQuery( ":not(code)", document.getElementById( "ap" ) );
1727         assert.deepEqual(
1728                 jQuery( ":not(code)", document.getElementById( "foo" ) ).get(),
1729                 q( "sndp", "en", "yahoo", "sap", "anchor2", "simon" ),
1730                 "Reusing selector with new context"
1731         );
1733         if ( QUnit.jQuerySelectorsPos ) {
1734                 assert.t( "Deep ancestry caching in post-positional element matcher (jQuery trac-14657)",
1735                         "#qunit-fixture a:lt(3):parent",
1736                         [ "simon1", "google", "groups" ] );
1737         } else {
1738                 assert.ok( "skip", "Positional selectors are not supported" );
1739         }
1741         sap.className = "original";
1742         jQuery( "#qunit-fixture .original" );
1743         document.getElementById( "nothiddendiv" ).appendChild(
1744                 sap.cloneNode( true ) ).className = "clone";
1745         assert.equal( jQuery( "#qunit-fixture .clone [href*='2']" ).length, 1,
1746                 "Cloning does not poison caches" );
1747 } );
1750 QUnit.test( "disconnected nodes", function( assert ) {
1751         assert.expect( 1 );
1753         var $div = jQuery( "<div></div>" );
1754         assert.equal( $div.is( "div" ), true, "Make sure .is('nodeName') works on disconnected nodes." );
1755 } );
1757 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "disconnected nodes", function( assert ) {
1758         assert.expect( 3 );
1760         var $opt = jQuery( "<option></option>" ).attr( "value", "whipit" ).appendTo( "#qunit-fixture" ).detach();
1761         assert.equal( $opt.val(), "whipit", "option value" );
1762         assert.equal( $opt.is( ":selected" ), false, "unselected option" );
1763         $opt.prop( "selected", true );
1764         assert.equal( $opt.is( ":selected" ), true, "selected option" );
1765 } );
1767 // Support: IE 11+
1768 // IE doesn't support Shadow DOM.
1769 QUnit.testUnlessIE( "Shadow DOM nodes supported as root", function( assert ) {
1770         assert.expect( 2 );
1772         var shadowHost = jQuery( "<div></div>" ).appendTo( "#qunit-fixture" )[ 0 ],
1773                 shadowRoot = shadowHost.attachShadow( { mode: "open" } );
1775         shadowRoot.innerHTML = "<div class='vagabond'><p></p></div>";
1776         assert.equal( jQuery( shadowRoot ).find( ".vagabond" ).length, 1,
1777                 "Selection by class with shadow root" );
1778         assert.equal( jQuery( shadowRoot ).find( "p" ).length, 1,
1779                 "Paragraph element selected from shadow root" );
1780 } );
1782 testIframe(
1783         "attributes - jQuery.attr",
1784         "selector/html5_selector.html",
1785         function( assert, jQuery, _window, document ) {
1786                 assert.expect( 38 );
1788                 /**
1789                  * Returns an array of elements with the given IDs
1790                  * q & t are added here for the iFrame's context
1791                  */
1792                 function q() {
1793                         var r = [],
1794                                 i = 0;
1796                         for ( ; i < arguments.length; i++ ) {
1797                                 r.push( document.getElementById( arguments[ i ] ) );
1798                         }
1799                         return r;
1800                 }
1802                 /**
1803                  * Asserts that a select matches the given IDs
1804                  * @example t("Check for something", "//[a]", ["foo", "bar"]);
1805                  * @param {String} message - Assertion name
1806                  * @param {String} selector - jQuery selector
1807                  * @param {Array} expectedIds - Array of ids to construct what is expected
1808                  */
1809                 function t( message, selector, expectedIds ) {
1810                         var elems = jQuery( selector ).get();
1812                         assert.deepEqual( elems, q.apply( q, expectedIds ), message + " (" + selector + ")" );
1813                 }
1815                 // ====== All known boolean attributes, including html5 booleans ======
1816                 // autobuffer, autofocus, autoplay, async, checked,
1817                 // compact, controls, declare, defer, disabled,
1818                 // formnovalidate, hidden, indeterminate (property only),
1819                 // ismap, itemscope, loop, multiple, muted, nohref, noresize,
1820                 // noshade, nowrap, novalidate, open, pubdate, readonly, required,
1821                 // reversed, scoped, seamless, selected, truespeed, visible (skipping visible attribute, which is on a barprop object)
1823                 t( "Attribute Exists", "[autobuffer]",     [ "video1" ] );
1824                 t( "Attribute Exists", "[autofocus]",      [ "text1" ] );
1825                 t( "Attribute Exists", "[autoplay]",       [ "video1" ] );
1826                 t( "Attribute Exists", "[async]",          [ "script1" ] );
1827                 t( "Attribute Exists", "[checked]",        [ "check1" ] );
1828                 t( "Attribute Exists", "[compact]",        [ "dl" ] );
1829                 t( "Attribute Exists", "[controls]",       [ "video1" ] );
1830                 t( "Attribute Exists", "[declare]",        [ "object1" ] );
1831                 t( "Attribute Exists", "[defer]",          [ "script1" ] );
1832                 t( "Attribute Exists", "[disabled]",       [ "check1" ] );
1833                 t( "Attribute Exists", "[formnovalidate]", [ "form1" ] );
1834                 t( "Attribute Exists", "[hidden]",         [ "div1" ] );
1835                 t( "Attribute Exists", "[indeterminate]",  [] );
1836                 t( "Attribute Exists", "[ismap]",          [ "img1" ] );
1837                 t( "Attribute Exists", "[itemscope]",      [ "div1" ] );
1838                 t( "Attribute Exists", "[loop]",           [ "video1" ] );
1839                 t( "Attribute Exists", "[multiple]",       [ "select1" ] );
1840                 t( "Attribute Exists", "[muted]",          [ "audio1" ] );
1841                 t( "Attribute Exists", "[nohref]",         [ "area1" ] );
1842                 t( "Attribute Exists", "[noresize]",       [ "textarea1" ] );
1843                 t( "Attribute Exists", "[noshade]",        [ "hr1" ] );
1844                 t( "Attribute Exists", "[nowrap]",         [ "td1", "div1" ] );
1845                 t( "Attribute Exists", "[novalidate]",     [ "form1" ] );
1846                 t( "Attribute Exists", "[open]",           [ "details1" ] );
1847                 t( "Attribute Exists", "[pubdate]",        [ "article1" ] );
1848                 t( "Attribute Exists", "[readonly]",       [ "text1" ] );
1849                 t( "Attribute Exists", "[required]",       [ "text1" ] );
1850                 t( "Attribute Exists", "[reversed]",       [ "ol1" ] );
1851                 t( "Attribute Exists", "[scoped]",         [ "style1" ] );
1852                 t( "Attribute Exists", "[seamless]",       [ "iframe1" ] );
1853                 t( "Attribute Exists", "[selected]",       [ "option1" ] );
1854                 t( "Attribute Exists", "[truespeed]",      [ "marquee1" ] );
1856                 // Enumerated attributes (these are not boolean content attributes)
1857                 jQuery.expandedEach = jQuery.each;
1858                 jQuery.expandedEach( [ "draggable", "contenteditable", "aria-disabled" ], function( _i, val ) {
1859                         t( "Enumerated attribute", "[" + val + "]", [ "div1" ] );
1860                 } );
1861                 t( "Enumerated attribute", "[spellcheck]", [ "span1" ] );
1863                 t( "tabindex selector does not retrieve all elements in IE6/7 (trac-8473)",
1864                         "form, [tabindex]", [ "form1", "text1" ] );
1865                 t( "Improperly named form elements do not interfere with form selections (trac-9570)", "form[name='formName']", [ "form1" ] );
1866         }
1869 QUnit.test( "find in document fragments", function( assert ) {
1870         assert.expect( 1 );
1872         var elem,
1873                 nonnodes = jQuery( "#nonnodes" ).contents(),
1874                 fragment = document.createDocumentFragment();
1876         nonnodes.each( function() {
1877                 fragment.appendChild( this );
1878         } );
1880         elem = jQuery( fragment ).find( "#nonnodesElement" );
1881         assert.strictEqual( elem.length, 1, "Selection works" );
1882 } );
1884 function getUniqueSortFixtures() {
1885         var i,
1886                 detached = [],
1887                 body = document.body,
1888                 fixture = document.getElementById( "qunit-fixture" ),
1889                 detached1 = document.createElement( "p" ),
1890                 detached2 = document.createElement( "ul" ),
1891                 detachedChild = detached1.appendChild( document.createElement( "a" ) ),
1892                 detachedGrandchild = detachedChild.appendChild( document.createElement( "b" ) );
1894         for ( i = 0; i < 12; i++ ) {
1895                 detached.push( document.createElement( "li" ) );
1896                 detached[ i ].id = "detached" + i;
1897                 detached2.appendChild( document.createElement( "li" ) ).id = "detachedChild" + i;
1898         }
1900         return {
1901                 "Empty": {
1902                         input: [],
1903                         expected: []
1904                 },
1905                 "Single-element": {
1906                         input: [ fixture ],
1907                         expected: [ fixture ]
1908                 },
1909                 "No duplicates": {
1910                         input: [ fixture, body ],
1911                         expected: [ body, fixture ]
1912                 },
1913                 "Duplicates": {
1914                         input: [ body, fixture, fixture, body ],
1915                         expected: [ body, fixture ]
1916                 },
1917                 "Detached": {
1918                         input: detached.slice( 0 ),
1919                         expected: detached.slice( 0 )
1920                 },
1921                 "Detached children": {
1922                         input: [
1923                                 detached2.childNodes[ 3 ],
1924                                 detached2.childNodes[ 0 ],
1925                                 detached2.childNodes[ 2 ],
1926                                 detached2.childNodes[ 1 ]
1927                         ],
1928                         expected: [
1929                                 detached2.childNodes[ 0 ],
1930                                 detached2.childNodes[ 1 ],
1931                                 detached2.childNodes[ 2 ],
1932                                 detached2.childNodes[ 3 ]
1933                         ]
1934                 },
1935                 "Attached/detached mixture": {
1936                         input: [ detached1, fixture, detached2, document, detachedChild, body, detachedGrandchild ],
1937                         expected: [ document, body, fixture ],
1938                         length: 3
1939                 }
1940         };
1943 QUnit.test( "jQuery.uniqueSort", function( assert ) {
1944         assert.expect( 14 );
1946         var fixtures = getUniqueSortFixtures();
1948         function Arrayish( arr ) {
1949                 var i = this.length = arr.length;
1950                 while ( i-- ) {
1951                         this[ i ] = arr[ i ];
1952                 }
1953         }
1954         Arrayish.prototype = {
1955                 sliceForTestOnly: [].slice
1956         };
1958         jQuery.each( fixtures, function( label, fixture ) {
1959                 var length = fixture.length || fixture.input.length;
1961                 // We duplicate `fixture.input` because otherwise it is modified by `uniqueSort`
1962                 // and the second test becomes worthless.
1963                 assert.deepEqual(
1964                         jQuery.uniqueSort( fixture.input.slice( 0 ) )
1965                                 .slice( 0, length ),
1966                         fixture.expected,
1967                         label + " (array)"
1968                 );
1970                 assert.deepEqual(
1971                         jQuery.uniqueSort( new Arrayish( fixture.input ) )
1972                                 .sliceForTestOnly( 0, length ),
1973                         fixture.expected,
1974                         label + " (quasi-array)"
1975                 );
1976         } );
1977 } );
1979 QUnit.test( "uniqueSort()", function( assert ) {
1980         assert.expect( 28 );
1982         var fixtures = getUniqueSortFixtures();
1984         jQuery.each( fixtures, function( label, fixture ) {
1985                 var length = fixture.length || fixture.input.length,
1986                         fixtureInputCopy = fixture.input.slice( 0 ),
1987                         sortedElem = jQuery( fixture.input ).uniqueSort();
1989                 assert.deepEqual( fixture.input, fixtureInputCopy, "Fixture not modified (" + label + ")" );
1991                 assert.deepEqual( sortedElem.slice( 0, length ).toArray(), fixture.expected, label );
1993                 // Chaining
1994                 assert.ok( sortedElem instanceof jQuery, "chaining" );
1995                 assert.deepEqual( sortedElem.end().toArray(), fixture.input, label );
1996         } );
1997 } );
1999 testIframe(
2000         "jQuery.uniqueSort works cross-window (trac-14381)",
2001         "selector/mixed_sort.html",
2002         function( assert, _jQuery, _window, _document, actual, expected ) {
2003                 assert.expect( 1 );
2005                 assert.deepEqual( actual, expected, "Mixed array was sorted correctly" );
2006         }
2009 testIframe(
2010         "jQuery selector cache collides with multiple jQueries on a page",
2011         "selector/cache.html",
2012         function( assert, jQuery, window, document ) {
2013                 var $cached = window.$cached;
2015                 assert.expect( 4 );
2016                 assert.notStrictEqual( jQuery, $cached, "Loaded two engines" );
2017                 assert.deepEqual( $cached( ".test a" ).get(), [ document.getElementById( "collision" ) ], "Select collision anchor with first sizzle" );
2018                 assert.equal( jQuery( ".evil a" ).length, 0, "Select nothing with second sizzle" );
2019                 assert.equal( jQuery( ".evil a" ).length, 0, "Select nothing again with second sizzle" );
2020         }
2023 QUnit.test( "Iframe dispatch should not affect jQuery (trac-13936)", function( assert ) {
2024         assert.expect( 1 );
2025         var loaded = false,
2026                 thrown = false,
2027                 iframe = document.getElementById( "iframe" ),
2028                 iframeDoc = iframe.contentDocument || iframe.contentWindow.document,
2029                 done = assert.async();
2031         jQuery( iframe ).on( "load", function() {
2032                 var form;
2034                 try {
2035                         iframeDoc = this.contentDocument || this.contentWindow.document;
2036                         form = jQuery( "#navigate", iframeDoc )[ 0 ];
2037                 } catch ( e ) {
2038                         thrown = e;
2039                 }
2041                 if ( loaded ) {
2042                         assert.strictEqual( thrown, false, "No error thrown from post-reload jQuery call" );
2044                         // clean up
2045                         jQuery( iframe ).off();
2047                         done();
2048                 } else {
2049                         loaded = true;
2050                         form.submit();
2051                 }
2052         } );
2054         iframeDoc.open();
2055         iframeDoc.write( "<body><form id='navigate' action='?'></form></body>" );
2056         iframeDoc.close();
2057 } );
2059 QUnit.test( "jQuery.escapeSelector", function( assert ) {
2060         assert.expect( 58 );
2062         // Edge cases
2063         assert.equal( jQuery.escapeSelector(), "undefined", "Converts undefined to string" );
2064         assert.equal( jQuery.escapeSelector( "-" ), "\\-", "Escapes standalone dash" );
2065         assert.equal( jQuery.escapeSelector( "-a" ), "-a", "Doesn't escape leading dash followed by non-number" );
2066         assert.equal( jQuery.escapeSelector( "--" ), "--", "Doesn't escape standalone double dash" );
2067         assert.equal( jQuery.escapeSelector( "\uFFFD" ), "\uFFFD",
2068                 "Doesn't escape standalone replacement character" );
2069         assert.equal( jQuery.escapeSelector( "a\uFFFD" ), "a\uFFFD",
2070                 "Doesn't escape trailing replacement character" );
2071         assert.equal( jQuery.escapeSelector( "\uFFFDb" ), "\uFFFDb",
2072                 "Doesn't escape leading replacement character" );
2073         assert.equal( jQuery.escapeSelector( "a\uFFFDb" ), "a\uFFFDb",
2074                 "Doesn't escape embedded replacement character" );
2076         // Derived from CSSOM tests
2077         // https://test.csswg.org/harness/test/cssom-1_dev/section/7.1/
2079         // String conversion
2080         assert.equal( jQuery.escapeSelector( true ), "true", "Converts boolean true to string" );
2081         assert.equal( jQuery.escapeSelector( false ), "false", "Converts boolean true to string" );
2082         assert.equal( jQuery.escapeSelector( null ), "null", "Converts null to string" );
2083         assert.equal( jQuery.escapeSelector( "" ), "", "Doesn't modify empty string" );
2085         // Null bytes
2086         assert.equal( jQuery.escapeSelector( "\0" ), "\uFFFD",
2087                 "Escapes null-character input as replacement character" );
2088         assert.equal( jQuery.escapeSelector( "a\0" ), "a\uFFFD",
2089                 "Escapes trailing-null input as replacement character" );
2090         assert.equal( jQuery.escapeSelector( "\0b" ), "\uFFFDb",
2091                 "Escapes leading-null input as replacement character" );
2092         assert.equal( jQuery.escapeSelector( "a\0b" ), "a\uFFFDb",
2093                 "Escapes embedded-null input as replacement character" );
2095         // Number prefix
2096         assert.equal( jQuery.escapeSelector( "0a" ), "\\30 a", "Escapes leading 0" );
2097         assert.equal( jQuery.escapeSelector( "1a" ), "\\31 a", "Escapes leading 1" );
2098         assert.equal( jQuery.escapeSelector( "2a" ), "\\32 a", "Escapes leading 2" );
2099         assert.equal( jQuery.escapeSelector( "3a" ), "\\33 a", "Escapes leading 3" );
2100         assert.equal( jQuery.escapeSelector( "4a" ), "\\34 a", "Escapes leading 4" );
2101         assert.equal( jQuery.escapeSelector( "5a" ), "\\35 a", "Escapes leading 5" );
2102         assert.equal( jQuery.escapeSelector( "6a" ), "\\36 a", "Escapes leading 6" );
2103         assert.equal( jQuery.escapeSelector( "7a" ), "\\37 a", "Escapes leading 7" );
2104         assert.equal( jQuery.escapeSelector( "8a" ), "\\38 a", "Escapes leading 8" );
2105         assert.equal( jQuery.escapeSelector( "9a" ), "\\39 a", "Escapes leading 9" );
2107         // Letter-number prefix
2108         assert.equal( jQuery.escapeSelector( "a0b" ), "a0b", "Doesn't escape embedded 0" );
2109         assert.equal( jQuery.escapeSelector( "a1b" ), "a1b", "Doesn't escape embedded 1" );
2110         assert.equal( jQuery.escapeSelector( "a2b" ), "a2b", "Doesn't escape embedded 2" );
2111         assert.equal( jQuery.escapeSelector( "a3b" ), "a3b", "Doesn't escape embedded 3" );
2112         assert.equal( jQuery.escapeSelector( "a4b" ), "a4b", "Doesn't escape embedded 4" );
2113         assert.equal( jQuery.escapeSelector( "a5b" ), "a5b", "Doesn't escape embedded 5" );
2114         assert.equal( jQuery.escapeSelector( "a6b" ), "a6b", "Doesn't escape embedded 6" );
2115         assert.equal( jQuery.escapeSelector( "a7b" ), "a7b", "Doesn't escape embedded 7" );
2116         assert.equal( jQuery.escapeSelector( "a8b" ), "a8b", "Doesn't escape embedded 8" );
2117         assert.equal( jQuery.escapeSelector( "a9b" ), "a9b", "Doesn't escape embedded 9" );
2119         // Dash-number prefix
2120         assert.equal( jQuery.escapeSelector( "-0a" ), "-\\30 a", "Escapes 0 after leading dash" );
2121         assert.equal( jQuery.escapeSelector( "-1a" ), "-\\31 a", "Escapes 1 after leading dash" );
2122         assert.equal( jQuery.escapeSelector( "-2a" ), "-\\32 a", "Escapes 2 after leading dash" );
2123         assert.equal( jQuery.escapeSelector( "-3a" ), "-\\33 a", "Escapes 3 after leading dash" );
2124         assert.equal( jQuery.escapeSelector( "-4a" ), "-\\34 a", "Escapes 4 after leading dash" );
2125         assert.equal( jQuery.escapeSelector( "-5a" ), "-\\35 a", "Escapes 5 after leading dash" );
2126         assert.equal( jQuery.escapeSelector( "-6a" ), "-\\36 a", "Escapes 6 after leading dash" );
2127         assert.equal( jQuery.escapeSelector( "-7a" ), "-\\37 a", "Escapes 7 after leading dash" );
2128         assert.equal( jQuery.escapeSelector( "-8a" ), "-\\38 a", "Escapes 8 after leading dash" );
2129         assert.equal( jQuery.escapeSelector( "-9a" ), "-\\39 a", "Escapes 9 after leading dash" );
2131         // Double dash prefix
2132         assert.equal( jQuery.escapeSelector( "--a" ), "--a", "Doesn't escape leading double dash" );
2134         // Miscellany
2135         assert.equal( jQuery.escapeSelector( "\x01\x02\x1E\x1F" ), "\\1 \\2 \\1e \\1f ",
2136                 "Escapes C0 control characters" );
2137         assert.equal( jQuery.escapeSelector( "\x80\x2D\x5F\xA9" ), "\x80\x2D\x5F\xA9",
2138                 "Doesn't escape general punctuation or non-ASCII ISO-8859-1 characters" );
2139         assert.equal(
2140                 jQuery.escapeSelector( "\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90" +
2141                         "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" ),
2142                 "\\7f \x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90" +
2143                 "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F",
2144                 "Escapes DEL control character"
2145         );
2146         assert.equal( jQuery.escapeSelector( "\xA0\xA1\xA2" ), "\xA0\xA1\xA2",
2147                 "Doesn't escape non-ASCII ISO-8859-1 characters" );
2148         assert.equal( jQuery.escapeSelector( "a0123456789b" ), "a0123456789b",
2149                 "Doesn't escape embedded numbers" );
2150         assert.equal( jQuery.escapeSelector( "abcdefghijklmnopqrstuvwxyz" ), "abcdefghijklmnopqrstuvwxyz",
2151                 "Doesn't escape lowercase ASCII letters" );
2152         assert.equal( jQuery.escapeSelector( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
2153                 "Doesn't escape uppercase ASCII letters" );
2154         assert.equal( jQuery.escapeSelector( "\x20\x21\x78\x79" ), "\\ \\!xy",
2155                 "Escapes non-word ASCII characters" );
2157         // Astral symbol (U+1D306 TETRAGRAM FOR CENTRE)
2158         assert.equal( jQuery.escapeSelector( "\uD834\uDF06" ), "\uD834\uDF06",
2159                 "Doesn't escape astral characters" );
2161         // Lone surrogates
2162         assert.equal( jQuery.escapeSelector( "\uDF06" ), "\uDF06", "Doesn't escape lone low surrogate" );
2163         assert.equal( jQuery.escapeSelector( "\uD834" ), "\uD834", "Doesn't escape lone high surrogate" );
2164 } );
2166 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "custom pseudos", function( assert ) {
2167         assert.expect( 6 );
2169         try {
2170                 jQuery.expr.filters.foundation = jQuery.expr.filters.root;
2171                 assert.deepEqual( jQuery.find( ":foundation" ), [ document.documentElement ], "Copy element filter with new name" );
2172         } finally {
2173                 delete jQuery.expr.filters.foundation;
2174         }
2176         try {
2177                 jQuery.expr.setFilters.primary = jQuery.expr.setFilters.first;
2178                 assert.t( "Copy set filter with new name", "div#qunit-fixture :primary", [ "firstp" ] );
2179         } finally {
2180                 delete jQuery.expr.setFilters.primary;
2181         }
2183         try {
2184                 jQuery.expr.filters.aristotlean = jQuery.expr.createPseudo( function() {
2185                         return function( elem ) {
2186                                 return !!elem.id;
2187                         };
2188                 } );
2189                 assert.t( "Custom element filter", "#foo :aristotlean", [ "sndp", "en", "yahoo", "sap", "anchor2", "simon" ] );
2190         } finally {
2191                 delete jQuery.expr.filters.aristotlean;
2192         }
2194         try {
2195                 jQuery.expr.filters.endswith = jQuery.expr.createPseudo( function( text ) {
2196                         return function( elem ) {
2197                                 return jQuery.text( elem ).slice( -text.length ) === text;
2198                         };
2199                 } );
2200                 assert.t( "Custom element filter with argument", "a:endswith(ogle)", [ "google" ] );
2201         } finally {
2202                 delete jQuery.expr.filters.endswith;
2203         }
2205         try {
2206                 jQuery.expr.setFilters.second = jQuery.expr.createPseudo( function() {
2207                         return jQuery.expr.createPseudo( function( seed, matches ) {
2208                                 if ( seed[ 1 ] ) {
2209                                         matches[ 1 ] = seed[ 1 ];
2210                                         seed[ 1 ] = false;
2211                                 }
2212                         } );
2213                 } );
2214                 assert.t( "Custom set filter", "#qunit-fixture p:second", [ "ap" ] );
2215         } finally {
2216                 delete jQuery.expr.filters.second;
2217         }
2219         try {
2220                 jQuery.expr.setFilters.slice = jQuery.expr.createPseudo( function( argument ) {
2221                         var bounds = argument.split( ":" );
2222                         return jQuery.expr.createPseudo( function( seed, matches ) {
2223                                 var i = bounds[ 1 ];
2225                                 // Match elements found at the specified indexes
2226                                 while ( --i >= bounds[ 0 ] ) {
2227                                         if ( seed[ i ] ) {
2228                                                 matches[ i ] = seed[ i ];
2229                                                 seed[ i ] = false;
2230                                         }
2231                                 }
2232                         } );
2233                 } );
2234                 assert.t( "Custom set filter with argument", "#qunit-fixture p:slice(1:3)", [ "ap", "sndp" ] );
2235         } finally {
2236                 delete jQuery.expr.filters.slice;
2237         }
2238 } );
2240 QUnit.test( "jQuery.find.matchesSelector", function( assert ) {
2241         assert.expect( 15 );
2243         var link = document.getElementById( "simon1" ),
2244                 input = document.getElementById( "text1" ),
2245                 option = document.getElementById( "option1a" ),
2246                 disconnected = document.createElement( "div" );
2248         link.title = "Don't click me";
2249         assert.ok( jQuery.find.matchesSelector( link, "[rel='bookmark']" ), "attribute-equals string" );
2250         assert.ok( jQuery.find.matchesSelector( link, "[rel=bookmark]" ), "attribute-equals identifier" );
2251         assert.ok( jQuery.find.matchesSelector( link, "[\nrel = bookmark\t]" ),
2252                 "attribute-equals identifier (whitespace ignored)" );
2253         assert.ok( jQuery.find.matchesSelector( link, "a[title=\"Don't click me\"]" ),
2254                 "attribute-equals string containing single quote" );
2256         // trac-12303
2257         input.setAttribute( "data-pos", ":first" );
2258         assert.ok( jQuery.find.matchesSelector( input, "input[data-pos=\\:first]" ),
2259                 "attribute-equals POS in identifier" );
2260         assert.ok( jQuery.find.matchesSelector( input, "input[data-pos=':first']" ),
2261                 "attribute-equals POS in string" );
2262         if ( QUnit.jQuerySelectors ) {
2263                 assert.ok( jQuery.find.matchesSelector( input, ":input[data-pos=':first']" ),
2264                         "attribute-equals POS in string after pseudo" );
2265         } else {
2266                 assert.ok( "skip", ":input not supported in selector-native" );
2267         }
2269         option.setAttribute( "test", "" );
2270         assert.ok( jQuery.find.matchesSelector( option, "[id=option1a]" ),
2271                 "id attribute-equals identifier" );
2272         if ( QUnit.jQuerySelectors ) {
2273                 assert.ok( jQuery.find.matchesSelector( option, "[id*=option1][type!=checkbox]" ),
2274                         "attribute-not-equals identifier" );
2275         } else {
2276                 assert.ok( "skip", "[key!=value] not supported in selector-native" );
2277         }
2278         assert.ok( jQuery.find.matchesSelector( option, "[id*=option1]" ), "attribute-contains identifier" );
2279         assert.ok( !jQuery.find.matchesSelector( option, "[test^='']" ),
2280                 "attribute-starts-with empty string (negative)" );
2282         option.className = "=]";
2283         assert.ok( jQuery.find.matchesSelector( option, ".\\=\\]" ),
2284                 "class selector with attribute-equals confusable" );
2286         assert.ok( jQuery.find.matchesSelector( disconnected, "div" ), "disconnected element" );
2287         assert.ok( jQuery.find.matchesSelector( link, "* > *" ), "child combinator matches in document" );
2288         assert.ok( !jQuery.find.matchesSelector( disconnected, "* > *" ), "child combinator fails in fragment" );
2289 } );
2291 QUnit.test( "jQuery.find.matches", function( assert ) {
2292         assert.expect( 4 );
2294         var iframeChild,
2295                 input = document.getElementById( "text1" ),
2296                 div = document.createElement( "div" ),
2297                 iframe = document.getElementById( "iframe" ),
2298                 iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
2300         assert.deepEqual( jQuery.find.matches( "input", [ input ] ), [ input ],
2301                 "jQuery.find.matches with seed of input element" );
2302         assert.deepEqual( jQuery.find.matches( "div", [ div ] ), [ div ],
2303                 "jQuery.find.matches with disconnected element" );
2305         iframeDoc.open();
2306         iframeDoc.write( "<body><div id='foo'><div id='bar'></div></div></body>" );
2307         iframeDoc.close();
2309         iframeChild = iframeDoc.getElementById( "bar" );
2311         assert.deepEqual(
2312                 jQuery.find.matches( ":root > body > #foo > #bar", [ iframeChild ] ),
2313                 [ iframeChild ],
2314                 "jQuery.find.matches infers context from element"
2315         );
2317         assert.deepEqual(
2318                 jQuery.find.matches( ":root *", [ div, iframeChild, input ] ),
2319                 [ iframeChild, input ],
2320                 "jQuery.find.matches infers context from each seed element"
2321         );
2322 } );
2324 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "jQuery.find.select with pre-compiled function", function( assert ) {
2325         assert.expect( 6 );
2327         supportjQuery.each( [
2328                 "#qunit-fixture #first",
2329                 "ol#listWithTabIndex > li[tabindex]",
2330                 "#liveSpan1"
2331         ], function( _i, selector ) {
2332                 var compiled = jQuery.find.compile( selector );
2333                 assert.equal( jQuery.find.select( compiled, document ).length,
2334                         1, "Should match using a compiled selector function" );
2335                 assert.equal(
2336                         jQuery.find.select( compiled, jQuery( "#first" )[ 0 ] ).length,
2337                         0, "Should not match with different context" );
2338         } );
2339 } );
2341 // Internal, but we test it for backwards compatibility for edge cases
2342 QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "jQuery.find.tokenize", function( assert ) {
2343         assert.expect( 1 );
2345         var selector = "#id .class > div[prop=\"value\"] + input:nth-child(1):button, span:contains(\"Text\") ~ div:has(div:has(span)):not(.not-this.not-that > div)",
2346                 tokens = [
2347                         [
2348                                 {
2349                                         "value": "#id",
2350                                         "type": "ID",
2351                                         "matches": [
2352                                                 "id"
2353                                         ]
2354                                 },
2355                                 {
2356                                         "value": " ",
2357                                         "type": " "
2358                                 },
2359                                 {
2360                                         "value": ".class",
2361                                         "type": "CLASS",
2362                                         "matches": [
2363                                                 "class"
2364                                         ]
2365                                 },
2366                                 {
2367                                         "value": " > ",
2368                                         "type": ">"
2369                                 },
2370                                 {
2371                                         "value": "div",
2372                                         "type": "TAG",
2373                                         "matches": [
2374                                                 "div"
2375                                         ]
2376                                 },
2377                                 {
2378                                         "value": "[prop=\"value\"]",
2379                                         "type": "ATTR",
2380                                         "matches": [
2381                                                 "prop",
2382                                                 "=",
2383                                                 "value"
2384                                         ]
2385                                 },
2386                                 {
2387                                         "value": " + ",
2388                                         "type": "+"
2389                                 },
2390                                 {
2391                                         "value": "input",
2392                                         "type": "TAG",
2393                                         "matches": [
2394                                                 "input"
2395                                         ]
2396                                 },
2397                                 {
2398                                         "value": ":nth-child(1)",
2399                                         "type": "CHILD",
2400                                         "matches": [
2401                                                 "nth",
2402                                                 "child",
2403                                                 "1",
2404                                                 0,
2405                                                 1,
2406                                                 undefined,
2407                                                 "",
2408                                                 "1"
2409                                         ]
2410                                 },
2411                                 {
2412                                         "value": ":button",
2413                                         "type": "PSEUDO",
2414                                         "matches": [
2415                                                 "button",
2416                                                 undefined
2417                                         ]
2418                                 }
2419                         ],
2420                         [
2421                                 {
2422                                         "value": "span",
2423                                         "type": "TAG",
2424                                         "matches": [
2425                                                 "span"
2426                                         ]
2427                                 },
2428                                 {
2429                                         "value": ":contains(\"Text\")",
2430                                         "type": "PSEUDO",
2431                                         "matches": [
2432                                                 "contains",
2433                                                 "Text"
2434                                         ]
2435                                 },
2436                                 {
2437                                         "value": " ~ ",
2438                                         "type": "~"
2439                                 },
2440                                 {
2441                                         "value": "div",
2442                                         "type": "TAG",
2443                                         "matches": [
2444                                                 "div"
2445                                         ]
2446                                 },
2447                                 {
2448                                         "value": ":has(div:has(span))",
2449                                         "type": "PSEUDO",
2450                                         "matches": [
2451                                                 "has",
2452                                                 "div:has(span)"
2453                                         ]
2454                                 },
2455                                 {
2456                                         "value": ":not(.not-this.not-that > div)",
2457                                         "type": "PSEUDO",
2458                                         "matches": [
2459                                                 "not",
2460                                                 ".not-this.not-that > div"
2461                                         ]
2462                                 }
2463                         ]
2464                 ];
2466         assert.deepEqual( jQuery.find.tokenize( selector ), tokens, "Tokenization successful" );
2467 } );