mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Merge pull request #134 from lightpanda-io/dom-queryselector
basic queryselector
This commit is contained in:
@@ -7,8 +7,10 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const Node = @import("node.zig").Node;
|
||||
const NodeList = @import("nodelist.zig").NodeList;
|
||||
const NodeUnion = @import("node.zig").Union;
|
||||
|
||||
const Walker = @import("html_collection.zig").WalkerDepthFirst;
|
||||
const collection = @import("html_collection.zig");
|
||||
|
||||
const Element = @import("element.zig").Element;
|
||||
@@ -190,6 +192,56 @@ pub const Document = struct {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO netsurf doesn't handle query selectors. We have to implement a
|
||||
// solution by ourselves.
|
||||
// For now we handle only * and single id selector like `#foo`.
|
||||
pub fn _querySelector(self: *parser.Document, selectors: []const u8) !?ElementUnion {
|
||||
if (selectors.len == 0) return null;
|
||||
|
||||
// catch-all, return the firstElementChild
|
||||
if (selectors[0] == '*') return try get_firstElementChild(self);
|
||||
|
||||
// support only simple id selector.
|
||||
if (selectors[0] != '#' or std.mem.indexOf(u8, selectors, " ") != null) return null;
|
||||
|
||||
return try _getElementById(self, selectors[1..]);
|
||||
}
|
||||
|
||||
// TODO netsurf doesn't handle query selectors. We have to implement a
|
||||
// solution by ourselves.
|
||||
// We handle only * and single id selector like `#foo`.
|
||||
pub fn _querySelectorAll(self: *parser.Document, alloc: std.mem.Allocator, selectors: []const u8) !NodeList {
|
||||
var list = try NodeList.init();
|
||||
errdefer list.deinit(alloc);
|
||||
|
||||
if (selectors.len == 0) return list;
|
||||
|
||||
// catch-all, return all elements
|
||||
if (selectors[0] == '*') {
|
||||
// walk over the node tree fo find the node by id.
|
||||
const root = parser.elementToNode(try parser.documentGetDocumentElement(self) orelse return list);
|
||||
const walker = Walker{};
|
||||
var next: ?*parser.Node = null;
|
||||
while (true) {
|
||||
next = try walker.get_next(root, next) orelse return list;
|
||||
// ignore non-element nodes.
|
||||
if (try parser.nodeType(next.?) != .element) {
|
||||
continue;
|
||||
}
|
||||
try list.append(alloc, next.?);
|
||||
}
|
||||
}
|
||||
|
||||
// support only simple id selector.
|
||||
if (selectors[0] != '#' or std.mem.indexOf(u8, selectors, " ") != null) return list;
|
||||
|
||||
// walk over the node tree fo find the node by id.
|
||||
const e = try parser.documentGetElementById(self, selectors[1..]) orelse return list;
|
||||
try list.append(alloc, parser.elementToNode(e));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {}
|
||||
};
|
||||
|
||||
@@ -325,13 +377,6 @@ pub fn testExecFn(
|
||||
};
|
||||
try checkCases(js_env, &importNode);
|
||||
|
||||
var adoptNode = [_]Case{
|
||||
.{ .src = "let nadop = document.getElementById('content')", .ex = "undefined" },
|
||||
.{ .src = "var v = document.adoptNode(nadop)", .ex = "undefined" },
|
||||
.{ .src = "v.nodeName", .ex = "DIV" },
|
||||
};
|
||||
try checkCases(js_env, &adoptNode);
|
||||
|
||||
var createAttr = [_]Case{
|
||||
.{ .src = "var v = document.createAttribute('foo')", .ex = "undefined" },
|
||||
.{ .src = "v.nodeName", .ex = "foo" },
|
||||
@@ -354,6 +399,23 @@ pub fn testExecFn(
|
||||
};
|
||||
try checkCases(js_env, &parentNode);
|
||||
|
||||
var querySelector = [_]Case{
|
||||
.{ .src = "document.querySelector('')", .ex = "null" },
|
||||
.{ .src = "document.querySelector('*').nodeName", .ex = "HTML" },
|
||||
.{ .src = "document.querySelector('#content').id", .ex = "content" },
|
||||
.{ .src = "document.querySelector('#para').id", .ex = "para" },
|
||||
};
|
||||
try checkCases(js_env, &querySelector);
|
||||
|
||||
// this test breaks the doc structure, keep it at the end of the test
|
||||
// suite.
|
||||
var adoptNode = [_]Case{
|
||||
.{ .src = "let nadop = document.getElementById('content')", .ex = "undefined" },
|
||||
.{ .src = "var v = document.adoptNode(nadop)", .ex = "undefined" },
|
||||
.{ .src = "v.nodeName", .ex = "DIV" },
|
||||
};
|
||||
try checkCases(js_env, &adoptNode);
|
||||
|
||||
const tags = comptime parser.Tag.all();
|
||||
comptime var createElements: [(tags.len) * 2]Case = undefined;
|
||||
inline for (tags, 0..) |tag, i| {
|
||||
|
||||
@@ -5,6 +5,7 @@ const EventTarget = @import("event_target.zig").EventTarget;
|
||||
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
||||
const NamedNodeMap = @import("namednodemap.zig").NamedNodeMap;
|
||||
const DOMTokenList = @import("token_list.zig").DOMTokenList;
|
||||
const NodeList = @import("nodelist.zig").NodeList;
|
||||
const Nod = @import("node.zig");
|
||||
|
||||
pub const Interfaces = generate.Tuple(.{
|
||||
@@ -13,6 +14,7 @@ pub const Interfaces = generate.Tuple(.{
|
||||
DOMImplementation,
|
||||
NamedNodeMap,
|
||||
DOMTokenList,
|
||||
NodeList,
|
||||
Nod.Node,
|
||||
Nod.Interfaces,
|
||||
});
|
||||
|
||||
@@ -9,6 +9,8 @@ const checkCases = jsruntime.test_utils.checkCases;
|
||||
const collection = @import("html_collection.zig");
|
||||
|
||||
const Node = @import("node.zig").Node;
|
||||
const Walker = @import("html_collection.zig").WalkerDepthFirst;
|
||||
const NodeList = @import("nodelist.zig").NodeList;
|
||||
const HTMLElem = @import("../html/elements.zig");
|
||||
pub const Union = @import("../html/elements.zig").Union;
|
||||
|
||||
@@ -191,6 +193,74 @@ pub const Element = struct {
|
||||
return try HTMLElem.toInterface(HTMLElem.Union, res.?);
|
||||
}
|
||||
|
||||
fn getElementById(self: *parser.Element, id: []const u8) !?*parser.Node {
|
||||
// walk over the node tree fo find the node by id.
|
||||
const root = parser.elementToNode(self);
|
||||
const walker = Walker{};
|
||||
var next: ?*parser.Node = null;
|
||||
while (true) {
|
||||
next = try walker.get_next(root, next) orelse return null;
|
||||
// ignore non-element nodes.
|
||||
if (try parser.nodeType(next.?) != .element) {
|
||||
continue;
|
||||
}
|
||||
const e = parser.nodeToElement(next.?);
|
||||
if (std.mem.eql(u8, id, try get_id(e))) return next;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO netsurf doesn't handle query selectors. We have to implement a
|
||||
// solution by ourselves.
|
||||
// We handle only * and single id selector like `#foo`.
|
||||
pub fn _querySelector(self: *parser.Element, selectors: []const u8) !?Union {
|
||||
if (selectors.len == 0) return null;
|
||||
|
||||
// catch-all, return the firstElementChild
|
||||
if (selectors[0] == '*') return try get_firstElementChild(self);
|
||||
|
||||
// support only simple id selector.
|
||||
if (selectors[0] != '#' or std.mem.indexOf(u8, selectors, " ") != null) return null;
|
||||
|
||||
// walk over the node tree fo find the node by id.
|
||||
const n = try getElementById(self, selectors[1..]) orelse return null;
|
||||
return try toInterface(parser.nodeToElement(n));
|
||||
}
|
||||
|
||||
// TODO netsurf doesn't handle query selectors. We have to implement a
|
||||
// solution by ourselves.
|
||||
// We handle only * and single id selector like `#foo`.
|
||||
pub fn _querySelectorAll(self: *parser.Element, alloc: std.mem.Allocator, selectors: []const u8) !NodeList {
|
||||
var list = try NodeList.init();
|
||||
errdefer list.deinit(alloc);
|
||||
|
||||
if (selectors.len == 0) return list;
|
||||
|
||||
// catch-all, return all elements
|
||||
if (selectors[0] == '*') {
|
||||
// walk over the node tree fo find the node by id.
|
||||
const root = parser.elementToNode(self);
|
||||
const walker = Walker{};
|
||||
var next: ?*parser.Node = null;
|
||||
while (true) {
|
||||
next = try walker.get_next(root, next) orelse return list;
|
||||
// ignore non-element nodes.
|
||||
if (try parser.nodeType(next.?) != .element) {
|
||||
continue;
|
||||
}
|
||||
try list.append(alloc, next.?);
|
||||
}
|
||||
}
|
||||
|
||||
// support only simple id selector.
|
||||
if (selectors[0] != '#' or std.mem.indexOf(u8, selectors, " ") != null) return list;
|
||||
|
||||
// walk over the node tree fo find the node by id.
|
||||
const n = try getElementById(self, selectors[1..]) orelse return list;
|
||||
try list.append(alloc, n);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
pub fn deinit(_: *parser.Element, _: std.mem.Allocator) void {}
|
||||
};
|
||||
|
||||
@@ -278,4 +348,22 @@ pub fn testExecFn(
|
||||
.{ .src = "d.nextElementSibling", .ex = "null" },
|
||||
};
|
||||
try checkCases(js_env, &elementSibling);
|
||||
|
||||
var querySelector = [_]Case{
|
||||
.{ .src = "let e = document.getElementById('content')", .ex = "undefined" },
|
||||
.{ .src = "e.querySelector('foo')", .ex = "null" },
|
||||
.{ .src = "e.querySelector('#foo')", .ex = "null" },
|
||||
.{ .src = "e.querySelector('#link').id", .ex = "link" },
|
||||
.{ .src = "e.querySelector('#para').id", .ex = "para" },
|
||||
.{ .src = "e.querySelector('*').id", .ex = "link" },
|
||||
|
||||
.{ .src = "e.querySelectorAll('foo').length", .ex = "0" },
|
||||
.{ .src = "e.querySelectorAll('#foo').length", .ex = "0" },
|
||||
.{ .src = "e.querySelectorAll('#link').length", .ex = "1" },
|
||||
.{ .src = "e.querySelectorAll('#link').item(0).id", .ex = "link" },
|
||||
.{ .src = "e.querySelectorAll('#para').length", .ex = "1" },
|
||||
.{ .src = "e.querySelectorAll('#para').item(0).id", .ex = "para" },
|
||||
.{ .src = "e.querySelectorAll('*').length", .ex = "4" },
|
||||
};
|
||||
try checkCases(js_env, &querySelector);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ const EventTarget = @import("event_target.zig").EventTarget;
|
||||
const Attr = @import("attribute.zig").Attr;
|
||||
const CData = @import("character_data.zig");
|
||||
const Element = @import("element.zig").Element;
|
||||
const NodeList = @import("nodelist.zig").NodeList;
|
||||
const Document = @import("document.zig").Document;
|
||||
const DocumentType = @import("document_type.zig").DocumentType;
|
||||
const DocumentFragment = @import("document_fragment.zig").DocumentFragment;
|
||||
@@ -193,6 +194,17 @@ pub const Node = struct {
|
||||
return try parser.nodeHasChildNodes(self);
|
||||
}
|
||||
|
||||
pub fn get_childNodes(self: *parser.Node, alloc: std.mem.Allocator) !NodeList {
|
||||
var list = try NodeList.init();
|
||||
errdefer list.deinit(alloc);
|
||||
|
||||
var n = try parser.nodeFirstChild(self) orelse return list;
|
||||
while (true) {
|
||||
try list.append(alloc, n);
|
||||
n = try parser.nodeNextSibling(n) orelse return list;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _insertBefore(self: *parser.Node, new_node: *parser.Node, ref_node: *parser.Node) !*parser.Node {
|
||||
return try parser.nodeInsertBefore(self, new_node, ref_node);
|
||||
}
|
||||
@@ -242,6 +254,8 @@ pub const Node = struct {
|
||||
const res = try parser.nodeReplaceChild(self, new_child, old_child);
|
||||
return try Node.toInterface(res);
|
||||
}
|
||||
|
||||
pub fn deinit(_: *parser.Node, _: std.mem.Allocator) void {}
|
||||
};
|
||||
|
||||
// Tests
|
||||
@@ -393,6 +407,12 @@ pub fn testExecFn(
|
||||
};
|
||||
try checkCases(js_env, &node_has_child_nodes);
|
||||
|
||||
var node_child_nodes = [_]Case{
|
||||
.{ .src = "link.childNodes.length", .ex = "1" },
|
||||
.{ .src = "text.childNodes.length", .ex = "0" },
|
||||
};
|
||||
try checkCases(js_env, &node_child_nodes);
|
||||
|
||||
var node_insert_before = [_]Case{
|
||||
.{ .src = "let insertBefore = document.createElement('a')", .ex = "undefined" },
|
||||
.{ .src = "link.insertBefore(insertBefore, text) !== undefined", .ex = "true" },
|
||||
|
||||
71
src/dom/nodelist.zig
Normal file
71
src/dom/nodelist.zig
Normal file
@@ -0,0 +1,71 @@
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const NodeUnion = @import("node.zig").Union;
|
||||
const Node = @import("node.zig").Node;
|
||||
|
||||
const DOMException = @import("exceptions.zig").DOMException;
|
||||
|
||||
// Nodelist is implemented in pure Zig b/c libdom's NodeList doesn't allow to
|
||||
// append nodes.
|
||||
// WEB IDL https://dom.spec.whatwg.org/#nodelist
|
||||
pub const NodeList = struct {
|
||||
pub const mem_guarantied = true;
|
||||
pub const Exception = DOMException;
|
||||
|
||||
const NodesArrayList = std.ArrayListUnmanaged(*parser.Node);
|
||||
|
||||
nodes: NodesArrayList,
|
||||
|
||||
pub fn init() !NodeList {
|
||||
return NodeList{
|
||||
.nodes = NodesArrayList{},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *NodeList, alloc: std.mem.Allocator) void {
|
||||
// TODO unref all nodes
|
||||
self.nodes.deinit(alloc);
|
||||
}
|
||||
|
||||
pub fn append(self: *NodeList, alloc: std.mem.Allocator, node: *parser.Node) !void {
|
||||
try self.nodes.append(alloc, node);
|
||||
}
|
||||
|
||||
pub fn get_length(self: *NodeList) u32 {
|
||||
return @intCast(self.nodes.items.len);
|
||||
}
|
||||
|
||||
pub fn _item(self: *NodeList, index: u32) !?NodeUnion {
|
||||
if (index >= self.nodes.items.len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const n = self.nodes.items[index];
|
||||
return try Node.toInterface(n);
|
||||
}
|
||||
|
||||
// TODO _symbol_iterator
|
||||
|
||||
// TODO implement postAttach
|
||||
};
|
||||
|
||||
// Tests
|
||||
// -----
|
||||
|
||||
pub fn testExecFn(
|
||||
_: std.mem.Allocator,
|
||||
js_env: *jsruntime.Env,
|
||||
comptime _: []jsruntime.API,
|
||||
) !void {
|
||||
var childnodes = [_]Case{
|
||||
.{ .src = "let list = document.getElementById('content').childNodes", .ex = "undefined" },
|
||||
.{ .src = "list.length", .ex = "9" },
|
||||
};
|
||||
try checkCases(js_env, &childnodes);
|
||||
}
|
||||
@@ -17,6 +17,7 @@ const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn;
|
||||
const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn;
|
||||
const NamedNodeMapExecFn = @import("dom/namednodemap.zig").testExecFn;
|
||||
const DOMTokenListExecFn = @import("dom/token_list.zig").testExecFn;
|
||||
const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn;
|
||||
|
||||
var doc: *parser.DocumentHTML = undefined;
|
||||
|
||||
@@ -65,6 +66,7 @@ fn testsAllExecFn(
|
||||
DOMImplementationExecFn,
|
||||
NamedNodeMapExecFn,
|
||||
DOMTokenListExecFn,
|
||||
NodeListTestExecFn,
|
||||
};
|
||||
|
||||
inline for (testFns) |testFn| {
|
||||
|
||||
73
tests/wpt/dom/nodes/Element-closest.html
Normal file
73
tests/wpt/dom/nodes/Element-closest.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE HTML>
|
||||
<meta charset=utf8>
|
||||
<title>Test for Element.closest</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<body id="body">
|
||||
<div id="test8" class="div3" style="display:none">
|
||||
<div id="test7" class="div2">
|
||||
<div id="test6" class="div1">
|
||||
<form id="test10" class="form2"></form>
|
||||
<form id="test5" class="form1" name="form-a">
|
||||
<input id="test1" class="input1" required>
|
||||
<fieldset class="fieldset2" id="test2">
|
||||
<select id="test3" class="select1" required>
|
||||
<option default id="test4" value="">Test4</option>
|
||||
<option selected id="test11">Test11</option>
|
||||
<option id="test12">Test12</option>
|
||||
<option id="test13">Test13</option>
|
||||
</select>
|
||||
<input id="test9" type="text" required>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
do_test("select" , "test12", "test3");
|
||||
do_test("fieldset" , "test13", "test2");
|
||||
do_test("div" , "test13", "test6");
|
||||
do_test("body" , "test3" , "body");
|
||||
|
||||
do_test("[default]" , "test4" , "test4");
|
||||
do_test("[selected]" , "test4" , "");
|
||||
do_test("[selected]" , "test11", "test11");
|
||||
do_test('[name="form-a"]' , "test12", "test5");
|
||||
do_test('form[name="form-a"]' , "test13", "test5");
|
||||
do_test("input[required]" , "test9" , "test9");
|
||||
do_test("select[required]" , "test9" , "");
|
||||
|
||||
do_test("div:not(.div1)" , "test13", "test7");
|
||||
do_test("div.div3" , "test6" , "test8");
|
||||
do_test("div#test7" , "test1" , "test7");
|
||||
|
||||
do_test(".div3 > .div2" , "test12", "test7");
|
||||
do_test(".div3 > .div1" , "test12", "");
|
||||
do_test("form > input[required]" , "test9" , "");
|
||||
do_test("fieldset > select[required]", "test12", "test3");
|
||||
|
||||
do_test("input + fieldset" , "test6" , "");
|
||||
do_test("form + form" , "test3" , "test5");
|
||||
do_test("form + form" , "test5" , "test5");
|
||||
|
||||
do_test(":empty" , "test10", "test10");
|
||||
do_test(":last-child" , "test11", "test2");
|
||||
do_test(":first-child" , "test12", "test3");
|
||||
do_test(":invalid" , "test11", "test2");
|
||||
|
||||
do_test(":scope" , "test4", "test4");
|
||||
do_test("select > :scope" , "test4", "test4");
|
||||
do_test("div > :scope" , "test4", "");
|
||||
do_test(":has(> :scope)" , "test4", "test3");
|
||||
function do_test(aSelector, aElementId, aTargetId) {
|
||||
test(function() {
|
||||
var el = document.getElementById(aElementId).closest(aSelector);
|
||||
if (el === null) {
|
||||
assert_equals("", aTargetId, aSelector);
|
||||
} else {
|
||||
assert_equals(el.id, aTargetId, aSelector);
|
||||
}
|
||||
}, "Element.closest with context node '" + aElementId + "' and selector '" + aSelector + "'");
|
||||
}
|
||||
</script>
|
||||
91
tests/wpt/dom/nodes/Element-insertAdjacentElement.html
Normal file
91
tests/wpt/dom/nodes/Element-insertAdjacentElement.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title></title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
|
||||
<div id="target"></div>
|
||||
<div id="parent"><span id=target2></span></div>
|
||||
<div id="log" style="visibility:visible"></div>
|
||||
<span id="test1"></span>
|
||||
<span id="test2"></span>
|
||||
<span id="test3"></span>
|
||||
<span id="test4"></span>
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var target2 = document.getElementById("target2");
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom("SyntaxError", function() {
|
||||
target.insertAdjacentElement("test", document.getElementById("test1"))
|
||||
});
|
||||
|
||||
assert_throws_dom("SyntaxError", function() {
|
||||
target2.insertAdjacentElement("test", document.getElementById("test1"))
|
||||
});
|
||||
}, "Inserting to an invalid location should cause a Syntax Error exception")
|
||||
|
||||
test(function() {
|
||||
var el = target.insertAdjacentElement("beforebegin", document.getElementById("test1"));
|
||||
assert_equals(target.previousSibling.id, "test1");
|
||||
assert_equals(el.id, "test1");
|
||||
|
||||
el = target2.insertAdjacentElement("beforebegin", document.getElementById("test1"));
|
||||
assert_equals(target2.previousSibling.id, "test1");
|
||||
assert_equals(el.id, "test1");
|
||||
}, "Inserted element should be target element's previous sibling for 'beforebegin' case")
|
||||
|
||||
test(function() {
|
||||
var el = target.insertAdjacentElement("afterbegin", document.getElementById("test2"));
|
||||
assert_equals(target.firstChild.id, "test2");
|
||||
assert_equals(el.id, "test2");
|
||||
|
||||
el = target2.insertAdjacentElement("afterbegin", document.getElementById("test2"));
|
||||
assert_equals(target2.firstChild.id, "test2");
|
||||
assert_equals(el.id, "test2");
|
||||
}, "Inserted element should be target element's first child for 'afterbegin' case")
|
||||
|
||||
test(function() {
|
||||
var el = target.insertAdjacentElement("beforeend", document.getElementById("test3"));
|
||||
assert_equals(target.lastChild.id, "test3");
|
||||
assert_equals(el.id, "test3");
|
||||
|
||||
el = target2.insertAdjacentElement("beforeend", document.getElementById("test3"));
|
||||
assert_equals(target2.lastChild.id, "test3");
|
||||
assert_equals(el.id, "test3");
|
||||
}, "Inserted element should be target element's last child for 'beforeend' case")
|
||||
|
||||
test(function() {
|
||||
var el = target.insertAdjacentElement("afterend", document.getElementById("test4"));
|
||||
assert_equals(target.nextSibling.id, "test4");
|
||||
assert_equals(el.id, "test4");
|
||||
|
||||
el = target2.insertAdjacentElement("afterend", document.getElementById("test4"));
|
||||
assert_equals(target2.nextSibling.id, "test4");
|
||||
assert_equals(el.id, "test4");
|
||||
}, "Inserted element should be target element's next sibling for 'afterend' case")
|
||||
|
||||
test(function() {
|
||||
var docElement = document.documentElement;
|
||||
docElement.style.visibility="hidden";
|
||||
|
||||
assert_throws_dom("HierarchyRequestError", function() {
|
||||
var el = docElement.insertAdjacentElement("beforebegin", document.getElementById("test1"));
|
||||
assert_equals(el, null);
|
||||
});
|
||||
|
||||
var el = docElement.insertAdjacentElement("afterbegin", document.getElementById("test2"));
|
||||
assert_equals(docElement.firstChild.id, "test2");
|
||||
assert_equals(el.id, "test2");
|
||||
|
||||
el = docElement.insertAdjacentElement("beforeend", document.getElementById("test3"));
|
||||
assert_equals(docElement.lastChild.id, "test3");
|
||||
assert_equals(el.id, "test3");
|
||||
|
||||
assert_throws_dom("HierarchyRequestError", function() {
|
||||
var el = docElement.insertAdjacentElement("afterend", document.getElementById("test4"));
|
||||
assert_equals(el, null);
|
||||
});
|
||||
}, "Adding more than one child to document should cause a HierarchyRequestError exception")
|
||||
|
||||
</script>
|
||||
76
tests/wpt/dom/nodes/Element-insertAdjacentText.html
Normal file
76
tests/wpt/dom/nodes/Element-insertAdjacentText.html
Normal file
@@ -0,0 +1,76 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title></title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<body style="visibility:hidden">
|
||||
<div id="target"></div>
|
||||
<div id="parent"><span id=target2></span></div>
|
||||
<div id="log" style="visibility:visible"></div>
|
||||
</body>
|
||||
<script>
|
||||
var target = document.getElementById("target");
|
||||
var target2 = document.getElementById("target2");
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom("SyntaxError", function() {
|
||||
target.insertAdjacentText("test", "text")
|
||||
});
|
||||
|
||||
assert_throws_dom("SyntaxError", function() {
|
||||
target2.insertAdjacentText("test", "test")
|
||||
});
|
||||
}, "Inserting to an invalid location should cause a Syntax Error exception")
|
||||
|
||||
test(function() {
|
||||
target.insertAdjacentText("beforebegin", "test1");
|
||||
assert_equals(target.previousSibling.nodeValue, "test1");
|
||||
|
||||
target2.insertAdjacentText("beforebegin", "test1");
|
||||
assert_equals(target2.previousSibling.nodeValue, "test1");
|
||||
}, "Inserted text node should be target element's previous sibling for 'beforebegin' case")
|
||||
|
||||
test(function() {
|
||||
target.insertAdjacentText("afterbegin", "test2");
|
||||
assert_equals(target.firstChild.nodeValue, "test2");
|
||||
|
||||
target2.insertAdjacentText("afterbegin", "test2");
|
||||
assert_equals(target2.firstChild.nodeValue, "test2");
|
||||
}, "Inserted text node should be target element's first child for 'afterbegin' case")
|
||||
|
||||
test(function() {
|
||||
target.insertAdjacentText("beforeend", "test3");
|
||||
assert_equals(target.lastChild.nodeValue, "test3");
|
||||
|
||||
target2.insertAdjacentText("beforeend", "test3");
|
||||
assert_equals(target2.lastChild.nodeValue, "test3");
|
||||
}, "Inserted text node should be target element's last child for 'beforeend' case")
|
||||
|
||||
test(function() {
|
||||
target.insertAdjacentText("afterend", "test4");
|
||||
assert_equals(target.nextSibling.nodeValue, "test4");
|
||||
|
||||
target2.insertAdjacentText("afterend", "test4");
|
||||
assert_equals(target.nextSibling.nodeValue, "test4");
|
||||
}, "Inserted text node should be target element's next sibling for 'afterend' case")
|
||||
|
||||
test(function() {
|
||||
var docElement = document.documentElement;
|
||||
docElement.style.visibility="hidden";
|
||||
|
||||
assert_throws_dom("HierarchyRequestError", function() {
|
||||
docElement.insertAdjacentText("beforebegin", "text1")
|
||||
});
|
||||
|
||||
docElement.insertAdjacentText("afterbegin", "test2");
|
||||
assert_equals(docElement.firstChild.nodeValue, "test2");
|
||||
|
||||
docElement.insertAdjacentText("beforeend", "test3");
|
||||
assert_equals(docElement.lastChild.nodeValue, "test3");
|
||||
|
||||
assert_throws_dom("HierarchyRequestError", function() {
|
||||
docElement.insertAdjacentText("afterend", "test4")
|
||||
});
|
||||
}, "Adding more than one child to document should cause a HierarchyRequestError exception")
|
||||
|
||||
</script>
|
||||
65
tests/wpt/dom/nodes/Element-matches-init.js
Normal file
65
tests/wpt/dom/nodes/Element-matches-init.js
Normal file
@@ -0,0 +1,65 @@
|
||||
function init(e, method) {
|
||||
/*
|
||||
* This test suite tests Selectors API methods in 4 different contexts:
|
||||
* 1. Document node
|
||||
* 2. In-document Element node
|
||||
* 3. Detached Element node (an element with no parent, not in the document)
|
||||
* 4. Document Fragment node
|
||||
*
|
||||
* For each context, the following tests are run:
|
||||
*
|
||||
* The interface check tests ensure that each type of node exposes the Selectors API methods.
|
||||
*
|
||||
* The matches() tests are run
|
||||
* All the selectors tested for both the valid and invalid selector tests are found in selectors.js.
|
||||
* See comments in that file for documentation of the format used.
|
||||
*
|
||||
* The level2-lib.js file contains all the common test functions for running each of the aforementioned tests
|
||||
*/
|
||||
|
||||
var docType = "html"; // Only run tests suitable for HTML
|
||||
|
||||
// Prepare the nodes for testing
|
||||
var doc = e.target.contentDocument; // Document Node tests
|
||||
|
||||
var element = doc.getElementById("root"); // In-document Element Node tests
|
||||
|
||||
//Setup the namespace tests
|
||||
setupSpecialElements(doc, element);
|
||||
|
||||
var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document
|
||||
// Element tests, but after running the Document tests. This
|
||||
// tests that no elements that are not descendants of element
|
||||
// are selected.
|
||||
|
||||
traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying
|
||||
elem.setAttribute("data-clone", ""); // that none of these elements ever match.
|
||||
});
|
||||
|
||||
|
||||
var detached = element.cloneNode(true); // Detached Element Node tests
|
||||
|
||||
var fragment = doc.createDocumentFragment(); // Fragment Node tests
|
||||
fragment.appendChild(element.cloneNode(true));
|
||||
|
||||
// Setup Tests
|
||||
interfaceCheckMatches(method, "Document", doc);
|
||||
interfaceCheckMatches(method, "Detached Element", detached);
|
||||
interfaceCheckMatches(method, "Fragment", fragment);
|
||||
interfaceCheckMatches(method, "In-document Element", element);
|
||||
|
||||
runSpecialMatchesTests(method, "DIV Element", element);
|
||||
runSpecialMatchesTests(method, "NULL Element", document.createElement("null"));
|
||||
runSpecialMatchesTests(method, "UNDEFINED Element", document.createElement("undefined"));
|
||||
|
||||
runInvalidSelectorTestMatches(method, "Document", doc, invalidSelectors);
|
||||
runInvalidSelectorTestMatches(method, "Detached Element", detached, invalidSelectors);
|
||||
runInvalidSelectorTestMatches(method, "Fragment", fragment, invalidSelectors);
|
||||
runInvalidSelectorTestMatches(method, "In-document Element", element, invalidSelectors);
|
||||
|
||||
runMatchesTest(method, "In-document", doc, validSelectors, "html");
|
||||
runMatchesTest(method, "Detached", detached, validSelectors, "html");
|
||||
runMatchesTest(method, "Fragment", fragment, validSelectors, "html");
|
||||
|
||||
runMatchesTest(method, "In-document", doc, scopedSelectors, "html");
|
||||
}
|
||||
24
tests/wpt/dom/nodes/Element-matches-namespaced-elements.html
Normal file
24
tests/wpt/dom/nodes/Element-matches-namespaced-elements.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>matches/webkitMatchesSelector must work when an element has a namespace</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression tests for https://github.com/jsdom/jsdom/issues/1846, https://github.com/jsdom/jsdom/issues/2247 -->
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
for (const method of ["matches", "webkitMatchesSelector"]) {
|
||||
test(() => {
|
||||
assert_true(document.createElementNS("", "element")[method]("element"));
|
||||
}, `empty string namespace, ${method}`);
|
||||
|
||||
test(() => {
|
||||
assert_true(document.createElementNS("urn:ns", "h")[method]("h"));
|
||||
}, `has a namespace, ${method}`);
|
||||
|
||||
test(() => {
|
||||
assert_true(document.createElementNS("urn:ns", "h")[method]("*|h"));
|
||||
}, `has a namespace, *|, ${method}`);
|
||||
}
|
||||
</script>
|
||||
22
tests/wpt/dom/nodes/Element-matches.html
Normal file
22
tests/wpt/dom/nodes/Element-matches.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title>
|
||||
<!-- Selectors API Test Suite Version 3 -->
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/dom/nodes/selectors.js"></script>
|
||||
<script src="/dom/nodes/ParentNode-querySelector-All.js"></script>
|
||||
<script src="Element-matches.js"></script>
|
||||
<script src="Element-matches-init.js"></script>
|
||||
<style>iframe { visibility: hidden; position: absolute; }</style>
|
||||
|
||||
<div id="log">This test requires JavaScript.</div>
|
||||
|
||||
<script>
|
||||
async_test(function() {
|
||||
var frame = document.createElement("iframe");
|
||||
frame.onload = this.step_func_done(e => init(e, "matches" ));
|
||||
frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target";
|
||||
document.body.appendChild(frame);
|
||||
});
|
||||
</script>
|
||||
135
tests/wpt/dom/nodes/Element-matches.js
Normal file
135
tests/wpt/dom/nodes/Element-matches.js
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Check that the matches() method exists on the given Node
|
||||
*/
|
||||
function interfaceCheckMatches(method, type, obj) {
|
||||
if (obj.nodeType === obj.ELEMENT_NODE) {
|
||||
test(function() {
|
||||
assert_idl_attribute(obj, method, type + " supports " + method);
|
||||
}, type + " supports " + method)
|
||||
} else {
|
||||
test(function() {
|
||||
assert_false(method in obj, type + " supports " + method);
|
||||
}, type + " should not support " + method)
|
||||
}
|
||||
}
|
||||
|
||||
function runSpecialMatchesTests(method, type, element) {
|
||||
test(function() { // 1
|
||||
if (element.tagName.toLowerCase() === "null") {
|
||||
assert_true(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match.");
|
||||
} else {
|
||||
assert_false(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match.");
|
||||
}
|
||||
}, type + "." + method + "(null)")
|
||||
|
||||
test(function() { // 2
|
||||
if (element.tagName.toLowerCase() === "undefined") {
|
||||
assert_true(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match.");
|
||||
} else {
|
||||
assert_false(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match.");
|
||||
}
|
||||
}, type + "." + method + "(undefined)")
|
||||
|
||||
test(function() { // 3
|
||||
assert_throws_js(element.ownerDocument.defaultView.TypeError, function() {
|
||||
element[method]();
|
||||
}, "This should throw a TypeError.")
|
||||
}, type + "." + method + " no parameter")
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute queries with the specified invalid selectors for matches()
|
||||
* Only run these tests when errors are expected. Don't run for valid selector tests.
|
||||
*/
|
||||
function runInvalidSelectorTestMatches(method, type, root, selectors) {
|
||||
if (root.nodeType === root.ELEMENT_NODE) {
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var s = selectors[i];
|
||||
var n = s["name"];
|
||||
var q = s["selector"];
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom(
|
||||
"SyntaxError",
|
||||
root.ownerDocument.defaultView.DOMException,
|
||||
function() {
|
||||
root[method](q)
|
||||
}
|
||||
);
|
||||
}, type + "." + method + ": " + n + ": " + q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runMatchesTest(method, type, root, selectors, docType) {
|
||||
var nodeType = getNodeType(root);
|
||||
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var s = selectors[i];
|
||||
var n = s["name"];
|
||||
var q = s["selector"];
|
||||
var e = s["expect"];
|
||||
var u = s["unexpected"];
|
||||
|
||||
var ctx = s["ctx"];
|
||||
var ref = s["ref"];
|
||||
|
||||
if ((!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1))
|
||||
&& (s["testType"] & TEST_MATCH) ) {
|
||||
|
||||
if (ctx && !ref) {
|
||||
test(function() {
|
||||
var j, element, refNode;
|
||||
for (j = 0; j < e.length; j++) {
|
||||
element = root.querySelector("#" + e[j]);
|
||||
refNode = root.querySelector(ctx);
|
||||
assert_true(element[method](q, refNode), "The element #" + e[j] + " should match the selector.")
|
||||
}
|
||||
|
||||
if (u) {
|
||||
for (j = 0; j < u.length; j++) {
|
||||
element = root.querySelector("#" + u[j]);
|
||||
refNode = root.querySelector(ctx);
|
||||
assert_false(element[method](q, refNode), "The element #" + u[j] + " should not match the selector.")
|
||||
}
|
||||
}
|
||||
}, type + " Element." + method + ": " + n + " (with refNode Element): " + q);
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
test(function() {
|
||||
var j, element, refNodes;
|
||||
for (j = 0; j < e.length; j++) {
|
||||
element = root.querySelector("#" + e[j]);
|
||||
refNodes = root.querySelectorAll(ref);
|
||||
assert_true(element[method](q, refNodes), "The element #" + e[j] + " should match the selector.")
|
||||
}
|
||||
|
||||
if (u) {
|
||||
for (j = 0; j < u.length; j++) {
|
||||
element = root.querySelector("#" + u[j]);
|
||||
refNodes = root.querySelectorAll(ref);
|
||||
assert_false(element[method](q, refNodes), "The element #" + u[j] + " should not match the selector.")
|
||||
}
|
||||
}
|
||||
}, type + " Element." + method + ": " + n + " (with refNodes NodeList): " + q);
|
||||
}
|
||||
|
||||
if (!ctx && !ref) {
|
||||
test(function() {
|
||||
for (var j = 0; j < e.length; j++) {
|
||||
var element = root.querySelector("#" + e[j]);
|
||||
assert_true(element[method](q), "The element #" + e[j] + " should match the selector.")
|
||||
}
|
||||
|
||||
if (u) {
|
||||
for (j = 0; j < u.length; j++) {
|
||||
element = root.querySelector("#" + u[j]);
|
||||
assert_false(element[method](q), "The element #" + u[j] + " should not match the selector.")
|
||||
}
|
||||
}
|
||||
}, type + " Element." + method + ": " + n + " (with no refNodes): " + q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
tests/wpt/dom/nodes/Element-remove.html
Normal file
16
tests/wpt/dom/nodes/Element-remove.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Element.remove</title>
|
||||
<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-remove">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="ChildNode-remove.js"></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
var node, parentNode;
|
||||
setup(function() {
|
||||
node = document.createElement("div");
|
||||
parentNode = document.createElement("div");
|
||||
});
|
||||
testRemove(node, parentNode, "element");
|
||||
</script>
|
||||
20
tests/wpt/dom/nodes/Element-siblingElement-null-svg.svg
Normal file
20
tests/wpt/dom/nodes/Element-siblingElement-null-svg.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:h="http://www.w3.org/1999/xhtml"
|
||||
version="1.1"
|
||||
width="100%" height="100%" viewBox="0 0 400 400">
|
||||
<title>Null test</title>
|
||||
<h:script src="/resources/testharness.js"/>
|
||||
<h:script src="/resources/testharnessreport.js"/>
|
||||
|
||||
<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of previousElementSibling and nextElementSibling returning null</text>
|
||||
<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is <tspan id="first_element_child" font-weight="bold">unknown.</tspan></text>
|
||||
|
||||
<h:script><![CDATA[
|
||||
test(function() {
|
||||
var fec = document.getElementById("first_element_child");
|
||||
assert_equals(fec.previousElementSibling, null)
|
||||
assert_equals(fec.nextElementSibling, null)
|
||||
})
|
||||
]]></h:script>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 869 B |
20
tests/wpt/dom/nodes/Element-siblingElement-null-xhtml.xhtml
Normal file
20
tests/wpt/dom/nodes/Element-siblingElement-null-xhtml.xhtml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Null Test</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test of previousElementSibling and nextElementSibling returning null</h1>
|
||||
<div id="log"></div>
|
||||
<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p>
|
||||
<script><![CDATA[
|
||||
test(function() {
|
||||
var fec = document.getElementById("first_element_child");
|
||||
assert_equals(fec.previousElementSibling, null)
|
||||
assert_equals(fec.nextElementSibling, null)
|
||||
})
|
||||
]]></script>
|
||||
</body>
|
||||
</html>
|
||||
16
tests/wpt/dom/nodes/Element-siblingElement-null.html
Normal file
16
tests/wpt/dom/nodes/Element-siblingElement-null.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<meta charset=utf-8>
|
||||
<title>Null test</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<h1>Test of previousElementSibling and nextElementSibling returning null</h1>
|
||||
<div id="log"></div>
|
||||
<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p>
|
||||
<script>
|
||||
test(function() {
|
||||
var fec = document.getElementById("first_element_child");
|
||||
assert_equals(fec.previousElementSibling, null)
|
||||
assert_equals(fec.nextElementSibling, null)
|
||||
})
|
||||
</script>
|
||||
|
||||
57
tests/wpt/dom/nodes/Element-tagName.html
Normal file
57
tests/wpt/dom/nodes/Element-tagName.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Element.tagName</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var HTMLNS = "http://www.w3.org/1999/xhtml"
|
||||
assert_equals(document.createElementNS(HTMLNS, "I").tagName, "I")
|
||||
assert_equals(document.createElementNS(HTMLNS, "i").tagName, "I")
|
||||
assert_equals(document.createElementNS(HTMLNS, "x:b").tagName, "X:B")
|
||||
}, "tagName should upper-case for HTML elements in HTML documents.")
|
||||
|
||||
test(function() {
|
||||
var SVGNS = "http://www.w3.org/2000/svg"
|
||||
assert_equals(document.createElementNS(SVGNS, "svg").tagName, "svg")
|
||||
assert_equals(document.createElementNS(SVGNS, "SVG").tagName, "SVG")
|
||||
assert_equals(document.createElementNS(SVGNS, "s:svg").tagName, "s:svg")
|
||||
assert_equals(document.createElementNS(SVGNS, "s:SVG").tagName, "s:SVG")
|
||||
|
||||
assert_equals(document.createElementNS(SVGNS, "textPath").tagName, "textPath");
|
||||
}, "tagName should not upper-case for SVG elements in HTML documents.")
|
||||
|
||||
test(() => {
|
||||
const el2 = document.createElementNS("http://example.com/", "mixedCase");
|
||||
assert_equals(el2.tagName, "mixedCase");
|
||||
}, "tagName should not upper-case for other non-HTML namespaces");
|
||||
|
||||
test(function() {
|
||||
if ("DOMParser" in window) {
|
||||
var xmlel = new DOMParser()
|
||||
.parseFromString('<div xmlns="http://www.w3.org/1999/xhtml">Test</div>', 'text/xml')
|
||||
.documentElement;
|
||||
assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML")
|
||||
var htmlel = document.importNode(xmlel, true)
|
||||
assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML")
|
||||
}
|
||||
}, "tagName should be updated when changing ownerDocument")
|
||||
|
||||
test(function() {
|
||||
var xmlel = document.implementation
|
||||
.createDocument("http://www.w3.org/1999/xhtml", "div", null)
|
||||
.documentElement;
|
||||
assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML")
|
||||
var htmlel = document.importNode(xmlel, true)
|
||||
assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML")
|
||||
}, "tagName should be updated when changing ownerDocument (createDocument without prefix)")
|
||||
|
||||
test(function() {
|
||||
var xmlel = document.implementation
|
||||
.createDocument("http://www.w3.org/1999/xhtml", "foo:div", null)
|
||||
.documentElement;
|
||||
assert_equals(xmlel.tagName, "foo:div", "tagName should be lowercase in XML")
|
||||
var htmlel = document.importNode(xmlel, true)
|
||||
assert_equals(htmlel.tagName, "FOO:DIV", "tagName should be uppercase in HTML")
|
||||
}, "tagName should be updated when changing ownerDocument (createDocument with prefix)")
|
||||
</script>
|
||||
22
tests/wpt/dom/nodes/Element-webkitMatchesSelector.html
Normal file
22
tests/wpt/dom/nodes/Element-webkitMatchesSelector.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title>
|
||||
<!-- Selectors API Test Suite Version 3 -->
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/dom/nodes/selectors.js"></script>
|
||||
<script src="/dom/nodes/ParentNode-querySelector-All.js"></script>
|
||||
<script src="Element-matches.js"></script>
|
||||
<script src="Element-matches-init.js"></script>
|
||||
<style>iframe { visibility: hidden; position: absolute; }</style>
|
||||
|
||||
<div id="log">This test requires JavaScript.</div>
|
||||
|
||||
<script>
|
||||
async_test(function() {
|
||||
var frame = document.createElement("iframe");
|
||||
frame.onload = this.step_func_done(e => init(e, "webkitMatchesSelector" ));
|
||||
frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target";
|
||||
document.body.appendChild(frame);
|
||||
});
|
||||
</script>
|
||||
61
tests/wpt/dom/nodes/NodeList-Iterable.html
Normal file
61
tests/wpt/dom/nodes/NodeList-Iterable.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>NodeList Iterable Test</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<p id="1"></p>
|
||||
<p id="2"></p>
|
||||
<p id="3"></p>
|
||||
<p id="4"></p>
|
||||
<p id="5"></p>
|
||||
|
||||
<div id="live"><b id="b1">1</b><b id="b2">2</b><b id="b3">3</b></div>
|
||||
<script>
|
||||
var paragraphs;
|
||||
setup(function() {
|
||||
paragraphs = document.querySelectorAll('p');
|
||||
})
|
||||
test(function() {
|
||||
assert_true('length' in paragraphs);
|
||||
}, 'NodeList has length method.');
|
||||
test(function() {
|
||||
assert_true('values' in paragraphs);
|
||||
}, 'NodeList has values method.');
|
||||
test(function() {
|
||||
assert_true('entries' in paragraphs);
|
||||
}, 'NodeList has entries method.');
|
||||
test(function() {
|
||||
assert_true('forEach' in paragraphs);
|
||||
}, 'NodeList has forEach method.');
|
||||
test(function() {
|
||||
assert_true(Symbol.iterator in paragraphs);
|
||||
}, 'NodeList has Symbol.iterator.');
|
||||
test(function() {
|
||||
var ids = "12345", idx=0;
|
||||
for(var node of paragraphs){
|
||||
assert_equals(node.getAttribute('id'), ids[idx++]);
|
||||
}
|
||||
}, 'NodeList is iterable via for-of loop.');
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(Object.keys(paragraphs), ['0', '1', '2', '3', '4']);
|
||||
}, 'NodeList responds to Object.keys correctly');
|
||||
|
||||
test(function() {
|
||||
var container = document.getElementById('live');
|
||||
var nodeList = container.childNodes;
|
||||
|
||||
var ids = [];
|
||||
for (var el of nodeList) {
|
||||
ids.push(el.id);
|
||||
assert_equals(el.localName, 'b');
|
||||
if (ids.length < 3) {
|
||||
var newEl = document.createElement('b');
|
||||
newEl.id = 'after' + el.id;
|
||||
container.appendChild(newEl);
|
||||
}
|
||||
}
|
||||
|
||||
assert_array_equals(ids, ['b1', 'b2', 'b3', 'afterb1', 'afterb2']);
|
||||
}, 'live NodeLists are for-of iterable and update appropriately');
|
||||
</script>
|
||||
79
tests/wpt/dom/nodes/NodeList-live-mutations.window.js
Normal file
79
tests/wpt/dom/nodes/NodeList-live-mutations.window.js
Normal file
@@ -0,0 +1,79 @@
|
||||
function testNodeList(name, hooks) {
|
||||
test(() => {
|
||||
const nodes = {
|
||||
root: document.createElement("div"),
|
||||
div1: document.createElement("div"),
|
||||
div2: document.createElement("div"),
|
||||
p: document.createElement("p")
|
||||
};
|
||||
|
||||
const list = nodes.root.childNodes;
|
||||
|
||||
hooks.initial(list, nodes);
|
||||
|
||||
nodes.root.appendChild(nodes.div1);
|
||||
nodes.root.appendChild(nodes.p);
|
||||
nodes.root.appendChild(nodes.div2);
|
||||
|
||||
hooks.afterInsertion(list, nodes);
|
||||
|
||||
nodes.root.removeChild(nodes.div1);
|
||||
|
||||
hooks.afterRemoval(list, nodes);
|
||||
}, `NodeList live mutations: ${name}`);
|
||||
}
|
||||
|
||||
testNodeList("NodeList.length", {
|
||||
initial(list) {
|
||||
assert_equals(list.length, 0);
|
||||
},
|
||||
afterInsertion(list) {
|
||||
assert_equals(list.length, 3);
|
||||
},
|
||||
afterRemoval(list) {
|
||||
assert_equals(list.length, 2);
|
||||
}
|
||||
});
|
||||
|
||||
testNodeList("NodeList.item(index)", {
|
||||
initial(list) {
|
||||
assert_equals(list.item(0), null);
|
||||
},
|
||||
afterInsertion(list, nodes) {
|
||||
assert_equals(list.item(0), nodes.div1);
|
||||
assert_equals(list.item(1), nodes.p);
|
||||
assert_equals(list.item(2), nodes.div2);
|
||||
},
|
||||
afterRemoval(list, nodes) {
|
||||
assert_equals(list.item(0), nodes.p);
|
||||
assert_equals(list.item(1), nodes.div2);
|
||||
}
|
||||
});
|
||||
|
||||
testNodeList("NodeList[index]", {
|
||||
initial(list) {
|
||||
assert_equals(list[0], undefined);
|
||||
},
|
||||
afterInsertion(list, nodes) {
|
||||
assert_equals(list[0], nodes.div1);
|
||||
assert_equals(list[1], nodes.p);
|
||||
assert_equals(list[2], nodes.div2);
|
||||
},
|
||||
afterRemoval(list, nodes) {
|
||||
assert_equals(list[0], nodes.p);
|
||||
assert_equals(list[1], nodes.div2);
|
||||
}
|
||||
});
|
||||
|
||||
testNodeList("NodeList ownPropertyNames", {
|
||||
initial(list) {
|
||||
assert_object_equals(Object.getOwnPropertyNames(list), []);
|
||||
},
|
||||
afterInsertion(list) {
|
||||
assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1", "2"]);
|
||||
},
|
||||
afterRemoval(list) {
|
||||
assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1"]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.defineProperty(nodeList, "length", { get() { return 10; } });
|
||||
|
||||
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.setPrototypeOf(nodeList, { get length() { return 10; } });
|
||||
|
||||
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } });
|
||||
|
||||
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.defineProperty(nodeList, "length", { get() { return 10; } });
|
||||
|
||||
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.setPrototypeOf(nodeList, { get length() { return 10; } });
|
||||
|
||||
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
|
||||
<script src="support/NodeList-static-length-tampered.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const nodeList = makeStaticNodeList(100);
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
if (i === 25)
|
||||
Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } });
|
||||
|
||||
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
377
tests/wpt/dom/nodes/ParentNode-querySelector-All-content.html
Normal file
377
tests/wpt/dom/nodes/ParentNode-querySelector-All-content.html
Normal file
@@ -0,0 +1,377 @@
|
||||
<!DOCTYPE html>
|
||||
<html id="html" lang="en">
|
||||
<head id="head">
|
||||
<meta id="meta" charset="UTF-8">
|
||||
<title id="title">Selectors-API Test Suite: HTML with Selectors Level 2 using TestHarness: Test Document</title>
|
||||
|
||||
<!-- Links for :link and :visited pseudo-class test -->
|
||||
<link id="pseudo-link-link1" href="">
|
||||
<link id="pseudo-link-link2" href="http://example.org/">
|
||||
<link id="pseudo-link-link3">
|
||||
<style>
|
||||
@namespace ns "http://www.w3.org/1999/xhtml";
|
||||
/* Declare the namespace prefix used in tests. This declaration should not be used by the API. */
|
||||
</style>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="root">
|
||||
<div id="target"></div>
|
||||
|
||||
<div id="universal">
|
||||
<p id="universal-p1">Universal selector tests inside element with <code id="universal-code1">id="universal"</code>.</p>
|
||||
<hr id="universal-hr1">
|
||||
<pre id="universal-pre1">Some preformatted text with some <span id="universal-span1">embedded code</span></pre>
|
||||
<p id="universal-p2">This is a normal link: <a id="universal-a1" href="http://www.w3.org/">W3C</a></p>
|
||||
<address id="universal-address1">Some more nested elements <code id="universal-code2"><a href="#" id="universal-a2">code hyperlink</a></code></address>
|
||||
</div>
|
||||
|
||||
<div id="attr-presence">
|
||||
<div class="attr-presence-div1" id="attr-presence-div1" align="center"></div>
|
||||
<div class="attr-presence-div2" id="attr-presence-div2" align=""></div>
|
||||
<div class="attr-presence-div3" id="attr-presence-div3" valign="center"></div>
|
||||
<div class="attr-presence-div4" id="attr-presence-div4" alignv="center"></div>
|
||||
<p id="attr-presence-p1"><a id="attr-presence-a1" tItLe=""></a><span id="attr-presence-span1" TITLE="attr-presence-span1"></span><i id="attr-presence-i1"></i></p>
|
||||
<pre id="attr-presence-pre1" data-attr-presence="pre1"></pre>
|
||||
<blockquote id="attr-presence-blockquote1" data-attr-presence="blockquote1"></blockquote>
|
||||
<ul id="attr-presence-ul1" data-中文=""></ul>
|
||||
|
||||
<select id="attr-presence-select1">
|
||||
<option id="attr-presence-select1-option1">A</option>
|
||||
<option id="attr-presence-select1-option2">B</option>
|
||||
<option id="attr-presence-select1-option3">C</option>
|
||||
<option id="attr-presence-select1-option4">D</option>
|
||||
</select>
|
||||
<select id="attr-presence-select2">
|
||||
<option id="attr-presence-select2-option1">A</option>
|
||||
<option id="attr-presence-select2-option2">B</option>
|
||||
<option id="attr-presence-select2-option3">C</option>
|
||||
<option id="attr-presence-select2-option4" selected="selected">D</option>
|
||||
</select>
|
||||
<select id="attr-presence-select3" multiple="multiple">
|
||||
<option id="attr-presence-select3-option1">A</option>
|
||||
<option id="attr-presence-select3-option2" selected="">B</option>
|
||||
<option id="attr-presence-select3-option3" selected="selected">C</option>
|
||||
<option id="attr-presence-select3-option4">D</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="attr-value">
|
||||
<div id="attr-value-div1" align="center"></div>
|
||||
<div id="attr-value-div2" align=""></div>
|
||||
<div id="attr-value-div3" data-attr-value="é"></div>
|
||||
<div id="attr-value-div4" data-attr-value_foo="é"></div>
|
||||
|
||||
<form id="attr-value-form1">
|
||||
<input id="attr-value-input1" type="text">
|
||||
<input id="attr-value-input2" type="password">
|
||||
<input id="attr-value-input3" type="hidden">
|
||||
<input id="attr-value-input4" type="radio">
|
||||
<input id="attr-value-input5" type="checkbox">
|
||||
<input id="attr-value-input6" type="radio">
|
||||
<input id="attr-value-input7" type="text">
|
||||
<input id="attr-value-input8" type="hidden">
|
||||
<input id="attr-value-input9" type="radio">
|
||||
</form>
|
||||
|
||||
<div id="attr-value-div5" data-attr-value="中文"></div>
|
||||
</div>
|
||||
|
||||
<div id="attr-whitespace">
|
||||
<div id="attr-whitespace-div1" class="foo div1 bar"></div>
|
||||
<div id="attr-whitespace-div2" class=""></div>
|
||||
<div id="attr-whitespace-div3" class="foo div3 bar"></div>
|
||||
|
||||
<div id="attr-whitespace-div4" data-attr-whitespace="foo é bar"></div>
|
||||
<div id="attr-whitespace-div5" data-attr-whitespace_foo="é foo"></div>
|
||||
|
||||
<a id="attr-whitespace-a1" rel="next bookmark"></a>
|
||||
<a id="attr-whitespace-a2" rel="tag nofollow"></a>
|
||||
<a id="attr-whitespace-a3" rel="tag bookmark"></a>
|
||||
<a id="attr-whitespace-a4" rel="book mark"></a> <!-- Intentional space in "book mark" -->
|
||||
<a id="attr-whitespace-a5" rel="nofollow"></a>
|
||||
<a id="attr-whitespace-a6" rev="bookmark nofollow"></a>
|
||||
<a id="attr-whitespace-a7" rel="prev next tag alternate nofollow author help icon noreferrer prefetch search stylesheet tag"></a>
|
||||
|
||||
<p id="attr-whitespace-p1" title="Chinese 中文 characters"></p>
|
||||
</div>
|
||||
|
||||
<div id="attr-hyphen">
|
||||
<div id="attr-hyphen-div1"></div>
|
||||
<div id="attr-hyphen-div2" lang="fr"></div>
|
||||
<div id="attr-hyphen-div3" lang="en-AU"></div>
|
||||
<div id="attr-hyphen-div4" lang="es"></div>
|
||||
</div>
|
||||
|
||||
<div id="attr-begins">
|
||||
<a id="attr-begins-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-begins-a2" href="http://example.org/"></a>
|
||||
<a id="attr-begins-a3" href="http://www.example.com/"></a>
|
||||
|
||||
<div id="attr-begins-div1" lang="fr"></div>
|
||||
<div id="attr-begins-div2" lang="en-AU"></div>
|
||||
<div id="attr-begins-div3" lang="es"></div>
|
||||
<div id="attr-begins-div4" lang="en-US"></div>
|
||||
<div id="attr-begins-div5" lang="en"></div>
|
||||
|
||||
<p id="attr-begins-p1" class=" apple"></p> <!-- Intentional space in class value " apple". -->
|
||||
</div>
|
||||
|
||||
<div id="attr-ends">
|
||||
<a id="attr-ends-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-ends-a2" href="http://example.org/"></a>
|
||||
<a id="attr-ends-a3" href="http://www.example.org"></a>
|
||||
|
||||
<div id="attr-ends-div1" lang="fr"></div>
|
||||
<div id="attr-ends-div2" lang="de-CH"></div>
|
||||
<div id="attr-ends-div3" lang="es"></div>
|
||||
<div id="attr-ends-div4" lang="fr-CH"></div>
|
||||
|
||||
<p id="attr-ends-p1" class="apple "></p> <!-- Intentional space in class value "apple ". -->
|
||||
</div>
|
||||
|
||||
<div id="attr-contains">
|
||||
<a id="attr-contains-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-contains-a2" href="http://example.org/"></a>
|
||||
<a id="attr-contains-a3" href="http://www.example.com/"></a>
|
||||
|
||||
<div id="attr-contains-div1" lang="fr"></div>
|
||||
<div id="attr-contains-div2" lang="en-AU"></div>
|
||||
<div id="attr-contains-div3" lang="de-CH"></div>
|
||||
<div id="attr-contains-div4" lang="es"></div>
|
||||
<div id="attr-contains-div5" lang="fr-CH"></div>
|
||||
<div id="attr-contains-div6" lang="en-US"></div>
|
||||
|
||||
<p id="attr-contains-p1" class=" apple banana orange "></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-nth">
|
||||
<table id="pseudo-nth-table1">
|
||||
<tr id="pseudo-nth-tr1"><td id="pseudo-nth-td1"></td><td id="pseudo-nth-td2"></td><td id="pseudo-nth-td3"></td><td id="pseudo-nth-td4"></td><td id="pseudo-nth--td5"></td><td id="pseudo-nth-td6"></td></tr>
|
||||
<tr id="pseudo-nth-tr2"><td id="pseudo-nth-td7"></td><td id="pseudo-nth-td8"></td><td id="pseudo-nth-td9"></td><td id="pseudo-nth-td10"></td><td id="pseudo-nth-td11"></td><td id="pseudo-nth-td12"></td></tr>
|
||||
<tr id="pseudo-nth-tr3"><td id="pseudo-nth-td13"></td><td id="pseudo-nth-td14"></td><td id="pseudo-nth-td15"></td><td id="pseudo-nth-td16"></td><td id="pseudo-nth-td17"></td><td id="pseudo-nth-td18"></td></tr>
|
||||
</table>
|
||||
|
||||
<ol id="pseudo-nth-ol1">
|
||||
<li id="pseudo-nth-li1"></li>
|
||||
<li id="pseudo-nth-li2"></li>
|
||||
<li id="pseudo-nth-li3"></li>
|
||||
<li id="pseudo-nth-li4"></li>
|
||||
<li id="pseudo-nth-li5"></li>
|
||||
<li id="pseudo-nth-li6"></li>
|
||||
<li id="pseudo-nth-li7"></li>
|
||||
<li id="pseudo-nth-li8"></li>
|
||||
<li id="pseudo-nth-li9"></li>
|
||||
<li id="pseudo-nth-li10"></li>
|
||||
<li id="pseudo-nth-li11"></li>
|
||||
<li id="pseudo-nth-li12"></li>
|
||||
</ol>
|
||||
|
||||
<p id="pseudo-nth-p1">
|
||||
<span id="pseudo-nth-span1">span1</span>
|
||||
<em id="pseudo-nth-em1">em1</em>
|
||||
<!-- comment node-->
|
||||
<em id="pseudo-nth-em2">em2</em>
|
||||
<span id="pseudo-nth-span2">span2</span>
|
||||
<strong id="pseudo-nth-strong1">strong1</strong>
|
||||
<em id="pseudo-nth-em3">em3</em>
|
||||
<span id="pseudo-nth-span3">span3</span>
|
||||
<span id="pseudo-nth-span4">span4</span>
|
||||
<strong id="pseudo-nth-strong2">strong2</strong>
|
||||
<em id="pseudo-nth-em4">em4</em>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-first-child">
|
||||
<div id="pseudo-first-child-div1"></div>
|
||||
<div id="pseudo-first-child-div2"></div>
|
||||
<div id="pseudo-first-child-div3"></div>
|
||||
|
||||
<p id="pseudo-first-child-p1"><span id="pseudo-first-child-span1"></span><span id="pseudo-first-child-span2"></span></p>
|
||||
<p id="pseudo-first-child-p2"><span id="pseudo-first-child-span3"></span><span id="pseudo-first-child-span4"></span></p>
|
||||
<p id="pseudo-first-child-p3"><span id="pseudo-first-child-span5"></span><span id="pseudo-first-child-span6"></span></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-last-child">
|
||||
<p id="pseudo-last-child-p1"><span id="pseudo-last-child-span1"></span><span id="pseudo-last-child-span2"></span></p>
|
||||
<p id="pseudo-last-child-p2"><span id="pseudo-last-child-span3"></span><span id="pseudo-last-child-span4"></span></p>
|
||||
<p id="pseudo-last-child-p3"><span id="pseudo-last-child-span5"></span><span id="pseudo-last-child-span6"></span></p>
|
||||
|
||||
<div id="pseudo-last-child-div1"></div>
|
||||
<div id="pseudo-last-child-div2"></div>
|
||||
<div id="pseudo-last-child-div3"></div>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-only">
|
||||
<p id="pseudo-only-p1">
|
||||
<span id="pseudo-only-span1"></span>
|
||||
</p>
|
||||
<p id="pseudo-only-p2">
|
||||
<span id="pseudo-only-span2"></span>
|
||||
<span id="pseudo-only-span3"></span>
|
||||
</p>
|
||||
<p id="pseudo-only-p3">
|
||||
<span id="pseudo-only-span4"></span>
|
||||
<em id="pseudo-only-em1"></em>
|
||||
<span id="pseudo-only-span5"></span>
|
||||
</p>
|
||||
</div>>
|
||||
|
||||
<div id="pseudo-empty">
|
||||
<p id="pseudo-empty-p1"></p>
|
||||
<p id="pseudo-empty-p2"><!-- comment node --></p>
|
||||
<p id="pseudo-empty-p3"> </p>
|
||||
<p id="pseudo-empty-p4">Text node</p>
|
||||
<p id="pseudo-empty-p5"><span id="pseudo-empty-span1"></span></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-link">
|
||||
<a id="pseudo-link-a1" href="">with href</a>
|
||||
<a id="pseudo-link-a2" href="http://example.org/">with href</a>
|
||||
<a id="pseudo-link-a3">without href</a>
|
||||
<map name="pseudo-link-map1" id="pseudo-link-map1">
|
||||
<area id="pseudo-link-area1" href="">
|
||||
<area id="pseudo-link-area2">
|
||||
</map>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-lang">
|
||||
<div id="pseudo-lang-div1"></div>
|
||||
<div id="pseudo-lang-div2" lang="fr"></div>
|
||||
<div id="pseudo-lang-div3" lang="en-AU"></div>
|
||||
<div id="pseudo-lang-div4" lang="es"></div>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-ui">
|
||||
<input id="pseudo-ui-input1" type="text">
|
||||
<input id="pseudo-ui-input2" type="password">
|
||||
<input id="pseudo-ui-input3" type="radio">
|
||||
<input id="pseudo-ui-input4" type="radio" checked="checked">
|
||||
<input id="pseudo-ui-input5" type="checkbox">
|
||||
<input id="pseudo-ui-input6" type="checkbox" checked="checked">
|
||||
<input id="pseudo-ui-input7" type="submit">
|
||||
<input id="pseudo-ui-input8" type="button">
|
||||
<input id="pseudo-ui-input9" type="hidden">
|
||||
<textarea id="pseudo-ui-textarea1"></textarea>
|
||||
<button id="pseudo-ui-button1">Enabled</button>
|
||||
|
||||
<input id="pseudo-ui-input10" disabled="disabled" type="text">
|
||||
<input id="pseudo-ui-input11" disabled="disabled" type="password">
|
||||
<input id="pseudo-ui-input12" disabled="disabled" type="radio">
|
||||
<input id="pseudo-ui-input13" disabled="disabled" type="radio" checked="checked">
|
||||
<input id="pseudo-ui-input14" disabled="disabled" type="checkbox">
|
||||
<input id="pseudo-ui-input15" disabled="disabled" type="checkbox" checked="checked">
|
||||
<input id="pseudo-ui-input16" disabled="disabled" type="submit">
|
||||
<input id="pseudo-ui-input17" disabled="disabled" type="button">
|
||||
<input id="pseudo-ui-input18" disabled="disabled" type="hidden">
|
||||
<textarea id="pseudo-ui-textarea2" disabled="disabled"></textarea>
|
||||
<button id="pseudo-ui-button2" disabled="disabled">Disabled</button>
|
||||
</div>
|
||||
|
||||
<div id="not">
|
||||
<div id="not-div1"></div>
|
||||
<div id="not-div2"></div>
|
||||
<div id="not-div3"></div>
|
||||
|
||||
<p id="not-p1"><span id="not-span1"></span><em id="not-em1"></em></p>
|
||||
<p id="not-p2"><span id="not-span2"></span><em id="not-em2"></em></p>
|
||||
<p id="not-p3"><span id="not-span3"></span><em id="not-em3"></em></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-element">All pseudo-element tests</div>
|
||||
|
||||
<div id="class">
|
||||
<p id="class-p1" class="foo class-p bar"></p>
|
||||
<p id="class-p2" class="class-p foo bar"></p>
|
||||
<p id="class-p3" class="foo bar class-p"></p>
|
||||
|
||||
<!-- All permutations of the classes should match -->
|
||||
<div id="class-div1" class="apple orange banana"></div>
|
||||
<div id="class-div2" class="apple banana orange"></div>
|
||||
<p id="class-p4" class="orange apple banana"></p>
|
||||
<div id="class-div3" class="orange banana apple"></div>
|
||||
<p id="class-p6" class="banana apple orange"></p>
|
||||
<div id="class-div4" class="banana orange apple"></div>
|
||||
<div id="class-div5" class="apple orange"></div>
|
||||
<div id="class-div6" class="apple banana"></div>
|
||||
<div id="class-div7" class="orange banana"></div>
|
||||
|
||||
<span id="class-span1" class="台北Táiběi 台北"></span>
|
||||
<span id="class-span2" class="台北"></span>
|
||||
|
||||
<span id="class-span3" class="foo:bar"></span>
|
||||
<span id="class-span4" class="test.foo[5]bar"></span>
|
||||
</div>
|
||||
|
||||
<div id="id">
|
||||
<div id="id-div1"></div>
|
||||
<div id="id-div2"></div>
|
||||
|
||||
<ul id="id-ul1">
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
</ul>
|
||||
|
||||
<span id="台北Táiběi"></span>
|
||||
<span id="台北"></span>
|
||||
|
||||
<span id="#foo:bar"></span>
|
||||
<span id="test.foo[5]bar"></span>
|
||||
</div>
|
||||
|
||||
<div id="descendant">
|
||||
<div id="descendant-div1" class="descendant-div1">
|
||||
<div id="descendant-div2" class="descendant-div2">
|
||||
<div id="descendant-div3" class="descendant-div3">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="descendant-div4" class="descendant-div4"></div>
|
||||
</div>
|
||||
|
||||
<div id="child">
|
||||
<div id="child-div1" class="child-div1">
|
||||
<div id="child-div2" class="child-div2">
|
||||
<div id="child-div3" class="child-div3">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="child-div4" class="child-div4"></div>
|
||||
</div>
|
||||
|
||||
<div id="adjacent">
|
||||
<div id="adjacent-div1" class="adjacent-div1"></div>
|
||||
<div id="adjacent-div2" class="adjacent-div2">
|
||||
<div id="adjacent-div3" class="adjacent-div3"></div>
|
||||
</div>
|
||||
<div id="adjacent-div4" class="adjacent-div4">
|
||||
<p id="adjacent-p1" class="adjacent-p1"></p>
|
||||
<div id="adjacent-div5" class="adjacent-div5"></div>
|
||||
</div>
|
||||
<div id="adjacent-div6" class="adjacent-div6"></div>
|
||||
<p id="adjacent-p2" class="adjacent-p2"></p>
|
||||
<p id="adjacent-p3" class="adjacent-p3"></p>
|
||||
</div>
|
||||
|
||||
<div id="sibling">
|
||||
<div id="sibling-div1" class="sibling-div"></div>
|
||||
<div id="sibling-div2" class="sibling-div">
|
||||
<div id="sibling-div3" class="sibling-div"></div>
|
||||
</div>
|
||||
<div id="sibling-div4" class="sibling-div">
|
||||
<p id="sibling-p1" class="sibling-p"></p>
|
||||
<div id="sibling-div5" class="sibling-div"></div>
|
||||
</div>
|
||||
<div id="sibling-div6" class="sibling-div"></div>
|
||||
<p id="sibling-p2" class="sibling-p"></p>
|
||||
<p id="sibling-p3" class="sibling-p"></p>
|
||||
</div>
|
||||
|
||||
<div id="group">
|
||||
<em id="group-em1"></em>
|
||||
<strong id="group-strong1"></strong>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
372
tests/wpt/dom/nodes/ParentNode-querySelector-All-content.xht
Normal file
372
tests/wpt/dom/nodes/ParentNode-querySelector-All-content.xht
Normal file
@@ -0,0 +1,372 @@
|
||||
<!DOCTYPE html>
|
||||
<html id="html" lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head id="head">
|
||||
<title id="title">Selectors-API Test Suite: HTML with Selectors Level 2 using TestHarness: Test Document</title>
|
||||
|
||||
<!-- Links for :link and :visited pseudo-class test -->
|
||||
<link id="pseudo-link-link1" href=""/>
|
||||
<link id="pseudo-link-link2" href="http://example.org/"/>
|
||||
<link id="pseudo-link-link3"/>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="root">
|
||||
<div id="target"></div>
|
||||
|
||||
<div id="universal">
|
||||
<p id="universal-p1">Universal selector tests inside element with <code id="universal-code1">id="universal"</code>.</p>
|
||||
<hr id="universal-hr1"/>
|
||||
<pre id="universal-pre1">Some preformatted text with some <span id="universal-span1">embedded code</span></pre>
|
||||
<p id="universal-p2">This is a normal link: <a id="universal-a1" href="http://www.w3.org/">W3C</a></p>
|
||||
<address id="universal-address1">Some more nested elements <code id="universal-code2"><a href="#" id="universal-a2">code hyperlink</a></code></address>
|
||||
</div>
|
||||
|
||||
<div id="attr-presence">
|
||||
<div class="attr-presence-div1" id="attr-presence-div1" align="center"></div>
|
||||
<div class="attr-presence-div2" id="attr-presence-div2" align=""></div>
|
||||
<div class="attr-presence-div3" id="attr-presence-div3" valign="center"></div>
|
||||
<div class="attr-presence-div4" id="attr-presence-div4" alignv="center"></div>
|
||||
<p id="attr-presence-p1"><a id="attr-presence-a1" tItLe=""></a><span id="attr-presence-span1" TITLE="attr-presence-span1"></span><i id="attr-presence-i1"></i></p>
|
||||
<pre id="attr-presence-pre1" data-attr-presence="pre1"></pre>
|
||||
<blockquote id="attr-presence-blockquote1" data-attr-presence="blockquote1"></blockquote>
|
||||
<ul id="attr-presence-ul1" data-中文=""></ul>
|
||||
|
||||
<select id="attr-presence-select1">
|
||||
<option id="attr-presence-select1-option1">A</option>
|
||||
<option id="attr-presence-select1-option2">B</option>
|
||||
<option id="attr-presence-select1-option3">C</option>
|
||||
<option id="attr-presence-select1-option4">D</option>
|
||||
</select>
|
||||
<select id="attr-presence-select2">
|
||||
<option id="attr-presence-select2-option1">A</option>
|
||||
<option id="attr-presence-select2-option2">B</option>
|
||||
<option id="attr-presence-select2-option3">C</option>
|
||||
<option id="attr-presence-select2-option4" selected="selected">D</option>
|
||||
</select>
|
||||
<select id="attr-presence-select3" multiple="multiple">
|
||||
<option id="attr-presence-select3-option1">A</option>
|
||||
<option id="attr-presence-select3-option2" selected="">B</option>
|
||||
<option id="attr-presence-select3-option3" selected="selected">C</option>
|
||||
<option id="attr-presence-select3-option4">D</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="attr-value">
|
||||
<div id="attr-value-div1" align="center"></div>
|
||||
<div id="attr-value-div2" align=""></div>
|
||||
<div id="attr-value-div3" data-attr-value="é"></div>
|
||||
<div id="attr-value-div4" data-attr-value_foo="é"></div>
|
||||
|
||||
<form id="attr-value-form1">
|
||||
<input id="attr-value-input1" type="text"/>
|
||||
<input id="attr-value-input2" type="password"/>
|
||||
<input id="attr-value-input3" type="hidden"/>
|
||||
<input id="attr-value-input4" type="radio"/>
|
||||
<input id="attr-value-input5" type="checkbox"/>
|
||||
<input id="attr-value-input6" type="radio"/>
|
||||
<input id="attr-value-input7" type="text"/>
|
||||
<input id="attr-value-input8" type="hidden"/>
|
||||
<input id="attr-value-input9" type="radio"/>
|
||||
</form>
|
||||
|
||||
<div id="attr-value-div5" data-attr-value="中文"></div>
|
||||
</div>
|
||||
|
||||
<div id="attr-whitespace">
|
||||
<div id="attr-whitespace-div1" class="foo div1 bar"></div>
|
||||
<div id="attr-whitespace-div2" class=""></div>
|
||||
<div id="attr-whitespace-div3" class="foo div3 bar"></div>
|
||||
|
||||
<div id="attr-whitespace-div4" data-attr-whitespace="foo é bar"></div>
|
||||
<div id="attr-whitespace-div5" data-attr-whitespace_foo="é foo"></div>
|
||||
|
||||
<a id="attr-whitespace-a1" rel="next bookmark"></a>
|
||||
<a id="attr-whitespace-a2" rel="tag nofollow"></a>
|
||||
<a id="attr-whitespace-a3" rel="tag bookmark"></a>
|
||||
<a id="attr-whitespace-a4" rel="book mark"></a> <!-- Intentional space in "book mark" -->
|
||||
<a id="attr-whitespace-a5" rel="nofollow"></a>
|
||||
<a id="attr-whitespace-a6" rev="bookmark nofollow"></a>
|
||||
<a id="attr-whitespace-a7" rel="prev next tag alternate nofollow author help icon noreferrer prefetch search stylesheet tag"></a>
|
||||
|
||||
<p id="attr-whitespace-p1" title="Chinese 中文 characters"></p>
|
||||
</div>
|
||||
|
||||
<div id="attr-hyphen">
|
||||
<div id="attr-hyphen-div1"></div>
|
||||
<div id="attr-hyphen-div2" lang="fr"></div>
|
||||
<div id="attr-hyphen-div3" lang="en-AU"></div>
|
||||
<div id="attr-hyphen-div4" lang="es"></div>
|
||||
</div>
|
||||
|
||||
<div id="attr-begins">
|
||||
<a id="attr-begins-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-begins-a2" href="http://example.org/"></a>
|
||||
<a id="attr-begins-a3" href="http://www.example.com/"></a>
|
||||
|
||||
<div id="attr-begins-div1" lang="fr"></div>
|
||||
<div id="attr-begins-div2" lang="en-AU"></div>
|
||||
<div id="attr-begins-div3" lang="es"></div>
|
||||
<div id="attr-begins-div4" lang="en-US"></div>
|
||||
<div id="attr-begins-div5" lang="en"></div>
|
||||
|
||||
<p id="attr-begins-p1" class=" apple"></p> <!-- Intentional space in class value " apple". -->
|
||||
</div>
|
||||
|
||||
<div id="attr-ends">
|
||||
<a id="attr-ends-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-ends-a2" href="http://example.org/"></a>
|
||||
<a id="attr-ends-a3" href="http://www.example.org"></a>
|
||||
|
||||
<div id="attr-ends-div1" lang="fr"></div>
|
||||
<div id="attr-ends-div2" lang="de-CH"></div>
|
||||
<div id="attr-ends-div3" lang="es"></div>
|
||||
<div id="attr-ends-div4" lang="fr-CH"></div>
|
||||
|
||||
<p id="attr-ends-p1" class="apple "></p> <!-- Intentional space in class value "apple ". -->
|
||||
</div>
|
||||
|
||||
<div id="attr-contains">
|
||||
<a id="attr-contains-a1" href="http://www.example.org"></a>
|
||||
<a id="attr-contains-a2" href="http://example.org/"></a>
|
||||
<a id="attr-contains-a3" href="http://www.example.com/"></a>
|
||||
|
||||
<div id="attr-contains-div1" lang="fr"></div>
|
||||
<div id="attr-contains-div2" lang="en-AU"></div>
|
||||
<div id="attr-contains-div3" lang="de-CH"></div>
|
||||
<div id="attr-contains-div4" lang="es"></div>
|
||||
<div id="attr-contains-div5" lang="fr-CH"></div>
|
||||
<div id="attr-contains-div6" lang="en-US"></div>
|
||||
|
||||
<p id="attr-contains-p1" class=" apple banana orange "></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-nth">
|
||||
<table id="pseudo-nth-table1">
|
||||
<tr id="pseudo-nth-tr1"><td id="pseudo-nth-td1"></td><td id="pseudo-nth-td2"></td><td id="pseudo-nth-td3"></td><td id="pseudo-nth-td4"></td><td id="pseudo-nth--td5"></td><td id="pseudo-nth-td6"></td></tr>
|
||||
<tr id="pseudo-nth-tr2"><td id="pseudo-nth-td7"></td><td id="pseudo-nth-td8"></td><td id="pseudo-nth-td9"></td><td id="pseudo-nth-td10"></td><td id="pseudo-nth-td11"></td><td id="pseudo-nth-td12"></td></tr>
|
||||
<tr id="pseudo-nth-tr3"><td id="pseudo-nth-td13"></td><td id="pseudo-nth-td14"></td><td id="pseudo-nth-td15"></td><td id="pseudo-nth-td16"></td><td id="pseudo-nth-td17"></td><td id="pseudo-nth-td18"></td></tr>
|
||||
</table>
|
||||
|
||||
<ol id="pseudo-nth-ol1">
|
||||
<li id="pseudo-nth-li1"></li>
|
||||
<li id="pseudo-nth-li2"></li>
|
||||
<li id="pseudo-nth-li3"></li>
|
||||
<li id="pseudo-nth-li4"></li>
|
||||
<li id="pseudo-nth-li5"></li>
|
||||
<li id="pseudo-nth-li6"></li>
|
||||
<li id="pseudo-nth-li7"></li>
|
||||
<li id="pseudo-nth-li8"></li>
|
||||
<li id="pseudo-nth-li9"></li>
|
||||
<li id="pseudo-nth-li10"></li>
|
||||
<li id="pseudo-nth-li11"></li>
|
||||
<li id="pseudo-nth-li12"></li>
|
||||
</ol>
|
||||
|
||||
<p id="pseudo-nth-p1">
|
||||
<span id="pseudo-nth-span1">span1</span>
|
||||
<em id="pseudo-nth-em1">em1</em>
|
||||
<!-- comment node-->
|
||||
<em id="pseudo-nth-em2">em2</em>
|
||||
<span id="pseudo-nth-span2">span2</span>
|
||||
<strong id="pseudo-nth-strong1">strong1</strong>
|
||||
<em id="pseudo-nth-em3">em3</em>
|
||||
<span id="pseudo-nth-span3">span3</span>
|
||||
<span id="pseudo-nth-span4">span4</span>
|
||||
<strong id="pseudo-nth-strong2">strong2</strong>
|
||||
<em id="pseudo-nth-em4">em4</em>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-first-child">
|
||||
<div id="pseudo-first-child-div1"></div>
|
||||
<div id="pseudo-first-child-div2"></div>
|
||||
<div id="pseudo-first-child-div3"></div>
|
||||
|
||||
<p id="pseudo-first-child-p1"><span id="pseudo-first-child-span1"></span><span id="pseudo-first-child-span2"></span></p>
|
||||
<p id="pseudo-first-child-p2"><span id="pseudo-first-child-span3"></span><span id="pseudo-first-child-span4"></span></p>
|
||||
<p id="pseudo-first-child-p3"><span id="pseudo-first-child-span5"></span><span id="pseudo-first-child-span6"></span></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-last-child">
|
||||
<p id="pseudo-last-child-p1"><span id="pseudo-last-child-span1"></span><span id="pseudo-last-child-span2"></span></p>
|
||||
<p id="pseudo-last-child-p2"><span id="pseudo-last-child-span3"></span><span id="pseudo-last-child-span4"></span></p>
|
||||
<p id="pseudo-last-child-p3"><span id="pseudo-last-child-span5"></span><span id="pseudo-last-child-span6"></span></p>
|
||||
|
||||
<div id="pseudo-last-child-div1"></div>
|
||||
<div id="pseudo-last-child-div2"></div>
|
||||
<div id="pseudo-last-child-div3"></div>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-only">
|
||||
<p id="pseudo-only-p1">
|
||||
<span id="pseudo-only-span1"></span>
|
||||
</p>
|
||||
<p id="pseudo-only-p2">
|
||||
<span id="pseudo-only-span2"></span>
|
||||
<span id="pseudo-only-span3"></span>
|
||||
</p>
|
||||
<p id="pseudo-only-p3">
|
||||
<span id="pseudo-only-span4"></span>
|
||||
<em id="pseudo-only-em1"></em>
|
||||
<span id="pseudo-only-span5"></span>
|
||||
</p>
|
||||
</div>>
|
||||
|
||||
<div id="pseudo-empty">
|
||||
<p id="pseudo-empty-p1"></p>
|
||||
<p id="pseudo-empty-p2"><!-- comment node --></p>
|
||||
<p id="pseudo-empty-p3"> </p>
|
||||
<p id="pseudo-empty-p4">Text node</p>
|
||||
<p id="pseudo-empty-p5"><span id="pseudo-empty-span1"></span></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-link">
|
||||
<a id="pseudo-link-a1" href="">with href</a>
|
||||
<a id="pseudo-link-a2" href="http://example.org/">with href</a>
|
||||
<a id="pseudo-link-a3">without href</a>
|
||||
<map name="pseudo-link-map1" id="pseudo-link-map1">
|
||||
<area id="pseudo-link-area1" href=""/>
|
||||
<area id="pseudo-link-area2"/>
|
||||
</map>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-lang">
|
||||
<div id="pseudo-lang-div1"></div>
|
||||
<div id="pseudo-lang-div2" lang="fr"></div>
|
||||
<div id="pseudo-lang-div3" lang="en-AU"></div>
|
||||
<div id="pseudo-lang-div4" lang="es"></div>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-ui">
|
||||
<input id="pseudo-ui-input1" type="text"/>
|
||||
<input id="pseudo-ui-input2" type="password"/>
|
||||
<input id="pseudo-ui-input3" type="radio"/>
|
||||
<input id="pseudo-ui-input4" type="radio" checked="checked"/>
|
||||
<input id="pseudo-ui-input5" type="checkbox"/>
|
||||
<input id="pseudo-ui-input6" type="checkbox" checked="checked"/>
|
||||
<input id="pseudo-ui-input7" type="submit"/>
|
||||
<input id="pseudo-ui-input8" type="button"/>
|
||||
<input id="pseudo-ui-input9" type="hidden"/>
|
||||
<textarea id="pseudo-ui-textarea1"></textarea>
|
||||
<button id="pseudo-ui-button1">Enabled</button>
|
||||
|
||||
<input id="pseudo-ui-input10" disabled="disabled" type="text"/>
|
||||
<input id="pseudo-ui-input11" disabled="disabled" type="password"/>
|
||||
<input id="pseudo-ui-input12" disabled="disabled" type="radio"/>
|
||||
<input id="pseudo-ui-input13" disabled="disabled" type="radio" checked="checked"/>
|
||||
<input id="pseudo-ui-input14" disabled="disabled" type="checkbox"/>
|
||||
<input id="pseudo-ui-input15" disabled="disabled" type="checkbox" checked="checked"/>
|
||||
<input id="pseudo-ui-input16" disabled="disabled" type="submit"/>
|
||||
<input id="pseudo-ui-input17" disabled="disabled" type="button"/>
|
||||
<input id="pseudo-ui-input18" disabled="disabled" type="hidden"/>
|
||||
<textarea id="pseudo-ui-textarea2" disabled="disabled"></textarea>
|
||||
<button id="pseudo-ui-button2" disabled="disabled">Disabled</button>
|
||||
</div>
|
||||
|
||||
<div id="not">
|
||||
<div id="not-div1"></div>
|
||||
<div id="not-div2"></div>
|
||||
<div id="not-div3"></div>
|
||||
|
||||
<p id="not-p1"><span id="not-span1"></span><em id="not-em1"></em></p>
|
||||
<p id="not-p2"><span id="not-span2"></span><em id="not-em2"></em></p>
|
||||
<p id="not-p3"><span id="not-span3"></span><em id="not-em3"></em></p>
|
||||
</div>
|
||||
|
||||
<div id="pseudo-element">All pseudo-element tests</div>
|
||||
|
||||
<div id="class">
|
||||
<p id="class-p1" class="foo class-p bar"></p>
|
||||
<p id="class-p2" class="class-p foo bar"></p>
|
||||
<p id="class-p3" class="foo bar class-p"></p>
|
||||
|
||||
<!-- All permutations of the classes should match -->
|
||||
<div id="class-div1" class="apple orange banana"></div>
|
||||
<div id="class-div2" class="apple banana orange"></div>
|
||||
<p id="class-p4" class="orange apple banana"></p>
|
||||
<div id="class-div3" class="orange banana apple"></div>
|
||||
<p id="class-p6" class="banana apple orange"></p>
|
||||
<div id="class-div4" class="banana orange apple"></div>
|
||||
<div id="class-div5" class="apple orange"></div>
|
||||
<div id="class-div6" class="apple banana"></div>
|
||||
<div id="class-div7" class="orange banana"></div>
|
||||
|
||||
<span id="class-span1" class="台北Táiběi 台北"></span>
|
||||
<span id="class-span2" class="台北"></span>
|
||||
|
||||
<span id="class-span3" class="foo:bar"></span>
|
||||
<span id="class-span4" class="test.foo[5]bar"></span>
|
||||
</div>
|
||||
|
||||
<div id="id">
|
||||
<div id="id-div1"></div>
|
||||
<div id="id-div2"></div>
|
||||
|
||||
<ul id="id-ul1">
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
<li id="id-li-duplicate"></li>
|
||||
</ul>
|
||||
|
||||
<span id="台北Táiběi"></span>
|
||||
<span id="台北"></span>
|
||||
|
||||
<span id="#foo:bar"></span>
|
||||
<span id="test.foo[5]bar"></span>
|
||||
</div>
|
||||
|
||||
<div id="descendant">
|
||||
<div id="descendant-div1" class="descendant-div1">
|
||||
<div id="descendant-div2" class="descendant-div2">
|
||||
<div id="descendant-div3" class="descendant-div3">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="descendant-div4" class="descendant-div4"></div>
|
||||
</div>
|
||||
|
||||
<div id="child">
|
||||
<div id="child-div1" class="child-div1">
|
||||
<div id="child-div2" class="child-div2">
|
||||
<div id="child-div3" class="child-div3">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="child-div4" class="child-div4"></div>
|
||||
</div>
|
||||
|
||||
<div id="adjacent">
|
||||
<div id="adjacent-div1" class="adjacent-div1"></div>
|
||||
<div id="adjacent-div2" class="adjacent-div2">
|
||||
<div id="adjacent-div3" class="adjacent-div3"></div>
|
||||
</div>
|
||||
<div id="adjacent-div4" class="adjacent-div4">
|
||||
<p id="adjacent-p1" class="adjacent-p1"></p>
|
||||
<div id="adjacent-div5" class="adjacent-div5"></div>
|
||||
</div>
|
||||
<div id="adjacent-div6" class="adjacent-div6"></div>
|
||||
<p id="adjacent-p2" class="adjacent-p2"></p>
|
||||
<p id="adjacent-p3" class="adjacent-p3"></p>
|
||||
</div>
|
||||
|
||||
<div id="sibling">
|
||||
<div id="sibling-div1" class="sibling-div"></div>
|
||||
<div id="sibling-div2" class="sibling-div">
|
||||
<div id="sibling-div3" class="sibling-div"></div>
|
||||
</div>
|
||||
<div id="sibling-div4" class="sibling-div">
|
||||
<p id="sibling-p1" class="sibling-p"></p>
|
||||
<div id="sibling-div5" class="sibling-div"></div>
|
||||
</div>
|
||||
<div id="sibling-div6" class="sibling-div"></div>
|
||||
<p id="sibling-p2" class="sibling-p"></p>
|
||||
<p id="sibling-p3" class="sibling-p"></p>
|
||||
</div>
|
||||
|
||||
<div id="group">
|
||||
<em id="group-em1"></em>
|
||||
<strong id="group-strong1"></strong>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
124
tests/wpt/dom/nodes/ParentNode-querySelector-All-xht.xht
Normal file
124
tests/wpt/dom/nodes/ParentNode-querySelector-All-xht.xht
Normal file
@@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<html id="html" lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head id="head">
|
||||
<meta name="timeout" content="long" />
|
||||
<title>Selectors-API Test Suite: XHTML</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="selectors.js"></script>
|
||||
<script src="ParentNode-querySelector-All.js"></script>
|
||||
<style>iframe { visibility: hidden; position: absolute; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log">This test requires JavaScript.</div>
|
||||
|
||||
<script><![CDATA[
|
||||
async_test(function() {
|
||||
var frame = document.createElement("iframe");
|
||||
var self = this;
|
||||
frame.onload = function() {
|
||||
// :target doesn't work before a page rendering on some browsers. We run
|
||||
// tests after an animation frame because it may be later than the first
|
||||
// page rendering.
|
||||
requestAnimationFrame(self.step_func_done(init.bind(self, frame)));
|
||||
};
|
||||
frame.src = "ParentNode-querySelector-All-content.xht#target";
|
||||
document.body.appendChild(frame);
|
||||
})
|
||||
|
||||
function init(target) {
|
||||
/*
|
||||
* This test suite tests Selectors API methods in 4 different contexts:
|
||||
* 1. Document node
|
||||
* 2. In-document Element node
|
||||
* 3. Detached Element node (an element with no parent, not in the document)
|
||||
* 4. Document Fragment node
|
||||
*
|
||||
* For each context, the following tests are run:
|
||||
*
|
||||
* The interface check tests ensure that each type of node exposes the Selectors API methods
|
||||
*
|
||||
* The special selector tests verify the result of passing special values for the selector parameter,
|
||||
* to ensure that the correct WebIDL processing is performed, such as stringification of null and
|
||||
* undefined and missing parameter. The universal selector is also tested here, rather than with the
|
||||
* rest of ordinary selectors for practical reasons.
|
||||
*
|
||||
* The static list verification tests ensure that the node lists returned by the method remain unchanged
|
||||
* due to subsequent document modication, and that a new list is generated each time the method is
|
||||
* invoked based on the current state of the document.
|
||||
*
|
||||
* The invalid selector tests ensure that SyntaxError is thrown for invalid forms of selectors
|
||||
*
|
||||
* The valid selector tests check the result from querying many different types of selectors, with a
|
||||
* list of expected elements. This checks that querySelector() always returns the first result from
|
||||
* querySelectorAll(), and that all matching elements are correctly returned in tree-order. The tests
|
||||
* can be limited by specifying the test types to run, using the testType variable. The constants for this
|
||||
* can be found in selectors.js.
|
||||
*
|
||||
* All the selectors tested for both the valid and invalid selector tests are found in selectors.js.
|
||||
* See comments in that file for documentation of the format used.
|
||||
*
|
||||
* The ParentNode-querySelector-All.js file contains all the common test functions for running each of the aforementioned tests
|
||||
*/
|
||||
|
||||
var testType = TEST_QSA;
|
||||
var docType = "xhtml"; // Only run tests suitable for XHTML
|
||||
|
||||
// Prepare the nodes for testing
|
||||
var doc = target.contentDocument; // Document Node tests
|
||||
|
||||
var element = doc.getElementById("root"); // In-document Element Node tests
|
||||
|
||||
//Setup the namespace tests
|
||||
setupSpecialElements(doc, element);
|
||||
|
||||
var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document
|
||||
// Element tests, but after running the Document tests. This
|
||||
// tests that no elements that are not descendants of element
|
||||
// are selected.
|
||||
|
||||
traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying
|
||||
elem.setAttribute("data-clone", ""); // that none of these elements ever match.
|
||||
});
|
||||
|
||||
|
||||
var detached = element.cloneNode(true); // Detached Element Node tests
|
||||
|
||||
var fragment = doc.createDocumentFragment(); // Fragment Node tests
|
||||
fragment.appendChild(element.cloneNode(true));
|
||||
|
||||
var empty = document.createElement("div"); // Empty Node tests
|
||||
|
||||
// Setup Tests
|
||||
interfaceCheck("Document", doc);
|
||||
interfaceCheck("Detached Element", detached);
|
||||
interfaceCheck("Fragment", fragment);
|
||||
interfaceCheck("In-document Element", element);
|
||||
|
||||
runSpecialSelectorTests("Document", doc);
|
||||
runSpecialSelectorTests("Detached Element", detached);
|
||||
runSpecialSelectorTests("Fragment", fragment);
|
||||
runSpecialSelectorTests("In-document Element", element);
|
||||
|
||||
verifyStaticList("Document", doc, doc);
|
||||
verifyStaticList("Detached Element", doc, detached);
|
||||
verifyStaticList("Fragment", doc, fragment);
|
||||
verifyStaticList("In-document Element", doc, element);
|
||||
|
||||
runInvalidSelectorTest("Document", doc, invalidSelectors);
|
||||
runInvalidSelectorTest("Detached Element", detached, invalidSelectors);
|
||||
runInvalidSelectorTest("Fragment", fragment, invalidSelectors);
|
||||
runInvalidSelectorTest("In-document Element", element, invalidSelectors);
|
||||
runInvalidSelectorTest("Empty Element", empty, invalidSelectors);
|
||||
|
||||
runValidSelectorTest("Document", doc, validSelectors, testType, docType);
|
||||
runValidSelectorTest("Detached Element", detached, validSelectors, testType, docType);
|
||||
runValidSelectorTest("Fragment", fragment, validSelectors, testType, docType);
|
||||
|
||||
doc.body.appendChild(outOfScope); // Append before in-document Element tests.
|
||||
// None of these elements should match
|
||||
runValidSelectorTest("In-document Element", element, validSelectors, testType, docType);
|
||||
}
|
||||
]]></script>
|
||||
</body>
|
||||
</html>
|
||||
120
tests/wpt/dom/nodes/ParentNode-querySelector-All.html
Normal file
120
tests/wpt/dom/nodes/ParentNode-querySelector-All.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<meta name=timeout content=long>
|
||||
<title>Selectors-API Test Suite: HTML</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="selectors.js"></script>
|
||||
<script src="ParentNode-querySelector-All.js"></script>
|
||||
<style>iframe { visibility: hidden; position: absolute; }</style>
|
||||
|
||||
<div id="log">This test requires JavaScript.</div>
|
||||
|
||||
<script>
|
||||
async_test(function() {
|
||||
var frame = document.createElement("iframe");
|
||||
var self = this;
|
||||
frame.onload = function() {
|
||||
// :target doesn't work before a page rendering on some browsers. We run
|
||||
// tests after an animation frame because it may be later than the first
|
||||
// page rendering.
|
||||
requestAnimationFrame(self.step_func_done(init.bind(self, frame)));
|
||||
};
|
||||
frame.src = "ParentNode-querySelector-All-content.html#target";
|
||||
document.body.appendChild(frame);
|
||||
});
|
||||
|
||||
function init(target) {
|
||||
/*
|
||||
* This test suite tests Selectors API methods in 4 different contexts:
|
||||
* 1. Document node
|
||||
* 2. In-document Element node
|
||||
* 3. Detached Element node (an element with no parent, not in the document)
|
||||
* 4. Document Fragment node
|
||||
*
|
||||
* For each context, the following tests are run:
|
||||
*
|
||||
* The interface check tests ensure that each type of node exposes the Selectors API methods
|
||||
*
|
||||
* The special selector tests verify the result of passing special values for the selector parameter,
|
||||
* to ensure that the correct WebIDL processing is performed, such as stringification of null and
|
||||
* undefined and missing parameter. The universal selector is also tested here, rather than with the
|
||||
* rest of ordinary selectors for practical reasons.
|
||||
*
|
||||
* The static list verification tests ensure that the node lists returned by the method remain unchanged
|
||||
* due to subsequent document modication, and that a new list is generated each time the method is
|
||||
* invoked based on the current state of the document.
|
||||
*
|
||||
* The invalid selector tests ensure that SyntaxError is thrown for invalid forms of selectors
|
||||
*
|
||||
* The valid selector tests check the result from querying many different types of selectors, with a
|
||||
* list of expected elements. This checks that querySelector() always returns the first result from
|
||||
* querySelectorAll(), and that all matching elements are correctly returned in tree-order. The tests
|
||||
* can be limited by specifying the test types to run, using the testType variable. The constants for this
|
||||
* can be found in selectors.js.
|
||||
*
|
||||
* All the selectors tested for both the valid and invalid selector tests are found in selectors.js.
|
||||
* See comments in that file for documentation of the format used.
|
||||
*
|
||||
* The ParentNode-querySelector-All.js file contains all the common test functions for running each of the aforementioned tests
|
||||
*/
|
||||
|
||||
var testType = TEST_QSA;
|
||||
var docType = "html"; // Only run tests suitable for HTML
|
||||
|
||||
// Prepare the nodes for testing
|
||||
var doc = target.contentDocument; // Document Node tests
|
||||
|
||||
var element = doc.getElementById("root"); // In-document Element Node tests
|
||||
|
||||
//Setup the namespace tests
|
||||
setupSpecialElements(doc, element);
|
||||
|
||||
var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document
|
||||
// Element tests, but after running the Document tests. This
|
||||
// tests that no elements that are not descendants of element
|
||||
// are selected.
|
||||
|
||||
traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying
|
||||
elem.setAttribute("data-clone", ""); // that none of these elements ever match.
|
||||
});
|
||||
|
||||
|
||||
var detached = element.cloneNode(true); // Detached Element Node tests
|
||||
|
||||
var fragment = doc.createDocumentFragment(); // Fragment Node tests
|
||||
fragment.appendChild(element.cloneNode(true));
|
||||
|
||||
var empty = document.createElement("div"); // Empty Node tests
|
||||
|
||||
// Setup Tests
|
||||
interfaceCheck("Document", doc);
|
||||
interfaceCheck("Detached Element", detached);
|
||||
interfaceCheck("Fragment", fragment);
|
||||
interfaceCheck("In-document Element", element);
|
||||
|
||||
runSpecialSelectorTests("Document", doc);
|
||||
runSpecialSelectorTests("Detached Element", detached);
|
||||
runSpecialSelectorTests("Fragment", fragment);
|
||||
runSpecialSelectorTests("In-document Element", element);
|
||||
|
||||
verifyStaticList("Document", doc, doc);
|
||||
verifyStaticList("Detached Element", doc, detached);
|
||||
verifyStaticList("Fragment", doc, fragment);
|
||||
verifyStaticList("In-document Element", doc, element);
|
||||
|
||||
runInvalidSelectorTest("Document", doc, invalidSelectors);
|
||||
runInvalidSelectorTest("Detached Element", detached, invalidSelectors);
|
||||
runInvalidSelectorTest("Fragment", fragment, invalidSelectors);
|
||||
runInvalidSelectorTest("In-document Element", element, invalidSelectors);
|
||||
runInvalidSelectorTest("Empty Element", empty, invalidSelectors);
|
||||
|
||||
runValidSelectorTest("Document", doc, validSelectors, testType, docType);
|
||||
runValidSelectorTest("Detached Element", detached, validSelectors, testType, docType);
|
||||
runValidSelectorTest("Fragment", fragment, validSelectors, testType, docType);
|
||||
|
||||
doc.body.appendChild(outOfScope); // Append before in-document Element tests.
|
||||
// None of these elements should match
|
||||
runValidSelectorTest("In-document Element", element, validSelectors, testType, docType);
|
||||
}
|
||||
</script>
|
||||
261
tests/wpt/dom/nodes/ParentNode-querySelector-All.js
Normal file
261
tests/wpt/dom/nodes/ParentNode-querySelector-All.js
Normal file
@@ -0,0 +1,261 @@
|
||||
// Require selectors.js to be included before this.
|
||||
|
||||
/*
|
||||
* Create and append special elements that cannot be created correctly with HTML markup alone.
|
||||
*/
|
||||
function setupSpecialElements(doc, parent) {
|
||||
// Setup null and undefined tests
|
||||
parent.appendChild(doc.createElement("null"));
|
||||
parent.appendChild(doc.createElement("undefined"));
|
||||
|
||||
// Setup namespace tests
|
||||
var anyNS = doc.createElement("div");
|
||||
var noNS = doc.createElement("div");
|
||||
anyNS.id = "any-namespace";
|
||||
noNS.id = "no-namespace";
|
||||
|
||||
var divs;
|
||||
div = [doc.createElement("div"),
|
||||
doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
|
||||
doc.createElementNS("", "div"),
|
||||
doc.createElementNS("http://www.example.org/ns", "div")];
|
||||
|
||||
div[0].id = "any-namespace-div1";
|
||||
div[1].id = "any-namespace-div2";
|
||||
div[2].setAttribute("id", "any-namespace-div3"); // Non-HTML elements can't use .id property
|
||||
div[3].setAttribute("id", "any-namespace-div4");
|
||||
|
||||
for (var i = 0; i < div.length; i++) {
|
||||
anyNS.appendChild(div[i])
|
||||
}
|
||||
|
||||
div = [doc.createElement("div"),
|
||||
doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
|
||||
doc.createElementNS("", "div"),
|
||||
doc.createElementNS("http://www.example.org/ns", "div")];
|
||||
|
||||
div[0].id = "no-namespace-div1";
|
||||
div[1].id = "no-namespace-div2";
|
||||
div[2].setAttribute("id", "no-namespace-div3"); // Non-HTML elements can't use .id property
|
||||
div[3].setAttribute("id", "no-namespace-div4");
|
||||
|
||||
for (i = 0; i < div.length; i++) {
|
||||
noNS.appendChild(div[i])
|
||||
}
|
||||
|
||||
parent.appendChild(anyNS);
|
||||
parent.appendChild(noNS);
|
||||
|
||||
var span = doc.getElementById("attr-presence-i1");
|
||||
span.setAttributeNS("http://www.example.org/ns", "title", "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the querySelector and querySelectorAll methods exist on the given Node
|
||||
*/
|
||||
function interfaceCheck(type, obj) {
|
||||
test(function() {
|
||||
var q = typeof obj.querySelector === "function";
|
||||
assert_true(q, type + " supports querySelector.");
|
||||
}, type + " supports querySelector")
|
||||
|
||||
test(function() {
|
||||
var qa = typeof obj.querySelectorAll === "function";
|
||||
assert_true( qa, type + " supports querySelectorAll.");
|
||||
}, type + " supports querySelectorAll")
|
||||
|
||||
test(function() {
|
||||
var list = obj.querySelectorAll("div");
|
||||
if (obj.ownerDocument) { // The object is not a Document
|
||||
assert_true(list instanceof obj.ownerDocument.defaultView.NodeList, "The result should be an instance of a NodeList")
|
||||
} else { // The object is a Document
|
||||
assert_true(list instanceof obj.defaultView.NodeList, "The result should be an instance of a NodeList")
|
||||
}
|
||||
}, type + ".querySelectorAll returns NodeList instance")
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the NodeList returned by querySelectorAll is static and and that a new list is created after
|
||||
* each call. A static list should not be affected by subsequent changes to the DOM.
|
||||
*/
|
||||
function verifyStaticList(type, doc, root) {
|
||||
var pre, post, preLength;
|
||||
|
||||
test(function() {
|
||||
pre = root.querySelectorAll("div");
|
||||
preLength = pre.length;
|
||||
|
||||
var div = doc.createElement("div");
|
||||
(root.body || root).appendChild(div);
|
||||
|
||||
assert_equals(pre.length, preLength, "The length of the NodeList should not change.")
|
||||
}, type + ": static NodeList")
|
||||
|
||||
test(function() {
|
||||
post = root.querySelectorAll("div"),
|
||||
assert_equals(post.length, preLength + 1, "The length of the new NodeList should be 1 more than the previous list.")
|
||||
}, type + ": new NodeList")
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify handling of special values for the selector parameter, including stringification of
|
||||
* null and undefined, and the handling of the empty string.
|
||||
*/
|
||||
function runSpecialSelectorTests(type, root) {
|
||||
let global = (root.ownerDocument || root).defaultView;
|
||||
|
||||
test(function() { // 1
|
||||
assert_equals(root.querySelectorAll(null).length, 1, "This should find one element with the tag name 'NULL'.");
|
||||
}, type + ".querySelectorAll null")
|
||||
|
||||
test(function() { // 2
|
||||
assert_equals(root.querySelectorAll(undefined).length, 1, "This should find one element with the tag name 'UNDEFINED'.");
|
||||
}, type + ".querySelectorAll undefined")
|
||||
|
||||
test(function() { // 3
|
||||
assert_throws_js(global.TypeError, function() {
|
||||
root.querySelectorAll();
|
||||
}, "This should throw a TypeError.")
|
||||
}, type + ".querySelectorAll no parameter")
|
||||
|
||||
test(function() { // 4
|
||||
var elm = root.querySelector(null)
|
||||
assert_not_equals(elm, null, "This should find an element.");
|
||||
assert_equals(elm.tagName.toUpperCase(), "NULL", "The tag name should be 'NULL'.")
|
||||
}, type + ".querySelector null")
|
||||
|
||||
test(function() { // 5
|
||||
var elm = root.querySelector(undefined)
|
||||
assert_not_equals(elm, undefined, "This should find an element.");
|
||||
assert_equals(elm.tagName.toUpperCase(), "UNDEFINED", "The tag name should be 'UNDEFINED'.")
|
||||
}, type + ".querySelector undefined")
|
||||
|
||||
test(function() { // 6
|
||||
assert_throws_js(global.TypeError, function() {
|
||||
root.querySelector();
|
||||
}, "This should throw a TypeError.")
|
||||
}, type + ".querySelector no parameter")
|
||||
|
||||
test(function() { // 7
|
||||
result = root.querySelectorAll("*");
|
||||
var i = 0;
|
||||
traverse(root, function(elem) {
|
||||
if (elem !== root) {
|
||||
assert_equals(elem, result[i], "The result in index " + i + " should be in tree order.");
|
||||
i++;
|
||||
}
|
||||
})
|
||||
}, type + ".querySelectorAll tree order");
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute queries with the specified valid selectors for both querySelector() and querySelectorAll()
|
||||
* Only run these tests when results are expected. Don't run for syntax error tests.
|
||||
*/
|
||||
function runValidSelectorTest(type, root, selectors, testType, docType) {
|
||||
var nodeType = "";
|
||||
switch (root.nodeType) {
|
||||
case Node.DOCUMENT_NODE:
|
||||
nodeType = "document";
|
||||
break;
|
||||
case Node.ELEMENT_NODE:
|
||||
nodeType = root.parentNode ? "element" : "detached";
|
||||
break;
|
||||
case Node.DOCUMENT_FRAGMENT_NODE:
|
||||
nodeType = "fragment";
|
||||
break;
|
||||
default:
|
||||
assert_unreached();
|
||||
nodeType = "unknown"; // This should never happen.
|
||||
}
|
||||
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var s = selectors[i];
|
||||
var n = s["name"];
|
||||
var q = s["selector"];
|
||||
var e = s["expect"];
|
||||
|
||||
if ((!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1))
|
||||
&& (s["testType"] & testType) ) {
|
||||
var foundall, found;
|
||||
|
||||
test(function() {
|
||||
foundall = root.querySelectorAll(q);
|
||||
assert_not_equals(foundall, null, "The method should not return null.")
|
||||
assert_equals(foundall.length, e.length, "The method should return the expected number of matches.")
|
||||
|
||||
for (var i = 0; i < e.length; i++) {
|
||||
assert_not_equals(foundall[i], null, "The item in index " + i + " should not be null.")
|
||||
assert_equals(foundall[i].getAttribute("id"), e[i], "The item in index " + i + " should have the expected ID.");
|
||||
assert_false(foundall[i].hasAttribute("data-clone"), "This should not be a cloned element.");
|
||||
}
|
||||
}, type + ".querySelectorAll: " + n + ": " + q);
|
||||
|
||||
test(function() {
|
||||
found = root.querySelector(q);
|
||||
|
||||
if (e.length > 0) {
|
||||
assert_not_equals(found, null, "The method should return a match.")
|
||||
assert_equals(found.getAttribute("id"), e[0], "The method should return the first match.");
|
||||
assert_equals(found, foundall[0], "The result should match the first item from querySelectorAll.");
|
||||
assert_false(found.hasAttribute("data-clone"), "This should not be annotated as a cloned element.");
|
||||
} else {
|
||||
assert_equals(found, null, "The method should not match anything.");
|
||||
}
|
||||
}, type + ".querySelector: " + n + ": " + q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function windowFor(root) {
|
||||
return root.defaultView || root.ownerDocument.defaultView;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute queries with the specified invalid selectors for both querySelector() and querySelectorAll()
|
||||
* Only run these tests when errors are expected. Don't run for valid selector tests.
|
||||
*/
|
||||
function runInvalidSelectorTest(type, root, selectors) {
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var s = selectors[i];
|
||||
var n = s["name"];
|
||||
var q = s["selector"];
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom("SyntaxError", windowFor(root).DOMException, function() {
|
||||
root.querySelector(q)
|
||||
});
|
||||
}, type + ".querySelector: " + n + ": " + q);
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom("SyntaxError", windowFor(root).DOMException, function() {
|
||||
root.querySelectorAll(q)
|
||||
});
|
||||
}, type + ".querySelectorAll: " + n + ": " + q);
|
||||
}
|
||||
}
|
||||
|
||||
function traverse(elem, fn) {
|
||||
if (elem.nodeType === elem.ELEMENT_NODE) {
|
||||
fn(elem);
|
||||
}
|
||||
elem = elem.firstChild;
|
||||
while (elem) {
|
||||
traverse(elem, fn);
|
||||
elem = elem.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function getNodeType(node) {
|
||||
switch (node.nodeType) {
|
||||
case Node.DOCUMENT_NODE:
|
||||
return "document";
|
||||
case Node.ELEMENT_NODE:
|
||||
return node.parentNode ? "element" : "detached";
|
||||
case Node.DOCUMENT_FRAGMENT_NODE:
|
||||
return "fragment";
|
||||
default:
|
||||
assert_unreached();
|
||||
return "unknown"; // This should never happen.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelector(All) must work with the i and *= selectors</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2551 -->
|
||||
|
||||
<input name="User" id="testInput"></input>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
const input = document.getElementById("testInput");
|
||||
|
||||
test(() => {
|
||||
assert_equals(document.querySelector("input[name*=user i]"), input);
|
||||
}, "querySelector");
|
||||
|
||||
test(() => {
|
||||
assert_array_equals(document.querySelectorAll("input[name*=user i]"), [input]);
|
||||
}, "querySelectorAll");
|
||||
</script>
|
||||
123
tests/wpt/dom/nodes/ParentNode-querySelector-escapes.html
Normal file
123
tests/wpt/dom/nodes/ParentNode-querySelector-escapes.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>querySelector() with CSS escapes</title>
|
||||
<link rel="help" href="https://dom.spec.whatwg.org/#dom-parentnode-queryselector">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-syntax/#consume-escaped-code-point">
|
||||
<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
|
||||
<link rel="author" title="bellbind" href="mailto:bellbind@gmail.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function testMatched(id, selector) {
|
||||
test(() => {
|
||||
const container = document.createElement("div");
|
||||
const child = document.createElement("span");
|
||||
child.id = id;
|
||||
|
||||
container.appendChild(child);
|
||||
|
||||
assert_equals(container.querySelector(selector), child);
|
||||
}, `${JSON.stringify(id)} should match with ${JSON.stringify(selector)}`);
|
||||
}
|
||||
|
||||
function testNeverMatched(id, selector) {
|
||||
test(() => {
|
||||
const container = document.createElement("div");
|
||||
const child = document.createElement("span");
|
||||
child.id = id;
|
||||
|
||||
container.appendChild(child);
|
||||
|
||||
assert_equals(container.querySelector(selector), null);
|
||||
}, `${JSON.stringify(id)} should never match with ${JSON.stringify(selector)}`);
|
||||
}
|
||||
|
||||
// 4.3.7 from https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
|
||||
testMatched("nonescaped", "#nonescaped");
|
||||
|
||||
// - escape hex digit
|
||||
testMatched("0nextIsWhiteSpace", "#\\30 nextIsWhiteSpace");
|
||||
testMatched("0nextIsNotHexLetters", "#\\30nextIsNotHexLetters");
|
||||
testMatched("0connectHexMoreThan6Hex", "#\\000030connectHexMoreThan6Hex");
|
||||
testMatched("0spaceMoreThan6Hex", "#\\000030 spaceMoreThan6Hex");
|
||||
|
||||
// - hex digit special replacement
|
||||
// 1. zero points
|
||||
testMatched("zero\u{fffd}", "#zero\\0");
|
||||
testNeverMatched("zero\u{0}", "#zero\\0");
|
||||
testMatched("zero\u{fffd}", "#zero\\000000");
|
||||
testNeverMatched("zero\u{0}", "#zero\\000000");
|
||||
// 2. surrogate points
|
||||
testMatched("\u{fffd}surrogateFirst", "#\\d83d surrogateFirst");
|
||||
testNeverMatched("\ud83dsurrogateFirst", "#\\d83d surrogateFirst");
|
||||
testMatched("surrogateSecond\u{fffd}", "#surrogateSecond\\dd11");
|
||||
testNeverMatched("surrogateSecond\udd11", "#surrogateSecond\\dd11");
|
||||
testMatched("surrogatePair\u{fffd}\u{fffd}", "#surrogatePair\\d83d\\dd11");
|
||||
testNeverMatched("surrogatePair\u{1f511}", "#surrogatePair\\d83d\\dd11");
|
||||
// 3. out of range points
|
||||
testMatched("outOfRange\u{fffd}", "#outOfRange\\110000");
|
||||
testMatched("outOfRange\u{fffd}", "#outOfRange\\110030");
|
||||
testNeverMatched("outOfRange\u{30}", "#outOfRange\\110030");
|
||||
testMatched("outOfRange\u{fffd}", "#outOfRange\\555555");
|
||||
testMatched("outOfRange\u{fffd}", "#outOfRange\\ffffff");
|
||||
|
||||
// - escape EOF
|
||||
testNeverMatched("eof\\", "#eof\\");
|
||||
|
||||
// - escape anythong else
|
||||
testMatched(".comma", "#\\.comma");
|
||||
testMatched("-minus", "#\\-minus");
|
||||
testMatched("g", "#\\g");
|
||||
|
||||
// non edge cases
|
||||
testMatched("aBMPRegular", "#\\61 BMPRegular");
|
||||
testMatched("\u{1f511}nonBMP", "#\\1f511 nonBMP");
|
||||
testMatched("00continueEscapes", "#\\30\\30 continueEscapes");
|
||||
testMatched("00continueEscapes", "#\\30 \\30 continueEscapes");
|
||||
testMatched("continueEscapes00", "#continueEscapes\\30 \\30 ");
|
||||
testMatched("continueEscapes00", "#continueEscapes\\30 \\30");
|
||||
testMatched("continueEscapes00", "#continueEscapes\\30\\30 ");
|
||||
testMatched("continueEscapes00", "#continueEscapes\\30\\30");
|
||||
|
||||
// ident tests case from CSS tests of chromium source: https://goo.gl/3Cxdov
|
||||
testMatched("hello", "#hel\\6Co");
|
||||
testMatched("&B", "#\\26 B");
|
||||
testMatched("hello", "#hel\\6C o");
|
||||
testMatched("spaces", "#spac\\65\r\ns");
|
||||
testMatched("spaces", "#sp\\61\tc\\65\fs");
|
||||
testMatched("test\u{D799}", "#test\\D799");
|
||||
testMatched("\u{E000}", "#\\E000");
|
||||
testMatched("test", "#te\\s\\t");
|
||||
testMatched("spaces in\tident", "#spaces\\ in\\\tident");
|
||||
testMatched(".,:!", "#\\.\\,\\:\\!");
|
||||
testMatched("null\u{fffd}", "#null\\0");
|
||||
testMatched("null\u{fffd}", "#null\\0000");
|
||||
testMatched("large\u{fffd}", "#large\\110000");
|
||||
testMatched("large\u{fffd}", "#large\\23456a");
|
||||
testMatched("surrogate\u{fffd}", "#surrogate\\D800");
|
||||
testMatched("surrogate\u{fffd}", "#surrogate\\0DBAC");
|
||||
testMatched("\u{fffd}surrogate", "#\\00DFFFsurrogate");
|
||||
testMatched("\u{10ffff}", "#\\10fFfF");
|
||||
testMatched("\u{10ffff}0", "#\\10fFfF0");
|
||||
testMatched("\u{100000}00", "#\\10000000");
|
||||
testMatched("eof\u{fffd}", "#eof\\");
|
||||
|
||||
testMatched("simple-ident", "#simple-ident");
|
||||
testMatched("testing123", "#testing123");
|
||||
testMatched("_underscore", "#_underscore");
|
||||
testMatched("-text", "#-text");
|
||||
testMatched("-m", "#-\\6d");
|
||||
testMatched("--abc", "#--abc");
|
||||
testMatched("--", "#--");
|
||||
testMatched("--11", "#--11");
|
||||
testMatched("---", "#---");
|
||||
testMatched("\u{2003}", "#\u{2003}");
|
||||
testMatched("\u{A0}", "#\u{A0}");
|
||||
testMatched("\u{1234}", "#\u{1234}");
|
||||
testMatched("\u{12345}", "#\u{12345}");
|
||||
testMatched("\u{fffd}", "#\u{0}");
|
||||
testMatched("ab\u{fffd}c", "#ab\u{0}c");
|
||||
</script>
|
||||
33
tests/wpt/dom/nodes/ParentNode-querySelector-scope.html
Normal file
33
tests/wpt/dom/nodes/ParentNode-querySelector-scope.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelector(All) scoped to a root element</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<div><h1 id="test"></h1><p><span>hello</span></p></div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
const div = document.querySelector("div");
|
||||
const p = document.querySelector("p");
|
||||
|
||||
test(() => {
|
||||
assert_equals(div.querySelector(":scope > p"), p);
|
||||
assert_equals(div.querySelector(":scope > span"), null);
|
||||
}, "querySelector with :scope");
|
||||
|
||||
test(() => {
|
||||
assert_equals(div.querySelector("#test + p"), p);
|
||||
assert_equals(p.querySelector("#test + p"), null);
|
||||
}, "querySelector with id and sibling");
|
||||
|
||||
test(() => {
|
||||
assert_array_equals(div.querySelectorAll(":scope > p"), [p]);
|
||||
assert_array_equals(div.querySelectorAll(":scope > span"), []);
|
||||
}, "querySelectorAll with :scope");
|
||||
|
||||
test(() => {
|
||||
assert_array_equals(div.querySelectorAll("#test + p"), [p]);
|
||||
assert_array_equals(p.querySelectorAll("#test + p"), []);
|
||||
}, "querySelectorAll with id and sibling");
|
||||
</script>
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelectorAll must not return removed elements</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2519 -->
|
||||
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
setup({ single_test: true });
|
||||
|
||||
const container = document.querySelector("#container");
|
||||
function getIDs() {
|
||||
return [...container.querySelectorAll("a.test")].map(el => el.id);
|
||||
}
|
||||
|
||||
container.innerHTML = `<a id="link-a" class="test">a link</a>`;
|
||||
assert_array_equals(getIDs(), ["link-a"], "Sanity check: initial setup");
|
||||
|
||||
container.innerHTML = `<a id="link-b" class="test"><img src="foo.jpg"></a>`;
|
||||
assert_array_equals(getIDs(), ["link-b"], "After replacement");
|
||||
|
||||
container.innerHTML = `<a id="link-a" class="test">a link</a>`;
|
||||
assert_array_equals(getIDs(), ["link-a"], "After changing back to the original HTML");
|
||||
|
||||
done();
|
||||
</script>
|
||||
39
tests/wpt/dom/nodes/ParentNode-querySelectors-exclusive.html
Normal file
39
tests/wpt/dom/nodes/ParentNode-querySelectors-exclusive.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelector/querySelectorAll should not include their thisArg</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2296 -->
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
setup({ single_test: true });
|
||||
|
||||
const button = document.createElement("button");
|
||||
|
||||
assert_equals(button.querySelector("*"), null, "querySelector, '*', before modification");
|
||||
assert_equals(button.querySelector("button"), null, "querySelector, 'button', before modification");
|
||||
assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', before modification");
|
||||
assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', before modification");
|
||||
assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', before modification");
|
||||
assert_array_equals(
|
||||
button.querySelectorAll("button, span"), [],
|
||||
"querySelectorAll, 'button, span', before modification"
|
||||
);
|
||||
|
||||
|
||||
button.innerHTML = "text";
|
||||
|
||||
assert_equals(button.querySelector("*"), null, "querySelector, '*', after modification");
|
||||
assert_equals(button.querySelector("button"), null, "querySelector, 'button', after modification");
|
||||
assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', after modification");
|
||||
assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', after modification");
|
||||
assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', after modification");
|
||||
assert_array_equals(
|
||||
button.querySelectorAll("button, span"), [],
|
||||
"querySelectorAll, 'button, span', after modification"
|
||||
);
|
||||
|
||||
done();
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelectorAll must work with namespace attribute selectors on SVG</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2028 -->
|
||||
|
||||
<svg id="thesvg" xlink:href="foo"></svg>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
setup({ single_test: true });
|
||||
|
||||
const el = document.getElementById("thesvg");
|
||||
|
||||
assert_equals(document.querySelector("[*|href]"), el);
|
||||
assert_array_equals(document.querySelectorAll("[*|href]"), [el]);
|
||||
|
||||
done();
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>querySelector(All) must work for attribute values that contain spaces and dashes</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2542 -->
|
||||
|
||||
<a title="test with - dash and space" id="testme">Test One</a>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
const el = document.getElementById("testme");
|
||||
|
||||
test(() => {
|
||||
assert_equals(document.querySelector("a[title='test with - dash and space']"), el);
|
||||
}, "querySelector");
|
||||
|
||||
test(() => {
|
||||
assert_equals(document.querySelector("a[title='test with - dash and space']"), el);
|
||||
}, "querySelectorAll");
|
||||
</script>
|
||||
755
tests/wpt/dom/nodes/selectors.js
Normal file
755
tests/wpt/dom/nodes/selectors.js
Normal file
@@ -0,0 +1,755 @@
|
||||
// Bit-mapped flags to indicate which tests the selector is suitable for
|
||||
var TEST_QSA = 0x01; // querySelector() and querySelectorAll() tests
|
||||
var TEST_FIND = 0x04; // find() and findAll() tests, may be unsuitable for querySelector[All]
|
||||
var TEST_MATCH = 0x10; // matches() tests
|
||||
|
||||
/*
|
||||
* All of these invalid selectors should result in a SyntaxError being thrown by the APIs.
|
||||
*
|
||||
* name: A descriptive name of the selector being tested
|
||||
* selector: The selector to test
|
||||
*/
|
||||
var invalidSelectors = [
|
||||
{name: "Empty String", selector: ""},
|
||||
{name: "Invalid character", selector: "["},
|
||||
{name: "Invalid character", selector: "]"},
|
||||
{name: "Invalid character", selector: "("},
|
||||
{name: "Invalid character", selector: ")"},
|
||||
{name: "Invalid character", selector: "{"},
|
||||
{name: "Invalid character", selector: "}"},
|
||||
{name: "Invalid character", selector: "<"},
|
||||
{name: "Invalid character", selector: ">"},
|
||||
{name: "Invalid ID", selector: "#"},
|
||||
{name: "Invalid group of selectors", selector: "div,"},
|
||||
{name: "Invalid class", selector: "."},
|
||||
{name: "Invalid class", selector: ".5cm"},
|
||||
{name: "Invalid class", selector: "..test"},
|
||||
{name: "Invalid class", selector: ".foo..quux"},
|
||||
{name: "Invalid class", selector: ".bar."},
|
||||
{name: "Invalid combinator", selector: "div % address, p"},
|
||||
{name: "Invalid combinator", selector: "div ++ address, p"},
|
||||
{name: "Invalid combinator", selector: "div ~~ address, p"},
|
||||
{name: "Invalid [att=value] selector", selector: "[*=test]"},
|
||||
{name: "Invalid [att=value] selector", selector: "[*|*=test]"},
|
||||
{name: "Invalid [att=value] selector", selector: "[class= space unquoted ]"},
|
||||
{name: "Unknown pseudo-class", selector: "div:example"},
|
||||
{name: "Unknown pseudo-class", selector: ":example"},
|
||||
{name: "Unknown pseudo-class", selector: "div:linkexample"},
|
||||
{name: "Unknown pseudo-element", selector: "div::example"},
|
||||
{name: "Unknown pseudo-element", selector: "::example"},
|
||||
{name: "Invalid pseudo-element", selector: ":::before"},
|
||||
{name: "Invalid pseudo-element", selector: ":: before"},
|
||||
{name: "Undeclared namespace", selector: "ns|div"},
|
||||
{name: "Undeclared namespace", selector: ":not(ns|div)"},
|
||||
{name: "Invalid namespace", selector: "^|div"},
|
||||
{name: "Invalid namespace", selector: "$|div"},
|
||||
{name: "Relative selector", selector: ">*"},
|
||||
];
|
||||
|
||||
/*
|
||||
* All of these should be valid selectors, expected to match zero or more elements in the document.
|
||||
* None should throw any errors.
|
||||
*
|
||||
* name: A descriptive name of the selector being tested
|
||||
* selector: The selector to test
|
||||
* expect: A list of IDs of the elements expected to be matched. List must be given in tree order.
|
||||
* exclude: An array of contexts to exclude from testing. The valid values are:
|
||||
* ["document", "element", "fragment", "detached", "html", "xhtml"]
|
||||
* The "html" and "xhtml" values represent the type of document being queried. These are useful
|
||||
* for tests that are affected by differences between HTML and XML, such as case sensitivity.
|
||||
* level: An integer indicating the CSS or Selectors level in which the selector being tested was introduced.
|
||||
* testType: A bit-mapped flag indicating the type of test.
|
||||
*
|
||||
* Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite.
|
||||
*/
|
||||
var validSelectors = [
|
||||
// Type Selector
|
||||
{name: "Type selector, matching html element", selector: "html", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Type selector, matching html element", selector: "html", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA},
|
||||
{name: "Type selector, matching body element", selector: "body", expect: ["body"], exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Type selector, matching body element", selector: "body", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA},
|
||||
|
||||
// Universal Selector
|
||||
{name: "Universal selector, matching all elements", selector: "*", expect: ["universal", "universal-p1", "universal-code1", "universal-hr1", "universal-pre1", "universal-span1", "universal-p2", "universal-a1", "universal-address1", "universal-code2", "universal-a2"], level: 2, testType: TEST_MATCH},
|
||||
{name: "Universal selector, matching all children of element with specified ID", selector: "#universal>*", expect: ["universal-p1", "universal-hr1", "universal-pre1", "universal-p2", "universal-address1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Universal selector, matching all grandchildren of element with specified ID", selector: "#universal>*>*", expect: ["universal-code1", "universal-span1", "universal-a1", "universal-code2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Universal selector, matching all children of empty element with specified ID", selector: "#empty>*", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Universal selector, matching all descendants of element with specified ID", selector: "#universal *", expect: ["universal-p1", "universal-code1", "universal-hr1", "universal-pre1", "universal-span1", "universal-p2", "universal-a1", "universal-address1", "universal-code2", "universal-a2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// Attribute Selectors
|
||||
// - presence [att]
|
||||
{name: "Attribute presence selector, matching align attribute with value", selector: ".attr-presence-div1[align]", expect: ["attr-presence-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching align attribute with empty value", selector: ".attr-presence-div2[align]", expect: ["attr-presence-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching title attribute, case insensitivity", selector: "#attr-presence [*|TiTlE]", expect: ["attr-presence-a1", "attr-presence-span1", "attr-presence-i1"], exclude: ["xhtml"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching title attribute, case sensitivity", selector: "#attr-presence [*|TiTlE]", expect: [], exclude: ["html"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching custom data-* attribute", selector: "[data-attr-presence]", expect: ["attr-presence-pre1", "attr-presence-blockquote1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching attribute with similar name", selector: ".attr-presence-div3[align], .attr-presence-div4[align]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute presence selector, matching attribute with non-ASCII characters", selector: "ul[data-中文]", expect: ["attr-presence-ul1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching default option without selected attribute", selector: "#attr-presence-select1 option[selected]", expect: [] /* no matches */, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute presence selector, matching option with selected attribute", selector: "#attr-presence-select2 option[selected]", expect: ["attr-presence-select2-option4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching multiple options with selected attributes", selector: "#attr-presence-select3 option[selected]", expect: ["attr-presence-select3-option2", "attr-presence-select3-option3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - value [att=val]
|
||||
{name: "Attribute value selector, matching align attribute with value", selector: "#attr-value [align=\"center\"]", expect: ["attr-value-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching align attribute with value, unclosed bracket", selector: "#attr-value [align=\"center\"", expect: ["attr-value-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching align attribute with empty value", selector: "#attr-value [align=\"\"]", expect: ["attr-value-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector, not matching align attribute with partial value", selector: "#attr-value [align=\"c\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute value selector, not matching align attribute with incorrect value", selector: "#attr-value [align=\"centera\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute value selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-value=\"\\e9\"]", expect: ["attr-value-div3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching custom data-* attribute with escaped character", selector: "[data-attr-value\_foo=\"\\e9\"]", expect: ["attr-value-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector with single-quoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type='hidden'],#attr-value input[type='radio']", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector with double-quoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector with unquoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type=hidden],#attr-value input[type=radio]", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching attribute with value using non-ASCII characters", selector: "[data-attr-value=中文]", expect: ["attr-value-div5"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - whitespace-separated list [att~=val]
|
||||
{name: "Attribute whitespace-separated list selector, matching class attribute with value", selector: "#attr-whitespace [class~=\"div1\"]", expect: ["attr-whitespace-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector, not matching class attribute with empty value", selector: "#attr-whitespace [class~=\"\"]", expect: [] /*no matches*/ , level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute whitespace-separated list selector, not matching class attribute with partial value", selector: "[data-attr-whitespace~=\"div\"]", expect: [] /*no matches*/ , level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-whitespace~=\"\\0000e9\"]", expect: ["attr-whitespace-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character", selector: "[data-attr-whitespace\_foo~=\"\\e9\"]", expect: ["attr-whitespace-div5"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with double-quoted value, not matching value with space", selector: "#attr-whitespace a[rel~=\"book mark\"]", expect: [] /* no matches */, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters", selector: "#attr-whitespace [title~=中文]", expect: ["attr-whitespace-p1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - hyphen-separated list [att|=val]
|
||||
{name: "Attribute hyphen-separated list selector, not matching unspecified lang attribute", selector: "#attr-hyphen-div1[lang|=\"en\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Attribute hyphen-separated list selector, matching lang attribute with exact value", selector: "#attr-hyphen-div2[lang|=\"fr\"]", expect: ["attr-hyphen-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute hyphen-separated list selector, matching lang attribute with partial value", selector: "#attr-hyphen-div3[lang|=\"en\"]", expect: ["attr-hyphen-div3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute hyphen-separated list selector, not matching incorrect value", selector: "#attr-hyphen-div4[lang|=\"es-AR\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
|
||||
// - substring begins-with [att^=val] (Level 3)
|
||||
{name: "Attribute begins with selector, matching href attributes beginning with specified substring", selector: "#attr-begins a[href^=\"http://www\"]", expect: ["attr-begins-a1", "attr-begins-a3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute begins with selector, matching lang attributes beginning with specified substring, ", selector: "#attr-begins [lang^=\"en-\"]", expect: ["attr-begins-div2", "attr-begins-div4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute begins with selector, not matching class attribute with empty value", selector: "#attr-begins [class^=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "Attribute begins with selector, not matching class attribute not beginning with specified substring", selector: "#attr-begins [class^=apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring", selector: "#attr-begins [class^=' apple']", expect: ["attr-begins-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring", selector: "#attr-begins [class^=\" apple\"]", expect: ["attr-begins-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring", selector: "#attr-begins [class^= apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - substring ends-with [att$=val] (Level 3)
|
||||
{name: "Attribute ends with selector, matching href attributes ending with specified substring", selector: "#attr-ends a[href$=\".org\"]", expect: ["attr-ends-a1", "attr-ends-a3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute ends with selector, matching lang attributes ending with specified substring, ", selector: "#attr-ends [lang$=\"-CH\"]", expect: ["attr-ends-div2", "attr-ends-div4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute ends with selector, not matching class attribute with empty value", selector: "#attr-ends [class$=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "Attribute ends with selector, not matching class attribute not ending with specified substring", selector: "#attr-ends [class$=apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring", selector: "#attr-ends [class$='apple ']", expect: ["attr-ends-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring", selector: "#attr-ends [class$=\"apple \"]", expect: ["attr-ends-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring", selector: "#attr-ends [class$=apple ]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - substring contains [att*=val] (Level 3)
|
||||
{name: "Attribute contains selector, matching href attributes beginning with specified substring", selector: "#attr-contains a[href*=\"http://www\"]", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching href attributes ending with specified substring", selector: "#attr-contains a[href*=\".org\"]", expect: ["attr-contains-a1", "attr-contains-a2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching href attributes containing specified substring", selector: "#attr-contains a[href*=\".example.\"]", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching lang attributes beginning with specified substring, ", selector: "#attr-contains [lang*=\"en-\"]", expect: ["attr-contains-div2", "attr-contains-div6"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching lang attributes ending with specified substring, ", selector: "#attr-contains [lang*=\"-CH\"]", expect: ["attr-contains-div3", "attr-contains-div5"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector, not matching class attribute with empty value", selector: "#attr-contains [class*=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*=' apple']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*='orange ']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*='ple banana ora']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*=\" apple\"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*=\"orange \"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*=\"ple banana ora\"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*= apple]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*=orange ]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*= banana ]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// Pseudo-classes
|
||||
// - :root (Level 3)
|
||||
{name: ":root pseudo-class selector, matching document root element", selector: ":root", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":root pseudo-class selector, not matching document root element", selector: ":root", expect: [] /*no matches*/, exclude: ["document"], level: 3, testType: TEST_QSA},
|
||||
|
||||
// - :nth-child(n) (Level 3)
|
||||
// XXX write descriptions
|
||||
{name: ":nth-child selector, matching the third child element", selector: "#pseudo-nth-table1 :nth-child(3)", expect: ["pseudo-nth-td3", "pseudo-nth-td9", "pseudo-nth-tr3", "pseudo-nth-td15"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every third child element", selector: "#pseudo-nth li:nth-child(3n)", expect: ["pseudo-nth-li3", "pseudo-nth-li6", "pseudo-nth-li9", "pseudo-nth-li12"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every second child element, starting from the fourth", selector: "#pseudo-nth li:nth-child(2n+4)", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every fourth child element, starting from the third", selector: "#pseudo-nth-p1 :nth-child(4n-1)", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :nth-last-child (Level 3)
|
||||
{name: ":nth-last-child selector, matching the third last child element", selector: "#pseudo-nth-table1 :nth-last-child(3)", expect: ["pseudo-nth-tr1", "pseudo-nth-td4", "pseudo-nth-td10", "pseudo-nth-td16"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every third child element from the end", selector: "#pseudo-nth li:nth-last-child(3n)", expect: ["pseudo-nth-li1", "pseudo-nth-li4", "pseudo-nth-li7", "pseudo-nth-li10"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every second child element from the end, starting from the fourth last", selector: "#pseudo-nth li:nth-last-child(2n+4)", expect: ["pseudo-nth-li1", "pseudo-nth-li3", "pseudo-nth-li5", "pseudo-nth-li7", "pseudo-nth-li9"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every fourth element from the end, starting from the third last", selector: "#pseudo-nth-p1 :nth-last-child(4n-1)", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :nth-of-type(n) (Level 3)
|
||||
{name: ":nth-of-type selector, matching the third em element", selector: "#pseudo-nth-p1 em:nth-of-type(3)", expect: ["pseudo-nth-em3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-of-type selector, matching every second element of their type", selector: "#pseudo-nth-p1 :nth-of-type(2n)", expect: ["pseudo-nth-em2", "pseudo-nth-span2", "pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-of-type selector, matching every second elemetn of their type, starting from the first", selector: "#pseudo-nth-p1 span:nth-of-type(2n-1)", expect: ["pseudo-nth-span1", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :nth-last-of-type(n) (Level 3)
|
||||
{name: ":nth-last-of-type selector, matching the third last em element", selector: "#pseudo-nth-p1 em:nth-last-of-type(3)", expect: ["pseudo-nth-em2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-last-of-type selector, matching every second last element of their type", selector: "#pseudo-nth-p1 :nth-last-of-type(2n)", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1", "pseudo-nth-em3", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":nth-last-of-type selector, matching every second last element of their type, starting from the last", selector: "#pseudo-nth-p1 span:nth-last-of-type(2n-1)", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :first-of-type (Level 3)
|
||||
{name: ":first-of-type selector, matching the first em element", selector: "#pseudo-nth-p1 em:first-of-type", expect: ["pseudo-nth-em1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":first-of-type selector, matching the first of every type of element", selector: "#pseudo-nth-p1 :first-of-type", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":first-of-type selector, matching the first td element in each table row", selector: "#pseudo-nth-table1 tr :first-of-type", expect: ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :last-of-type (Level 3)
|
||||
{name: ":last-of-type selector, matching the last em elemnet", selector: "#pseudo-nth-p1 em:last-of-type", expect: ["pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":last-of-type selector, matching the last of every type of element", selector: "#pseudo-nth-p1 :last-of-type", expect: ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":last-of-type selector, matching the last td element in each table row", selector: "#pseudo-nth-table1 tr :last-of-type", expect: ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :first-child
|
||||
{name: ":first-child pseudo-class selector, matching first child div element", selector: "#pseudo-first-child div:first-child", expect: ["pseudo-first-child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":first-child pseudo-class selector, doesn't match non-first-child elements", selector: ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: ":first-child pseudo-class selector, matching first-child of multiple elements", selector: "#pseudo-first-child span:first-child", expect: ["pseudo-first-child-span1", "pseudo-first-child-span3", "pseudo-first-child-span5"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :last-child (Level 3)
|
||||
{name: ":last-child pseudo-class selector, matching last child div element", selector: "#pseudo-last-child div:last-child", expect: ["pseudo-last-child-div3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":last-child pseudo-class selector, doesn't match non-last-child elements", selector: ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: ":last-child pseudo-class selector, matching first-child of multiple elements", selector: "#pseudo-last-child span:last-child", expect: ["pseudo-last-child-span2", "pseudo-last-child-span4", "pseudo-last-child-span6"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :only-child (Level 3)
|
||||
{name: ":pseudo-only-child pseudo-class selector, matching all only-child elements", selector: "#pseudo-only :only-child", expect: ["pseudo-only-span1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":pseudo-only-child pseudo-class selector, matching only-child em elements", selector: "#pseudo-only em:only-child", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - :only-of-type (Level 3)
|
||||
{name: ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type", selector: "#pseudo-only :only-of-type", expect: ["pseudo-only-span1", "pseudo-only-em1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type", selector: "#pseudo-only em:only-of-type", expect: ["pseudo-only-em1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :empty (Level 3)
|
||||
{name: ":empty pseudo-class selector, matching empty p elements", selector: "#pseudo-empty p:empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":empty pseudo-class selector, matching all empty elements", selector: "#pseudo-empty :empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :link and :visited
|
||||
// Implementations may treat all visited links as unvisited, so these cannot be tested separately.
|
||||
// The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets.
|
||||
{name: ":link and :visited pseudo-class selectors, matching a and area elements with href attributes", selector: "#pseudo-link :link, #pseudo-link :visited", expect: ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":link and :visited pseudo-class selectors, matching no elements", selector: "#head :link, #head :visited", expect: [] /*no matches*/, exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":link and :visited pseudo-class selectors, not matching link elements with href attributes", selector: "#head :link, #head :visited", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA},
|
||||
{name: ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing", selector: ":link:visited", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA},
|
||||
|
||||
// - :target (Level 3)
|
||||
{name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", expect: [] /*no matches*/, exclude: ["document", "element"], level: 3, testType: TEST_QSA},
|
||||
{name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", expect: ["target"], exclude: ["fragment", "detached"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :lang()
|
||||
{name: ":lang pseudo-class selector, matching inherited language", selector: "#pseudo-lang-div1:lang(en)", expect: ["pseudo-lang-div1"], exclude: ["detached", "fragment"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, not matching element with no inherited language", selector: "#pseudo-lang-div1:lang(en)", expect: [] /*no matches*/, exclude: ["document", "element"], level: 2, testType: TEST_QSA},
|
||||
{name: ":lang pseudo-class selector, matching specified language with exact value", selector: "#pseudo-lang-div2:lang(fr)", expect: ["pseudo-lang-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, matching specified language with partial value", selector: "#pseudo-lang-div3:lang(en)", expect: ["pseudo-lang-div3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, not matching incorrect language", selector: "#pseudo-lang-div4:lang(es-AR)", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
|
||||
// - :enabled (Level 3)
|
||||
{name: ":enabled pseudo-class selector, matching all enabled form controls", selector: "#pseudo-ui :enabled", expect: ["pseudo-ui-input1", "pseudo-ui-input2", "pseudo-ui-input3", "pseudo-ui-input4", "pseudo-ui-input5", "pseudo-ui-input6",
|
||||
"pseudo-ui-input7", "pseudo-ui-input8", "pseudo-ui-input9", "pseudo-ui-textarea1", "pseudo-ui-button1"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":enabled pseudo-class selector, not matching link elements", selector: "#pseudo-link :enabled", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :disabled (Level 3)
|
||||
{name: ":disabled pseudo-class selector, matching all disabled form controls", selector: "#pseudo-ui :disabled", expect: ["pseudo-ui-input10", "pseudo-ui-input11", "pseudo-ui-input12", "pseudo-ui-input13", "pseudo-ui-input14", "pseudo-ui-input15",
|
||||
"pseudo-ui-input16", "pseudo-ui-input17", "pseudo-ui-input18", "pseudo-ui-textarea2", "pseudo-ui-button2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":disabled pseudo-class selector, not matching link elements", selector: "#pseudo-link :disabled", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :checked (Level 3)
|
||||
{name: ":checked pseudo-class selector, matching checked radio buttons and checkboxes", selector: "#pseudo-ui :checked", expect: ["pseudo-ui-input4", "pseudo-ui-input6", "pseudo-ui-input13", "pseudo-ui-input15"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :not(s) (Level 3)
|
||||
{name: ":not pseudo-class selector, matching ", selector: "#not>:not(div)", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":not pseudo-class selector, matching ", selector: "#not * :not(:first-child)", expect: ["not-em1", "not-em2", "not-em3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: ":not pseudo-class selector, matching nothing", selector: ":not(*)", expect: [] /* no matches */, level: 3, testType: TEST_QSA},
|
||||
{name: ":not pseudo-class selector, matching nothing", selector: ":not(*|*)", expect: [] /* no matches */, level: 3, testType: TEST_QSA},
|
||||
{name: ":not pseudo-class selector argument surrounded by spaces, matching ", selector: "#not>:not( div )", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// Pseudo-elements
|
||||
// - ::first-line
|
||||
{name: ":first-line pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-line", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "::first-line pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-line", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - ::first-letter
|
||||
{name: ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-letter", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-letter", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - ::before
|
||||
{name: ":before pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:before", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "::before pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::before", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// - ::after
|
||||
{name: ":after pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:after", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "::after pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::after", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
|
||||
// Class Selectors
|
||||
{name: "Class selector, matching element with specified class", selector: ".class-p", expect: ["class-p1","class-p2", "class-p3"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, chained, matching only elements with all specified classes", selector: "#class .apple.orange.banana", expect: ["class-div1", "class-div2", "class-p4", "class-div3", "class-p6", "class-div4"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class Selector, chained, with type selector", selector: "div.apple.banana.orange", expect: ["class-div1", "class-div2", "class-div3", "class-div4"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class value using non-ASCII characters (1)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci", expect: ["class-span1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, matching multiple elements with class value using non-ASCII characters", selector: ".\u53F0\u5317", expect: ["class-span1","class-span2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, chained, matching element with multiple class values using non-ASCII characters (1)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci.\u53F0\u5317", expect: ["class-span1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class with escaped character", selector: ".foo\\:bar", expect: ["class-span3"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class with escaped character", selector: ".test\\.foo\\[5\\]bar", expect: ["class-span4"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// ID Selectors
|
||||
{name: "ID selector, matching element with specified id", selector: "#id #id-div1", expect: ["id-div1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID selector, chained, matching element with specified id", selector: "#id-div1, #id-div1", expect: ["id-div1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID selector, chained, matching element with specified id", selector: "#id-div1, #id-div2", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID Selector, chained, with type selector", selector: "div#id-div1, div#id-div2", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID selector, not matching non-existent descendant", selector: "#id #none", expect: [] /*no matches*/, level: 1, testType: TEST_QSA},
|
||||
{name: "ID selector, not matching non-existent ancestor", selector: "#none #id-div1", expect: [] /*no matches*/, level: 1, testType: TEST_QSA},
|
||||
{name: "ID selector, matching multiple elements with duplicate id", selector: "#id-li-duplicate", expect: ["id-li-duplicate", "id-li-duplicate", "id-li-duplicate", "id-li-duplicate"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
{name: "ID selector, matching id value using non-ASCII characters (1)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID selector, matching id value using non-ASCII characters (2)", selector: "#\u53F0\u5317", expect: ["\u53F0\u5317"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "ID selector, matching id values using non-ASCII characters (1)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci, #\u53F0\u5317", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci", "\u53F0\u5317"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values
|
||||
{name: "ID selector, matching element with id with escaped character", selector: "#\\#foo\\:bar", expect: ["#foo:bar"], level: 1, testType: TEST_QSA},
|
||||
{name: "ID selector, matching element with id with escaped character", selector: "#test\\.foo\\[5\\]bar", expect: ["test.foo[5]bar"], level: 1, testType: TEST_QSA},
|
||||
|
||||
// Namespaces
|
||||
// XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id
|
||||
{name: "Namespace selector, matching element with any namespace", selector: "#any-namespace *|div", expect: ["any-namespace-div1", "any-namespace-div2", "any-namespace-div3", "any-namespace-div4"], level: 3, testType: TEST_QSA},
|
||||
{name: "Namespace selector, matching div elements in no namespace only", selector: "#no-namespace |div", expect: ["no-namespace-div3"], level: 3, testType: TEST_QSA},
|
||||
{name: "Namespace selector, matching any elements in no namespace only", selector: "#no-namespace |*", expect: ["no-namespace-div3"], level: 3, testType: TEST_QSA},
|
||||
|
||||
// Combinators
|
||||
// - Descendant combinator ' '
|
||||
{name: "Descendant combinator, matching element that is a descendant of an element with id", selector: "#descendant div", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element", selector: "body #descendant-div1", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element", selector: "div #descendant-div1", expect: ["descendant-div1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element with id", selector: "#descendant #descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with class that is a descendant of an element with id", selector: "#descendant .descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with class that is a descendant of an element with class", selector: ".descendant-div1 .descendant-div3", expect: ["descendant-div3"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Descendant combinator, not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1 #descendant-div4", expect: [] /*no matches*/, level: 1, testType: TEST_QSA},
|
||||
{name: "Descendant combinator, whitespace characters", selector: "#descendant\t\r\n#descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
/* The future of this combinator is uncertain, see
|
||||
* https://github.com/w3c/csswg-drafts/issues/641
|
||||
* These tests are commented out until a final decision is made on whether to
|
||||
* keep the feature in the spec.
|
||||
*/
|
||||
|
||||
// // - Descendant combinator '>>'
|
||||
// {name: "Descendant combinator '>>', matching element that is a descendant of an element with id", selector: "#descendant>>div", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element", selector: "body>>#descendant-div1", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element", selector: "div>>#descendant-div1", expect: ["descendant-div1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element with id", selector: "#descendant>>#descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with id", selector: "#descendant>>.descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with class", selector: ".descendant-div1>>.descendant-div3", expect: ["descendant-div3"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1>>#descendant-div4", expect: [] /*no matches*/, level: 1, testType: TEST_QSA},
|
||||
|
||||
// - Child combinator '>'
|
||||
{name: "Child combinator, matching element that is a child of an element with id", selector: "#child>div", expect: ["child-div1", "child-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element", selector: "div>#child-div1", expect: ["child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element with id", selector: "#child>#child-div1", expect: ["child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element with class", selector: "#child-div1>.child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with class that is a child of an element with class", selector: ".child-div1>.child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, not matching element with id that is not a child of an element with id", selector: "#child>#child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Child combinator, not matching element with id that is not a child of an element with class", selector: "#child-div1>.child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Child combinator, not matching element with class that is not a child of an element with class", selector: ".child-div1>.child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Child combinator, surrounded by whitespace", selector: "#child-div1\t\r\n>\t\r\n#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, whitespace after", selector: "#child-div1>\t\r\n#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, whitespace before", selector: "#child-div1\t\r\n>#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Child combinator, no whitespace", selector: "#child-div1>#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - Adjacent sibling combinator '+'
|
||||
{name: "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id", selector: "#adjacent-div2+div", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element", selector: "div+#adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id", selector: "#adjacent-div2+.adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class", selector: ".adjacent-div2+.adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element", selector: "#adjacent div+p", expect: ["adjacent-p2"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1", expect: [] /*no matches*/, level: 2, testType: TEST_QSA},
|
||||
{name: "Adjacent sibling combinator, surrounded by whitespace", selector: "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, whitespace after", selector: "#adjacent-p2+\t\r\n#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, whitespace before", selector: "#adjacent-p2\t\r\n+#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, no whitespace", selector: "#adjacent-p2+#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - General sibling combinator ~ (Level 3)
|
||||
{name: "General sibling combinator, matching element that is a sibling of an element with id", selector: "#sibling-div2~div", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with id that is a sibling of an element", selector: "div~#sibling-div4", expect: ["sibling-div4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with id that is a sibling of an element with id", selector: "#sibling-div2~#sibling-div4", expect: ["sibling-div4"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with class that is a sibling of an element with id", selector: "#sibling-div2~.sibling-div", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching p element that is a sibling of a div element", selector: "#sibling div~p", expect: ["sibling-p2", "sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, not matching element with id that is not a sibling after a p element", selector: "#sibling>p~div", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "General sibling combinator, not matching element with id that is not a sibling after an element with id", selector: "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1", expect: [] /*no matches*/, level: 3, testType: TEST_QSA},
|
||||
{name: "General sibling combinator, surrounded by whitespace", selector: "#sibling-p2\t\r\n~\t\r\n#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, whitespace after", selector: "#sibling-p2~\t\r\n#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, whitespace before", selector: "#sibling-p2\t\r\n~#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "General sibling combinator, no whitespace", selector: "#sibling-p2~#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// Group of selectors (comma)
|
||||
{name: "Syntax, group of selectors separator, surrounded by whitespace", selector: "#group em\t\r \n,\t\r \n#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, whitespace after", selector: "#group em,\t\r\n#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, whitespace before", selector: "#group em\t\r\n,#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, no whitespace", selector: "#group em,#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// ::slotted (shouldn't match anything, but is a valid selector)
|
||||
{name: "Slotted selector", selector: "::slotted(foo)", expect: [], level: 3, testType: TEST_QSA},
|
||||
{name: "Slotted selector (no matching closing paren)", selector: "::slotted(foo", expect: [], level: 3, testType: TEST_QSA},
|
||||
];
|
||||
|
||||
|
||||
/*
|
||||
* These selectors are intended to be used with the find(), findAll() and matches() methods. Expected results
|
||||
* should be determined under the assumption that :scope will be prepended to the selector where appropriate,
|
||||
* in accordance with the specification.
|
||||
*
|
||||
* All of these should be valid relative selectors, expected to match zero or more elements in the document.
|
||||
* None should throw any errors.
|
||||
*
|
||||
* name: A descriptive name of the selector being tested
|
||||
*
|
||||
* selector: The selector to test
|
||||
*
|
||||
* ctx: A selector to obtain the context object to use for tests invoking context.find(),
|
||||
* and to use as a single reference node for tests invoking document.find().
|
||||
* Note: context = root.querySelector(ctx);
|
||||
*
|
||||
* ref: A selector to obtain the reference nodes to be used for the selector.
|
||||
* Note: If root is the document or an in-document element:
|
||||
* refNodes = document.querySelectorAll(ref);
|
||||
* Otherwise, if root is a fragment or detached element:
|
||||
* refNodes = root.querySelectorAll(ref);
|
||||
*
|
||||
* expect: A list of IDs of the elements expected to be matched. List must be given in tree order.
|
||||
*
|
||||
* unexpected: A list of IDs of some elements that are not expected to match the given selector.
|
||||
* This is used to verify that unexpected.matches(selector, refNode) does not match.
|
||||
*
|
||||
* exclude: An array of contexts to exclude from testing. The valid values are:
|
||||
* ["document", "element", "fragment", "detached", "html", "xhtml"]
|
||||
* The "html" and "xhtml" values represent the type of document being queried. These are useful
|
||||
* for tests that are affected by differences between HTML and XML, such as case sensitivity.
|
||||
*
|
||||
* level: An integer indicating the CSS or Selectors level in which the selector being tested was introduced.
|
||||
*
|
||||
* testType: A bit-mapped flag indicating the type of test.
|
||||
*
|
||||
* The test function for these tests accepts a specified root node, on which the methods will be invoked during the tests.
|
||||
*
|
||||
* Based on whether either 'context' or 'refNodes', or both, are specified the tests will execute the following methods:
|
||||
*
|
||||
* Where testType is TEST_FIND:
|
||||
*
|
||||
* context.findAll(selector, refNodes)
|
||||
* context.findAll(selector) // Only if refNodes is not specified
|
||||
* root.findAll(selector, context) // Only if refNodes is not specified
|
||||
* root.findAll(selector, refNodes) // Only if context is not specified
|
||||
* root.findAll(selector) // Only if neither context nor refNodes is specified
|
||||
*
|
||||
* Where testType is TEST_QSA
|
||||
*
|
||||
* context.querySelectorAll(selector)
|
||||
* root.querySelectorAll(selector) // Only if neither context nor refNodes is specified
|
||||
*
|
||||
* Equivalent tests will be run for .find() as well.
|
||||
* Note: Do not specify a testType of TEST_QSA where either implied :scope or explicit refNodes
|
||||
* are required.
|
||||
*
|
||||
* Where testType is TEST_MATCH:
|
||||
* For each expected result given, within the specified root:
|
||||
*
|
||||
* expect.matches(selector, context) // Only where refNodes is not specified
|
||||
* expect.matches(selector, refNodes)
|
||||
* expect.matches(selector) // Only if neither context nor refNodes is specified
|
||||
*
|
||||
* The tests involving refNodes for both find(), findAll() and matches() will each be run by passing the
|
||||
* collection as a NodeList, an Array and, if there is only a single element, an Element node.
|
||||
*
|
||||
* Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite.
|
||||
*/
|
||||
|
||||
var scopedSelectors = [
|
||||
//{name: "", selector: "", ctx: "", ref: "", expect: [], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// Attribute Selectors
|
||||
// - presence [att]
|
||||
{name: "Attribute presence selector, matching align attribute with value", selector: ".attr-presence-div1[align]", ctx: "#attr-presence", expect: ["attr-presence-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching align attribute with empty value", selector: ".attr-presence-div2[align]", ctx: "#attr-presence", expect: ["attr-presence-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching title attribute, case insensitivity", selector: "[TiTlE]", ctx: "#attr-presence", expect: ["attr-presence-a1", "attr-presence-span1"], exclude: ["xhtml"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching title attribute, case sensitivity", selector: "[TiTlE]", ctx: "#attr-presence", expect: [], exclude: ["html"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching custom data-* attribute", selector: "[data-attr-presence]", ctx: "#attr-presence", expect: ["attr-presence-pre1", "attr-presence-blockquote1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching attribute with similar name", selector: ".attr-presence-div3[align], .attr-presence-div4[align]", ctx: "#attr-presence", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute presence selector, matching attribute with non-ASCII characters", selector: "ul[data-中文]", ctx: "#attr-presence", expect: ["attr-presence-ul1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, not matching default option without selected attribute", selector: "#attr-presence-select1 option[selected]", ctx: "#attr-presence", expect: [] /* no matches */, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute presence selector, matching option with selected attribute", selector: "#attr-presence-select2 option[selected]", ctx: "#attr-presence", expect: ["attr-presence-select2-option4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute presence selector, matching multiple options with selected attributes", selector: "#attr-presence-select3 option[selected]", ctx: "#attr-presence", expect: ["attr-presence-select3-option2", "attr-presence-select3-option3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - value [att=val]
|
||||
{name: "Attribute value selector, matching align attribute with value", selector: "[align=\"center\"]", ctx: "#attr-value", expect: ["attr-value-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching align attribute with empty value", selector: "[align=\"\"]", ctx: "#attr-value", expect: ["attr-value-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector, not matching align attribute with partial value", selector: "[align=\"c\"]", ctx: "#attr-value", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute value selector, not matching align attribute with incorrect value", selector: "[align=\"centera\"]", ctx: "#attr-value", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute value selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-value=\"\\e9\"]", ctx: "#attr-value", expect: ["attr-value-div3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching custom data-* attribute with escaped character", selector: "[data-attr-value\_foo=\"\\e9\"]", ctx: "#attr-value", expect: ["attr-value-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector with single-quoted value, matching multiple inputs with type attributes", selector: "input[type='hidden'],#attr-value input[type='radio']", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector with double-quoted value, matching multiple inputs with type attributes", selector: "input[type=\"hidden\"],#attr-value input[type='radio']", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector with unquoted value, matching multiple inputs with type attributes", selector: "input[type=hidden],#attr-value input[type=radio]", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute value selector, matching attribute with value using non-ASCII characters", selector: "[data-attr-value=中文]", ctx: "#attr-value", expect: ["attr-value-div5"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - whitespace-separated list [att~=val]
|
||||
{name: "Attribute whitespace-separated list selector, matching class attribute with value", selector: "[class~=\"div1\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector, not matching class attribute with empty value", selector: "[class~=\"\"]", ctx: "#attr-whitespace", expect: [] /*no matches*/ , level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute whitespace-separated list selector, not matching class attribute with partial value", selector: "[data-attr-whitespace~=\"div\"]", ctx: "#attr-whitespace", expect: [] /*no matches*/ , level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-whitespace~=\"\\0000e9\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character", selector: "[data-attr-whitespace\_foo~=\"\\e9\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div5"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes", selector: "a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes", selector: "a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes", selector: "a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute whitespace-separated list selector with double-quoted value, not matching value with space", selector: "a[rel~=\"book mark\"]", ctx: "#attr-whitespace", expect: [] /* no matches */, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters", selector: "[title~=中文]", ctx: "#attr-whitespace", expect: ["attr-whitespace-p1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - hyphen-separated list [att|=val]
|
||||
{name: "Attribute hyphen-separated list selector, not matching unspecified lang attribute", selector: "#attr-hyphen-div1[lang|=\"en\"]", ctx: "#attr-hyphen", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Attribute hyphen-separated list selector, matching lang attribute with exact value", selector: "#attr-hyphen-div2[lang|=\"fr\"]", ctx: "#attr-hyphen", expect: ["attr-hyphen-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute hyphen-separated list selector, matching lang attribute with partial value", selector: "#attr-hyphen-div3[lang|=\"en\"]", ctx: "#attr-hyphen", expect: ["attr-hyphen-div3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute hyphen-separated list selector, not matching incorrect value", selector: "#attr-hyphen-div4[lang|=\"es-AR\"]", ctx: "#attr-hyphen", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
|
||||
// - substring begins-with [att^=val] (Level 3)
|
||||
{name: "Attribute begins with selector, matching href attributes beginning with specified substring", selector: "a[href^=\"http://www\"]", ctx: "#attr-begins", expect: ["attr-begins-a1", "attr-begins-a3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute begins with selector, matching lang attributes beginning with specified substring, ", selector: "[lang^=\"en-\"]", ctx: "#attr-begins", expect: ["attr-begins-div2", "attr-begins-div4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute begins with selector, not matching class attribute with empty value", selector: "[class^=\"\"]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "Attribute begins with selector, not matching class attribute not beginning with specified substring", selector: "[class^=apple]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring", selector: "[class^=' apple']", ctx: "#attr-begins", expect: ["attr-begins-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring", selector: "[class^=\" apple\"]", ctx: "#attr-begins", expect: ["attr-begins-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring", selector: "[class^= apple]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - substring ends-with [att$=val] (Level 3)
|
||||
{name: "Attribute ends with selector, matching href attributes ending with specified substring", selector: "a[href$=\".org\"]", ctx: "#attr-ends", expect: ["attr-ends-a1", "attr-ends-a3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute ends with selector, matching lang attributes ending with specified substring, ", selector: "[lang$=\"-CH\"]", ctx: "#attr-ends", expect: ["attr-ends-div2", "attr-ends-div4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute ends with selector, not matching class attribute with empty value", selector: "[class$=\"\"]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "Attribute ends with selector, not matching class attribute not ending with specified substring", selector: "[class$=apple]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring", selector: "[class$='apple ']", ctx: "#attr-ends", expect: ["attr-ends-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring", selector: "[class$=\"apple \"]", ctx: "#attr-ends", expect: ["attr-ends-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring", selector: "[class$=apple ]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - substring contains [att*=val] (Level 3)
|
||||
{name: "Attribute contains selector, matching href attributes beginning with specified substring", selector: "a[href*=\"http://www\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching href attributes ending with specified substring", selector: "a[href*=\".org\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a2"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching href attributes containing specified substring", selector: "a[href*=\".example.\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching lang attributes beginning with specified substring, ", selector: "[lang*=\"en-\"]", ctx: "#attr-contains", expect: ["attr-contains-div2", "attr-contains-div6"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector, matching lang attributes ending with specified substring, ", selector: "[lang*=\"-CH\"]", ctx: "#attr-contains", expect: ["attr-contains-div3", "attr-contains-div5"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector, not matching class attribute with empty value", selector: "[class*=\"\"]", ctx: "#attr-contains", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring", selector: "[class*=' apple']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring", selector: "[class*='orange ']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with single-quoted value, matching class attribute containing specified substring", selector: "[class*='ple banana ora']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring", selector: "[class*=\" apple\"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring", selector: "[class*=\"orange \"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with double-quoted value, matching class attribute containing specified substring", selector: "[class*=\"ple banana ora\"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring", selector: "[class*= apple]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute ending with specified substring", selector: "[class*=orange ]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Attribute contains selector with unquoted value, matching class attribute containing specified substring", selector: "[class*= banana ]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// Pseudo-classes
|
||||
// - :root (Level 3)
|
||||
{name: ":root pseudo-class selector, matching document root element", selector: ":root", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 3, testType: TEST_FIND},
|
||||
{name: ":root pseudo-class selector, not matching document root element", selector: ":root", expect: [] /*no matches*/, exclude: ["document"], level: 3, testType: TEST_FIND},
|
||||
{name: ":root pseudo-class selector, not matching document root element", selector: ":root", ctx: "#html", expect: [] /*no matches*/, exclude: ["fragment", "detached"], level: 3, testType: TEST_FIND},
|
||||
|
||||
// - :nth-child(n) (Level 3)
|
||||
{name: ":nth-child selector, matching the third child element", selector: ":nth-child(3)", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td3", "pseudo-nth-td9", "pseudo-nth-tr3", "pseudo-nth-td15"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every third child element", selector: "li:nth-child(3n)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li3", "pseudo-nth-li6", "pseudo-nth-li9", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every second child element, starting from the fourth", selector: "li:nth-child(2n+4)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every second child element, starting from the fourth, with whitespace", selector: "li:nth-child(2n \t\r\n+ \t\r\n4)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every fourth child element, starting from the third", selector: ":nth-child(4n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector, matching every fourth child element, starting from the third, with whitespace", selector: ":nth-child(4n \t\r\n- \t\r\n1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-child selector used twice, matching ", selector: ":nth-child(1) :nth-child(1)", ctx: "#pseudo-nth", expect: ["pseudo-nth-table1", "pseudo-nth-tr1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :nth-last-child (Level 3)
|
||||
{name: ":nth-last-child selector, matching the third last child element", selector: ":nth-last-child(3)", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-tr1", "pseudo-nth-td4", "pseudo-nth-td10", "pseudo-nth-td16"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every third child element from the end", selector: "li:nth-last-child(3n)", ctx: "pseudo-nth", expect: ["pseudo-nth-li1", "pseudo-nth-li4", "pseudo-nth-li7", "pseudo-nth-li10"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every second child element from the end, starting from the fourth last", selector: "li:nth-last-child(2n+4)", ctx: "pseudo-nth", expect: ["pseudo-nth-li1", "pseudo-nth-li3", "pseudo-nth-li5", "pseudo-nth-li7", "pseudo-nth-li9"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-last-child selector, matching every fourth element from the end, starting from the third last", selector: ":nth-last-child(4n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :nth-of-type(n) (Level 3)
|
||||
{name: ":nth-of-type selector, matching the third em element", selector: "em:nth-of-type(3)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-of-type selector, matching every second element of their type", selector: ":nth-of-type(2n)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span2", "pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-of-type selector, matching every second elemetn of their type, starting from the first", selector: "span:nth-of-type(2n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :nth-last-of-type(n) (Level 3)
|
||||
{name: ":nth-last-of-type selector, matching the third last em element", selector: "em:nth-last-of-type(3)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-last-of-type selector, matching every second last element of their type", selector: ":nth-last-of-type(2n)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1", "pseudo-nth-em3", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":nth-last-of-type selector, matching every second last element of their type, starting from the last", selector: "span:nth-last-of-type(2n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :first-of-type (Level 3)
|
||||
{name: ":first-of-type selector, matching the first em element", selector: "em:first-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":first-of-type selector, matching the first of every type of element", selector: ":first-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":first-of-type selector, matching the first td element in each table row", selector: "tr :first-of-type", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :last-of-type (Level 3)
|
||||
{name: ":last-of-type selector, matching the last em elemnet", selector: "em:last-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":last-of-type selector, matching the last of every type of element", selector: ":last-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":last-of-type selector, matching the last td element in each table row", selector: "tr :last-of-type", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :first-child
|
||||
{name: ":first-child pseudo-class selector, matching first child div element", selector: "div:first-child", ctx: "#pseudo-first-child", expect: ["pseudo-first-child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":first-child pseudo-class selector, doesn't match non-first-child elements", selector: ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child", ctx: "#pseudo-first-child", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: ":first-child pseudo-class selector, matching first-child of multiple elements", selector: "span:first-child", ctx: "#pseudo-first-child", expect: ["pseudo-first-child-span1", "pseudo-first-child-span3", "pseudo-first-child-span5"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :last-child (Level 3)
|
||||
{name: ":last-child pseudo-class selector, matching last child div element", selector: "div:last-child", ctx: "#pseudo-last-child", expect: ["pseudo-last-child-div3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":last-child pseudo-class selector, doesn't match non-last-child elements", selector: ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child", ctx: "#pseudo-last-child", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: ":last-child pseudo-class selector, matching first-child of multiple elements", selector: "span:last-child", ctx: "#pseudo-last-child", expect: ["pseudo-last-child-span2", "pseudo-last-child-span4", "pseudo-last-child-span6"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :only-child (Level 3)
|
||||
{name: ":pseudo-only-child pseudo-class selector, matching all only-child elements", selector: ":only-child", ctx: "#pseudo-only", expect: ["pseudo-only-span1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":pseudo-only-child pseudo-class selector, matching only-child em elements", selector: "em:only-child", ctx: "#pseudo-only", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - :only-of-type (Level 3)
|
||||
{name: ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type", selector: " :only-of-type", ctx: "#pseudo-only", expect: ["pseudo-only-span1", "pseudo-only-em1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type", selector: " em:only-of-type", ctx: "#pseudo-only", expect: ["pseudo-only-em1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :empty (Level 3)
|
||||
{name: ":empty pseudo-class selector, matching empty p elements", selector: "p:empty", ctx: "#pseudo-empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":empty pseudo-class selector, matching all empty elements", selector: ":empty", ctx: "#pseudo-empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :link and :visited
|
||||
// Implementations may treat all visited links as unvisited, so these cannot be tested separately.
|
||||
// The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets.
|
||||
{name: ":link and :visited pseudo-class selectors, matching a and area elements with href attributes", selector: " :link, #pseudo-link :visited", ctx: "#pseudo-link", expect: ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":link and :visited pseudo-class selectors, matching no elements", selector: " :link, #head :visited", ctx: "#head", expect: [] /*no matches*/, exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":link and :visited pseudo-class selectors, not matching link elements with href attributes", selector: " :link, #head :visited", ctx: "#head", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_FIND},
|
||||
{name: ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing", selector: ":link:visited", ctx: "#html", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_FIND},
|
||||
|
||||
// XXX Figure out context or refNodes for this
|
||||
// - :target (Level 3)
|
||||
{name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", ctx: "", expect: [] /*no matches*/, exclude: ["document", "element"], level: 3, testType: TEST_FIND},
|
||||
{name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", ctx: "", expect: ["target"], exclude: ["fragment", "detached"], level: 3, testType: TEST_FIND},
|
||||
|
||||
// XXX Fix ctx in tests below
|
||||
|
||||
// - :lang()
|
||||
{name: ":lang pseudo-class selector, matching inherited language (1)", selector: "#pseudo-lang-div1:lang(en)", ctx: "", expect: ["pseudo-lang-div1"], exclude: ["detached", "fragment"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, not matching element with no inherited language", selector: "#pseudo-lang-div1:lang(en)", ctx: "", expect: [] /*no matches*/, exclude: ["document", "element"], level: 2, testType: TEST_FIND},
|
||||
{name: ":lang pseudo-class selector, matching specified language with exact value (1)", selector: "#pseudo-lang-div2:lang(fr)", ctx: "", expect: ["pseudo-lang-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, matching specified language with partial value (1)", selector: "#pseudo-lang-div3:lang(en)", ctx: "", expect: ["pseudo-lang-div3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":lang pseudo-class selector, not matching incorrect language", selector: "#pseudo-lang-div4:lang(es-AR)", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
|
||||
// - :enabled (Level 3)
|
||||
{name: ":enabled pseudo-class selector, matching all enabled form controls (1)", selector: "#pseudo-ui :enabled", ctx: "", expect: ["pseudo-ui-input1", "pseudo-ui-input2", "pseudo-ui-input3", "pseudo-ui-input4", "pseudo-ui-input5", "pseudo-ui-input6",
|
||||
"pseudo-ui-input7", "pseudo-ui-input8", "pseudo-ui-input9", "pseudo-ui-textarea1", "pseudo-ui-button1"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":enabled pseudo-class selector, not matching link elements (1)", selector: "#pseudo-link :enabled", ctx: "", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :disabled (Level 3)
|
||||
{name: ":disabled pseudo-class selector, matching all disabled form controls (1)", selector: "#pseudo-ui :disabled", ctx: "", expect: ["pseudo-ui-input10", "pseudo-ui-input11", "pseudo-ui-input12", "pseudo-ui-input13", "pseudo-ui-input14", "pseudo-ui-input15",
|
||||
"pseudo-ui-input16", "pseudo-ui-input17", "pseudo-ui-input18", "pseudo-ui-textarea2", "pseudo-ui-button2"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":disabled pseudo-class selector, not matching link elements (1)", selector: "#pseudo-link :disabled", ctx: "", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH},
|
||||
|
||||
// - :checked (Level 3)
|
||||
{name: ":checked pseudo-class selector, matching checked radio buttons and checkboxes (1)", selector: "#pseudo-ui :checked", ctx: "", expect: ["pseudo-ui-input4", "pseudo-ui-input6", "pseudo-ui-input13", "pseudo-ui-input15"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - :not(s) (Level 3)
|
||||
{name: ":not pseudo-class selector, matching (1)", selector: "#not>:not(div)", ctx: "", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":not pseudo-class selector, matching (1)", selector: "#not * :not(:first-child)", ctx: "", expect: ["not-em1", "not-em2", "not-em3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: ":not pseudo-class selector, matching nothing", selector: ":not(*)", ctx: "", expect: [] /* no matches */, level: 3, testType: TEST_FIND},
|
||||
{name: ":not pseudo-class selector, matching nothing", selector: ":not(*|*)", ctx: "", expect: [] /* no matches */, level: 3, testType: TEST_FIND},
|
||||
|
||||
// Pseudo-elements
|
||||
// - ::first-line
|
||||
{name: ":first-line pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-line", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "::first-line pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-line", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - ::first-letter
|
||||
{name: ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-letter", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-letter", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - ::before
|
||||
{name: ":before pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:before", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "::before pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::before", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// - ::after
|
||||
{name: ":after pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:after", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "::after pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::after", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
|
||||
// Class Selectors
|
||||
{name: "Class selector, matching element with specified class (1)", selector: ".class-p", ctx: "", expect: ["class-p1","class-p2", "class-p3"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, chained, matching only elements with all specified classes (1)", selector: "#class .apple.orange.banana", ctx: "", expect: ["class-div1", "class-div2", "class-p4", "class-div3", "class-p6", "class-div4"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class Selector, chained, with type selector (1)", selector: "div.apple.banana.orange", ctx: "", expect: ["class-div1", "class-div2", "class-div3", "class-div4"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class value using non-ASCII characters (2)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci", ctx: "", expect: ["class-span1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, matching multiple elements with class value using non-ASCII characters (1)", selector: ".\u53F0\u5317", ctx: "", expect: ["class-span1","class-span2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, chained, matching element with multiple class values using non-ASCII characters (2)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci.\u53F0\u5317", ctx: "", expect: ["class-span1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class with escaped character (1)", selector: ".foo\\:bar", ctx: "", expect: ["class-span3"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Class selector, matching element with class with escaped character (1)", selector: ".test\\.foo\\[5\\]bar", ctx: "", expect: ["class-span4"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// ID Selectors
|
||||
{name: "ID selector, matching element with specified id (1)", selector: "#id #id-div1", ctx: "", expect: ["id-div1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID selector, chained, matching element with specified id (1)", selector: "#id-div1, #id-div1", ctx: "", expect: ["id-div1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID selector, chained, matching element with specified id (1)", selector: "#id-div1, #id-div2", ctx: "", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID Selector, chained, with type selector (1)", selector: "div#id-div1, div#id-div2", ctx: "", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID selector, not matching non-existent descendant", selector: "#id #none", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND},
|
||||
{name: "ID selector, not matching non-existent ancestor", selector: "#none #id-div1", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND},
|
||||
{name: "ID selector, matching multiple elements with duplicate id (1)", selector: "#id-li-duplicate", ctx: "", expect: ["id-li-duplicate", "id-li-duplicate", "id-li-duplicate", "id-li-duplicate"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
{name: "ID selector, matching id value using non-ASCII characters (3)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci", ctx: "", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID selector, matching id value using non-ASCII characters (4)", selector: "#\u53F0\u5317", ctx: "", expect: ["\u53F0\u5317"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "ID selector, matching id values using non-ASCII characters (2)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci, #\u53F0\u5317", ctx: "", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci", "\u53F0\u5317"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values
|
||||
{name: "ID selector, matching element with id with escaped character", selector: "#\\#foo\\:bar", ctx: "", expect: ["#foo:bar"], level: 1, testType: TEST_FIND},
|
||||
{name: "ID selector, matching element with id with escaped character", selector: "#test\\.foo\\[5\\]bar", ctx: "", expect: ["test.foo[5]bar"], level: 1, testType: TEST_FIND},
|
||||
|
||||
// Namespaces
|
||||
// XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id
|
||||
{name: "Namespace selector, matching element with any namespace", selector: "#any-namespace *|div", ctx: "", expect: ["any-namespace-div1", "any-namespace-div2", "any-namespace-div3", "any-namespace-div4"], level: 3, testType: TEST_FIND},
|
||||
{name: "Namespace selector, matching div elements in no namespace only", selector: "#no-namespace |div", ctx: "", expect: ["no-namespace-div3"], level: 3, testType: TEST_FIND},
|
||||
{name: "Namespace selector, matching any elements in no namespace only", selector: "#no-namespace |*", ctx: "", expect: ["no-namespace-div3"], level: 3, testType: TEST_FIND},
|
||||
|
||||
// Combinators
|
||||
// - Descendant combinator ' '
|
||||
{name: "Descendant combinator, matching element that is a descendant of an element with id (1)", selector: "#descendant div", ctx: "", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element (1)", selector: "body #descendant-div1", ctx: "", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element (1)", selector: "div #descendant-div1", ctx: "", expect: ["descendant-div1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with id that is a descendant of an element with id (1)", selector: "#descendant #descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with class that is a descendant of an element with id (1)", selector: "#descendant .descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, matching element with class that is a descendant of an element with class (1)", selector: ".descendant-div1 .descendant-div3", ctx: "", expect: ["descendant-div3"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Descendant combinator, not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1 #descendant-div4", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND},
|
||||
{name: "Descendant combinator, whitespace characters (1)", selector: "#descendant\t\r\n#descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// // - Descendant combinator '>>'
|
||||
// {name: "Descendant combinator '>>', matching element that is a descendant of an element with id (1)", selector: "#descendant>>div", ctx: "", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element (1)", selector: "body>>#descendant-div1", ctx: "", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element (1)", selector: "div>>#descendant-div1", ctx: "", expect: ["descendant-div1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with id that is a descendant of an element with id (1)", selector: "#descendant>>#descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with id (1)", selector: "#descendant>>.descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator, '>>', matching element with class that is a descendant of an element with class (1)", selector: ".descendant-div1>>.descendant-div3", ctx: "", expect: ["descendant-div3"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
// {name: "Descendant combinator '>>', not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1>>#descendant-div4", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND},
|
||||
|
||||
// - Child combinator '>'
|
||||
{name: "Child combinator, matching element that is a child of an element with id (1)", selector: "#child>div", ctx: "", expect: ["child-div1", "child-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element (1)", selector: "div>#child-div1", ctx: "", expect: ["child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element with id (1)", selector: "#child>#child-div1", ctx: "", expect: ["child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with id that is a child of an element with class (1)", selector: "#child-div1>.child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, matching element with class that is a child of an element with class (1)", selector: ".child-div1>.child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, not matching element with id that is not a child of an element with id", selector: "#child>#child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Child combinator, not matching element with id that is not a child of an element with class", selector: "#child-div1>.child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Child combinator, not matching element with class that is not a child of an element with class", selector: ".child-div1>.child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Child combinator, surrounded by whitespace (1)", selector: "#child-div1\t\r\n>\t\r\n#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, whitespace after (1)", selector: "#child-div1>\t\r\n#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, whitespace before (1)", selector: "#child-div1\t\r\n>#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Child combinator, no whitespace (1)", selector: "#child-div1>#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - Adjacent sibling combinator '+'
|
||||
{name: "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+div", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element (1)", selector: "div+#adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+#adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+.adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class (1)", selector: ".adjacent-div2+.adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element (1)", selector: "#adjacent div+p", ctx: "", expect: ["adjacent-p2"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND},
|
||||
{name: "Adjacent sibling combinator, surrounded by whitespace (1)", selector: "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, whitespace after (1)", selector: "#adjacent-p2+\t\r\n#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, whitespace before (1)", selector: "#adjacent-p2\t\r\n+#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Adjacent sibling combinator, no whitespace (1)", selector: "#adjacent-p2+#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// - General sibling combinator ~ (Level 3)
|
||||
{name: "General sibling combinator, matching element that is a sibling of an element with id (1)", selector: "#sibling-div2~div", ctx: "", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with id that is a sibling of an element (1)", selector: "div~#sibling-div4", ctx: "", expect: ["sibling-div4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with id that is a sibling of an element with id (1)", selector: "#sibling-div2~#sibling-div4", ctx: "", expect: ["sibling-div4"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching element with class that is a sibling of an element with id (1)", selector: "#sibling-div2~.sibling-div", ctx: "", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, matching p element that is a sibling of a div element (1)", selector: "#sibling div~p", ctx: "", expect: ["sibling-p2", "sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, not matching element with id that is not a sibling after a p element (1)", selector: "#sibling>p~div", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "General sibling combinator, not matching element with id that is not a sibling after an element with id", selector: "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND},
|
||||
{name: "General sibling combinator, surrounded by whitespace (1)", selector: "#sibling-p2\t\r\n~\t\r\n#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, whitespace after (1)", selector: "#sibling-p2~\t\r\n#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, whitespace before (1)", selector: "#sibling-p2\t\r\n~#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "General sibling combinator, no whitespace (1)", selector: "#sibling-p2~#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH},
|
||||
|
||||
// Group of selectors (comma)
|
||||
{name: "Syntax, group of selectors separator, surrounded by whitespace (1)", selector: "#group em\t\r \n,\t\r \n#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, whitespace after (1)", selector: "#group em,\t\r\n#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, whitespace before (1)", selector: "#group em\t\r\n,#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
{name: "Syntax, group of selectors separator, no whitespace (1)", selector: "#group em,#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH},
|
||||
];
|
||||
@@ -0,0 +1,46 @@
|
||||
"use strict";
|
||||
|
||||
function makeStaticNodeList(length) {
|
||||
const fooRoot = document.createElement("div");
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
const el = document.createElement("span");
|
||||
el.className = "foo";
|
||||
fooRoot.append(el);
|
||||
}
|
||||
|
||||
document.body.append(fooRoot);
|
||||
return fooRoot.querySelectorAll(".foo");
|
||||
}
|
||||
|
||||
const indexOfNodeList = new Function("nodeList", `
|
||||
const __cacheBust = ${Math.random()};
|
||||
|
||||
const el = nodeList[50];
|
||||
|
||||
let index = -1;
|
||||
|
||||
for (var i = 0; i < 1e5 / 2; i++) {
|
||||
for (var j = 0; j < nodeList.length; j++) {
|
||||
if (nodeList[j] === el) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
`);
|
||||
|
||||
const arrayIndexOfNodeList = new Function("nodeList", `
|
||||
const __cacheBust = ${Math.random()};
|
||||
|
||||
const el = nodeList[50];
|
||||
const {indexOf} = Array.prototype;
|
||||
|
||||
for (var i = 0; i < 1e5; i++) {
|
||||
var index = indexOf.call(nodeList, el);
|
||||
}
|
||||
|
||||
return index;
|
||||
`);
|
||||
Reference in New Issue
Block a user