selector.html revision dd02386244f04f36bb138d55c2889aac556d689e
<html>
<head>
<title>Selector Test Suite</title>
.yui-skin-sam .yui-console-entry-pass .yui-console-entry-cat {
background: #070;
color: #fff;
}
.yui-skin-sam .yui-console-entry-fail .yui-console-entry-cat {
background: #700;
color: #fff;
}
</style>
<script>
document.createElement('foo'); // enable custom element for IE native querySelector
onload = function() {
var SELECTOR_MODULE = 'selector-css3';
YUI({filter: 'debug'}).use('node', SELECTOR_MODULE, 'test-console', 'test', 'dom-deprecated', function(Y) {
String.prototype.test = function() {
// simulate Moo monkey-patch
return false;
};
Y.Test.Runner.setName('Selector Tests');
Y.Dom = {
get: function (id) {
return document.getElementById(id);
},
getChildren: function (el) {
el = typeof el === 'string' ? document.getElementById(el) : el;
var children = [],
i, len;
}
}
return children;
},
getElementsByClassName: function (clz, tag, root) {
root = typeof root === 'string' ?
nodes = [],
S = ' ',
i, len;
clz = S + clz + S;
if ((S + els[i].className + S).indexOf(clz)) {
nodes.push(els[i]);
}
}
return nodes;
},
getFirstChild: function (el) {
el = typeof el === 'string' ? document.getElementById(el) : el;
var node = el.firstChild;
while (node && node.nodeType !== 1) {
node = node.nextSibling;
}
return node;
},
getLastChild: function (el) {
el = typeof el === 'string' ? document.getElementById(el) : el;
var node = el.lastChild;
while (node && node.nodeType !== 1) {
node = node.previousSibling;
}
return node;
},
addClass: function (els, clz) {
var S = ' ',
i, len;
if (typeof els === 'string') {
els = [ document.getElementById( els ) ];
} else if (els.nodeType === 1) {
els = [ els ];
} else if (({}).toString.call(els) === '[object Array]') {
for (i = els.length - 1; i >= 0; --i) {
if (typeof els[i] === 'string') {
els[i] = document.getElementById(els[i]);
if (!els[i]) {
els.splice(i,1);
}
}
}
} else {
els = [];
}
clz = S + clz + S;
if ((S + els[i].className + S).indexOf(clz)) {
}
}
}
};
var Selector = Y.Selector;
var Assert = Y.Assert;
var ArrayAssert = Y.ArrayAssert;
var $ = Selector.query;
children = Y.Dom.getChildren(demo);
var demoFirstChild = children[0];
name: 'Query All',
testFilter: function() {
ArrayAssert.itemsAreEqual([all[0], all[1], all[2]], Selector.filter(all, '[type=checkbox]'), '[type=checkbox]');
//ArrayAssert.itemsAreEqual([document.getElementById('test-inputs')], Selector.filter(['root-test', 'test-inputs'], 'form'), 'form (string inputs)');
// no longer supporting string input for element
//ArrayAssert.itemsAreEqual([document.getElementById('test-inputs')], Selector.filter(['root-test', document.getElementById('test-inputs'), document.createTextNode('foo')], 'form'), 'form (mixed inputs)');
},
testTest: function() {
Assert.isTrue(Selector.test(Y.Dom.get('checkbox-unchecked'), '[type=checkbox], button'), '[type=checkbox], button');
Assert.isTrue(Selector.test(Y.Dom.get('checkbox-unchecked'), 'button, [type=checkbox]'), 'button, [type=checkbox]');
Assert.isTrue(Selector.test(Y.Dom.get('test-lang-en-us'), '[lang|=en]'), '[lang|=en] (lang="en-us")');
Assert.isFalse(Selector.test(Y.Dom.get('checkbox-unchecked'), 'for [type=checkbox]'), 'for [type=checkbox] false pos');
Assert.isTrue(Selector.test(Y.Dom.get('checkbox-unchecked'), 'form [type=checkbox]'), 'form [type=checkbox]');
Assert.isFalse(Selector.test(Y.Dom.get('checkbox-unchecked'), 'for [type=checkbox]'), 'for [type=checkbox] false pos');
Assert.isTrue(Selector.test(Y.Dom.get('checkbox-checked'), '[type=checkbox]:checked'), 'type=checkbox:checked');
Assert.isFalse(Selector.test(Y.Dom.get('radio-unchecked'), ':checked'), ':checked (radio) false pos');
Assert.isFalse(Selector.test(Y.Dom.get('checkbox-unchecked'), '[type=checkbox]:checked'), 'type=checkbox:checked false pos');
Assert.isTrue(Selector.test(Y.Dom.get('checkbox-unchecked'), '[type=checkbox]:not(:checked)'), 'type=checkbox:not(:checked)');
Assert.isFalse(Selector.test(document.getElementsByTagName('dd')[0], '.test-dd2'), '.test-dd2 (dd1)');
Assert.isFalse(Selector.test(document.getElementsByTagName('dd')[1], '.test-dd1'), '.test-dd1 (dd2)');
// with optional root arg
},
testRootQuery: function() {
"$('a, a span') === $('a span, a')");
node.innerHTML = '<li><em>foo</em></li>';
"$('h2', Y.DOM.byId('test:colon'), true)");
"$('.foo #demo-last-child', true, document.body)");
// standard: no element-scoped query
//ArrayAssert.itemsAreEqual(document.body.getElementsByTagName('p'), $('body p', document.body), "$('body p', document.body)");
// based on non-standard behavior
ArrayAssert.itemsAreEqual([], $('#root-test li', Y.Dom.get('nth-test')), 'id selector w/root false pos');
},
/*
testNthLastChild: function() {
},
*/
testNthType: function() {
//"$('#nth-type-test div:nth-of-type(3)')");
//"$('#nth-type-test div:nth-of-type(even)')");
//"$('#nth-type-test div:nth-of-type(2n)')");
},
testNthChild: function() {
/*
*/
},
testQuery: function() {
ArrayAssert.itemsAreEqual(Y.Dom.get('demo').getElementsByTagName('p'), $('#demo.foo p'), '#demo.foo p');
//ArrayAssert.itemsAreEqual(Y.Dom.getElementsByClassName('para'), $('[class~=para]'), '[class~=para]');
//ArrayAssert.itemsAreEqual(Y.Dom.getElementsByClassName('para'), $('[class~="para"]'), '[class~="para"]');
//ArrayAssert.itemsAreEqual(Y.Dom.getElementsByClassName('para', 'p'), $('div .para'), 'div .para');
//ArrayAssert.itemsAreEqual(Y.Dom.getElementsByClassName('first', null, Y.DOM.byId(demo)), $('#demo .first'), '#demo .first');
Assert.areEqual(document.getElementById('label-checkbox-unchecked'), $('label[for=checkbox-unchecked]', null, true), 'for attribute');
Assert.areEqual($('.not-button', root).length, $('input:not([type=button])', root).length, '.not-button = input:not([type=button]) - root query');
//ArrayAssert.itemsAreEqual(Y.Dom.get('demo2').getElementsByTagName('div'), $('div:contains(child of demo2)', Y.DOM.byId('demo2')), 'div:contains:(child of demo2) ');
//Assert.areEqual(document.getElementById('contains-special'), $(':contains(contains "\' & ])'), 'contains "\' & ]');
Assert.areEqual(Y.DOM.byId('test-select'), $('#test-select', null, true), "($('#test-select'), null, true)");
Assert.areEqual(document.getElementsByTagName('link')[0], $('[rel^=style]', null, true), "($('[rel^=style]), null, true)");
Assert.areEqual(Y.DOM.byId('test-rel-div'), $('div[rel^=foo2]', null, true), "($('[rel^=foo2]), null, true)");
Assert.areEqual(Y.DOM.byId('test-rel-div'), $("div[rel^='foo2']", null, true), "($('[rel^=\'foo2\']), null, true)");
Assert.areEqual(Y.DOM.byId('foo-bar'), $("input[name='foo.bar']", null, true), "input[name='foo.bar'], null, true)");
ArrayAssert.itemsAreEqual([demoFirstChild, Y.DOM.next(demoFirstChild)], $('#demo > p:not(.last)'), '#demo > p:not(.last)');
Assert.areEqual(Y.DOM.byId('foo-bar'), $("[id^='foo-']", null, true), "[id^='foo-'], null, true");
Assert.areEqual(Y.DOM.byId('test-custom-attr'), $("#test-custom-attr[foo=bar]", null, true), "#test-custom-attr[foo=bar], null, true");
Assert.areEqual(Y.DOM.byId('test-custom-attr'), $("div[foo=bar]", null, true), "div[foo=bar], null, true");
Assert.areEqual(Y.DOM.byId('test-custom-attr'), $("div#test-custom-attr[foo=bar]", null, true), "div#test-custom-attr[foo=bar], null, true");
Assert.areEqual(Y.DOM.byId('test-custom-attr'), $("div[foo]", null, true), "div[foo], null, true");
ArrayAssert.itemsAreEqual([Y.DOM.byId('test-custom-attr')], $("[foo]"), "[foo]");
Assert.areEqual(document.body, $('body, span', null, true), "$('body, span', null, true)");
Assert.areEqual(document.getElementById('foo-bar'),
$('[id=foo-bar]', null, true),
"$('[id=foo-bar]', null, true)");
Assert.areEqual(document.getElementById('test-custom-attr'),
$('[foo-bar]', null, true),
"$('[foo-bar]', null, true)");
Assert.areEqual(document.getElementById('foo-bar'),
$('[aria-controls]', null, true),
"$('[aria-controls]', null, true)");
Assert.areEqual(document.getElementById('foo-bar'),
$('[-hyphen-start]', null, true),
"$('[-hyphen-start]', null, true)");
Assert.areEqual(Y.DOM.byId('test-lang-en-us'), $('[lang|=en]', null, true), "$('[lang|=en]')");
Assert.areEqual(Y.DOM.byId('href-test'), $('[href$=".html"]', null, true), "$('[href$=\".html\"]')");
Assert.isNull($('[href$="?html"]', null, true), "$('[href$=\?html\]')");
/* failing in brute (ticket 2528057)
Assert.areEqual(Y.DOM.byId('test:colon'),
$('#test\\:colon', null, true),
"$('#test\\:colon', null, true)");
*/
}
});
var simpleTest = new Y.Test.Case({
name: 'Simple Node Test',
testPseudo: function() {
Assert.isFalse(Selector.test(Y.Dom.getFirstChild('demo'), ':first-child.last'), 'first-child class false pos');
Assert.isTrue(Selector.test(Y.Dom.getFirstChild('demo'), ':first-child.first'), 'first-child class');
Assert.isTrue(Selector.test(demoFirstChild, ':not(.last)'), 'not(.last)');
Assert.isFalse(Selector.test(Y.Dom.getFirstChild('demo'), ':only-of-type'), 'only-of-type false pos');
/* non-standard
Assert.isFalse(Selector.test(Y.Dom.get('demo2'), ':not(:contains(demo2))'), ':not(:contains(demo2))');
Assert.isTrue(Selector.test(Y.Dom.get('demo2'), ':not(:contains(demo1))'), ':not(:contains(demo1))');
Assert.isTrue(Selector.test(Y.Dom.get('demo2'), ':contains(child of demo2)'), 'contains(child of demo2)');
*/
},
testAttr: function() {
Assert.isTrue(Selector.test(Y.Dom.get('demo'), 'div[id=demo][title~=demo]'), 'tag & multiple attributes');
Assert.isTrue(Selector.test(Y.Dom.get('demo'), 'div[title="this is a demo"]'), 'quoted attribute with spaces');
Assert.isTrue(Selector.test(Y.Dom.get('demo'), "div[title='this is a demo']"), 'single quoted attribute with spaces');
Assert.isFalse(Selector.test(Y.Dom.get('demo'), '[id=demo][title=demo]'), 'multiple attributes false pos');
/* non-standard
alert(Y.Dom.get('demo').querySelector('[id!=bar]'));
Assert.isTrue(Selector.test(Y.Dom.get('demo'), 'div[title=this is a demo]'), 'attribute with spaces');
*/
},
testClass: function() {
Assert.isTrue(Selector.test(Y.Dom.getFirstChild('demo'), 'p.first.para'), 'tag & multiple class match');
},
testId: function() {
},
testTag: function() {
},
testDisabled: function() {
Assert.areEqual(Y.DOM.byId('disabled-button'), $('#test-inputs :disabled', null, true), "$('#test-inputs :disabled')");
},
testEnabled: function() {
Assert.areEqual(Y.DOM.byId('checkbox-unchecked'), $('#test-inputs input:enabled', null, true), "$('#test-inputs input:enabled')");
},
testIframe: function() {
var frameDoc = Y.DOM.byId('test-frame').contentWindow.document;
Assert.areEqual('iframe foo', Y.Lang.trim($('#demo li', frameDoc, true).innerHTML), "Y.get('#demo li', frameDoc, true)");
},
// to support:
// $('> p', myNode) === ('#my-node-id > p');
// $('+ p', myNode) === ('#my-node-id + p');
// $('~ p', myNode) === ('#my-node-id ~ p');
testScoped: function() {
var demo = Y.DOM.byId('demo'),
paraChildren = [];
Y.each(demo.getElementsByTagName('p'), function(el) {
if (el.parentNode === demo) {
paraChildren.push(el);
}
});
ArrayAssert.itemsAreEqual(paraChildren, $('> p', Y.DOM.byId('demo')), '#demo > p');
ArrayAssert.itemsAreEqual($('#demo > p'), $('foo, > p', Y.DOM.byId('demo')), '#demo foo, #demo > p');
//ArrayAssert.itemsAreEqual($('#demo-first-child ~ p'), $('~ p', Y.DOM.byId('demo-first-child')), '#demo-first-child ~ div');
},
'should run scoped query when form has input with name="id"': function() {
},
'should run scoped query when root has ID with special chars': function() {
},
testAncestor: function() {
var node = Y.DOM.byId('demo-first-child');
Assert.isNull(Y.Selector.ancestor(node, 'p'));
Assert.areEqual(node, Y.Selector.ancestor(node, 'p', true));
},
'should return all checked inputs': function() {
Assert.areEqual(4, Y.Selector.query('#test-inputs :checked', null).length);
},
'should apply function for filter test': function() {
var nodes = document.getElementsByTagName('div'),
filtered = Y.Selector.filter(nodes, function(n) {
return n.tagName == 'SPAN';
});
ArrayAssert.itemsAreEqual([], filtered);
},
'should find element with quoted number ID': function() {
var node = document.getElementById('1');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('[id="1"]', null, true));
},
'should find element with number ID': function() {
var node = document.getElementById('1');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('[id=1]', null, true));
},
'should find element with colon in quoted ID': function() {
var node = document.getElementById('foo:bar');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('[id="foo:bar"]', null, true));
},
'should find element with colon in ID': function() {
var node = document.getElementById('foo:bar');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('[id=foo:bar]', null, true));
},
'should find element with colon in ID shorthand': function() {
var node = document.getElementById('foo:bar');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('#foo\\:bar', null, true));
},
'should find element with number ID shorthand': function() {
var node = document.getElementById('1');
Assert.isNotNull(node);
Assert.areEqual(node, Y.Selector.query('#1', null, true));
},
'should omit comments from children': function() {
var node = document.getElementById('test-dl');
Assert.areEqual(document.getElementById('last-dd'),
Y.Selector.query(':last-child', node, true));
},
'should allow documentFragment root node': function() {
var frag = document.createDocumentFragment();
frag.appendChild(document.createElement('div'));
Assert.areEqual('DIV',
Y.Selector.query('div', frag, true).tagName);
frag.appendChild(document.createElement('span'));
Assert.areEqual('SPAN',
Y.Selector.query('span', frag, true).tagName);
},
'should find custom element by tag': function() {
var node = Y.Selector.query('foo', null, true);
Assert.areEqual(document.getElementsByTagName('foo')[0], node);
},
'should find custom element by class': function() {
var node = Y.Selector.query('.custom-foo', null, true);
Assert.areEqual(document.getElementsByTagName('foo')[0], node);
},
'should find custom element by tag and class': function() {
var node = Y.Selector.query('foo.custom-foo', null, true);
Assert.areEqual(document.getElementsByTagName('foo')[0], node);
},
'should support multiple :not pseudos': function() {
Assert.areEqual(1, Y.Selector.query('tr:not(.class1):not(.class2)').length);
},
'should test multiple :not pseudos with attribute': function() {
var node = document.getElementById('href-test');
Assert.isTrue(Selector.test(node, 'a:not(.foo):not([target])'));
},
'should support boolean custom attribute via quoted attr': function() {
var node = document.createElement('div');
node.setAttribute('foo', true);
document.body.appendChild(node);
Assert.areEqual(1, Y.Selector.query('[foo="true"]').length);
document.body.removeChild(node);
},
'should allow special chars in attribute': function() {
var node = document.getElementById('test-chars');
Assert.areEqual(node, Y.Selector.query('input[value="ML キshigo, Mfg., Co."]', null, true));
}
});
suite.add(selectorQueryAll);
suite.add(simpleTest);
Y.Test.Runner.add(suite);
});
};
</script>
</style>
</head>
<body class="yui3-skin-sam">
<div id="demo" class="foo" title="this is a demo">
<p class="para first" id="demo-first-child"><em>lorem ipsum</em></p>
<p class="para">lorem ipsum</p>
<p class="para last">lorem ipsum</p>
<div><p>div lorem</p></div>
<div id="demo-last-child"><p>last child</p></div>
</div>
<div id="demo2">
<div>child of demo2</div>
</div>
<div id="empty"></div>
<select id="test-select" name="test-select">
<option value="0">foo</option>
<option value="1">bar</option>
<option>baz</option>
</select>
<div id="root-test">
<ol id="nth-test">
<li class="odd three-1 four-1">foo</li>
<li class="even four-2 last-four-1">foo</li>
<li class="odd four-3">foo</li>
<li class="even three-1 four-4">foo</li>
<li class="odd four-1">foo</li>
<li class="even four-2 last-four-1">foo</li>
<li class="odd three-1 four-3">foo</li>
<li class="even four-4" id="test-lang-none">foo</li>
<li class="odd four-1" lang="en-US" id="test-lang-en-us">foo</li>
<li class="even three-1 four-2 last-four-1" lang="en" id="test-lang-en">foo</li>
</ol>
</div>
<div id="nth-type-test">
<span>span</span>
<div>first div</div>
<span>span</span>
<div class="even">second div</div>
<div>third div</div>
<div class="even">fourth div</div>
<span>span</span>
</div>
<form>
<input name="id" value="input-named-id">
</form>
<form id="test-inputs">
<label for="checkbox-unchecked" id="label-checkbox-unchecked">label</label>
<input type="checkbox" id="checkbox-unchecked" class="not-button">
<input type="checkbox" checked id="checkbox-checked-noval" class="not-button">
<input type="checkbox" checked="true" id="checkbox-checked" class="not-button">
<input type="radio" id="radio-unchecked" class="not-button">
<input type="radio" checked="true" id="radio-checked" class="not-button">
<input type="button" value="foo" disabled id="disabled-button">
<input name="id" class="not-button" value="test-input-name">
<select>
<option>foo</option>
<option selected>bar</option>
</select>
</form>
<form id="form-root">
<input type="button" value="foo">
<input name="foo" class="text-input">
</form>
<div id="mod1">
<div><h3>H3 - Title</h3></div>
<div><p>lorem ipsum dolor sit <a href="#" target="_blank"><span>link</span></a></p></div>
</div>
<div class="Bar" id="class-bar"></div>
<div id="contains-special">contains "' & ]</div>
<div id="test-rel-div" rel="foo2"></div>
<dl id="test-dl">
<dt>Window size</dt>
<dd class="test-dd1">dd1</dd>
<dt>Document size</dt>
<dd id="last-dd" class="test-dd2">dd2</dd>
<!-- test comment -->
</dl>
<div id="test:colon"><h2>test</h2></div>
<div id="test-custom-attr" foo="bar" foo-bar="bar">custom attribute</div>
<div id="1"></div>
<div id="foo:bar"></div>
<foo class="custom-foo"></foo>
<table>
<tbody>
<tr class="class1"></tr>
<tr class="class1 class2"></tr>
<tr></tr>
</tbody>
</table>
<code id="(0:0-178~690#2+21[255], <1>92)">
<span>foo</span>
</code>
<input id="test-chars" type="hidden" value="ML キshigo, Mfg., Co.">
</body>
</html>