Skip to content

Commit

Permalink
Selector: pass jQuery unit tests with selector-native
Browse files Browse the repository at this point in the history
- Ignore certain tests that obviously are not supported
- Beefed up the sortOrder, uniqueSort, isXMLDoc, and attr functions

Fixes gh-1742
Fixes gh-2048
Close gh-2703
  • Loading branch information
timmywil committed Nov 11, 2015
1 parent ab06be5 commit 8804644
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 216 deletions.
125 changes: 76 additions & 49 deletions src/selector-native.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
define( [
"./core",
"./var/document",
"./var/documentElement"
], function( jQuery, document, documentElement ) {
"./var/documentElement",
"./var/hasOwn",
"./var/indexOf"
], function( jQuery, document, documentElement, hasOwn, indexOf ) {

/*
* Optional (non-Sizzle) selector module for custom builds.
Expand All @@ -29,69 +31,84 @@ define( [
* customize this stub for the project's specific needs.
*/

var hasDuplicate,
var hasDuplicate, sortInput,
sortStable = jQuery.expando.split( "" ).sort( sortOrder ).join( "" ) === jQuery.expando,
matches = documentElement.matches ||
documentElement.webkitMatchesSelector ||
documentElement.mozMatchesSelector ||
documentElement.oMatchesSelector ||
documentElement.msMatchesSelector,
sortOrder = function( a, b ) {
documentElement.msMatchesSelector;

// Flag for duplicate removal
if ( a === b ) {
hasDuplicate = true;
return 0;
}
function sortOrder( a, b ) {

var compare = b.compareDocumentPosition &&
a.compareDocumentPosition &&
a.compareDocumentPosition( b );
// Flag for duplicate removal
if ( a === b ) {
hasDuplicate = true;
return 0;
}

if ( compare ) {
// Sort on method existence if only one input has compareDocumentPosition
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if ( compare ) {
return compare;
}

// Disconnected nodes
if ( compare & 1 ) {
// Calculate position if both inputs belong to the same document
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
a.compareDocumentPosition( b ) :

// Choose the first element that is related to our document
if ( a === document || jQuery.contains( document, a ) ) {
return -1;
}
if ( b === document || jQuery.contains( document, b ) ) {
return 1;
}
// Otherwise we know they are disconnected
1;

// Maintain original order
return 0;
}
// Disconnected nodes
if ( compare & 1 ) {

return compare & 4 ? -1 : 1;
// Choose the first element that is related to our preferred document
if ( a === document || a.ownerDocument === document &&
jQuery.contains( document, a ) ) {
return -1;
}
if ( b === document || b.ownerDocument === document &&
jQuery.contains( document, b ) ) {
return 1;
}

// Not directly comparable, sort on existence of method
return a.compareDocumentPosition ? -1 : 1;
},
uniqueSort = function( results ) {
var elem,
duplicates = [],
i = 0,
j = 0;
// Maintain original order
return sortInput ?
( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
0;
}

hasDuplicate = false;
results.sort( sortOrder );
return compare & 4 ? -1 : 1;
}

if ( hasDuplicate ) {
while ( ( elem = results[ i++ ] ) ) {
if ( elem === results[ i ] ) {
j = duplicates.push( i );
}
}
while ( j-- ) {
results.splice( duplicates[ j ], 1 );
function uniqueSort( results ) {
var elem,
duplicates = [],
j = 0,
i = 0;

hasDuplicate = false;
sortInput = !sortStable && results.slice( 0 );
results.sort( sortOrder );

if ( hasDuplicate ) {
while ( ( elem = results[ i++ ] ) ) {
if ( elem === results[ i ] ) {
j = duplicates.push( i );
}
}
while ( j-- ) {
results.splice( duplicates[ j ], 1 );
}
}

return results;
};
// Clear input after sorting to release objects
// See https://github.com/jquery/sizzle/pull/225
sortInput = null;

return results;
}

jQuery.extend( {
find: function( selector, context, results, seed ) {
Expand Down Expand Up @@ -157,7 +174,11 @@ jQuery.extend( {
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains( bup ) );
},
isXMLDoc: function( elem ) {
return ( elem.ownerDocument || elem ).documentElement.nodeName !== "HTML";

// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = elem && ( elem.ownerDocument || elem ).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
},
expr: {
attrHandle: {},
Expand All @@ -177,7 +198,13 @@ jQuery.extend( jQuery.find, {
return matches.call( elem, expr );
},
attr: function( elem, name ) {
return elem.getAttribute( name );
var fn = jQuery.expr.attrHandle[ name.toLowerCase() ],

// Don't get fooled by Object.prototype properties (jQuery #13807)
value = fn && hasOwn.call( jQuery.expr.attrHandle, name.toLowerCase() ) ?
fn( elem, name, jQuery.isXMLDoc( elem ) ) :
undefined;
return value !== undefined ? value : elem.getAttribute( name );
}
} );

Expand Down
10 changes: 7 additions & 3 deletions test/unit/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ QUnit.test( "jQuery()", function( assert ) {
"Empty attributes object is not interpreted as a document (trac-8950)" );
} );

QUnit.test( "jQuery(selector, context)", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "jQuery(selector, context)", function( assert ) {
assert.expect( 3 );
assert.deepEqual( jQuery( "div p", "#qunit-fixture" ).get(), q( "sndp", "en", "sap" ), "Basic selector with string as context" );
assert.deepEqual( jQuery( "div p", q( "qunit-fixture" )[ 0 ] ).get(), q( "sndp", "en", "sap" ), "Basic selector with element as context" );
Expand Down Expand Up @@ -618,8 +618,12 @@ QUnit.test( "jQuery('html')", function( assert ) {

//equal( jQuery( "element[attribute=<div></div>]" ).length, 0,
// "When html is within brackets, do not recognize as html." );
assert.equal( jQuery( "element:not(<div></div>)" ).length, 0,
"When html is within parens, do not recognize as html." );
if ( jQuery.find.compile ) {
assert.equal( jQuery( "element:not(<div></div>)" ).length, 0,
"When html is within parens, do not recognize as html." );
} else {
assert.ok( "skip", "Complex :not not supported in selector-native" );
}
assert.equal( jQuery( "\\<div\\>" ).length, 0, "Ignore escaped html characters" );
} );

Expand Down
8 changes: 2 additions & 6 deletions test/unit/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -666,9 +666,7 @@ QUnit.test( "show() after hide() should always set display to initial value (#14

}

if ( jQuery.fn.toggle ) {

QUnit.test( "toggle()", function( assert ) {
QUnit[ jQuery.find.compile && jQuery.fn.toggle ? "test" : "skip" ]( "toggle()", function( assert ) {
assert.expect( 9 );
var div, oldHide,
x = jQuery( "#foo" );
Expand Down Expand Up @@ -701,8 +699,6 @@ QUnit.test( "toggle()", function( assert ) {
jQuery.fn.hide = oldHide;
} );

}

QUnit.test( "jQuery.css(elem, 'height') doesn't clear radio buttons (bug #1095)", function( assert ) {
assert.expect( 4 );

Expand Down Expand Up @@ -1012,7 +1008,7 @@ QUnit.test( "css opacity consistency across browsers (#12685)", function( assert
assert.equal( Math.round( el.css( "opacity" ) * 100 ), 20, "remove opacity override" );
} );

QUnit.test( ":visible/:hidden selectors", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( ":visible/:hidden selectors", function( assert ) {
assert.expect( 17 );

var $div, $table, $a;
Expand Down
41 changes: 31 additions & 10 deletions test/unit/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ QUnit.module( "effects", {
}
} );

QUnit.test( "sanity check", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "sanity check", function( assert ) {
assert.expect( 1 );
assert.equal( jQuery( "#dl:visible, #qunit-fixture:visible, #foo:visible" ).length, 3, "QUnit state is correct for testing effects" );
} );
Expand Down Expand Up @@ -769,7 +769,7 @@ QUnit.test( "stop( queue, ..., ... ) - Stop single queues", function( assert ) {
this.clock.tick( 500 );
} );

QUnit.test( "toggle()", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "toggle()", function( assert ) {
assert.expect( 6 );
var x = jQuery( "#foo" );
assert.ok( x.is( ":visible" ), "is visible" );
Expand Down Expand Up @@ -1534,9 +1534,9 @@ QUnit.test( "User supplied callback called after show when fx off (#8892)", func
jQuery.fx.off = true;
foo.hide();
foo.fadeIn( 500, function() {
assert.ok( jQuery( this ).is( ":visible" ), "Element is visible in callback" );
assert.ok( supportjQuery( this ).is( ":visible" ), "Element is visible in callback" );
foo.fadeOut( 500, function() {
assert.ok( jQuery( this ).is( ":hidden" ), "Element is hidden in callback" );
assert.ok( supportjQuery( this ).is( ":hidden" ), "Element is hidden in callback" );
jQuery.fx.off = false;
} );
} );
Expand Down Expand Up @@ -1592,7 +1592,7 @@ QUnit.test( "animate should set display for disconnected nodes", function( asser
clock.tick( 400 );
} );

QUnit.test( "Animation callback should not show animated element as :animated (#7157)", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "Animation callback should not show animated element as :animated (#7157)", function( assert ) {
assert.expect( 1 );

var foo = jQuery( "#foo" );
Expand All @@ -1605,7 +1605,7 @@ QUnit.test( "Animation callback should not show animated element as :animated (#
this.clock.tick( 100 );
} );

QUnit.test( "Initial step callback should show element as :animated (#14623)", function( assert ) {
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "Initial step callback should show element as :animated (#14623)", function( assert ) {
assert.expect( 1 );

var foo = jQuery( "#foo" );
Expand Down Expand Up @@ -2125,7 +2125,12 @@ QUnit.test( ".finish() completes all queued animations", function( assert ) {
assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
} );
assert.equal( div.queue().length, 0, "empty queue when done" );
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );

if ( jQuery.find.compile ) {
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
} else {
assert.ok( "skip", ":animated selector not supported with selector-native" );
}

// cleanup
div.remove();
Expand Down Expand Up @@ -2160,7 +2165,12 @@ QUnit.test( ".finish( false ) - unqueued animations", function( assert ) {
jQuery.each( animations, function( prop, value ) {
assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
} );
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );

if ( jQuery.find.compile ) {
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
} else {
assert.ok( "skip", ":animated selector not supported with selector-native" );
}

// cleanup
div.remove();
Expand Down Expand Up @@ -2194,12 +2204,23 @@ QUnit.test( ".finish( \"custom\" ) - custom queue animations", function( assert

// start the first animation
div.dequeue( "custom" );
assert.equal( div.is( ":animated" ), true, ":animated matches" );

if ( jQuery.find.compile ) {
assert.equal( div.is( ":animated" ), true, ":animated matches" );
} else {
assert.ok( "skip", ":animated selector not supported with selector-native" );
}

div.finish( "custom" );
jQuery.each( animations, function( prop, value ) {
assert.equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
} );
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );

if ( jQuery.find.compile ) {
assert.equal( div.is( ":animated" ), false, ":animated doesn't match" );
} else {
assert.ok( "skip", ":animated selector not supported with selector-native" );
}

// cleanup
div.remove();
Expand Down
3 changes: 2 additions & 1 deletion test/unit/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,8 @@ QUnit.test( "jQuery.off using dispatched jQuery.Event", function( assert ) {
.remove();
} );

QUnit.test( "delegated event with delegateTarget-relative selector", function( assert ) {
// selector-native does not support scope-fixing in delegation
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
assert.expect( 3 );
var markup = jQuery( "<div><ul><li><a id=\"a0\"></a><ul id=\"ul0\"><li class=test><a id=\"a0_0\"></a></li><li><a id=\"a0_1\"></a></li></ul></li></ul></div>" ).appendTo( "#qunit-fixture" );

Expand Down
Loading

0 comments on commit 8804644

Please sign in to comment.