|
|
define([ |
|
|
'intern!object', |
|
|
'intern/chai!assert', |
|
|
'require', |
|
|
'dojo/_base/array' |
|
|
], function (registerSuite, assert, require, array) { |
|
|
|
|
|
array.forEach(["query.html", "queryQuirks.html"], function (file) { |
|
|
array.forEach(["lite", "css2", "css2.1", "css3", "acme"], function (selector) { |
|
|
var tests = { |
|
|
name: file + ": " + selector, |
|
|
|
|
|
before: function () { |
|
|
return this.get("remote") |
|
|
.get(require.toUrl("./" + file)) |
|
|
.setExecuteAsyncTimeout(10000) |
|
|
.executeAsync(function (selector, send) { |
|
|
require([ |
|
|
'dojo/query!' + selector, |
|
|
'dojo/sniff', |
|
|
'dojo/_base/array', |
|
|
'dojo/dom', |
|
|
'dojo/dom-construct', |
|
|
'dojo/request/iframe', |
|
|
'dojo/domReady!' |
|
|
], function (_query, _sniff, _array, _dom, _domConstruct, _iframe) { |
|
|
query = _query; |
|
|
has = _sniff; |
|
|
array = _array; |
|
|
dom = _dom; |
|
|
domConstruct = _domConstruct; |
|
|
iframe = _iframe; |
|
|
|
|
|
send(); |
|
|
}) |
|
|
}, [selector]) |
|
|
.execute(function () { |
|
|
createDocument = function (xml) { |
|
|
var fauxXhr = {responseText: xml}; |
|
|
if ("DOMParser" in window) { |
|
|
var parser = new DOMParser(); |
|
|
fauxXhr.responseXML = parser.parseFromString(xml, "text/xml"); |
|
|
} |
|
|
// kludge: code from dojo.xhr contentHandler to create doc on IE |
|
|
var result = fauxXhr.responseXML; |
|
|
if (has("ie")) { |
|
|
// Needed for IE6-8 |
|
|
if ((!result || !result.documentElement)) { |
|
|
var ms = function (n) { |
|
|
return "MSXML" + n + ".DOMDocument"; |
|
|
}; |
|
|
var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)]; |
|
|
array.some(dp, function (p) { |
|
|
try { |
|
|
var dom = new ActiveXObject(p); |
|
|
dom.async = false; |
|
|
dom.loadXML(fauxXhr.responseText); |
|
|
result = dom; |
|
|
} catch (e) { |
|
|
return false; |
|
|
} |
|
|
return true; |
|
|
}); |
|
|
} |
|
|
} |
|
|
return result; // DOMDocument |
|
|
} |
|
|
}); |
|
|
}, |
|
|
|
|
|
css2: { |
|
|
"basic sanity checks": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['h3'] = query('h3').length; |
|
|
result['#t'] = query('#t').length; |
|
|
result['#bug'] = query('#bug').length; |
|
|
result['#t h3'] = query('#t h3').length; |
|
|
result['div#t'] = query('div#t').length; |
|
|
result['div#t h3'] = query('div#t h3').length; |
|
|
result['span#t'] = query('span#t').length; |
|
|
result['.bogus'] = query('.bogus').length; |
|
|
result['.bogus-scoped'] = query('.bogus', dom.byId('container')).length; |
|
|
result['#bogus'] = query('#bogus').length; |
|
|
result['#bogus-scoped'] = query('#bogus', dom.byId('container')).length; |
|
|
result['#t div > h3'] = query('#t div > h3').length; |
|
|
result['.foo'] = query('.foo').length; |
|
|
result['.foo.bar'] = query('.foo.bar').length; |
|
|
result['.baz'] = query('.baz').length; |
|
|
result['#t > h3'] = query('#t > h3').length; |
|
|
result['null'] = query(null).length; |
|
|
|
|
|
return result; |
|
|
}).then(function (results) { |
|
|
assert.equal((results['h3']), 4); |
|
|
assert.equal((results['#t']), 1); |
|
|
assert.equal((results['#bug']), 1); |
|
|
assert.equal((results['#t h3']), 4); |
|
|
assert.equal((results['div#t']), 1); |
|
|
assert.equal((results['div#t h3']), 4); |
|
|
assert.equal((results['span#t']), 0); |
|
|
assert.equal((results['.bogus']), 0); |
|
|
assert.equal((results['.bogus-scoped']), 0); |
|
|
assert.equal((results['#bogus']), 0); |
|
|
assert.equal((results['#bogus-scoped']), 0); |
|
|
assert.equal((results['#t div > h3']), 1); |
|
|
assert.equal((results['.foo']), 2); |
|
|
assert.equal((results['.foo.bar']), 1); |
|
|
assert.equal((results['.baz']), 2); |
|
|
assert.equal((results['#t > h3']), 3); |
|
|
assert.equal((results['null']), 0); |
|
|
}); |
|
|
}, |
|
|
"comma1": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query('#baz,#foo,#t').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 2); |
|
|
}); |
|
|
}, |
|
|
"comma2": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query('#foo,#baz,#t').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 2); |
|
|
}); |
|
|
}, |
|
|
"syntactic equivalents": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["#t > *"] = query('#t > *').length; |
|
|
result[".foo > *"] = query('.foo > *').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result["#t > *"], 12); |
|
|
assert.equal(result[".foo > *"], 3); |
|
|
}); |
|
|
}, |
|
|
"with a root, by ID": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['> *'] = query('> *', 'container').length; |
|
|
result['> *, > h3'] = query('> *, > h3', 'container').length; |
|
|
result['> h3'] = query('> h3', 't').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['> *'], 3); |
|
|
assert.equal(result['> *, > h3'], 3); |
|
|
assert.equal(result['> h3'], 3); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"compound queries": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['.foo, .bar'] = query('.foo, .bar').length; |
|
|
result['.foo,.bar'] = query('.foo,.bar').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['.foo, .bar'], 2); |
|
|
assert.equal(result['.foo,.bar'], 2); |
|
|
}); |
|
|
}, |
|
|
|
|
|
"multiple class attribute": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['.foo.bar'] = query('.foo.bar').length; |
|
|
result['.foo'] = query('.foo').length; |
|
|
result['.baz'] = query('.baz').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['.foo.bar'], 1); |
|
|
assert.equal(result['.foo'], 2); |
|
|
assert.equal(result['.baz'], 2); |
|
|
}); |
|
|
}, |
|
|
"case sensitivity": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return { |
|
|
baz: [query('span.baz').length, query('sPaN.baz').length, query('SPAN.baz').length], |
|
|
fooBar: query('.fooBar').length |
|
|
}; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.deepEqual(result.baz, [1, 1, 1]); |
|
|
|
|
|
// For quirks mode, case sensitivity is browser dependent, so querying .fooBar |
|
|
// may return 1 or 2 entries. See #8775 and #14874 for details.
|
|
|
if (!/quirks/i.test(file)) { |
|
|
assert.equal(result.fooBar, 1); |
|
|
} |
|
|
}); |
|
|
}, |
|
|
"attribute selectors": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query('[foo]').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 3); |
|
|
}); |
|
|
}, |
|
|
"attribute substring selectors": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['[foo$=\"thud\"]'] = query('[foo$=\"thud\"]').length; |
|
|
result['[foo$=thud]'] = query('[foo$=thud]').length; |
|
|
result['[foo$=\"thudish\"]'] = query('[foo$=\"thudish\"]').length; |
|
|
result['#t [foo$=thud]'] = query('#t [foo$=thud]').length; |
|
|
result['#t [title$=thud]'] = query('#t [title$=thud]').length; |
|
|
result['#t span[title$=thud ]'] = query('#t span[title$=thud ]').length; |
|
|
result['[id$=\'55555\']'] = query('[id$=\'55555\']').length; |
|
|
result['[foo~=\"bar\"]'] = query('[foo~=\"bar\"]').length; |
|
|
result['[ foo ~= \"bar\" ]'] = query('[ foo ~= \"bar\" ]').length; |
|
|
result['[foo|=\"bar\"]'] = query('[foo|=\"bar\"]').length; |
|
|
result['[foo|=\"bar-baz\"]'] = query('[foo|=\"bar-baz\"]').length; |
|
|
result['[foo|=\"baz\"]'] = query('[foo|=\"baz\"]').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['[foo$=\"thud\"]'], 1); |
|
|
assert.equal(result['[foo$=thud]'], 1); |
|
|
assert.equal(result['[foo$=\"thudish\"]'], 1); |
|
|
assert.equal(result['#t [foo$=thud]'], 1); |
|
|
assert.equal(result['#t [title$=thud]'], 1); |
|
|
assert.equal(result['#t span[title$=thud ]'], 0); |
|
|
assert.equal(result['[id$=\'55555\']'], 1); |
|
|
assert.equal(result['[foo~=\"bar\"]'], 2); |
|
|
assert.equal(result['[ foo ~= \"bar\" ]'], 2); |
|
|
assert.equal(result['[foo|=\"bar\"]'], 2); |
|
|
assert.equal(result['[foo|=\"bar-baz\"]'], 1); |
|
|
assert.equal(result['[foo|=\"baz\"]'], 0); |
|
|
}); |
|
|
}, |
|
|
"descendant selectors": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['> *'] = query('> *', 'container').length; |
|
|
result['> [qux]'] = query('> [qux]', 'container').length; |
|
|
result['> [qux][0].id'] = query('> [qux]', 'container')[0].id; |
|
|
result['> [qux][1].id'] = query('> [qux]', 'container')[1].id; |
|
|
result['>*'] = query('>*', 'container').length; |
|
|
result['#bug[0].value'] = query('#bug')[0].value; // test id query doesn't match name |
|
|
|
|
|
|
|
|
// suppress exception for known bug #18516; remove this code if that bug is fixed. |
|
|
if(has("ie") <= 9 && has("quirks")){ |
|
|
result['#bug[0].value'] = "passed"; |
|
|
} |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['> *'], 3, '> *'); |
|
|
assert.equal(result['> [qux]'], 2, '> [qux]'); |
|
|
assert.equal(result['> [qux][0].id'], "child1", '> [qux][0].id'); |
|
|
assert.equal(result['> [qux][1].id'], "child3", '> [qux][1].id'); |
|
|
assert.equal(result['>*'], 3, '>*'); |
|
|
assert.equal(result['#bug[0].value'], "passed", '#bug[0].value'); |
|
|
}); |
|
|
}, |
|
|
"bug 9071": function () { |
|
|
// bug 9071 |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['t4 a'] = query('a', 't4').length; |
|
|
result['t4 p a'] = query('p a', 't4').length; |
|
|
result['t4 div p'] = query('div p', 't4').length; |
|
|
result['t4 div p a'] = query('div p a', 't4').length; |
|
|
result['t4 .subA'] = query('.subA', 't4').length; |
|
|
result['t4 .subP .subA'] = query('.subP .subA', 't4').length; |
|
|
result['t4 .subDiv .subP'] = query('.subDiv .subP', 't4').length; |
|
|
result['t4 .subDiv .subP .subA'] = query('.subDiv .subP .subA', 't4').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['t4 a'], 2); |
|
|
assert.equal(result['t4 p a'], 2); |
|
|
assert.equal(result['t4 div p'], 2); |
|
|
assert.equal(result['t4 div p a'], 2); |
|
|
assert.equal(result['t4 .subA'], 2); |
|
|
assert.equal(result['t4 .subP .subA'], 2); |
|
|
assert.equal(result['t4 .subDiv .subP'], 2); |
|
|
assert.equal(result['t4 .subDiv .subP .subA'], 2); |
|
|
}); |
|
|
}, |
|
|
"failed scope arg": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['thinger *'] = query('*', 'thinger').length; |
|
|
result['div#foo'] = query('div#foo').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['thinger *'], 0); |
|
|
assert.equal(result['div#foo'], 0); |
|
|
}); |
|
|
}, |
|
|
"escaping special characters with quotes": function () { |
|
|
// http://www.w3.org/TR/CSS21/syndata.html#strings |
|
|
// bug 10651 |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['option[value="a+b"]'] = query('option[value="a+b"]', "attrSpecialChars").length; |
|
|
result['option[value="a~b"]'] = query('option[value="a~b"]', "attrSpecialChars").length; |
|
|
result['option[value="a^b"]'] = query('option[value="a^b"]', "attrSpecialChars").length; |
|
|
result['option[value="a,b"]'] = query('option[value="a,b"]', "attrSpecialChars").length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['option[value="a+b"]'], 1); |
|
|
assert.equal(result['option[value="a~b"]'], 1); |
|
|
assert.equal(result['option[value="a^b"]'], 1); |
|
|
assert.equal(result['option[value="a,b"]'], 1); |
|
|
}); |
|
|
}, |
|
|
"selector with substring that contains equals sign - bug 7479": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query("a[href*='foo=bar']", 'attrSpecialChars').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 1); |
|
|
}); |
|
|
}, |
|
|
"selector with substring that contains brackets - bug 9193, 11189, 13084": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['input[name="data[foo][bar]"]'] = query('input[name="data[foo][bar]"]', "attrSpecialChars").length; |
|
|
result['input[name="foo[0].bar'] = query('input[name="foo[0].bar"]', "attrSpecialChars").length; |
|
|
result['input[name="test[0]"]'] = query('input[name="test[0]"]', "attrSpecialChars").length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['input[name="data[foo][bar]"]'], 1); |
|
|
assert.equal(result['input[name="foo[0].bar'], 1); |
|
|
assert.equal(result['input[name="test[0]"]'], 1); |
|
|
}); |
|
|
}, |
|
|
"escaping special characters with backslashes": function () { |
|
|
//http://www.w3.org/TR/CSS21/syndata.html#characters |
|
|
// selector with substring that contains brackets (bug 9193, 11189, 13084) |
|
|
// eval() converts 4 backslashes --> 1 by the time dojo.query() sees the string |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['input[name=data\\[foo\\]\\[bar\\]]'] = query("input[name=data\\[foo\\]\\[bar\\]]", "attrSpecialChars").length; |
|
|
result['input[name=foo\\[0\\]\\.bar]'] = query("input[name=foo\\[0\\]\\.bar]", "attrSpecialChars").length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['input[name=data\\[foo\\]\\[bar\\]]'], 1); |
|
|
assert.equal(result['input[name=foo\\[0\\]\\.bar]'], 1); |
|
|
}); |
|
|
}, |
|
|
"crossDocumentQuery": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
var t3 = window.frames["t3"]; |
|
|
var doc = iframe.doc(t3); |
|
|
doc.open(); |
|
|
doc.write([ |
|
|
"<html><head>", |
|
|
"<title>inner document</title>", |
|
|
"</head>", |
|
|
"<body>", |
|
|
" <div id='st1'>", |
|
|
" <h3>h3", |
|
|
" <span>", |
|
|
" span", |
|
|
" <span>", |
|
|
" inner", |
|
|
" <span>", |
|
|
" inner-inner", |
|
|
" </span>", |
|
|
" </span>", |
|
|
" </span>", |
|
|
" endh3", |
|
|
" </h3>", |
|
|
" </div>", |
|
|
"</body>", |
|
|
"</html>" |
|
|
].join("")); |
|
|
|
|
|
doc.close(); |
|
|
|
|
|
result["st1 h3"] = query('h3', dom.byId("st1", doc)).length; |
|
|
// use a long query to force a test of the XPath system on FF. see bug #7075 |
|
|
result['st1 h3 > span > span > span'] = query('h3 > span > span > span', dom.byId("st1", doc)).length; |
|
|
result['body.children[0] h3 > span > span > span'] = query('h3 > span > span > span', doc.body.children[0]).length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['st1 h3'], 1); |
|
|
assert.equal(result['st1 h3 > span > span > span'], 1); |
|
|
assert.equal(result['body.children[0] h3 > span > span > span'], 1); |
|
|
}); |
|
|
}, |
|
|
"escaping of ':' chars inside an ID": { |
|
|
"silly_IDs1": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["silly:id::with:colons"] = document.getElementById("silly:id::with:colons"); |
|
|
result["#silly\\:id\\:\\:with\\:colons"] = query("#silly\\:id\\:\\:with\\:colons").length; |
|
|
result["#silly\\~id"] = query("#silly\\~id").length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.isNotNull(result["silly:id::with:colons"], "getElementById"); |
|
|
assert.equal(result["#silly\\:id\\:\\:with\\:colons"], 1, "query(\"#silly\\:id\\:\\:with\\:colons\")"); |
|
|
assert.equal(result["#silly\\~id"], 1, "query(\"#silly\\~id\")"); |
|
|
}); |
|
|
} |
|
|
}, |
|
|
"xml": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var doc = createDocument([ |
|
|
"<ResultSet>", |
|
|
"<Result>One</Result>", |
|
|
"<RESULT>Two</RESULT>", |
|
|
"<result><nested>Three</nested></result>", |
|
|
"<result>Four</result>", |
|
|
"</ResultSet>" |
|
|
].join("")); |
|
|
|
|
|
var de = doc.documentElement; |
|
|
|
|
|
// note: don't name structure members after elements because it gets corrupted on IE (webdriver bug) |
|
|
return { |
|
|
lower: query("result", de).length, |
|
|
mixed: query("Result", de).length, |
|
|
upper: query("RESULT", de).length, |
|
|
nomatch1: query("resulT", de).length, |
|
|
nomatch2: query("rEsulT", de).length |
|
|
}; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result.lower, 2, "all lower"); |
|
|
assert.equal(result.mixed, 1, "mixed case"); |
|
|
assert.equal(result.upper, 1, "all upper"); |
|
|
assert.equal(result.nomatch1, 0, "no match 1"); |
|
|
assert.equal(result.nomatch2, 0, "no match 2"); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"xml_attrs": function () { |
|
|
var remote = this.get("remote"); |
|
|
if (/internet explorer/.test(remote.environmentType.browserName)) { |
|
|
return this.skip("do not run in IE till bug #14880 is fixed"); |
|
|
} |
|
|
return remote.execute(function () { |
|
|
var doc = createDocument([ |
|
|
"<ResultSet>", |
|
|
"<RESULT thinger='blah'>ONE</RESULT>", |
|
|
"<RESULT thinger='gadzooks'><CHILD>Two</CHILD></RESULT>", |
|
|
"</ResultSet>" |
|
|
].join("")); |
|
|
var de = doc.documentElement; |
|
|
|
|
|
return { |
|
|
RESULT: query("RESULT", de).length, |
|
|
"RESULT[THINGER]": query("RESULT[THINGER]", de).length, |
|
|
"RESULT[thinger]": query("RESULT[thinger]", de).length, |
|
|
"RESULT[thinger=blah]": query("RESULT[thinger=blah]", de).length, |
|
|
"RESULT > CHILD": query("RESULT > CHILD", de).length |
|
|
}; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result["RESULT"], 2, "result elements"); |
|
|
assert.equal(result["RESULT[THINGER]"], 0, "result elements with attrs (wrong)"); |
|
|
assert.equal(result["RESULT[thinger]"], 2, "result elements with attrs"); |
|
|
assert.equal(result["RESULT[thinger=blah]"], 1, "result elements with attr value"); |
|
|
assert.equal(result["RESULT > CHILD"], 1, "Using child operator"); |
|
|
}); |
|
|
}, |
|
|
"sort": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var i = query("div"); |
|
|
// smoke test |
|
|
i.sort(function (a, b) { |
|
|
return 1; |
|
|
}); |
|
|
return true; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.isTrue(result); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"document_fragment": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
var detachedDom = domConstruct.toDom("<i><u><a></a><b id='b'></b></u></i>"); |
|
|
var documentFragment = domConstruct.toDom("<i></i> <u><a></a><b id='b'></b></u>"); |
|
|
var detachedDom2 = domConstruct.toDom("<i><u><a></a><b></b></u></i>"); |
|
|
var documentFragment2 = domConstruct.toDom("<i></i> <u><a></a><b></b></u>"); |
|
|
|
|
|
result["#b detached"] = query("#b", detachedDom).length; |
|
|
result["#b detached first child"] = query("#b", detachedDom.firstChild).length; |
|
|
result["#b fragment"] = query("#b", documentFragment).length; |
|
|
// In IE8 in quirks mode there is no text node on the document fragment |
|
|
result["#b fragment child"] = query("#b", has('ie') === 8 && has("quirks") ? |
|
|
documentFragment.childNodes[1] : documentFragment.childNodes[2]).length; |
|
|
result["#b detached2"] = query("#b", detachedDom2).length; |
|
|
result["#b fragment2"] = query("#b", documentFragment2).length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result["#b detached"], 1); |
|
|
assert.equal(result["#b detached first child"], 1); |
|
|
assert.equal(result["#b fragment"], 1); |
|
|
assert.equal(result["#b fragment child"], 1); |
|
|
assert.equal(result["#b detached2"], 0); |
|
|
assert.equal(result["#b fragment2"], 0); |
|
|
}); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
if (/css2.1|css3|acme/.test(selector)) { |
|
|
tests["css2.1"] = function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["h1:first-child"] = query('h1:first-child').length; |
|
|
result["h3:first-child"] = query('h3:first-child').length; |
|
|
result[".foo+ span"] = query('.foo+ span').length; |
|
|
result[".foo+span"] = query('.foo+span').length; |
|
|
result[".foo +span"] = query('.foo +span').length; |
|
|
result[".foo + span"] = query('.foo + span').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
// first-child |
|
|
assert.equal(result["h1:first-child"], 1); |
|
|
assert.equal(result["h3:first-child"], 2); |
|
|
|
|
|
// + sibling selector |
|
|
assert.equal(result[".foo+ span"], 1); |
|
|
assert.equal(result[".foo+span"], 1); |
|
|
assert.equal(result[".foo +span"], 1); |
|
|
assert.equal(result[".foo + span"], 1); |
|
|
}); |
|
|
}; |
|
|
} |
|
|
|
|
|
if (/css3|acme/.test(selector)) { |
|
|
tests["css3"] = { |
|
|
"sub-selector parsing": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query('#t span.foo:not(:first-child)').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 1); |
|
|
}); |
|
|
}, |
|
|
"~ sibling selector": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result[".foo~ span"] = query('.foo~ span').length; |
|
|
result[".foo~span"] = query('.foo~span').length; |
|
|
result[".foo ~span"] = query('.foo ~span').length; |
|
|
result[".foo ~ span"] = query('.foo ~ span').length; |
|
|
result["#foo~ *"] = query('#foo~ *').length; |
|
|
result["#foo ~*"] = query('#foo ~*').length; |
|
|
result["#foo ~*"] = query('#foo ~*').length; |
|
|
result["#foo ~ *"] = query('#foo ~ *').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result[".foo~ span"], 4); |
|
|
assert.equal(result[".foo~span"], 4); |
|
|
assert.equal(result[".foo ~span"], 4); |
|
|
assert.equal(result[".foo ~ span"], 4); |
|
|
assert.equal(result["#foo~ *"], 1); |
|
|
assert.equal(result["#foo ~*"], 1); |
|
|
assert.equal(result["#foo ~*"], 1); |
|
|
assert.equal(result["#foo ~ *"], 1); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"nth-child tests": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["#t > h3:nth-child(odd)"] = query('#t > h3:nth-child(odd)').length; |
|
|
result["#t h3:nth-child(odd)"] = query('#t h3:nth-child(odd)').length; |
|
|
result["#t h3:nth-child(2n+1)"] = query('#t h3:nth-child(2n+1)').length; |
|
|
result["#t h3:nth-child(even)"] = query('#t h3:nth-child(even)').length; |
|
|
result["#t h3:nth-child(2n)"] = query('#t h3:nth-child(2n)').length; |
|
|
result["#t h3:nth-child(2n+3)"] = query('#t h3:nth-child(2n+3)').length; |
|
|
result["#t h3:nth-child(1)"] = query('#t h3:nth-child(1)').length; |
|
|
result["#t > h3:nth-child(1)"] = query('#t > h3:nth-child(1)').length; |
|
|
result["#t :nth-child(3)"] = query('#t :nth-child(3)').length; |
|
|
result["#t > div:nth-child(1)"] = query('#t > div:nth-child(1)').length; |
|
|
result["#t :nth-child(3)"] = query('#t :nth-child(3)').length; |
|
|
result["#t > div:nth-child(1)"] = query('#t > div:nth-child(1)').length; |
|
|
result["#t span"] = query('#t span').length; |
|
|
result["#t > *:nth-child(n+10)"] = query('#t > *:nth-child(n+10)').length; |
|
|
result["#t > *:nth-child(n+12)"] = query('#t > *:nth-child(n+12)').length; |
|
|
result["#t > *:nth-child(-n+10)"] = query('#t > *:nth-child(-n+10)').length; |
|
|
result["#t > *:nth-child(-2n+10)"] = query('#t > *:nth-child(-2n+10)').length; |
|
|
result["#t > *:nth-child(2n+2)"] = query('#t > *:nth-child(2n+2)').length; |
|
|
result["#t > *:nth-child(2n+4)"] = query('#t > *:nth-child(2n+4)').length; |
|
|
result["#t> *:nth-child(2n+4)"] = query('#t> *:nth-child(2n+4)').length; |
|
|
result["#t > *:nth-child(n-5)"] = query('#t > *:nth-child(n-5)').length; |
|
|
result["#t >*:nth-child(n-5)"] = query('#t >*:nth-child(n-5)').length; |
|
|
result["#t > *:nth-child(2n-5)"] = query('#t > *:nth-child(2n-5)').length; |
|
|
result["#t>*:nth-child(2n-5)"] = query('#t>*:nth-child(2n-5)').length; |
|
|
// function(){ doh.is(dom.byId('_foo'), result[".foo:nth-child(2)"][0], ".foo:nth-child(2)"); }, |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
// nth-child tests |
|
|
assert.equal(result["#t > h3:nth-child(odd)"], 2, "#t > h3:nth-child(odd)"); |
|
|
assert.equal(result["#t h3:nth-child(odd)"], 3, "#t h3:nth-child(odd)"); |
|
|
assert.equal(result["#t h3:nth-child(2n+1)"], 3, "#t h3:nth-child(2n+1)"); |
|
|
assert.equal(result["#t h3:nth-child(even)"], 1, "#t h3:nth-child(even)"); |
|
|
assert.equal(result["#t h3:nth-child(2n)"], 1, "#t h3:nth-child(2n)"); |
|
|
assert.equal(result["#t h3:nth-child(2n+3)"], 1, "#t h3:nth-child(2n+3)"); |
|
|
assert.equal(result["#t h3:nth-child(1)"], 2, "#t h3:nth-child(1)"); |
|
|
assert.equal(result["#t > h3:nth-child(1)"], 1, "#t > h3:nth-child(1)"); |
|
|
assert.equal(result["#t :nth-child(3)"], 3, "#t :nth-child(3)"); |
|
|
assert.equal(result["#t > div:nth-child(1)"], 0, "#t > div:nth-child(1)"); |
|
|
assert.equal(result["#t span"], 7, "#t span"); |
|
|
assert.equal(result["#t > *:nth-child(n+10)"], 3, "#t > *:nth-child(n+10)"); |
|
|
assert.equal(result["#t > *:nth-child(n+12)"], 1, "#t > *:nth-child(n+12)"); |
|
|
assert.equal(result["#t > *:nth-child(-n+10)"], 10, "#t > *:nth-child(-n+10)"); |
|
|
assert.equal(result["#t > *:nth-child(-2n+10)"], 5, "#t > *:nth-child(-2n+10)"); |
|
|
assert.equal(result["#t > *:nth-child(2n+2)"], 6, "#t > *:nth-child(2n+2)"); |
|
|
assert.equal(result["#t > *:nth-child(2n+4)"], 5, "#t > *:nth-child(2n+4)"); |
|
|
assert.equal(result["#t> *:nth-child(2n+4)"], 5, "#t> *:nth-child(2n+4)"); |
|
|
assert.equal(result["#t > *:nth-child(n-5)"], 12, "#t > *:nth-child(n-5)"); |
|
|
assert.equal(result["#t >*:nth-child(n-5)"], 12, "#t >*:nth-child(n-5)"); |
|
|
assert.equal(result["#t > *:nth-child(2n-5)"], 6, "#t > *:nth-child(2n-5)"); |
|
|
assert.equal(result["#t>*:nth-child(2n-5)"], 6, "#t>*:nth-child(2n-5)"); |
|
|
// function(){ doh.is(dom.byId('_foo'), result[".foo:nth-child(2)"][0], ".foo:nth-child(2)"); }, |
|
|
}); |
|
|
|
|
|
}, |
|
|
":checked pseudo-selector": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["#t2 > :checked"] = query('#t2 > :checked').length; |
|
|
result["#t2 > input[type=checkbox]:checked"] = |
|
|
query('#t2 > input[type=checkbox]:checked')[0] === dom.byId('checkbox2'); |
|
|
result["#t2 > input[type=radio]:checked"] = |
|
|
query('#t2 > input[type=radio]:checked')[0] === dom.byId('radio2'); |
|
|
|
|
|
result["#t2select option:checked"] = query('#t2select option:checked').length; |
|
|
|
|
|
result["#radio1:disabled"] = query('#radio1:disabled').length; |
|
|
result["#radio1:enabled"] = query('#radio1:enabled').length; |
|
|
result["#radio2:disabled"] = query('#radio2:disabled').length; |
|
|
result["#radio2:enabled"] = query('#radio2:enabled').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['#t2 > :checked'], 2); |
|
|
assert.isTrue(result['#t2 > input[type=checkbox]:checked']); |
|
|
assert.isTrue(result['#t2 > input[type=radio]:checked']); |
|
|
// This :checked selector is only defined for elements that have the checked property, option elements are not specified by the spec (http://www.w3.org/TR/css3-selectors/#checked) and not universally supported |
|
|
//assert.equal(result['#t2select option:checked'], 2); |
|
|
|
|
|
assert.equal(result['#radio1:disabled'], 1); |
|
|
assert.equal(result['#radio1:enabled'], 0); |
|
|
assert.equal(result['#radio2:disabled'], 0); |
|
|
assert.equal(result['#radio2:enabled'], 1); |
|
|
}); |
|
|
|
|
|
}, |
|
|
":empty pseudo-selector": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["#t > span:empty"] = query('#t > span:empty').length; |
|
|
result["#t span:empty"] = query('#t span:empty').length; |
|
|
result["h3 span:empty"] = query('h3 span:empty').length; |
|
|
result["h3 :not(:empty)"] = query('h3 :not(:empty)').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['#t > span:empty'], 4); |
|
|
assert.equal(result['#t span:empty'], 6); |
|
|
assert.equal(result['h3 span:empty'], 0); |
|
|
assert.equal(result['h3 :not(:empty)'], 1); |
|
|
}); |
|
|
|
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
if (selector == "acme") { |
|
|
tests.acme = { |
|
|
"Case insensitive class selectors - bug #8775, #14874": function () { |
|
|
// Case insensitive class selectors (#8775, #14874). |
|
|
// In standards mode documents, querySelectorAll() is case-sensitive about class selectors, |
|
|
// but acme is case-insensitive for backwards compatibility. |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query(".fooBar").length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 1); |
|
|
}); |
|
|
}, |
|
|
"sub-selector parsing": function () { |
|
|
// TODO: move this test to CSS3 section when #14875 is fixed |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
return query('#t span.foo:not(span:first-child)').length; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, 1); |
|
|
}); |
|
|
}, |
|
|
"special characters in attribute values without backslashes": function () { |
|
|
// supported by acme but apparently not standard, see http://www.w3.org/TR/CSS21/syndata.html#characters |
|
|
function attrSpecialCharsNoEscape() { |
|
|
// bug 10651 |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result["option[value=a+b]"] = query('option[value=a+b]', 'attrSpecialChars').length; |
|
|
result["option[value=a~b]"] = query('option[value=a~b]', 'attrSpecialChars').length; |
|
|
result["option[value=a^b]"] = query('option[value=a^b]', 'attrSpecialChars').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result["option[value=a+b]"], 1, "value=a+b"); |
|
|
assert.equal(result["option[value=a~b]"], 1, "value=a~b"); |
|
|
assert.equal(result["option[value=a^b]"], 1, "value=a^b"); |
|
|
}); |
|
|
} |
|
|
}, |
|
|
"implied * after > (non-standard syntax)": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
result['#t >'] = query('#t >').length; |
|
|
result['.foo >'] = query('.foo >').length; |
|
|
result['>'] = query('>', 'container').length; |
|
|
result['> .not-there'] = query('> .not-there').length; |
|
|
result['#foo ~'] = query('#foo ~').length; |
|
|
result['#foo~'] = query('#foo~').length; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['#t >'], 12); |
|
|
assert.equal(result['.foo >'], 3); |
|
|
assert.equal(result['>'], 3); |
|
|
assert.equal(result['> .not-there'], 0); |
|
|
assert.equal(result['#foo ~'], 1); |
|
|
assert.equal(result['#foo~'], 1); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"implied * before and after + and ~ (non-standard syntax)": function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
result["+"] = query('+', 'container').length; |
|
|
result["~"] = query('~', 'container').length; |
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result['+'], 1); |
|
|
assert.equal(result['~'], 3); |
|
|
}); |
|
|
|
|
|
}, |
|
|
"check for correct document order": { |
|
|
// not sure if this is guaranteed by css3, so putting in acme section |
|
|
domOrder: function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var result = {}; |
|
|
|
|
|
var inputs = query(".upperclass .lowerclass input"); |
|
|
|
|
|
result["notbug"] = inputs[0].id; |
|
|
result["bug"] = inputs[1].id; |
|
|
result["checkbox1"] = inputs[2].id; |
|
|
result["checkbox2"] = inputs[3].id; |
|
|
result["radio1"] = inputs[4].id; |
|
|
result["radio2"] = inputs[5].id; |
|
|
result["radio3"] = inputs[6].id; |
|
|
|
|
|
return result; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result["notbug"], "notbug"); |
|
|
assert.equal(result["bug"], "bug"); |
|
|
assert.equal(result["checkbox1"], "checkbox1"); |
|
|
assert.equal(result["checkbox2"], "checkbox2"); |
|
|
assert.equal(result["radio1"], "radio1"); |
|
|
assert.equal(result["radio2"], "radio2"); |
|
|
assert.equal(result["radio3"], "radio3"); |
|
|
}); |
|
|
}, |
|
|
|
|
|
// TODO: move to css2 section after #7869 fixed for lite engine (on IE) |
|
|
xml_nthchild: function () { |
|
|
return this.get("remote") |
|
|
.execute(function () { |
|
|
var doc = createDocument([ |
|
|
"<ResultSet>", |
|
|
"<result>One</result>", |
|
|
"<result>Two</result>", |
|
|
"<result>Three</result>", |
|
|
"<result>Four</result>", |
|
|
"</ResultSet>" |
|
|
].join("") |
|
|
); |
|
|
var de = doc.documentElement; |
|
|
|
|
|
return query("result:nth-child(4)", de)[0].firstChild.data; |
|
|
}) |
|
|
.then(function (result) { |
|
|
assert.equal(result, "Four", "fourth child"); |
|
|
}); |
|
|
} |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
registerSuite(tests); |
|
|
}); |
|
|
}); |
|
|
});
|
|
|
|