mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb: Add WPT tests related to XPath evaluation
This commit is contained in:
parent
d2030a5377
commit
e9e58d83b3
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<link rel="help" href="https://github.com/servo/servo/issues/36971">
|
||||
<meta name="assert" content="Using variables in xpath expression should not crash.">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// The exact behaviour here is not defined. Firefox throws an error, Chrome doesn't.
|
||||
document.evaluate("$foo", document.createElement("div"));
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Evaluating XPath expressions with orhpaned Attr as context node doesn't crash</title>
|
||||
<link rel=author href="mailto:jarhar@chromium.org">
|
||||
<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1236967">
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
for (const expression of [
|
||||
"..",
|
||||
"parent",
|
||||
"ancestor::*",
|
||||
"ancestor-or-self::*",
|
||||
"following::*",
|
||||
"preceding::*",
|
||||
]) {
|
||||
const orphanedAttr = document.createAttribute("foo");
|
||||
new XPathEvaluator().evaluate(expression, orphanedAttr, null, 2);
|
||||
}
|
||||
</script>
|
||||
12
Tests/LibWeb/Text/expected/wpt-import/domxpath/booleans.txt
Normal file
12
Tests/LibWeb/Text/expected/wpt-import/domxpath/booleans.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 7 tests
|
||||
|
||||
7 Pass
|
||||
Pass "or" operator depending on the context node
|
||||
Pass "=" operator depending on the context node
|
||||
Pass "!=" operator depending on the context node
|
||||
Pass "<" operator depending on the context node
|
||||
Pass ">" operator depending on the context node
|
||||
Pass ">=" operator depending on the context node
|
||||
Pass "<=" operator depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass XPath parent of documentElement
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 2 tests
|
||||
|
||||
2 Pass
|
||||
Pass Constructor with 'new'
|
||||
Pass Constructor without 'new'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 4 tests
|
||||
|
||||
4 Fail
|
||||
Fail evaluator from realm with XML associated document, context node in XML document, no namespace resolver
|
||||
Fail evaluator from realm with XML associated document, context node in HTML document, no namespace resolver
|
||||
Fail evaluator from realm with HTML associated document, context node in XML document, no namespace resolver
|
||||
Fail evaluator from realm with HTML associated document, context node in HTML document, no namespace resolver
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 8 tests
|
||||
|
||||
4 Pass
|
||||
4 Fail
|
||||
Fail evaluate operation on XML document, context node in XML document, no namespace resolver
|
||||
Pass evaluate operation on HTML document, context node in HTML document, no namespace resolver
|
||||
Pass evaluate operation on XML document, context node in HTML document, no namespace resolver
|
||||
Fail evaluate operation on HTML document, context node in XML document, no namespace resolver
|
||||
Fail evaluate operation on XML document, context node in XML document, with namespace resolver
|
||||
Pass evaluate operation on HTML document, context node in HTML document, with namespace resolver
|
||||
Pass evaluate operation on XML document, context node in HTML document, with namespace resolver
|
||||
Fail evaluate operation on HTML document, context node in XML document, with namespace resolver
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 4 tests
|
||||
|
||||
4 Fail
|
||||
Fail expression from realm with XML associated document, context node in XML document, no namespace resolver
|
||||
Fail expression from realm with XML associated document, context node in HTML document, no namespace resolver
|
||||
Fail expression from realm with HTML associated document, context node in XML document, no namespace resolver
|
||||
Fail expression from realm with HTML associated document, context node in HTML document, no namespace resolver
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 8 tests
|
||||
|
||||
4 Pass
|
||||
4 Fail
|
||||
Fail expression from XML document, context node in XML document, no namespace resolver
|
||||
Pass expression from HTML document, context node in HTML document, no namespace resolver
|
||||
Pass expression from XML document, context node in HTML document, no namespace resolver
|
||||
Fail expression from HTML document, context node in XML document, no namespace resolver
|
||||
Fail expression from XML document, context node in XML document, with namespace resolver
|
||||
Pass expression from HTML document, context node in HTML document, with namespace resolver
|
||||
Pass expression from XML document, context node in HTML document, with namespace resolver
|
||||
Fail expression from HTML document, context node in XML document, with namespace resolver
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass concat() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass contains() arguments depending on the context node
|
||||
14
Tests/LibWeb/Text/expected/wpt-import/domxpath/fn-id.txt
Normal file
14
Tests/LibWeb/Text/expected/wpt-import/domxpath/fn-id.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 8 tests
|
||||
|
||||
6 Pass
|
||||
2 Fail
|
||||
Pass id("test1"): <root><div id="test1">Match</div></root>
|
||||
Pass id("test1 test2"): <root><div id="test1">First</div><div id="test2">Second</div></root>
|
||||
Pass id("nonexistent"): <root><div id="test1">No match</div></root>
|
||||
Pass id("Test1"): <root><div id="test1">No match</div></root>
|
||||
Fail id("duplicate"): <root><div id="duplicate">First</div><div id="duplicate">Second</div></root>
|
||||
Pass id("test-1"): <root><div id="test-1">Match</div></root>
|
||||
Pass id(""): <root><div id="">Empty ID</div></root>
|
||||
Fail id(" test1 "): <root><div id="test1">Match</div></root>
|
||||
13
Tests/LibWeb/Text/expected/wpt-import/domxpath/fn-lang.txt
Normal file
13
Tests/LibWeb/Text/expected/wpt-import/domxpath/fn-lang.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 7 tests
|
||||
|
||||
6 Pass
|
||||
1 Fail
|
||||
Pass lang("en"): <root><match xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="en"/></root>
|
||||
Pass lang("en"): <root><match xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="EN"/></root>
|
||||
Pass lang("en"): <root><match xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="en-us"/></root>
|
||||
Pass lang("en"): <root><unmatch/></root>
|
||||
Fail lang("ja"): <root xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="ja"><match/></root>
|
||||
Pass lang("ja"): <root xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="ja-jp"><unmatch xmlns:ns2="http://www.w3.org/XML/1998/namespace" ns2:lang="ja_JP"/></root>
|
||||
Pass lang("ko"): <root><unmatch xmlns:ns1="http://www.w3.org/XML/1998/namespace" ns1:lang="Ko"/></root>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 2 tests
|
||||
|
||||
1 Pass
|
||||
1 Fail
|
||||
Pass normalize-space() without arguments
|
||||
Fail normalize-space() should handle only #x20, #x9, #xD, and #xA
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass starts-with() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass substring-after() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass substring-before() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass substring() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass translate() arguments depending on the context node
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 2 tests
|
||||
|
||||
2 Pass
|
||||
Pass Literal: Only ' and " should be handled as literal quotes.
|
||||
Pass ExprWhitespace: Only #x20 #x9 #xD or #xA must be handled as a whitespace.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass | operator should evaluate both sides of expressions with the same context node
|
||||
10
Tests/LibWeb/Text/expected/wpt-import/domxpath/numbers.txt
Normal file
10
Tests/LibWeb/Text/expected/wpt-import/domxpath/numbers.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 5 tests
|
||||
|
||||
5 Pass
|
||||
Pass "+" operator depending on the context node
|
||||
Pass "-" operator depending on the context node
|
||||
Pass "*" operator depending on the context node
|
||||
Pass "div" operator depending on the context node
|
||||
Pass "mod" operator depending on the context node
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass An expression in a predicate should not change the context node
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 5 tests
|
||||
|
||||
5 Fail
|
||||
Fail XPathNSResolver is cross-realm plain object without 'lookupNamespaceURI' property
|
||||
Fail XPathNSResolver is cross-realm plain object with non-callable 'lookupNamespaceURI' property
|
||||
Fail XPathNSResolver is cross-realm non-callable revoked Proxy
|
||||
Fail XPathNSResolver is cross-realm callable revoked Proxy
|
||||
Fail XPathNSResolver is cross-realm plain object with revoked Proxy as 'lookupNamespaceURI' property
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 10 tests
|
||||
|
||||
10 Fail
|
||||
Fail callable resolver
|
||||
Fail callable resolver: result is not cached
|
||||
Fail callable resolver: abrupt completion from Call
|
||||
Fail callable resolver: no 'lookupNamespaceURI' lookups
|
||||
Fail object resolver
|
||||
Fail object resolver: this value and `prefix` argument
|
||||
Fail object resolver: 'lookupNamespaceURI' is not cached
|
||||
Fail object resolver: abrupt completion from Get
|
||||
Fail object resolver: 'lookupNamespaceURI' is thruthy and not callable
|
||||
Fail object resolver: 'lookupNamespaceURI' is falsy and not callable
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 6 tests
|
||||
|
||||
6 Fail
|
||||
Fail undefined
|
||||
Fail null
|
||||
Fail number
|
||||
Fail boolean
|
||||
Fail symbol
|
||||
Fail object coercion (abrupt completion)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 7 tests
|
||||
|
||||
3 Pass
|
||||
4 Fail
|
||||
Pass Using an ordered iterator without modifying the dom should yield the expected elements in correct order without errors.
|
||||
Pass Using an unordered iterator without modifying the dom should yield the correct number of elements without errors.
|
||||
Pass invalidIteratorState should be false for non-iterable results.
|
||||
Fail Calling iterateNext on a non-iterable XPathResult should throw a TypeError.
|
||||
Fail Calling iterateNext on a non-iterable XPathResult after modifying the DOM should throw a TypeError.
|
||||
Fail Calling iterateNext after having modified the DOM should throw an exception.
|
||||
Fail Calling iterateNext after having modified the DOM should throw an exception even if the iterator is exhausted.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 15 tests
|
||||
|
||||
10 Pass
|
||||
5 Fail
|
||||
Pass Select html element based on attribute
|
||||
Fail Select html element based on attribute mixed case
|
||||
Pass Select both HTML and SVG elements based on attribute
|
||||
Pass Select HTML element with non-ascii attribute 1
|
||||
Pass Select HTML element with non-ascii attribute 2
|
||||
Fail Select HTML element with non-ascii attribute 3
|
||||
Pass Select SVG element based on mixed case attribute
|
||||
Fail Select both HTML and SVG elements based on mixed case attribute
|
||||
Pass Select SVG elements with refX attribute
|
||||
Pass Select SVG elements with refX attribute incorrect case
|
||||
Pass Select SVG elements with refX attribute lowercase
|
||||
Pass Select SVG element with non-ascii attribute 1
|
||||
Pass Select SVG element with non-ascii attribute 2
|
||||
Fail xmlns attribute
|
||||
Fail svg element with XLink attribute
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 11 tests
|
||||
|
||||
4 Pass
|
||||
7 Fail
|
||||
Pass HTML elements no namespace prefix
|
||||
Fail HTML elements namespace prefix
|
||||
Fail HTML elements mixed use of prefix
|
||||
Fail SVG elements no namespace prefix
|
||||
Fail SVG elements namespace prefix
|
||||
Fail HTML elements mixed case
|
||||
Pass SVG elements mixed case selector
|
||||
Pass Non-ascii HTML element
|
||||
Pass Non-ascii HTML element2
|
||||
Fail Non-ascii HTML element3
|
||||
Fail Throw with invalid prefix
|
||||
1029
Tests/LibWeb/Text/expected/wpt-import/domxpath/xml_xpath_runner.txt
Normal file
1029
Tests/LibWeb/Text/expected/wpt-import/domxpath/xml_xpath_runner.txt
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,9 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 4 tests
|
||||
|
||||
4 Pass
|
||||
Pass createNSResolver() should return the specified node as is. (HTMLDocument)
|
||||
Pass createNSResolver() resultant object should not add support of 'xml' prefix. (HTMLDocument)
|
||||
Pass createNSResolver() should return the specified node as is. (XPathEvaluator)
|
||||
Pass createNSResolver() resultant object should not add support of 'xml' prefix. (XPathEvaluator)
|
||||
52
Tests/LibWeb/Text/input/wpt-import/domxpath/booleans.html
Normal file
52
Tests/LibWeb/Text/input/wpt-import/domxpath/booleans.html
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#booleans">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_true(evaluateBoolean('(./span)[4] or ./br[2]', context));
|
||||
}, '"or" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_true(evaluateBoolean('count((./span)[3]) = count(./br[2])', context));
|
||||
}, '"=" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_false(evaluateBoolean('count((./span)[3]) != count(./br[2])', context));
|
||||
}, '"!=" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_true(evaluateBoolean('count((./span)[3]) < count(./br)', context));
|
||||
}, '"<" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_false(evaluateBoolean('count((./span)[3]) > count(./br[2])', context));
|
||||
}, '">" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_false(evaluateBoolean('count((./span)[3]) >= count(./br)', context));
|
||||
}, '">=" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_true(evaluateBoolean('count((./span)[3]) <= count(./br[2])', context));
|
||||
}, '"<=" operator depending on the context node');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<title>XPath parent of documentElement</title>
|
||||
<script src='../resources/testharness.js'></script>
|
||||
<script src='../resources/testharnessreport.js'></script>
|
||||
<body>
|
||||
<script>
|
||||
test(function() {
|
||||
var result = document.evaluate("..", // expression
|
||||
document.documentElement, // context node
|
||||
null, // resolver
|
||||
XPathResult.ANY_TYPE, // type
|
||||
null); // result
|
||||
var matched = [];
|
||||
var cur;
|
||||
while ((cur = result.iterateNext()) !== null) {
|
||||
matched.push(cur);
|
||||
}
|
||||
assert_array_equals(matched, [document]);
|
||||
// Evaluate again, but reuse result from previous evaluation.
|
||||
result = document.evaluate("..", // expression
|
||||
document.documentElement, // context node
|
||||
null, // resolver
|
||||
XPathResult.ANY_TYPE, // type
|
||||
result); // result
|
||||
matched = [];
|
||||
while ((cur = result.iterateNext()) !== null) {
|
||||
matched.push(cur);
|
||||
}
|
||||
assert_array_equals(matched, [document]);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>XPathEvaluator constructor</title>
|
||||
<link rel=help href="http://wiki.whatwg.org/wiki/DOM_XPath">
|
||||
<script src=../resources/testharness.js></script>
|
||||
<script src=../resources/testharnessreport.js></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var x = new XPathEvaluator();
|
||||
assert_true(x instanceof XPathEvaluator);
|
||||
}, "Constructor with 'new'");
|
||||
test(function() {
|
||||
assert_throws_js(TypeError, "var x = XPathEvaluator()");
|
||||
}, "Constructor without 'new'");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cross-realm XPath evaluator</title>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
function toArray(result) {
|
||||
var a = [];
|
||||
while (true) {
|
||||
var node = result.iterateNext();
|
||||
if (node === null) break;
|
||||
a.push(node);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
var html_ns = "http://www.w3.org/1999/xhtml";
|
||||
var xml_doc = document.implementation.createDocument(html_ns, "html");
|
||||
var html_doc = document.implementation.createHTMLDocument();
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/dummy.xml";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_evaluator = new iframe.contentWindow.XPathEvaluator();
|
||||
assert_array_equals(toArray(iframe_evaluator.evaluate("//html", xml_doc)), []);
|
||||
}, "evaluator from realm with XML associated document, context node in XML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/dummy.xml";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_evaluator = new iframe.contentWindow.XPathEvaluator();
|
||||
assert_array_equals(toArray(iframe_evaluator.evaluate("//html", html_doc)), [html_doc.documentElement]);
|
||||
}, "evaluator from realm with XML associated document, context node in HTML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/blank.html";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_evaluator = new iframe.contentWindow.XPathEvaluator();
|
||||
assert_array_equals(toArray(iframe_evaluator.evaluate("//html", xml_doc)), []);
|
||||
}, "evaluator from realm with HTML associated document, context node in XML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/blank.html";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_evaluator = new iframe.contentWindow.XPathEvaluator();
|
||||
assert_array_equals(toArray(iframe_evaluator.evaluate("//html", html_doc)), [html_doc.documentElement]);
|
||||
}, "evaluator from realm with HTML associated document, context node in HTML document, no namespace resolver");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cross-document XPath evaluation</title>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
function toArray(result) {
|
||||
var a = [];
|
||||
while (true) {
|
||||
var node = result.iterateNext();
|
||||
if (node === null) break;
|
||||
a.push(node);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
var html_ns = "http://www.w3.org/1999/xhtml";
|
||||
var xml_doc = document.implementation.createDocument(html_ns, "html");
|
||||
var html_doc = document.implementation.createHTMLDocument();
|
||||
|
||||
function ns_resolver(x) {
|
||||
if (x === "html") {
|
||||
return html_ns;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(xml_doc.evaluate("//html", xml_doc)), []);
|
||||
}, "evaluate operation on XML document, context node in XML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(html_doc.evaluate("//html", html_doc)), [html_doc.documentElement]);
|
||||
}, "evaluate operation on HTML document, context node in HTML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(xml_doc.evaluate("//html", html_doc)), [html_doc.documentElement]);
|
||||
}, "evaluate operation on XML document, context node in HTML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(html_doc.evaluate("//html", xml_doc)), []);
|
||||
}, "evaluate operation on HTML document, context node in XML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(xml_doc.evaluate("//html", xml_doc, ns_resolver)), []);
|
||||
}, "evaluate operation on XML document, context node in XML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(html_doc.evaluate("//html", html_doc, ns_resolver)), [html_doc.documentElement]);
|
||||
}, "evaluate operation on HTML document, context node in HTML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(xml_doc.evaluate("//html", html_doc, ns_resolver)), [html_doc.documentElement]);
|
||||
}, "evaluate operation on XML document, context node in HTML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
assert_array_equals(toArray(html_doc.evaluate("//html", xml_doc, ns_resolver)), []);
|
||||
}, "evaluate operation on HTML document, context node in XML document, with namespace resolver");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cross-realm XPath evaluator</title>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
function toArray(result) {
|
||||
var a = [];
|
||||
while (true) {
|
||||
var node = result.iterateNext();
|
||||
if (node === null) break;
|
||||
a.push(node);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
var html_ns = "http://www.w3.org/1999/xhtml";
|
||||
var xml_doc = document.implementation.createDocument(html_ns, "html");
|
||||
var html_doc = document.implementation.createHTMLDocument();
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/dummy.xml";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_expression = iframe.contentDocument.createExpression("//html");
|
||||
assert_array_equals(toArray(iframe_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from realm with XML associated document, context node in XML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/dummy.xml";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_expression = iframe.contentDocument.createExpression("//html");
|
||||
assert_array_equals(toArray(iframe_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from realm with XML associated document, context node in HTML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/blank.html";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_expression = iframe.contentDocument.createExpression("//html");
|
||||
assert_array_equals(toArray(iframe_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from realm with HTML associated document, context node in XML document, no namespace resolver");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "/common/blank.html";
|
||||
document.body.appendChild(iframe);
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, {once: true});
|
||||
});
|
||||
t.add_cleanup(() => iframe.remove());
|
||||
const iframe_expression = iframe.contentDocument.createExpression("//html");
|
||||
assert_array_equals(toArray(iframe_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from realm with HTML associated document, context node in HTML document, no namespace resolver");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cross-document XPath expressions</title>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
function toArray(result) {
|
||||
var a = [];
|
||||
while (true) {
|
||||
var node = result.iterateNext();
|
||||
if (node === null) break;
|
||||
a.push(node);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
var html_ns = "http://www.w3.org/1999/xhtml";
|
||||
var xml_doc = document.implementation.createDocument(html_ns, "html");
|
||||
var html_doc = document.implementation.createHTMLDocument();
|
||||
|
||||
function ns_resolver(x) {
|
||||
if (x === "html") {
|
||||
return html_ns;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
test(function() {
|
||||
var xml_doc_expression = xml_doc.createExpression("//html");
|
||||
assert_array_equals(toArray(xml_doc_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from XML document, context node in XML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var html_doc_expression = html_doc.createExpression("//html");
|
||||
assert_array_equals(toArray(html_doc_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from HTML document, context node in HTML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var xml_doc_expression = xml_doc.createExpression("//html");
|
||||
assert_array_equals(toArray(xml_doc_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from XML document, context node in HTML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var html_doc_expression = html_doc.createExpression("//html");
|
||||
assert_array_equals(toArray(html_doc_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from HTML document, context node in XML document, no namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var xml_doc_expression = xml_doc.createExpression("//html", ns_resolver);
|
||||
assert_array_equals(toArray(xml_doc_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from XML document, context node in XML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var html_doc_expression = html_doc.createExpression("//html", ns_resolver);
|
||||
assert_array_equals(toArray(html_doc_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from HTML document, context node in HTML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var xml_doc_expression = xml_doc.createExpression("//html", ns_resolver);
|
||||
assert_array_equals(toArray(xml_doc_expression.evaluate(html_doc)), [html_doc.documentElement]);
|
||||
}, "expression from XML document, context node in HTML document, with namespace resolver");
|
||||
|
||||
test(function() {
|
||||
var html_doc_expression = html_doc.createExpression("//html", ns_resolver);
|
||||
assert_array_equals(toArray(html_doc_expression.evaluate(xml_doc)), []);
|
||||
}, "expression from HTML document, context node in XML document, with namespace resolver");
|
||||
</script>
|
||||
15
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-concat.html
Normal file
15
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-concat.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-concat">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>foo</span><span>bar</span><b>ber</b>';
|
||||
assert_equals(evaluateString('concat((./span)[2], ./b)', context), 'barber');
|
||||
}, 'concat() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
15
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-contains.html
Normal file
15
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-contains.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-contains">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>bar bar</span><span>bar<b>ber</b></span><b>bar</b>';
|
||||
assert_true(evaluateBoolean('contains((./span)[1], ./b)', context));
|
||||
}, 'contains() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
47
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-id.html
Normal file
47
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-id.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-id">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
// Test the id() function with various scenarios
|
||||
function testIdFunction(expression, xmlString, expectedIds) {
|
||||
let doc = (new DOMParser()).parseFromString(xmlString, 'text/xml');
|
||||
test(() => {
|
||||
let result = doc.evaluate(expression, doc.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||
assert_equals(result.resultType, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
|
||||
let actualIds = [];
|
||||
for (let i = 0; i < result.snapshotLength; i++) {
|
||||
actualIds.push(result.snapshotItem(i).getAttribute('id'));
|
||||
}
|
||||
actualIds.sort();
|
||||
expectedIds.sort();
|
||||
assert_array_equals(actualIds, expectedIds, `Expected IDs ${expectedIds}, got ${actualIds}`);
|
||||
}, `${expression}: ${doc.documentElement.outerHTML}`);
|
||||
}
|
||||
|
||||
// Test single ID
|
||||
testIdFunction('id("test1")', '<root><div id="test1">Match</div></root>', ['test1']);
|
||||
|
||||
// Test multiple IDs in space-separated string
|
||||
testIdFunction('id("test1 test2")', '<root><div id="test1">First</div><div id="test2">Second</div></root>', ['test1', 'test2']);
|
||||
|
||||
// Test non-existent ID
|
||||
testIdFunction('id("nonexistent")', '<root><div id="test1">No match</div></root>', []);
|
||||
|
||||
// Test mixed case IDs (should be case-sensitive)
|
||||
testIdFunction('id("Test1")', '<root><div id="test1">No match</div></root>', []);
|
||||
|
||||
// Test multiple elements with same ID (should return all)
|
||||
testIdFunction('id("duplicate")', '<root><div id="duplicate">First</div><div id="duplicate">Second</div></root>', ['duplicate', 'duplicate']);
|
||||
|
||||
// Test IDs with special characters
|
||||
testIdFunction('id("test-1")', '<root><div id="test-1">Match</div></root>', ['test-1']);
|
||||
|
||||
// Test empty ID string
|
||||
testIdFunction('id("")', '<root><div id="">Empty ID</div></root>', []);
|
||||
|
||||
// Test whitespace in ID string
|
||||
testIdFunction('id(" test1 ")', '<root><div id="test1">Match</div></root>', ['test1']);
|
||||
</script>
|
||||
</body>
|
||||
40
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-lang.html
Normal file
40
Tests/LibWeb/Text/input/wpt-import/domxpath/fn-lang.html
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-lang">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
// Set the context node to the first child of the root element, and evaluate
|
||||
// the specified XPath expression. The test passes if
|
||||
// - The first child element name is 'match' and XPath result is true, or
|
||||
// - The first child element name is not 'match' and XPath result is false.
|
||||
function testFirstChild(expression, xmlString) {
|
||||
let doc = (new DOMParser()).parseFromString(xmlString, 'text/xml');
|
||||
test(() => {
|
||||
let element = doc.documentElement.firstChild;
|
||||
let result = doc.evaluate(expression, element, null, XPathResult.BOOLEAN_TYPE, null);
|
||||
assert_equals(result.resultType, XPathResult.BOOLEAN_TYPE);
|
||||
assert_equals(result.booleanValue, element.localName == 'match', element.outerHTML);
|
||||
}, `${expression}: ${doc.documentElement.outerHTML}`);
|
||||
}
|
||||
|
||||
testFirstChild('lang("en")', '<root><match xml:lang="en"/></root>');
|
||||
testFirstChild('lang("en")', '<root><match xml:lang="EN"/></root>');
|
||||
testFirstChild('lang("en")', '<root><match xml:lang="en-us"/></root>');
|
||||
testFirstChild('lang("en")', '<root><unmatch/></root>');
|
||||
|
||||
// XPath 1.0 says:
|
||||
// if the context node has no xml:lang attribute, by the value of the
|
||||
// xml:lang attribute on the nearest ancestor of the context node that has
|
||||
// an xml:lang attribute.
|
||||
testFirstChild('lang("ja")', '<root xml:lang="ja"><match/></root>');
|
||||
|
||||
// XPath 1.0 says:
|
||||
// if there is some suffix starting with - such that the attribute value is
|
||||
// equal to the argument ignoring that suffix of the attribute value
|
||||
testFirstChild('lang("ja")', '<root xml:lang="ja-jp"><unmatch xml:lang="ja_JP"/></root>');
|
||||
|
||||
// XPath 3.1 is not to be followed as per: https://github.com/whatwg/dom/issues/1199
|
||||
testFirstChild('lang("ko")', '<root><unmatch xml:lang="Ko"/></root>');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-normalize-space">
|
||||
<link rel="help" href="https://www.w3.org/TR/xpath-functions-31/#func-normalize-space">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<div id="target"> a <br> b</div>
|
||||
<script>
|
||||
function normalizeSpace(exp) {
|
||||
return document.evaluate(`normalize-space("${exp}")`, document).stringValue;
|
||||
}
|
||||
|
||||
test(() => {
|
||||
assert_equals(document.evaluate('normalize-space()', document.querySelector('#target')).stringValue, 'a b');
|
||||
}, 'normalize-space() without arguments');
|
||||
|
||||
test(() => {
|
||||
assert_equals(normalizeSpace(' a \t b\r\nc '), 'a b c');
|
||||
|
||||
assert_equals(normalizeSpace('y\x0B\x0C\x0E\x0Fz'), 'y\x0b\x0c\x0e\x0fz');
|
||||
assert_equals(normalizeSpace('\xA0 \u3000'), '\xA0 \u3000');
|
||||
}, 'normalize-space() should handle only #x20, #x9, #xD, and #xA');
|
||||
</script>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-starts-with">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>foo</span><span>bar<b>ber</b></span><b>bar</b>';
|
||||
assert_true(evaluateBoolean('starts-with((./span)[2], ./b)', context));
|
||||
}, 'starts-with() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring-after">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>^^^bar$$$</span><span>bar<b>^</b></span><b>bar</b>';
|
||||
assert_equals(evaluateString('substring-after((./span)[1], ./b)', context), '$$$');
|
||||
}, 'substring-after() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring-before">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>^^^bar$$$</span><span>bar<b>$</b></span><b>bar</b>';
|
||||
assert_equals(evaluateString('substring-before((./span)[1], ./b)', context), '^^^');
|
||||
}, 'substring-before() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>^^^bar$$$</span><span></span><br><br><br><br>';
|
||||
assert_equals(evaluateString('substring((./span)[1], count(./br))', context), 'bar$$$');
|
||||
}, 'substring() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-translate">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<body>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span>^^^bar$$$</span><span><b>^^^</b></span><b>bar</b><b>foo</b>';
|
||||
assert_equals(evaluateString('translate((./span)[1], (./b)[1], ./b[2])', context), '^^^foo$$$');
|
||||
}, 'translate() arguments depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
14
Tests/LibWeb/Text/input/wpt-import/domxpath/helpers.js
Normal file
14
Tests/LibWeb/Text/input/wpt-import/domxpath/helpers.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
function evaluateBoolean(expression, context) {
|
||||
let doc = context.ownerDocument || context;
|
||||
return doc.evaluate(expression, context, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;
|
||||
}
|
||||
|
||||
function evaluateNumber(expression, context) {
|
||||
let doc = context.ownerDocument || context;
|
||||
return doc.evaluate(expression, context, null, XPathResult.NUMBER_TYPE, null).numberValue;
|
||||
}
|
||||
|
||||
function evaluateString(expression, context) {
|
||||
let doc = context.ownerDocument || context;
|
||||
return doc.evaluate(expression, context, null, XPathResult.STRING_TYPE, null).stringValue;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#exprlex">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
function parse(expression) {
|
||||
document.evaluate(expression, document, null, XPathResult.ANY_TYPE, null);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-Literal
|
||||
test(() => {
|
||||
parse(' \'a"bc\' ');
|
||||
parse(' "a\'bc" ');
|
||||
|
||||
assert_throws_dom('SyntaxError', () => { parse(' \u2019xyz\u2019 '); });
|
||||
}, 'Literal: Only \' and " should be handled as literal quotes.');
|
||||
|
||||
// https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-ExprWhitespace
|
||||
test(() => {
|
||||
parse(' \t\r\n.\r\n\t ');
|
||||
|
||||
assert_throws_dom('SyntaxError', () => { parse('\x0B\x0C .'); });
|
||||
assert_throws_dom('SyntaxError', () => { parse('\x0E\x0F .'); });
|
||||
assert_throws_dom('SyntaxError', () => { parse('\u3000 .'); });
|
||||
assert_throws_dom('SyntaxError', () => { parse('\u2029 .'); });
|
||||
}, 'ExprWhitespace: Only #x20 #x9 #xD or #xA must be handled as a whitespace.');
|
||||
</script>
|
||||
</body>
|
||||
24
Tests/LibWeb/Text/input/wpt-import/domxpath/node-sets.html
Normal file
24
Tests/LibWeb/Text/input/wpt-import/domxpath/node-sets.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#node-sets">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
function nodesetToSet(result) {
|
||||
const set = new Set();
|
||||
for (let node = result.iterateNext(); node; node = result.iterateNext()) {
|
||||
set.add(node);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
test(() => {
|
||||
const doc = document.implementation.createHTMLDocument();
|
||||
doc.documentElement.innerHTML = '<body><div></div></body>';
|
||||
const result = nodesetToSet(doc.evaluate('(.//div)[1]|.', doc.documentElement));
|
||||
assert_equals(result.size, 2);
|
||||
assert_true(result.has(doc.documentElement));
|
||||
assert_true(result.has(doc.body.firstChild));
|
||||
}, '| operator should evaluate both sides of expressions with the same context node');
|
||||
</script>
|
||||
</body>
|
||||
39
Tests/LibWeb/Text/input/wpt-import/domxpath/numbers.html
Normal file
39
Tests/LibWeb/Text/input/wpt-import/domxpath/numbers.html
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#numbers">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<div id="context"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_equals(evaluateNumber('count((./span)[1]) + count(./br)', context), 3);
|
||||
}, '"+" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_equals(evaluateNumber('count((./span)[1]) - count(./br)', context), -1);
|
||||
}, '"-" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_equals(evaluateNumber('count((./span)[1]) * count(./br)', context), 2);
|
||||
}, '"*" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_equals(evaluateNumber('count((./span)[1]) div count(./br)', context), 0.5);
|
||||
}, '"div" operator depending on the context node');
|
||||
|
||||
test(() => {
|
||||
const context = document.querySelector('#context');
|
||||
context.innerHTML = '<span></span><span></span><span></span><br><br>';
|
||||
assert_equals(evaluateNumber('count((./span)[1]) mod count(./br)', context), 1);
|
||||
}, '"mod" operator depending on the context node');
|
||||
</script>
|
||||
</body>
|
||||
25
Tests/LibWeb/Text/input/wpt-import/domxpath/predicates.html
Normal file
25
Tests/LibWeb/Text/input/wpt-import/domxpath/predicates.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#predicates">
|
||||
<body>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
function nodesetToSet(result) {
|
||||
const set = new Set();
|
||||
for (let node = result.iterateNext(); node; node = result.iterateNext()) {
|
||||
set.add(node);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
test(() => {
|
||||
const doc = document.implementation.createHTMLDocument();
|
||||
doc.body.innerHTML = '<table></table>' +
|
||||
'<table><tr><th><th><th><th></table>' +
|
||||
'<table></table>';
|
||||
const result = nodesetToSet(doc.evaluate('(//table)[count((//table)[2]/descendant::th)-1]', doc.documentElement));
|
||||
assert_equals(result.size, 1);
|
||||
assert_true(result.has(doc.body.lastChild));
|
||||
}, 'An expression in a predicate should not change the context node');
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cross-realm XPathNSResolver throws TypeError of its associated Realm</title>
|
||||
<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
|
||||
<iframe name="evaluateGlobalObject" src="resources/empty-document.html"></iframe>
|
||||
<iframe name="resolverGlobalObject" src="resources/empty-document.html"></iframe>
|
||||
<iframe name="lookupNamespaceURIGlobalObject" src="resources/empty-document.html"></iframe>
|
||||
<iframe name="relevantGlobalObject" src="resources/empty-document.html"></iframe>
|
||||
<iframe name="incumbentGlobalObject" src="resources/empty-document.html"></iframe>
|
||||
|
||||
<script>
|
||||
setup({ allow_uncaught_exception: true });
|
||||
|
||||
const expectedDOMExceptionType = "NAMESPACE_ERR";
|
||||
|
||||
test_onload(() => {
|
||||
const resolver = new resolverGlobalObject.Object;
|
||||
|
||||
assert_reports_exception(() => {
|
||||
assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver));
|
||||
});
|
||||
}, "XPathNSResolver is cross-realm plain object without 'lookupNamespaceURI' property");
|
||||
|
||||
test_onload(() => {
|
||||
const resolver = new resolverGlobalObject.Object;
|
||||
resolver.lookupNamespaceURI = new lookupNamespaceURIGlobalObject.Object;
|
||||
|
||||
assert_reports_exception(() => {
|
||||
assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver));
|
||||
});
|
||||
}, "XPathNSResolver is cross-realm plain object with non-callable 'lookupNamespaceURI' property");
|
||||
|
||||
test_onload(() => {
|
||||
const { proxy, revoke } = resolverGlobalObject.Proxy.revocable(new resolverGlobalObject.Object, {});
|
||||
revoke();
|
||||
|
||||
assert_reports_exception(() => {
|
||||
assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(proxy));
|
||||
});
|
||||
}, "XPathNSResolver is cross-realm non-callable revoked Proxy");
|
||||
|
||||
test_onload(() => {
|
||||
const { proxy, revoke } = resolverGlobalObject.Proxy.revocable(new resolverGlobalObject.Function, {});
|
||||
revoke();
|
||||
|
||||
assert_reports_exception(() => {
|
||||
assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(proxy));
|
||||
});
|
||||
}, "XPathNSResolver is cross-realm callable revoked Proxy");
|
||||
|
||||
test_onload(() => {
|
||||
const { proxy, revoke } = lookupNamespaceURIGlobalObject.Proxy.revocable(new lookupNamespaceURIGlobalObject.Function, {});
|
||||
revoke();
|
||||
|
||||
const resolver = new resolverGlobalObject.Object;
|
||||
resolver.lookupNamespaceURI = proxy;
|
||||
|
||||
assert_reports_exception(() => {
|
||||
assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver));
|
||||
});
|
||||
}, "XPathNSResolver is cross-realm plain object with revoked Proxy as 'lookupNamespaceURI' property");
|
||||
|
||||
function test_onload(fn, desc) {
|
||||
async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc);
|
||||
}
|
||||
|
||||
function assert_reports_exception(fn) {
|
||||
let error;
|
||||
const onErrorHandler = event => {
|
||||
error = event.error;
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
resolverGlobalObject.addEventListener("error", onErrorHandler);
|
||||
fn();
|
||||
resolverGlobalObject.removeEventListener("error", onErrorHandler);
|
||||
|
||||
assert_equals(typeof error, "object");
|
||||
assert_equals(error.constructor, evaluateGlobalObject.TypeError);
|
||||
}
|
||||
|
||||
function bind_evaluate(resolver) {
|
||||
const boundEvaluate = new incumbentGlobalObject.Function("evaluate", "relevantDocument", "resolver", `
|
||||
evaluate.call(relevantDocument, "/foo:bar", relevantDocument.documentElement, resolver);
|
||||
`);
|
||||
|
||||
return () => {
|
||||
boundEvaluate(evaluateGlobalObject.document.evaluate, relevantGlobalObject.document, resolver);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>XPathNSResolver implements callback interface</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator">
|
||||
<link rel="help" href="https://webidl.spec.whatwg.org/#call-a-user-objects-operation">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="resources/invalid_namespace_test.js"></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
test(() => {
|
||||
let resolverCalls = 0;
|
||||
document.evaluate("/foo:bar", document.documentElement, () => {
|
||||
resolverCalls++;
|
||||
return "";
|
||||
});
|
||||
|
||||
assert_equals(resolverCalls, 1);
|
||||
}, "callable resolver");
|
||||
|
||||
test(() => {
|
||||
let resolverCalls = 0;
|
||||
const resolver = () => {
|
||||
resolverCalls++;
|
||||
return "";
|
||||
};
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
|
||||
assert_equals(resolverCalls, 2);
|
||||
}, "callable resolver: result is not cached");
|
||||
|
||||
promise_test(t => {
|
||||
const testError = { name: "test" };
|
||||
const resolver = () => {
|
||||
throw testError;
|
||||
};
|
||||
|
||||
return promise_rejects_exactly(t, testError,
|
||||
invalid_namespace_test(t, resolver)
|
||||
);
|
||||
}, "callable resolver: abrupt completion from Call");
|
||||
|
||||
test(() => {
|
||||
let resolverCalls = 0;
|
||||
const resolver = () => {
|
||||
resolverCalls++;
|
||||
return "";
|
||||
};
|
||||
|
||||
let resolverGets = 0;
|
||||
Object.defineProperty(resolver, "lookupNamespaceURI", {
|
||||
get() {
|
||||
resolverGets++;
|
||||
},
|
||||
});
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
|
||||
assert_equals(resolverCalls, 1);
|
||||
assert_equals(resolverGets, 0);
|
||||
}, "callable resolver: no 'lookupNamespaceURI' lookups");
|
||||
|
||||
test(() => {
|
||||
let resolverCalls = 0;
|
||||
document.evaluate("/foo:bar", document.documentElement, {
|
||||
lookupNamespaceURI() {
|
||||
resolverCalls++;
|
||||
return "";
|
||||
},
|
||||
});
|
||||
|
||||
assert_equals(resolverCalls, 1);
|
||||
}, "object resolver");
|
||||
|
||||
test(() => {
|
||||
let thisValue, prefixArg;
|
||||
const resolver = {
|
||||
lookupNamespaceURI(prefix) {
|
||||
thisValue = this;
|
||||
prefixArg = prefix;
|
||||
return "";
|
||||
},
|
||||
};
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
|
||||
assert_equals(thisValue, resolver);
|
||||
assert_equals(prefixArg, "foo");
|
||||
}, "object resolver: this value and `prefix` argument");
|
||||
|
||||
test(() => {
|
||||
let resolverCalls = 0;
|
||||
const lookupNamespaceURI = () => {
|
||||
resolverCalls++;
|
||||
return "";
|
||||
};
|
||||
|
||||
let resolverGets = 0;
|
||||
const resolver = {
|
||||
get lookupNamespaceURI() {
|
||||
resolverGets++;
|
||||
return lookupNamespaceURI;
|
||||
},
|
||||
};
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
|
||||
assert_equals(resolverCalls, 2);
|
||||
assert_equals(resolverGets, 2);
|
||||
}, "object resolver: 'lookupNamespaceURI' is not cached");
|
||||
|
||||
promise_test(t => {
|
||||
const testError = { name: "test" };
|
||||
const resolver = {
|
||||
get lookupNamespaceURI() {
|
||||
throw testError;
|
||||
},
|
||||
};
|
||||
|
||||
return promise_rejects_exactly(t, testError,
|
||||
invalid_namespace_test(t, resolver)
|
||||
);
|
||||
}, "object resolver: abrupt completion from Get");
|
||||
|
||||
promise_test(t => {
|
||||
const resolver = {
|
||||
lookupNamespaceURI: {},
|
||||
};
|
||||
|
||||
return promise_rejects_js(t, TypeError,
|
||||
invalid_namespace_test(t, resolver)
|
||||
);
|
||||
}, "object resolver: 'lookupNamespaceURI' is thruthy and not callable");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError,
|
||||
invalid_namespace_test(t, {})
|
||||
);
|
||||
}, "object resolver: 'lookupNamespaceURI' is falsy and not callable");
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>XPathNSResolver non-string return value</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="resources/invalid_namespace_test.js"></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
promise_test(t => {
|
||||
return invalid_namespace_test(t, () => undefined);
|
||||
}, "undefined");
|
||||
|
||||
promise_test(t => {
|
||||
return invalid_namespace_test(t, () => null);
|
||||
}, "null");
|
||||
|
||||
test(t => {
|
||||
let resolverCalls = 0;
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, () => {
|
||||
resolverCalls++;
|
||||
return 0;
|
||||
});
|
||||
|
||||
assert_equals(resolverCalls, 1);
|
||||
}, "number");
|
||||
|
||||
test(t => {
|
||||
let resolverCalls = 0;
|
||||
|
||||
document.evaluate("/foo:bar", document.documentElement, () => {
|
||||
resolverCalls++;
|
||||
return false;
|
||||
});
|
||||
|
||||
assert_equals(resolverCalls, 1);
|
||||
}, "boolean");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError,
|
||||
invalid_namespace_test(t, () => Symbol())
|
||||
);
|
||||
}, "symbol");
|
||||
|
||||
promise_test(t => {
|
||||
const testError = { name: "test" };
|
||||
const resolverResult = {
|
||||
toString: () => { throw testError; },
|
||||
valueOf: t.unreached_func("`valueOf` should not be called."),
|
||||
};
|
||||
|
||||
return promise_rejects_exactly(t, testError,
|
||||
invalid_namespace_test(t, () => resolverResult)
|
||||
);
|
||||
}, "object coercion (abrupt completion)");
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<body>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
setup({ allow_uncaught_exception: true });
|
||||
|
||||
const invalid_namespace_test = (t, resolver, resolverWindow = window) => {
|
||||
const result = new Promise((resolve, reject) => {
|
||||
const handler = event => {
|
||||
reject(event.error);
|
||||
};
|
||||
|
||||
resolverWindow.addEventListener("error", handler);
|
||||
t.add_cleanup(() => {
|
||||
resolverWindow.removeEventListener("error", handler);
|
||||
});
|
||||
|
||||
t.step_timeout(resolve, 0);
|
||||
});
|
||||
|
||||
assert_throws_dom("NAMESPACE_ERR", () => {
|
||||
document.evaluate("/foo:bar", document.documentElement, resolver);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Invalidation of iterators over XPath results</title>
|
||||
<link rel="author" title="Simon Wülker" href="mailto:simon.wuelker@arcor.de">
|
||||
<link rel="help" href="https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult-iterateNext">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<ul id="list">
|
||||
<li id="first-child"></li>
|
||||
<li id="second-child"></li>
|
||||
</ul>
|
||||
<script>
|
||||
function make_xpath_query(result_type) {
|
||||
return document.evaluate(
|
||||
"//li",
|
||||
document,
|
||||
null,
|
||||
result_type,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
function invalidate_iterator(test) {
|
||||
let new_element = document.createElement("li");
|
||||
document.getElementById("list").appendChild(new_element);
|
||||
test.add_cleanup(() => {
|
||||
new_element.remove();
|
||||
})
|
||||
}
|
||||
|
||||
test((t) => {
|
||||
let iterator = make_xpath_query(XPathResult.ORDERED_NODE_ITERATOR_TYPE);
|
||||
|
||||
assert_equals(iterator.iterateNext(), document.getElementById("first-child"));
|
||||
assert_equals(iterator.iterateNext(), document.getElementById("second-child"));
|
||||
assert_equals(iterator.iterateNext(), null);
|
||||
assert_false(iterator.invalidIteratorState);
|
||||
}, "Using an ordered iterator without modifying the dom should yield the expected elements in correct order without errors.");
|
||||
|
||||
test((t) => {
|
||||
let iterator = make_xpath_query(XPathResult.UNORDERED_NODE_ITERATOR_TYPE);
|
||||
|
||||
assert_not_equals(iterator.iterateNext(), null);
|
||||
assert_not_equals(iterator.iterateNext(), null);
|
||||
assert_equals(iterator.iterateNext(), null);
|
||||
assert_false(iterator.invalidIteratorState);
|
||||
}, "Using an unordered iterator without modifying the dom should yield the correct number of elements without errors.");
|
||||
|
||||
test((t) => {
|
||||
let non_iterator_query = make_xpath_query(XPathResult.BOOLEAN_TYPE);
|
||||
|
||||
assert_false(non_iterator_query.invalidIteratorState);
|
||||
invalidate_iterator(t);
|
||||
assert_false(non_iterator_query.invalidIteratorState);
|
||||
}, "invalidIteratorState should be false for non-iterable results.");
|
||||
|
||||
test((t) => {
|
||||
let non_iterator_query = make_xpath_query(XPathResult.BOOLEAN_TYPE);
|
||||
|
||||
assert_throws_js(TypeError, () => non_iterator_query.iterateNext());
|
||||
}, "Calling iterateNext on a non-iterable XPathResult should throw a TypeError.");
|
||||
|
||||
test((t) => {
|
||||
let non_iterator_query = make_xpath_query(XPathResult.BOOLEAN_TYPE);
|
||||
invalidate_iterator(t);
|
||||
assert_throws_js(TypeError, () => non_iterator_query.iterateNext());
|
||||
}, "Calling iterateNext on a non-iterable XPathResult after modifying the DOM should throw a TypeError.");
|
||||
|
||||
test((t) => {
|
||||
let iterator = make_xpath_query(XPathResult.ORDERED_NODE_ITERATOR_TYPE);
|
||||
|
||||
iterator.iterateNext();
|
||||
|
||||
invalidate_iterator(t);
|
||||
|
||||
assert_throws_dom(
|
||||
"InvalidStateError",
|
||||
() => iterator.iterateNext(),
|
||||
);
|
||||
}, "Calling iterateNext after having modified the DOM should throw an exception.");
|
||||
|
||||
test((t) => {
|
||||
let iterator = make_xpath_query(XPathResult.ORDERED_NODE_ITERATOR_TYPE);
|
||||
|
||||
iterator.iterateNext();
|
||||
iterator.iterateNext();
|
||||
|
||||
invalidate_iterator(t);
|
||||
|
||||
assert_throws_dom(
|
||||
"InvalidStateError",
|
||||
() => iterator.iterateNext(),
|
||||
);
|
||||
}, "Calling iterateNext after having modified the DOM should throw an exception even if the iterator is exhausted.");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf8">
|
||||
<title>XPath in text/html: attributes</title>
|
||||
<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<div id="log" nonÄsciiAttribute><span></span></div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path id="a" refx />
|
||||
<path id="b" nonÄscii xlink:href />
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
function test_xpath_succeeds(path, expected, resolver) {
|
||||
resolver = resolver ? resolver : null;
|
||||
var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||
actual = [];
|
||||
for (var i=0;;i++) {
|
||||
var node = res.snapshotItem(i);
|
||||
if (node === null) {
|
||||
break;
|
||||
}
|
||||
actual.push(node);
|
||||
}
|
||||
assert_array_equals(actual, expected);
|
||||
}
|
||||
|
||||
function test_xpath_throws(path, error_code, resolver) {
|
||||
resolver = resolver ? resolver : null;
|
||||
assert_throws_dom(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)})
|
||||
}
|
||||
|
||||
function ns_resolver(x) {
|
||||
map = {"html":"http://www.w3.org/1999/xhtml",
|
||||
"svg":"http://www.w3.org/2000/svg",
|
||||
"math":"http://www.w3.org/1998/Math/MathML",
|
||||
"xlink":"http://www.w3.org/1999/xlink"};
|
||||
var rv = map.hasOwnProperty(x) ? map[x] : null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//div[@id='log']", [document.getElementById("log")]);
|
||||
}, "Select html element based on attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//div[@Id='log']", [document.getElementById("log")]);
|
||||
}, "Select html element based on attribute mixed case");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@id]", [document.getElementById("log")].concat(Array.prototype.slice.call(document.getElementsByTagName("path"))));
|
||||
}, "Select both HTML and SVG elements based on attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@nonÄsciiattribute]", [document.getElementById("log")]);
|
||||
}, "Select HTML element with non-ascii attribute 1");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@nonäsciiattribute]", []);
|
||||
}, "Select HTML element with non-ascii attribute 2");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@nonÄsciiAttribute]", [document.getElementById("log")]);
|
||||
}, "Select HTML element with non-ascii attribute 3");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//svg:path[@Id]", [], ns_resolver);
|
||||
}, "Select SVG element based on mixed case attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@Id]", [document.getElementById("log")]);
|
||||
}, "Select both HTML and SVG elements based on mixed case attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@refX]", [document.getElementById("a")]);
|
||||
}, "Select SVG elements with refX attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@Refx]", []);
|
||||
}, "Select SVG elements with refX attribute incorrect case");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@refx]", []);
|
||||
}, "Select SVG elements with refX attribute lowercase");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@nonÄscii]", [document.getElementById("b")]);
|
||||
}, "Select SVG element with non-ascii attribute 1");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@nonäscii]", []);
|
||||
}, "Select SVG element with non-ascii attribute 2");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@xmlns]", []);
|
||||
}, "xmlns attribute");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//*[@xlink:href]", [document.getElementById("b")], ns_resolver);
|
||||
}, "svg element with XLink attribute");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf8">
|
||||
<title>XPath in text/html: elements</title>
|
||||
<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<div id="log"><span></span></div>
|
||||
<div><span></span></div>
|
||||
<dØdd></dØdd>
|
||||
<svg>
|
||||
<path />
|
||||
<path />
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
function test_xpath_succeeds(path, expected, resolver) {
|
||||
resolver = resolver ? resolver : null;
|
||||
var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||
actual = [];
|
||||
for (var i=0;;i++) {
|
||||
var node = res.snapshotItem(i);
|
||||
if (node === null) {
|
||||
break;
|
||||
}
|
||||
actual.push(node);
|
||||
}
|
||||
assert_array_equals(actual, expected);
|
||||
}
|
||||
|
||||
function test_xpath_throws(path, error_code, resolver) {
|
||||
resolver = resolver ? resolver : null;
|
||||
assert_throws_dom(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)})
|
||||
}
|
||||
|
||||
function ns_resolver(x) {
|
||||
map = {"html":"http://www.w3.org/1999/xhtml",
|
||||
"svg":"http://www.w3.org/2000/svg",
|
||||
"math":"http://www.w3.org/1998/Math/MathML"};
|
||||
var rv = map.hasOwnProperty(x) ? map[x] : null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//div", document.getElementsByTagName("div"));
|
||||
}, "HTML elements no namespace prefix");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//html:div", document.getElementsByTagName("div"), ns_resolver);
|
||||
}, "HTML elements namespace prefix");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//html:div/span", document.getElementsByTagName("span"), ns_resolver);
|
||||
}, "HTML elements mixed use of prefix");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//path", []);
|
||||
}, "SVG elements no namespace prefix");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//svg:path", document.getElementsByTagName("path"), ns_resolver);
|
||||
}, "SVG elements namespace prefix");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//DiV", document.getElementsByTagName("div"));
|
||||
}, "HTML elements mixed case");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//svg:PatH", [], ns_resolver);
|
||||
}, "SVG elements mixed case selector");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//dØdd", document.getElementsByTagName("dØdd"), ns_resolver);
|
||||
}, "Non-ascii HTML element");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//dødd", [], ns_resolver);
|
||||
}, "Non-ascii HTML element2");
|
||||
|
||||
test(function() {
|
||||
test_xpath_succeeds("//DØDD", document.getElementsByTagName("dØdd"), ns_resolver);
|
||||
}, "Non-ascii HTML element3");
|
||||
|
||||
test(function() {
|
||||
test_xpath_throws("//invalid:path", "NAMESPACE_ERR");
|
||||
}, "Throw with invalid prefix");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<!doctype html>
|
||||
<title>XPath tests</title>
|
||||
<meta name="timeout" content="long">
|
||||
<script src='../resources/testharness.js'></script>
|
||||
<script src='../resources/testharnessreport.js'></script>
|
||||
<script>
|
||||
setup({ explicit_done: true });
|
||||
|
||||
function find_child_element(context, element) {
|
||||
for (var i = 0; i < context.childNodes.length; i++) {
|
||||
var child = context.childNodes[i];
|
||||
if (child.nodeType === Node.ELEMENT_NODE && child.tagName === element)
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
function xpath_test(test_el) {
|
||||
/* note this func adopts the tree! */
|
||||
var new_doc = document.implementation.createDocument("", "");
|
||||
var xpath = find_child_element(test_el, "xpath");
|
||||
var result = find_child_element(test_el, "result");
|
||||
var namespace = find_child_element(result, "namespace");
|
||||
var localname = find_child_element(result, "localname");
|
||||
var nth = find_child_element(result, "nth");
|
||||
var tree = find_child_element(test_el, "tree");
|
||||
var actual_tree = new_doc.adoptNode(tree.firstElementChild);
|
||||
new_doc.appendChild(actual_tree);
|
||||
test(function() {
|
||||
var result = new_doc.evaluate(xpath.textContent, // expression
|
||||
actual_tree, // context node
|
||||
new_doc.createNSResolver(actual_tree), // resolver
|
||||
XPathResult.ANY_TYPE, // type
|
||||
null); // result
|
||||
var matched = [];
|
||||
var cur;
|
||||
while ((cur = result.iterateNext()) !== null) {
|
||||
matched.push(cur);
|
||||
}
|
||||
assert_equals(matched.length, 1, "Should match one node");
|
||||
var similar = new_doc.getElementsByTagNameNS(namespace.textContent,
|
||||
localname.textContent);
|
||||
assert_equals(matched[0], similar[nth.textContent]);
|
||||
});
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "xml_xpath_tests.xml");
|
||||
xhr.onload = function(e) {
|
||||
var tests = xhr.responseXML.documentElement;
|
||||
for (var i = 0; i < tests.childNodes.length; i++) {
|
||||
var child = tests.childNodes[i];
|
||||
if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
xpath_test(child);
|
||||
}
|
||||
}
|
||||
done();
|
||||
};
|
||||
xhr.send();
|
||||
</script>
|
||||
34919
Tests/LibWeb/Text/input/wpt-import/domxpath/xml_xpath_tests.xml
Normal file
34919
Tests/LibWeb/Text/input/wpt-import/domxpath/xml_xpath_tests.xml
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<script src='../resources/testharness.js'></script>
|
||||
<script src='../resources/testharnessreport.js'></script>
|
||||
<body>
|
||||
<script>
|
||||
[document, new XPathEvaluator()].forEach(evaluator => {
|
||||
test(() => {
|
||||
assert_equals(evaluator.createNSResolver(document), document, 'Document');
|
||||
const fragment = document.createDocumentFragment();
|
||||
assert_equals(evaluator.createNSResolver(fragment), fragment,
|
||||
'DocumentFragment');
|
||||
assert_equals(evaluator.createNSResolver(document.doctype),
|
||||
document.doctype, 'DocumentType');
|
||||
assert_equals(evaluator.createNSResolver(document.body), document.body,
|
||||
'Element');
|
||||
assert_equals(evaluator.createNSResolver(document.body.firstChild),
|
||||
document.body.firstChild, 'Text');
|
||||
const attr = document.createAttribute('foo');
|
||||
assert_equals(evaluator.createNSResolver(attr), attr, 'Attr');
|
||||
}, `createNSResolver() should return the specified node as is. (${evaluator.constructor.name})`);
|
||||
|
||||
function createAndLookup(evaluator, node) {
|
||||
return evaluator.createNSResolver(node).lookupNamespaceURI('xml');
|
||||
}
|
||||
|
||||
test(() => {
|
||||
assert_equals(createAndLookup(evaluator, new Document()), null, 'Document');
|
||||
assert_equals(createAndLookup(evaluator, new DocumentFragment()), null,
|
||||
'DocumentFragment');
|
||||
assert_equals(createAndLookup(evaluator, document.doctype), null,
|
||||
'DocumentType');
|
||||
assert_equals(createAndLookup(evaluator, document.createElement('body')),
|
||||
'http://www.w3.org/XML/1998/namespace', 'Element');
|
||||
assert_equals(createAndLookup(evaluator, document.createTextNode('foo')),
|
||||
null, 'Text');
|
||||
assert_equals(createAndLookup(evaluator, document.createAttribute('bar')),
|
||||
null, 'Attr');
|
||||
}, `createNSResolver() resultant object should not add support of 'xml' prefix. (${evaluator.constructor.name})`);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
Loading…
Reference in New Issue
Block a user