Bug 751842 part 6 - Import editing spec tests; r=Ms2ger

This commit is contained in:
Aryeh Gregor 2012-05-07 08:54:55 +03:00
parent 7bfb6521ff
commit fa1916b560
35 changed files with 80490 additions and 0 deletions

View File

@ -9,11 +9,14 @@ VPATH = @srcdir@
relativesrcdir = dom/imported-tests
DIRS = \
failures/editing/conformancetest \
failures/editing/selecttest \
failures/webapps/WebStorage/tests/submissions/Ms2ger \
failures/webapps/WebStorage/tests/submissions/Infraware \
failures/webapps/DOMCore/tests/submissions/Opera \
$(NULL)
include $(srcdir)/editing.mk
include $(srcdir)/html.mk
include $(srcdir)/webapps.mk
include $(DEPTH)/config/autoconf.mk

3
dom/imptests/editing.mk Normal file
View File

@ -0,0 +1,3 @@
DIRS += \
editing/ \
$(NULL)

2
dom/imptests/editing.txt Normal file
View File

@ -0,0 +1,2 @@
https://dvcs.w3.org/hg/editing|editing

View File

@ -0,0 +1,28 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing
DIRS = \
css \
conformancetest \
selecttest \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
$(NULL)
_TESTS += \
implementation.js \
tests.js \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,26 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/conformancetest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_runtest.html \
test_event.html \
$(NULL)
_TESTS += \
data.js \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
<!doctype html>
<title>Editing event tests</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id=test></div>
<div id=log></div>
<script>
"use strict";
var div = document.querySelector("#test");
add_completion_callback(function() { div.parentNode.removeChild(div) });
function copyEvent(e) {
var ret = {};
ret.original = e;
["type", "target", "currentTarget", "eventPhase", "bubbles", "cancelable",
"defaultPrevented", "isTrusted", "command", "value"].forEach(function(k) {
ret[k] = e[k];
});
return ret;
}
var tests = [
{
name: "Simple editable div",
html: "<div contenteditable>foo<b>bar</b>baz</div>",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return div.firstChild },
command: "bold",
value: "",
},
{
name: "Editable b",
html: "foo<b contenteditable>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return div.querySelector("b") },
command: "bold",
value: "",
},
{
name: "No editable content",
html: "foo<b>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Partially-selected editable content",
html: "foo<b contenteditable>bar</b>baz",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div, 3);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Selection spans two editing hosts",
html: "<div contenteditable>foo</div><div contenteditable>bar</div>",
initRange: function(range) {
range.setStart(div.querySelector("div").firstChild, 2);
range.setEnd(div.querySelector("div + div").firstChild, 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Selection includes two editing hosts",
html: "foo<div contenteditable>bar</div>baz<div contenteditable>quz</div>qoz",
initRange: function(range) {
range.setStart(div.firstChild, 2);
range.setEnd(div.lastChild, 1);
},
target: function() { return null },
command: "bold",
value: "",
},
{
name: "Changing selection from handler",
html: "<div contenteditable>foo</div><div contenteditable>bar</div>",
initRange: function(range) {
range.setStart(div.querySelector("div").firstChild, 0);
range.setEnd(div.querySelector("div").firstChild, 3);
},
target: function() { return div.firstChild },
finalTarget: function() { return div.lastChild },
beforeInputAction: function() {
getSelection().removeAllRanges();
var range = document.createRange();
range.setStart(div.querySelector("div + div").firstChild, 0);
range.setEnd(div.querySelector("div + div").firstChild, 3);
getSelection().addRange(range);
},
command: "bold",
value: "",
},
];
var commandTests = {
backColor: ["green"],
createLink: ["http://www.w3.org/community/editing/"],
fontName: ["serif", "Helvetica"],
fontSize: ["6", "15px"],
foreColor: ["green"],
hiliteColor: ["green"],
italic: [],
removeFormat: [],
strikeThrough: [],
subscript: [],
superscript: [],
underline: [],
unlink: [],
delete: [],
formatBlock: ["p"],
forwardDelete: [],
indent: [],
insertHorizontalRule: ["id"],
insertHTML: ["<b>hi</b>"],
insertImage: ["http://example.com/some-image"],
insertLineBreak: [],
insertOrderedList: [],
insertParagraph: [],
insertText: ["abc"],
insertUnorderedList: [],
justifyCenter: [],
justifyFull: [],
justifyLeft: [],
justifyRight: [],
outdent: [],
redo: [],
selectAll: [],
styleWithCSS: [],
undo: [],
useCSS: [],
};
Object.keys(commandTests).forEach(function(command) {
commandTests[command] = ["", "quasit"].concat(commandTests[command]);
commandTests[command].forEach(function(value) {
tests.push({
name: "Command " + command + ", value " + format_value(value),
html: "<div contenteditable>foo<b>bar</b>baz</div>",
initRange: function(range) {
range.setStart(div.querySelector("b").firstChild, 0);
range.setEnd(div.querySelector("b"), 1);
},
target: function() {
return ["redo", "selectAll", "styleWithCSS", "undo", "useCSS"]
.indexOf(command) == -1 ? div.firstChild : null;
},
command: command,
value: value,
});
});
});
tests.forEach(function(obj) {
[true, false].forEach(function(cancel) {
// Kill all event handlers first
var newDiv = div.cloneNode(false);
div.parentNode.insertBefore(newDiv, div);
div.parentNode.removeChild(div);
div = newDiv;
div.innerHTML = obj.html;
var originalContents = div.cloneNode(true);
getSelection().removeAllRanges();
var range = document.createRange();
obj.initRange(range);
getSelection().addRange(range);
var target = obj.target();
var finalTarget = "finalTarget" in obj ? obj.finalTarget() : target;
var command = obj.command;
var value = obj.value;
var beforeInputEvents = [];
var inputEvents = [];
div.addEventListener("beforeinput", function(e) {
var copied = copyEvent(e);
copied.inputEventsLength = inputEvents.length;
beforeInputEvents.push(copied);
if (cancel) {
e.preventDefault();
}
if ("beforeInputAction" in obj) {
obj.beforeInputAction();
}
});
div.addEventListener("input", function(e) { inputEvents.push(copyEvent(e)) });
// Uncomment this code instead of the execCommand() to make all the
// tests pass, as a sanity check
//var e = new Event("beforeinput", {bubbles: true, cancelable: true});
//e.command = command;
//e.value = value;
//var ret = target ? target.dispatchEvent(e) : false;
//if (ret) {
// var e = new Event("input", {bubbles: true});
// e.command = command;
// e.value = value;
// finalTarget.dispatchEvent(e);
//}
var exception = null;
try {
document.execCommand(command, false, value);
} catch(e) {
exception = e;
}
test(function() {
assert_equals(exception, null, "Unexpected exception");
}, obj.name + ": execCommand() must not throw, "
+ (cancel ? "canceled" : "uncanceled"));
test(function() {
assert_equals(beforeInputEvents.length, target ? 1 : 0,
"number of beforeinput events fired");
if (beforeInputEvents.length == 0) {
assert_equals(inputEvents.length, 0, "number of input events fired");
return;
}
var e = beforeInputEvents[0];
assert_equals(e.inputEventsLength, 0, "number of input events fired");
assert_equals(e.type, "beforeinput", "event.type");
assert_equals(e.target, target, "event.target");
assert_equals(e.currentTarget, div, "event.currentTarget");
assert_equals(e.eventPhase, Event.BUBBLING_PHASE, "event.eventPhase");
assert_equals(e.bubbles, true, "event.bubbles");
assert_equals(e.cancelable, true, "event.cancelable");
assert_equals(e.defaultPrevented, false, "event.defaultPrevented");
assert_equals(e.command, command, "e.command");
assert_equals(e.value, value, "e.value");
assert_own_property(window, "EditingBeforeInputEvent",
"window.EditingBeforeInputEvent must exist");
assert_equals(Object.getPrototypeOf(e.original),
EditingBeforeInputEvent.prototype,
"event prototype");
assert_true(originalContents.isEqualNode(div),
"div contents not yet changed");
assert_equals(e.isTrusted, true, "event.isTrusted");
}, obj.name + ": beforeinput event, " + (cancel ? "canceled" : "uncanceled"));
test(function() {
assert_equals(inputEvents.length, target && !cancel ? 1 : 0,
"number of input events fired");
if (!target || cancel) {
assert_true(originalContents.isEqualNode(div),
"div contents must not be changed");
return;
}
var e = inputEvents[0];
assert_equals(e.type, "input", "event.type");
assert_equals(e.target, finalTarget, "event.target");
assert_equals(e.currentTarget, div, "event.currentTarget");
assert_equals(e.eventPhase, Event.BUBBLING_PHASE, "event.eventPhase");
assert_equals(e.bubbles, true, "event.bubbles");
assert_equals(e.cancelable, false, "event.cancelable");
assert_equals(e.defaultPrevented, false, "event.defaultPrevented");
assert_equals(e.command, command, "e.command");
assert_equals(e.value, value, "e.value");
assert_own_property(window, "EditingInputEvent",
"window.EditingInputEvent must exist");
assert_equals(Object.getPrototypeOf(e.original),
EditingInputEvent.prototype,
"event prototype");
assert_equals(e.isTrusted, true, "event.isTrusted");
}, obj.name + ": input event, " + (cancel ? "canceled" : "uncanceled"));
});
});
// Thanks, Gecko.
document.body.bgColor = "";
</script>

View File

@ -0,0 +1,48 @@
<!doctype html>
<meta charset=utf-8>
<link rel=stylesheet href=../css/reset.css>
<title>HTML editing conformance tests</title>
<p>See the <a href=editing.html#tests>Tests</a> section of the specification
for documentation.
<p id=timing></p>
<div id=log></div>
<div id=test-container></div>
<script src=../implementation.js></script>
<script>var testsJsLibraryOnly = true</script>
<script src=../tests.js></script>
<script src=data.js></script>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
runTests();
function runTests() {
var startTime = Date.now();
// Make document.body.innerHTML more tidy by removing unnecessary things.
// We can't remove the testharness.js script, because at the time of this
// writing, for some reason that stops it from adding appropriate CSS.
[].forEach.call(document.querySelectorAll("script"), function(node) {
if (!/testharness\.js$/.test(node.src)) {
node.parentNode.removeChild(node);
}
});
browserTests.forEach(runConformanceTest);
document.getElementById("test-container").parentNode
.removeChild(document.getElementById("test-container"));
var elapsed = Math.round(Date.now() - startTime)/1000;
document.getElementById("timing").textContent =
"Time elapsed: " + Math.floor(elapsed/60) + ":"
+ ((elapsed % 60) < 10 ? "0" : "")
+ (elapsed % 60).toFixed(3) + " min.";
}
</script>

View File

@ -0,0 +1,24 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/css
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
$(NULL)
_TESTS += \
reset.css \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,27 @@
/* Make sure various CSS values are what are expected, so that tests work
* right. */
body { font-family: serif }
/* http://www.w3.org/Bugs/Public/show_bug.cgi?id=12154
* https://bugzilla.mozilla.org/show_bug.cgi?id=589124
* https://bugs.webkit.org/show_bug.cgi?id=56400 */
b, strong { font-weight: bold }
.bold { font-weight: bold }
.notbold { font-weight: normal }
.underline { text-decoration: underline }
.line-through { text-decoration: line-through }
.underline-and-line-through { text-decoration: underline line-through }
#purple { color: purple }
/* https://bugs.webkit.org/show_bug.cgi?id=56670 */
dfn { font-style: italic }
/* Opera has weird default blockquote style */
blockquote { margin: 1em 40px }
/* Some tests assume links are blue, for the sake of argument, but they aren't
* blue in any browser. And :visited definitely isn't blue, except in engines
* like Gecko that lie.
*
* This should really be #00e, probably. See:
* http://www.w3.org/Bugs/Public/show_bug.cgi?id=13330 */
:link, :visited { color: blue }
/* http://www.w3.org/Bugs/Public/show_bug.cgi?id=14066
* https://bugs.webkit.org/show_bug.cgi?id=68392 */
quasit { text-align: inherit }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/editing/selecttest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_addRange.html \
test_collapse.html \
test_collapseToStartEnd.html \
test_deleteFromDocument.html \
test_Document-open.html \
test_extend.html \
test_getRangeAt.html \
test_getSelection.html \
test_interfaces.html \
test_isCollapsed.html \
test_removeAllRanges.html \
test_selectAllChildren.html \
$(NULL)
_TESTS += \
common.js \
test-iframe.html \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,952 @@
"use strict";
// TODO: iframes, contenteditable/designMode
// Everything is done in functions in this test harness, so we have to declare
// all the variables before use to make sure they can be reused.
var selection;
var testDiv, paras, detachedDiv, detachedPara1, detachedPara2,
foreignDoc, foreignPara1, foreignPara2, xmlDoc, xmlElement,
detachedXmlElement, detachedTextNode, foreignTextNode,
detachedForeignTextNode, xmlTextNode, detachedXmlTextNode,
processingInstruction, detachedProcessingInstruction, comment,
detachedComment, foreignComment, detachedForeignComment, xmlComment,
detachedXmlComment, docfrag, foreignDocfrag, xmlDocfrag, doctype,
foreignDoctype, xmlDoctype;
var testRanges, testPoints, testNodes;
function setupRangeTests() {
selection = getSelection();
testDiv = document.querySelector("#test");
if (testDiv) {
testDiv.parentNode.removeChild(testDiv);
}
testDiv = document.createElement("div");
testDiv.id = "test";
document.body.insertBefore(testDiv, document.body.firstChild);
// Test some diacritics, to make sure browsers are using code units here
// and not something like grapheme clusters.
testDiv.innerHTML = "<p id=a>A&#x308;b&#x308;c&#x308;d&#x308;e&#x308;f&#x308;g&#x308;h&#x308;\n"
+ "<p id=b style=display:none>Ijklmnop\n"
+ "<p id=c>Qrstuvwx"
+ "<p id=d style=display:none>Yzabcdef"
+ "<p id=e style=display:none>Ghijklmn";
paras = testDiv.querySelectorAll("p");
detachedDiv = document.createElement("div");
detachedPara1 = document.createElement("p");
detachedPara1.appendChild(document.createTextNode("Opqrstuv"));
detachedPara2 = document.createElement("p");
detachedPara2.appendChild(document.createTextNode("Wxyzabcd"));
detachedDiv.appendChild(detachedPara1);
detachedDiv.appendChild(detachedPara2);
// Opera doesn't automatically create a doctype for a new HTML document,
// contrary to spec. It also doesn't let you add doctypes to documents
// after the fact through any means I've tried. So foreignDoc in Opera
// will have no doctype, foreignDoctype will be null, and Opera will fail
// some tests somewhat mysteriously as a result.
foreignDoc = document.implementation.createHTMLDocument("");
foreignPara1 = foreignDoc.createElement("p");
foreignPara1.appendChild(foreignDoc.createTextNode("Efghijkl"));
foreignPara2 = foreignDoc.createElement("p");
foreignPara2.appendChild(foreignDoc.createTextNode("Mnopqrst"));
foreignDoc.body.appendChild(foreignPara1);
foreignDoc.body.appendChild(foreignPara2);
// Now we get to do really silly stuff, which nobody in the universe is
// ever going to actually do, but the spec defines behavior, so too bad.
// Testing is fun!
xmlDoctype = document.implementation.createDocumentType("qorflesnorf", "abcde", "x\"'y");
xmlDoc = document.implementation.createDocument(null, null, xmlDoctype);
detachedXmlElement = xmlDoc.createElement("everyone-hates-hyphenated-element-names");
detachedTextNode = document.createTextNode("Uvwxyzab");
detachedForeignTextNode = foreignDoc.createTextNode("Cdefghij");
detachedXmlTextNode = xmlDoc.createTextNode("Klmnopqr");
// PIs only exist in XML documents, so don't bother with document or
// foreignDoc.
detachedProcessingInstruction = xmlDoc.createProcessingInstruction("whippoorwill", "chirp chirp chirp");
detachedComment = document.createComment("Stuvwxyz");
// Hurrah, we finally got to "z" at the end!
detachedForeignComment = foreignDoc.createComment("אריה יהודה");
detachedXmlComment = xmlDoc.createComment("בן חיים אליעזר");
// We should also test with document fragments that actually contain stuff
// . . . but, maybe later.
docfrag = document.createDocumentFragment();
foreignDocfrag = foreignDoc.createDocumentFragment();
xmlDocfrag = xmlDoc.createDocumentFragment();
xmlElement = xmlDoc.createElement("igiveuponcreativenames");
xmlTextNode = xmlDoc.createTextNode("do re mi fa so la ti");
xmlElement.appendChild(xmlTextNode);
processingInstruction = xmlDoc.createProcessingInstruction("somePI", 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?');
xmlDoc.appendChild(xmlElement);
xmlDoc.appendChild(processingInstruction);
xmlComment = xmlDoc.createComment("I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt");
xmlDoc.appendChild(xmlComment);
comment = document.createComment("Alphabet soup?");
testDiv.appendChild(comment);
foreignComment = foreignDoc.createComment('"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.');
foreignDoc.appendChild(foreignComment);
foreignTextNode = foreignDoc.createTextNode("I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.");
foreignDoc.body.appendChild(foreignTextNode);
doctype = document.doctype;
foreignDoctype = foreignDoc.doctype;
testRanges = [
// Various ranges within the text node children of different
// paragraphs. All should be valid.
"[paras[0].firstChild, 0, paras[0].firstChild, 0]",
"[paras[0].firstChild, 0, paras[0].firstChild, 1]",
"[paras[0].firstChild, 2, paras[0].firstChild, 8]",
"[paras[0].firstChild, 2, paras[0].firstChild, 9]",
"[paras[1].firstChild, 0, paras[1].firstChild, 0]",
"[paras[1].firstChild, 0, paras[1].firstChild, 1]",
"[paras[1].firstChild, 2, paras[1].firstChild, 8]",
"[paras[1].firstChild, 2, paras[1].firstChild, 9]",
"[detachedPara1.firstChild, 0, detachedPara1.firstChild, 0]",
"[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]",
"[detachedPara1.firstChild, 2, detachedPara1.firstChild, 8]",
"[foreignPara1.firstChild, 0, foreignPara1.firstChild, 0]",
"[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]",
"[foreignPara1.firstChild, 2, foreignPara1.firstChild, 8]",
// Now try testing some elements, not just text nodes.
"[document.documentElement, 0, document.documentElement, 1]",
"[document.documentElement, 0, document.documentElement, 2]",
"[document.documentElement, 1, document.documentElement, 2]",
"[document.head, 1, document.head, 1]",
"[document.body, 0, document.body, 1]",
"[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]",
"[foreignDoc.head, 1, foreignDoc.head, 1]",
"[foreignDoc.body, 0, foreignDoc.body, 0]",
"[paras[0], 0, paras[0], 0]",
"[paras[0], 0, paras[0], 1]",
"[detachedPara1, 0, detachedPara1, 0]",
"[detachedPara1, 0, detachedPara1, 1]",
// Now try some ranges that span elements.
"[paras[0].firstChild, 0, paras[1].firstChild, 0]",
"[paras[0].firstChild, 0, paras[1].firstChild, 8]",
"[paras[0].firstChild, 3, paras[3], 1]",
// How about something that spans a node and its descendant?
"[paras[0], 0, paras[0].firstChild, 7]",
"[testDiv, 2, paras[4], 1]",
"[testDiv, 1, paras[2].firstChild, 5]",
"[document.documentElement, 1, document.body, 0]",
"[foreignDoc.documentElement, 1, foreignDoc.body, 0]",
// Then a few more interesting things just for good measure.
"[document, 0, document, 1]",
"[document, 0, document, 2]",
"[document, 1, document, 2]",
"[testDiv, 0, comment, 5]",
"[paras[2].firstChild, 4, comment, 2]",
"[paras[3], 1, comment, 8]",
"[foreignDoc, 0, foreignDoc, 0]",
"[foreignDoc, 1, foreignComment, 2]",
"[foreignDoc.body, 0, foreignTextNode, 36]",
"[xmlDoc, 0, xmlDoc, 0]",
// Opera 11 crashes if you extractContents() a range that ends at offset
// zero in a comment. Comment out this line to run the tests successfully.
"[xmlDoc, 1, xmlComment, 0]",
"[detachedTextNode, 0, detachedTextNode, 8]",
"[detachedForeignTextNode, 7, detachedForeignTextNode, 7]",
"[detachedForeignTextNode, 0, detachedForeignTextNode, 8]",
"[detachedXmlTextNode, 7, detachedXmlTextNode, 7]",
"[detachedXmlTextNode, 0, detachedXmlTextNode, 8]",
"[detachedComment, 3, detachedComment, 4]",
"[detachedComment, 5, detachedComment, 5]",
"[detachedForeignComment, 0, detachedForeignComment, 1]",
"[detachedForeignComment, 4, detachedForeignComment, 4]",
"[detachedXmlComment, 2, detachedXmlComment, 6]",
"[docfrag, 0, docfrag, 0]",
"[foreignDocfrag, 0, foreignDocfrag, 0]",
"[xmlDocfrag, 0, xmlDocfrag, 0]",
];
testPoints = [
// Various positions within the page, some invalid. Remember that
// paras[0] is visible, and paras[1] is display: none.
"[paras[0].firstChild, -1]",
"[paras[0].firstChild, 0]",
"[paras[0].firstChild, 1]",
"[paras[0].firstChild, 2]",
"[paras[0].firstChild, 8]",
"[paras[0].firstChild, 9]",
"[paras[0].firstChild, 10]",
"[paras[0].firstChild, 65535]",
"[paras[1].firstChild, -1]",
"[paras[1].firstChild, 0]",
"[paras[1].firstChild, 1]",
"[paras[1].firstChild, 2]",
"[paras[1].firstChild, 8]",
"[paras[1].firstChild, 9]",
"[paras[1].firstChild, 10]",
"[paras[1].firstChild, 65535]",
"[detachedPara1.firstChild, 0]",
"[detachedPara1.firstChild, 1]",
"[detachedPara1.firstChild, 8]",
"[detachedPara1.firstChild, 9]",
"[foreignPara1.firstChild, 0]",
"[foreignPara1.firstChild, 1]",
"[foreignPara1.firstChild, 8]",
"[foreignPara1.firstChild, 9]",
// Now try testing some elements, not just text nodes.
"[document.documentElement, -1]",
"[document.documentElement, 0]",
"[document.documentElement, 1]",
"[document.documentElement, 2]",
"[document.documentElement, 7]",
"[document.head, 1]",
"[document.body, 3]",
"[foreignDoc.documentElement, 0]",
"[foreignDoc.documentElement, 1]",
"[foreignDoc.head, 0]",
"[foreignDoc.body, 1]",
"[paras[0], 0]",
"[paras[0], 1]",
"[paras[0], 2]",
"[paras[1], 0]",
"[paras[1], 1]",
"[paras[1], 2]",
"[detachedPara1, 0]",
"[detachedPara1, 1]",
"[testDiv, 0]",
"[testDiv, 3]",
// Then a few more interesting things just for good measure.
"[document, -1]",
"[document, 0]",
"[document, 1]",
"[document, 2]",
"[document, 3]",
"[comment, -1]",
"[comment, 0]",
"[comment, 4]",
"[comment, 96]",
"[foreignDoc, 0]",
"[foreignDoc, 1]",
"[foreignComment, 2]",
"[foreignTextNode, 0]",
"[foreignTextNode, 36]",
"[xmlDoc, -1]",
"[xmlDoc, 0]",
"[xmlDoc, 1]",
"[xmlDoc, 5]",
"[xmlComment, 0]",
"[xmlComment, 4]",
"[processingInstruction, 0]",
"[processingInstruction, 5]",
"[processingInstruction, 9]",
"[detachedTextNode, 0]",
"[detachedTextNode, 8]",
"[detachedForeignTextNode, 0]",
"[detachedForeignTextNode, 8]",
"[detachedXmlTextNode, 0]",
"[detachedXmlTextNode, 8]",
"[detachedProcessingInstruction, 12]",
"[detachedComment, 3]",
"[detachedComment, 5]",
"[detachedForeignComment, 0]",
"[detachedForeignComment, 4]",
"[detachedXmlComment, 2]",
"[docfrag, 0]",
"[foreignDocfrag, 0]",
"[xmlDocfrag, 0]",
"[doctype, 0]",
"[doctype, -17]",
"[doctype, 1]",
"[foreignDoctype, 0]",
"[xmlDoctype, 0]",
];
testNodes = [
"paras[0]",
"paras[0].firstChild",
"paras[1]",
"paras[1].firstChild",
"foreignPara1",
"foreignPara1.firstChild",
"detachedPara1",
"detachedPara1.firstChild",
"detachedPara1",
"detachedPara1.firstChild",
"testDiv",
"document",
"detachedDiv",
"detachedPara2",
"foreignDoc",
"foreignPara2",
"xmlDoc",
"xmlElement",
"detachedXmlElement",
"detachedTextNode",
"foreignTextNode",
"detachedForeignTextNode",
"xmlTextNode",
"detachedXmlTextNode",
"processingInstruction",
"detachedProcessingInstruction",
"comment",
"detachedComment",
"foreignComment",
"detachedForeignComment",
"xmlComment",
"detachedXmlComment",
"docfrag",
"foreignDocfrag",
"xmlDocfrag",
"doctype",
"foreignDoctype",
"xmlDoctype",
];
}
if ("setup" in window) {
setup(setupRangeTests);
} else {
// Presumably we're running from within an iframe or something
setupRangeTests();
}
/**
* Return the length of a node as specified in DOM Range.
*/
function getNodeLength(node) {
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
return 0;
}
if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE || node.nodeType == Node.COMMENT_NODE) {
return node.length;
}
return node.childNodes.length;
}
/**
* Returns the furthest ancestor of a Node as defined by the spec.
*/
function furthestAncestor(node) {
var root = node;
while (root.parentNode != null) {
root = root.parentNode;
}
return root;
}
/**
* "The ancestor containers of a Node are the Node itself and all its
* ancestors."
*
* Is node1 an ancestor container of node2?
*/
function isAncestorContainer(node1, node2) {
return node1 == node2 ||
(node2.compareDocumentPosition(node1) & Node.DOCUMENT_POSITION_CONTAINS);
}
/**
* Returns the first Node that's after node in tree order, or null if node is
* the last Node.
*/
function nextNode(node) {
if (node.hasChildNodes()) {
return node.firstChild;
}
return nextNodeDescendants(node);
}
/**
* Returns the last Node that's before node in tree order, or null if node is
* the first Node.
*/
function previousNode(node) {
if (node.previousSibling) {
node = node.previousSibling;
while (node.hasChildNodes()) {
node = node.lastChild;
}
return node;
}
return node.parentNode;
}
/**
* Returns the next Node that's after node and all its descendants in tree
* order, or null if node is the last Node or an ancestor of it.
*/
function nextNodeDescendants(node) {
while (node && !node.nextSibling) {
node = node.parentNode;
}
if (!node) {
return null;
}
return node.nextSibling;
}
/**
* Returns the ownerDocument of the Node, or the Node itself if it's a
* Document.
*/
function ownerDocument(node) {
return node.nodeType == Node.DOCUMENT_NODE
? node
: node.ownerDocument;
}
/**
* Returns true if ancestor is an ancestor of descendant, false otherwise.
*/
function isAncestor(ancestor, descendant) {
if (!ancestor || !descendant) {
return false;
}
while (descendant && descendant != ancestor) {
descendant = descendant.parentNode;
}
return descendant == ancestor;
}
/**
* Returns true if descendant is a descendant of ancestor, false otherwise.
*/
function isDescendant(descendant, ancestor) {
return isAncestor(ancestor, descendant);
}
/**
* The position of two boundary points relative to one another, as defined by
* the spec.
*/
function getPosition(nodeA, offsetA, nodeB, offsetB) {
// "If node A is the same as node B, return equal if offset A equals offset
// B, before if offset A is less than offset B, and after if offset A is
// greater than offset B."
if (nodeA == nodeB) {
if (offsetA == offsetB) {
return "equal";
}
if (offsetA < offsetB) {
return "before";
}
if (offsetA > offsetB) {
return "after";
}
}
// "If node A is after node B in tree order, compute the position of (node
// B, offset B) relative to (node A, offset A). If it is before, return
// after. If it is after, return before."
if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_FOLLOWING) {
var pos = getPosition(nodeB, offsetB, nodeA, offsetA);
if (pos == "before") {
return "after";
}
if (pos == "after") {
return "before";
}
}
// "If node A is an ancestor of node B:"
if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_CONTAINS) {
// "Let child equal node B."
var child = nodeB;
// "While child is not a child of node A, set child to its parent."
while (child.parentNode != nodeA) {
child = child.parentNode;
}
// "If the index of child is less than offset A, return after."
if (indexOf(child) < offsetA) {
return "after";
}
}
// "Return before."
return "before";
}
/**
* "contained" as defined by DOM Range: "A Node node is contained in a range
* range if node's furthest ancestor is the same as range's root, and (node, 0)
* is after range's start, and (node, length of node) is before range's end."
*/
function isContained(node, range) {
var pos1 = getPosition(node, 0, range.startContainer, range.startOffset);
var pos2 = getPosition(node, getNodeLength(node), range.endContainer, range.endOffset);
return furthestAncestor(node) == furthestAncestor(range.startContainer)
&& pos1 == "after"
&& pos2 == "before";
}
/**
* "partially contained" as defined by DOM Range: "A Node is partially
* contained in a range if it is an ancestor container of the range's start but
* not its end, or vice versa."
*/
function isPartiallyContained(node, range) {
var cond1 = isAncestorContainer(node, range.startContainer);
var cond2 = isAncestorContainer(node, range.endContainer);
return (cond1 && !cond2) || (cond2 && !cond1);
}
/**
* Index of a node as defined by the spec.
*/
function indexOf(node) {
if (!node.parentNode) {
// No preceding sibling nodes, right?
return 0;
}
var i = 0;
while (node != node.parentNode.childNodes[i]) {
i++;
}
return i;
}
/**
* extractContents() implementation, following the spec. If an exception is
* supposed to be thrown, will return a string with the name (e.g.,
* "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also
* return an arbitrary human-readable string if a condition is hit that implies
* a spec bug.
*/
function myExtractContents(range) {
// "If the context object's detached flag is set, raise an
// INVALID_STATE_ERR exception and abort these steps."
try {
range.collapsed;
} catch (e) {
return "INVALID_STATE_ERR";
}
// "Let frag be a new DocumentFragment whose ownerDocument is the same as
// the ownerDocument of the context object's start node."
var ownerDoc = range.startContainer.nodeType == Node.DOCUMENT_NODE
? range.startContainer
: range.startContainer.ownerDocument;
var frag = ownerDoc.createDocumentFragment();
// "If the context object's start and end are the same, abort this method,
// returning frag."
if (range.startContainer == range.endContainer
&& range.startOffset == range.endOffset) {
return frag;
}
// "Let original start node, original start offset, original end node, and
// original end offset be the context object's start and end nodes and
// offsets, respectively."
var originalStartNode = range.startContainer;
var originalStartOffset = range.startOffset;
var originalEndNode = range.endContainer;
var originalEndOffset = range.endOffset;
// "If original start node and original end node are the same, and they are
// a Text or Comment node:"
if (range.startContainer == range.endContainer
&& (range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// start node."
var clone = originalStartNode.cloneNode(false);
// "Set the data of clone to the result of calling
// substringData(original start offset, original end offset original
// start offset) on original start node."
clone.data = originalStartNode.substringData(originalStartOffset,
originalEndOffset - originalStartOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData(original start offset, original end offset
// original start offset) on original start node."
originalStartNode.deleteData(originalStartOffset,
originalEndOffset - originalStartOffset);
// "Abort this method, returning frag."
return frag;
}
// "Let common ancestor equal original start node."
var commonAncestor = originalStartNode;
// "While common ancestor is not an ancestor container of original end
// node, set common ancestor to its own parent."
while (!isAncestorContainer(commonAncestor, originalEndNode)) {
commonAncestor = commonAncestor.parentNode;
}
// "If original start node is an ancestor container of original end node,
// let first partially contained child be null."
var firstPartiallyContainedChild;
if (isAncestorContainer(originalStartNode, originalEndNode)) {
firstPartiallyContainedChild = null;
// "Otherwise, let first partially contained child be the first child of
// common ancestor that is partially contained in the context object."
} else {
for (var i = 0; i < commonAncestor.childNodes.length; i++) {
if (isPartiallyContained(commonAncestor.childNodes[i], range)) {
firstPartiallyContainedChild = commonAncestor.childNodes[i];
break;
}
}
if (!firstPartiallyContainedChild) {
throw "Spec bug: no first partially contained child!";
}
}
// "If original end node is an ancestor container of original start node,
// let last partially contained child be null."
var lastPartiallyContainedChild;
if (isAncestorContainer(originalEndNode, originalStartNode)) {
lastPartiallyContainedChild = null;
// "Otherwise, let last partially contained child be the last child of
// common ancestor that is partially contained in the context object."
} else {
for (var i = commonAncestor.childNodes.length - 1; i >= 0; i--) {
if (isPartiallyContained(commonAncestor.childNodes[i], range)) {
lastPartiallyContainedChild = commonAncestor.childNodes[i];
break;
}
}
if (!lastPartiallyContainedChild) {
throw "Spec bug: no last partially contained child!";
}
}
// "Let contained children be a list of all children of common ancestor
// that are contained in the context object, in tree order."
//
// "If any member of contained children is a DocumentType, raise a
// HIERARCHY_REQUEST_ERR exception and abort these steps."
var containedChildren = [];
for (var i = 0; i < commonAncestor.childNodes.length; i++) {
if (isContained(commonAncestor.childNodes[i], range)) {
if (commonAncestor.childNodes[i].nodeType
== Node.DOCUMENT_TYPE_NODE) {
return "HIERARCHY_REQUEST_ERR";
}
containedChildren.push(commonAncestor.childNodes[i]);
}
}
// "If original start node is an ancestor container of original end node,
// set new node to original start node and new offset to original start
// offset."
var newNode, newOffset;
if (isAncestorContainer(originalStartNode, originalEndNode)) {
newNode = originalStartNode;
newOffset = originalStartOffset;
// "Otherwise:"
} else {
// "Let reference node equal original start node."
var referenceNode = originalStartNode;
// "While reference node's parent is not null and is not an ancestor
// container of original end node, set reference node to its parent."
while (referenceNode.parentNode
&& !isAncestorContainer(referenceNode.parentNode, originalEndNode)) {
referenceNode = referenceNode.parentNode;
}
// "Set new node to the parent of reference node, and new offset to one
// plus the index of reference node."
newNode = referenceNode.parentNode;
newOffset = 1 + indexOf(referenceNode);
}
// "If first partially contained child is a Text or Comment node:"
if (firstPartiallyContainedChild
&& (firstPartiallyContainedChild.nodeType == Node.TEXT_NODE
|| firstPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// start node."
var clone = originalStartNode.cloneNode(false);
// "Set the data of clone to the result of calling substringData() on
// original start node, with original start offset as the first
// argument and (length of original start node original start offset)
// as the second."
clone.data = originalStartNode.substringData(originalStartOffset,
getNodeLength(originalStartNode) - originalStartOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData() on original start node, with original start
// offset as the first argument and (length of original start node
// original start offset) as the second."
originalStartNode.deleteData(originalStartOffset,
getNodeLength(originalStartNode) - originalStartOffset);
// "Otherwise, if first partially contained child is not null:"
} else if (firstPartiallyContainedChild) {
// "Let clone be the result of calling cloneNode(false) on first
// partially contained child."
var clone = firstPartiallyContainedChild.cloneNode(false);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Let subrange be a new Range whose start is (original start node,
// original start offset) and whose end is (first partially contained
// child, length of first partially contained child)."
var subrange = ownerDoc.createRange();
subrange.setStart(originalStartNode, originalStartOffset);
subrange.setEnd(firstPartiallyContainedChild,
getNodeLength(firstPartiallyContainedChild));
// "Let subfrag be the result of calling extractContents() on
// subrange."
var subfrag = myExtractContents(subrange);
// "For each child of subfrag, in order, append that child to clone as
// its last child."
for (var i = 0; i < subfrag.childNodes.length; i++) {
clone.appendChild(subfrag.childNodes[i]);
}
}
// "For each contained child in contained children, append contained child
// as the last child of frag."
for (var i = 0; i < containedChildren.length; i++) {
frag.appendChild(containedChildren[i]);
}
// "If last partially contained child is a Text or Comment node:"
if (lastPartiallyContainedChild
&& (lastPartiallyContainedChild.nodeType == Node.TEXT_NODE
|| lastPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) {
// "Let clone be the result of calling cloneNode(false) on original
// end node."
var clone = originalEndNode.cloneNode(false);
// "Set the data of clone to the result of calling substringData(0,
// original end offset) on original end node."
clone.data = originalEndNode.substringData(0, originalEndOffset);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Call deleteData(0, original end offset) on original end node."
originalEndNode.deleteData(0, originalEndOffset);
// "Otherwise, if last partially contained child is not null:"
} else if (lastPartiallyContainedChild) {
// "Let clone be the result of calling cloneNode(false) on last
// partially contained child."
var clone = lastPartiallyContainedChild.cloneNode(false);
// "Append clone as the last child of frag."
frag.appendChild(clone);
// "Let subrange be a new Range whose start is (last partially
// contained child, 0) and whose end is (original end node, original
// end offset)."
var subrange = ownerDoc.createRange();
subrange.setStart(lastPartiallyContainedChild, 0);
subrange.setEnd(originalEndNode, originalEndOffset);
// "Let subfrag be the result of calling extractContents() on
// subrange."
var subfrag = myExtractContents(subrange);
// "For each child of subfrag, in order, append that child to clone as
// its last child."
for (var i = 0; i < subfrag.childNodes.length; i++) {
clone.appendChild(subfrag.childNodes[i]);
}
}
// "Set the context object's start and end to (new node, new offset)."
range.setStart(newNode, newOffset);
range.setEnd(newNode, newOffset);
// "Return frag."
return frag;
}
/**
* insertNode() implementation, following the spec. If an exception is
* supposed to be thrown, will return a string with the name (e.g.,
* "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also
* return an arbitrary human-readable string if a condition is hit that implies
* a spec bug.
*/
function myInsertNode(range, newNode) {
// "If the context object's detached flag is set, raise an
// INVALID_STATE_ERR exception and abort these steps."
//
// Assume that if accessing collapsed throws, it's detached.
try {
range.collapsed;
} catch (e) {
return "INVALID_STATE_ERR";
}
// "If the context object's start node is a Text or Comment node and its
// parent is null, raise an HIERARCHY_REQUEST_ERR exception and abort these
// steps."
if ((range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE)
&& !range.startContainer.parentNode) {
return "HIERARCHY_REQUEST_ERR";
}
// "If the context object's start node is a Text node, run splitText() on
// it with the context object's start offset as its argument, and let
// reference node be the result."
var referenceNode;
if (range.startContainer.nodeType == Node.TEXT_NODE) {
// We aren't testing how ranges vary under mutations, and browsers vary
// in how they mutate for splitText, so let's just force the correct
// way.
var start = [range.startContainer, range.startOffset];
var end = [range.endContainer, range.endOffset];
referenceNode = range.startContainer.splitText(range.startOffset);
if (start[0] == end[0]
&& end[1] > start[1]) {
end[0] = referenceNode;
end[1] -= start[1];
} else if (end[0] == start[0].parentNode
&& end[1] > indexOf(referenceNode)) {
end[1]++;
}
range.setStart(start[0], start[1]);
range.setEnd(end[0], end[1]);
// "Otherwise, if the context object's start node is a Comment, let
// reference node be the context object's start node."
} else if (range.startContainer.nodeType == Node.COMMENT_NODE) {
referenceNode = range.startContainer;
// "Otherwise, let reference node be the child of the context object's
// start node with index equal to the context object's start offset, or
// null if there is no such child."
} else {
referenceNode = range.startContainer.childNodes[range.startOffset];
if (typeof referenceNode == "undefined") {
referenceNode = null;
}
}
// "If reference node is null, let parent node be the context object's
// start node."
var parentNode;
if (!referenceNode) {
parentNode = range.startContainer;
// "Otherwise, let parent node be the parent of reference node."
} else {
parentNode = referenceNode.parentNode;
}
// "Call insertBefore(newNode, reference node) on parent node, re-raising
// any exceptions that call raised."
try {
parentNode.insertBefore(newNode, referenceNode);
} catch (e) {
return getDomExceptionName(e);
}
}
/**
* Asserts that two nodes are equal, in the sense of isEqualNode(). If they
* aren't, tries to print a relatively informative reason why not. TODO: Move
* this to testharness.js?
*/
function assertNodesEqual(actual, expected, msg) {
if (!actual.isEqualNode(expected)) {
msg = "Actual and expected mismatch for " + msg + ". ";
while (actual && expected) {
assert_true(actual.nodeType === expected.nodeType
&& actual.nodeName === expected.nodeName
&& actual.nodeValue === expected.nodeValue
&& actual.childNodes.length === expected.childNodes.length,
"First differing node: expected " + format_value(expected)
+ ", got " + format_value(actual));
actual = nextNode(actual);
expected = nextNode(expected);
}
assert_unreached("DOMs were not equal but we couldn't figure out why");
}
}
/**
* Given a DOMException, return the name (e.g., "HIERARCHY_REQUEST_ERR"). In
* theory this should be just e.name, but in practice it's not. So I could
* legitimately just return e.name, but then every engine but WebKit would fail
* every test, since no one seems to care much for standardizing DOMExceptions.
* Instead I mangle it to account for browser bugs, so as not to fail
* insertNode() tests (for instance) for insertBefore() bugs. Of course, a
* standards-compliant browser will work right in any event.
*
* If the exception has no string property called "name" or "message", we just
* re-throw it.
*/
function getDomExceptionName(e) {
if (typeof e.name == "string"
&& /^[A-Z_]+_ERR$/.test(e.name)) {
// Either following the standard, or prefixing NS_ERROR_DOM (I'm
// looking at you, Gecko).
return e.name.replace(/^NS_ERROR_DOM_/, "");
}
if (typeof e.message == "string"
&& /^[A-Z_]+_ERR$/.test(e.message)) {
// Opera
return e.message;
}
if (typeof e.message == "string"
&& /^DOM Exception:/.test(e.message)) {
// IE
return /[A-Z_]+_ERR/.exec(e.message)[0];
}
throw e;
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], returns a Range with those endpoints.
*/
function rangeFromEndpoints(endpoints) {
// If we just use document instead of the ownerDocument of endpoints[0],
// WebKit will throw on setStart/setEnd. This is a WebKit bug, but it's in
// range, not selection, so we don't want to fail anything for it.
var range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
return range;
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], sets the selection to have those endpoints. Uses
* addRange, so the range will be forwards. Accepts an empty array for
* endpoints, in which case the selection will just be emptied.
*/
function setSelectionForwards(endpoints) {
selection.removeAllRanges();
if (endpoints.length) {
selection.addRange(rangeFromEndpoints(endpoints));
}
}
/**
* Given an array of endpoint data [start container, start offset, end
* container, end offset], sets the selection to have those endpoints, with the
* direction backwards. Uses extend, so it will throw in IE. Accepts an empty
* array for endpoints, in which case the selection will just be emptied.
*/
function setSelectionBackwards(endpoints) {
selection.removeAllRanges();
if (endpoints.length) {
selection.collapse(endpoints[2], endpoints[3]);
selection.extend(endpoints[0], endpoints[1]);
}
}

View File

@ -0,0 +1,33 @@
<!doctype html>
<title>Selection test iframe</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<body>
<script src=common.js></script>
<script>
"use strict";
// This script only exists because we want to evaluate the range endpoints
// in each iframe using that iframe's local variables set up by common.js. It
// just creates a range with the endpoints given by
// eval(window.testRangeInput), and assigns the result to window.testRange. If
// there's an exception, it's assigned to window.unexpectedException.
// Everything else is to be done by the script that created the iframe.
window.unexpectedException = null;
function run() {
window.unexpectedException = null;
try {
window.testRange = rangeFromEndpoints(eval(window.testRangeInput));
} catch(e) {
window.unexpectedException = e;
}
}
// Remove the scripts so they don't run repeatedly when the iframe is
// reinitialized
[].forEach.call(document.querySelectorAll("script"), function(script) {
script.parentNode.removeChild(script);
});
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,44 @@
<!doctype html>
<title>Selection Document.open() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
// This tests the HTML spec requirement "Replace the Document's singleton
// objects with new instances of those objects. (This includes in particular
// the Window, Location, History, ApplicationCache, and Navigator, objects, the
// various BarProp objects, the two Storage objects, the various HTMLCollection
// objects, and objects defined by other specifications, like Selection and the
// document's UndoManager. It also includes all the Web IDL prototypes in the
// JavaScript binding, including the Document object's prototype.)" in the
// document.open() algorithm.
var iframe = document.createElement("iframe");
var t = async_test("Selection must be replaced with a new object after document.open()");
iframe.onload = function() {
t.step(function() {
var originalSelection = iframe.contentWindow.getSelection();
assert_equals(originalSelection.rangeCount, 0,
"Sanity check: rangeCount must be initially 0");
iframe.contentDocument.body.appendChild(
iframe.contentDocument.createTextNode("foo"));
var range = iframe.contentDocument.createRange();
range.selectNodeContents(iframe.contentDocument.body);
iframe.contentWindow.getSelection().addRange(range);
assert_equals(originalSelection.rangeCount, 1,
"Sanity check: rangeCount must be 1 after adding a range");
iframe.contentDocument.open();
assert_not_equals(iframe.contentWindow.getSelection(), originalSelection,
"After document.open(), the Selection object must no longer be the same");
assert_equals(iframe.contentWindow.getSelection().rangeCount, 0,
"After document.open(), rangeCount must be 0 again");
});
t.done();
document.body.removeChild(iframe);
};
document.body.appendChild(iframe);
</script>

View File

@ -0,0 +1,177 @@
<!doctype html>
<title>Selection.addRange() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
function testAddRange(exception, range, endpoints, qualifier, testName) {
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
selection.addRange(range);
assert_equals(range.startContainer, endpoints[0],
"addRange() must not modify the startContainer of the Range it's given");
assert_equals(range.startOffset, endpoints[1],
"addRange() must not modify the startOffset of the Range it's given");
assert_equals(range.endContainer, endpoints[2],
"addRange() must not modify the endContainer of the Range it's given");
assert_equals(range.endOffset, endpoints[3],
"addRange() must not modify the endOffset of the Range it's given");
}, testName + ": " + qualifier + " addRange() must not throw exceptions or modify the range it's given");
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_equals(selection.rangeCount, 1, "rangeCount must be 1");
}, testName + ": " + qualifier + " addRange() must result in rangeCount being 1");
// From here on out we check selection.getRangeAt(selection.rangeCount - 1)
// so as not to double-fail Gecko.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
var newRange = selection.getRangeAt(selection.rangeCount - 1);
assert_not_equals(newRange, null,
"getRangeAt(rangeCount - 1) must not return null");
assert_equals(typeof newRange, "object",
"getRangeAt(rangeCount - 1) must return an object");
assert_equals(newRange.startContainer, range.startContainer,
"startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"endOffset of the Selection's last Range must match the added Range");
}, testName + ": " + qualifier + " addRange() must result in the selection's last range having the specified endpoints");
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
assert_equals(selection.getRangeAt(selection.rangeCount - 1), range,
"getRangeAt(rangeCount - 1) must return the same object we added");
}, testName + ": " + qualifier + " addRange() must result in the selection's last range being the same object we added");
// Let's not test many different modifications -- one should be enough.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
if (range.startContainer == paras[0].firstChild
&& range.startOffset == 0
&& range.endContainer == paras[0].firstChild
&& range.endOffset == 2) {
// Just in case . . .
range.setStart(paras[0].firstChild, 1);
} else {
range.setStart(paras[0].firstChild, 0);
range.setEnd(paras[0].firstChild, 2);
}
var newRange = selection.getRangeAt(selection.rangeCount - 1);
assert_equals(newRange.startContainer, range.startContainer,
"After mutating the " + qualifier + " added Range, startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"After mutating the " + qualifier + " added Range, startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"After mutating the " + qualifier + " added Range, endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"After mutating the " + qualifier + " added Range, endOffset of the Selection's last Range must match the added Range");
}, testName + ": modifying the " + qualifier + " added range must modify the Selection's last Range");
// Now test the other way too.
test(function() {
assert_equals(exception, null, "Test setup must not throw exceptions");
assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
var newRange = selection.getRangeAt(selection.rangeCount - 1);
if (newRange.startContainer == paras[0].firstChild
&& newRange.startOffset == 4
&& newRange.endContainer == paras[0].firstChild
&& newRange.endOffset == 6) {
newRange.setStart(paras[0].firstChild, 5);
} else {
newRange.setStart(paras[0].firstChild, 4);
newRange.setStart(paras[0].firstChild, 6);
}
assert_equals(newRange.startContainer, range.startContainer,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, startContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.startOffset, range.startOffset,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, startOffset of the Selection's last Range must match the added Range");
assert_equals(newRange.endContainer, range.endContainer,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, endContainer of the Selection's last Range must match the added Range");
assert_equals(newRange.endOffset, range.endOffset,
"After " + qualifier + " addRange(), after mutating the Selection's last Range, endOffset of the Selection's last Range must match the added Range");
}, testName + ": modifying the Selection's last Range must modify the " + qualifier + " added Range");
}
// Do only n evals, not n^2
var testRangesEvaled = testRanges.map(eval);
for (var i = 0; i < testRanges.length; i++) {
for (var j = 0; j < testRanges.length; j++) {
var testName = "Range " + i + " " + testRanges[i]
+ " followed by Range " + j + " " + testRanges[j];
var exception = null;
try {
selection.removeAllRanges();
var endpoints1 = testRangesEvaled[i];
var range1 = ownerDocument(endpoints1[0]).createRange();
range1.setStart(endpoints1[0], endpoints1[1]);
range1.setEnd(endpoints1[2], endpoints1[3]);
if (range1.startContainer !== endpoints1[0]) {
throw "Sanity check: the first Range we created must have the desired startContainer";
}
if (range1.startOffset !== endpoints1[1]) {
throw "Sanity check: the first Range we created must have the desired startOffset";
}
if (range1.endContainer !== endpoints1[2]) {
throw "Sanity check: the first Range we created must have the desired endContainer";
}
if (range1.endOffset !== endpoints1[3]) {
throw "Sanity check: the first Range we created must have the desired endOffset";
}
var endpoints2 = testRangesEvaled[j];
var range2 = ownerDocument(endpoints2[0]).createRange();
range2.setStart(endpoints2[0], endpoints2[1]);
range2.setEnd(endpoints2[2], endpoints2[3]);
if (range2.startContainer !== endpoints2[0]) {
throw "Sanity check: the second Range we created must have the desired startContainer";
}
if (range2.startOffset !== endpoints2[1]) {
throw "Sanity check: the second Range we created must have the desired startOffset";
}
if (range2.endContainer !== endpoints2[2]) {
throw "Sanity check: the second Range we created must have the desired endContainer";
}
if (range2.endOffset !== endpoints2[3]) {
throw "Sanity check: the second Range we created must have the desired endOffset";
}
} catch (e) {
exception = e;
}
testAddRange(exception, range1, endpoints1, "first", testName);
testAddRange(exception, range2, endpoints2, "second", testName);
}
}
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,87 @@
<!doctype html>
<title>Selection.collapse() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
function testCollapse(range, point) {
selection.removeAllRanges();
var addedRange;
if (range) {
addedRange = range.cloneRange();
selection.addRange(addedRange);
}
if (point[0].nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.collapse(point[0], point[1]);
}, "Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType");
return;
}
if (point[1] < 0 || point[1] > getNodeLength(point[0])) {
assert_throws("INDEX_SIZE_ERR", function() {
selection.collapse(point[0], point[1]);
}, "Must throw INDEX_SIZE_ERR when collapse()ing if the offset is negative or greater than the node's length");
return;
}
selection.collapse(point[0], point[1]);
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1 after collapse()");
assert_equals(selection.focusNode, point[0],
"focusNode must equal the node we collapse()d to");
assert_equals(selection.focusOffset, point[1],
"focusOffset must equal the offset we collapse()d to");
assert_equals(selection.focusNode, selection.anchorNode,
"focusNode and anchorNode must be equal after collapse()");
assert_equals(selection.focusOffset, selection.anchorOffset,
"focusOffset and anchorOffset must be equal after collapse()");
if (range) {
assert_equals(addedRange.startContainer, range.startContainer,
"collapse() must not change the startContainer of a preexisting Range");
assert_equals(addedRange.endContainer, range.endContainer,
"collapse() must not change the endContainer of a preexisting Range");
assert_equals(addedRange.startOffset, range.startOffset,
"collapse() must not change the startOffset of a preexisting Range");
assert_equals(addedRange.endOffset, range.endOffset,
"collapse() must not change the endOffset of a preexisting Range");
}
}
// Also test a selection with no ranges
testRanges.unshift("[]");
// Don't want to eval() each point a bazillion times
var testPointsCached = [];
for (var i = 0; i < testPoints.length; i++) {
testPointsCached.push(eval(testPoints[i]));
}
var tests = [];
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
var range;
test(function() {
if (endpoints.length) {
range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
} else {
// Empty selection
range = null;
}
}, "Set up range " + i + " " + testRanges[i]);
for (var j = 0; j < testPoints.length; j++) {
tests.push(["Range " + i + " " + testRanges[i] + ", point " + j + " " + testPoints[j], range, testPointsCached[j]]);
}
}
generate_tests(testCollapse, tests);
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,121 @@
<!doctype html>
<title>Selection.collapseTo(Start|End)() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
for (var i = 0; i < testRanges.length; i++) {
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
if (!endpoints.length) {
assert_throws("INVALID_STATE_ERR", function() {
selection.collapseToStart();
}, "Must throw InvalidStateErr if the selection's range is null");
return;
}
var addedRange = ownerDocument(endpoints[0]).createRange();
addedRange.setStart(endpoints[0], endpoints[1]);
addedRange.setEnd(endpoints[2], endpoints[3]);
selection.addRange(addedRange);
// We don't penalize browsers here for mishandling addRange() and
// adding a different range than we specified. They fail addRange()
// tests for that, and don't have to fail collapseToStart/End() tests
// too. They do fail if they throw unexpectedly, though. I also fail
// them if there's no range at all, because otherwise they could pass
// all tests if addRange() always does nothing and collapseToStart()
// always throws.
assert_equals(selection.rangeCount, 1,
"Sanity check: rangeCount must equal 1 after addRange()");
var expectedEndpoint = [
selection.getRangeAt(0).startContainer,
selection.getRangeAt(0).startOffset
];
selection.collapseToStart();
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1");
assert_equals(selection.focusNode, expectedEndpoint[0],
"focusNode must equal the original start node");
assert_equals(selection.focusOffset, expectedEndpoint[1],
"focusOffset must equal the original start offset");
assert_equals(selection.anchorNode, expectedEndpoint[0],
"anchorNode must equal the original start node");
assert_equals(selection.anchorOffset, expectedEndpoint[1],
"anchorOffset must equal the original start offset");
assert_equals(addedRange.startContainer, endpoints[0],
"collapseToStart() must not change the startContainer of the selection's original range");
assert_equals(addedRange.startOffset, endpoints[1],
"collapseToStart() must not change the startOffset of the selection's original range");
assert_equals(addedRange.endContainer, endpoints[2],
"collapseToStart() must not change the endContainer of the selection's original range");
assert_equals(addedRange.endOffset, endpoints[3],
"collapseToStart() must not change the endOffset of the selection's original range");
}, "Range " + i + " " + testRanges[i] + " collapseToStart()");
// Copy-paste of above
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
if (!endpoints.length) {
assert_throws("INVALID_STATE_ERR", function() {
selection.collapseToEnd();
}, "Must throw InvalidStateErr if the selection's range is null");
return;
}
var addedRange = ownerDocument(endpoints[0]).createRange();
addedRange.setStart(endpoints[0], endpoints[1]);
addedRange.setEnd(endpoints[2], endpoints[3]);
selection.addRange(addedRange);
// We don't penalize browsers here for mishandling addRange() and
// adding a different range than we specified. They fail addRange()
// tests for that, and don't have to fail collapseToStart/End() tests
// too. They do fail if they throw unexpectedly, though. I also fail
// them if there's no range at all, because otherwise they could pass
// all tests if addRange() always does nothing and collapseToStart()
// always throws.
assert_equals(selection.rangeCount, 1,
"Sanity check: rangeCount must equal 1 after addRange()");
var expectedEndpoint = [
selection.getRangeAt(0).endContainer,
selection.getRangeAt(0).endOffset
];
selection.collapseToEnd();
assert_equals(selection.rangeCount, 1,
"selection.rangeCount must equal 1");
assert_equals(selection.focusNode, expectedEndpoint[0],
"focusNode must equal the original end node");
assert_equals(selection.focusOffset, expectedEndpoint[1],
"focusOffset must equal the original end offset");
assert_equals(selection.anchorNode, expectedEndpoint[0],
"anchorNode must equal the original end node");
assert_equals(selection.anchorOffset, expectedEndpoint[1],
"anchorOffset must equal the original end offset");
assert_equals(addedRange.startContainer, endpoints[0],
"collapseToEnd() must not change the startContainer of the selection's original range");
assert_equals(addedRange.startOffset, endpoints[1],
"collapseToEnd() must not change the startOffset of the selection's original range");
assert_equals(addedRange.endContainer, endpoints[2],
"collapseToEnd() must not change the endContainer of the selection's original range");
assert_equals(addedRange.endOffset, endpoints[3],
"collapseToEnd() must not change the endOffset of the selection's original range");
}, "Range " + i + " " + testRanges[i] + " collapseToEnd()");
}
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,97 @@
<!doctype html>
<title>Selection.deleteFromDocument() tests</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<p>To debug test failures, add a query parameter with the test id (like
"?5"). Only that test will be run. Then you can look at the resulting
iframes in the DOM.
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// We need to use explicit_done, because in Chrome 16 dev and Opera 12.00, the
// second iframe doesn't block the load event -- even though it is added before
// the load event.
setup({explicit_done: true});
// Specified by WebIDL
test(function() {
assert_equals(Selection.prototype.deleteFromDocument.length, 0,
"Selection.prototype.deleteFromDocument.length must equal 0");
}, "Selection.prototype.deleteFromDocument.length must equal 0");
testDiv.parentNode.removeChild(testDiv);
// Test an empty selection too
testRanges.unshift("empty");
var actualIframe = document.createElement("iframe");
var expectedIframe = document.createElement("iframe");
var referenceDoc = document.implementation.createHTMLDocument("");
referenceDoc.removeChild(referenceDoc.documentElement);
actualIframe.onload = function() {
expectedIframe.onload = function() {
for (var i = 0; i < testRanges.length; i++) {
if (location.search && i != Number(location.search)) {
continue;
}
test(function() {
initializeIframe(actualIframe, testRanges[i]);
initializeIframe(expectedIframe, testRanges[i]);
var actualRange = actualIframe.contentWindow.testRange;
var expectedRange = expectedIframe.contentWindow.testRange;
assert_equals(actualIframe.contentWindow.unexpectedException, null,
"Unexpected exception thrown when setting up Range for actual deleteFromDocument");
assert_equals(expectedIframe.contentWindow.unexpectedException, null,
"Unexpected exception thrown when setting up Range for simulated deleteFromDocument");
actualIframe.contentWindow.getSelection().removeAllRanges();
if (testRanges[i] != "empty") {
assert_equals(typeof actualRange, "object",
"Range produced in actual iframe must be an object");
assert_equals(typeof expectedRange, "object",
"Range produced in expected iframe must be an object");
assert_true(actualRange instanceof actualIframe.contentWindow.Range,
"Range produced in actual iframe must be instanceof Range");
assert_true(expectedRange instanceof expectedIframe.contentWindow.Range,
"Range produced in expected iframe must be instanceof Range");
actualIframe.contentWindow.getSelection().addRange(actualIframe.contentWindow.testRange);
expectedIframe.contentWindow.testRange.deleteContents();
}
actualIframe.contentWindow.getSelection().deleteFromDocument();
assertNodesEqual(actualIframe.contentDocument, expectedIframe.contentDocument, "DOM contents");
}, "Range " + i + ": " + testRanges[i]);
}
actualIframe.style.display = "none";
expectedIframe.style.display = "none";
done();
};
expectedIframe.src = "test-iframe.html";
document.body.appendChild(expectedIframe);
referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true));
};
actualIframe.src = "test-iframe.html";
document.body.appendChild(actualIframe);
function initializeIframe(iframe, endpoints) {
while (iframe.contentDocument.firstChild) {
iframe.contentDocument.removeChild(iframe.contentDocument.lastChild);
}
iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", ""));
iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true));
iframe.contentWindow.setupRangeTests();
if (endpoints != "empty") {
iframe.contentWindow.testRangeInput = endpoints;
iframe.contentWindow.run();
}
}
</script>

View File

@ -0,0 +1,148 @@
<!doctype html>
<title>Selection extend() tests</title>
<meta charset=utf-8>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<div id=log></div>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
/**
* We test Selections that go both forwards and backwards here. In the latter
* case we need to use extend() to force it to go backwards, which is fair
* enough, since that's what we're testing. We test collapsed selections only
* once.
*/
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
for (var j = 0; j < testPoints.length; j++) {
if (endpoints[0] == endpoints[2]
&& endpoints[1] == endpoints[3]) {
// Test collapsed selections only once
test(function() {
setSelectionForwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
} else {
test(function() {
setSelectionForwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() forwards with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
test(function() {
setSelectionBackwards(endpoints);
testExtend(endpoints, eval(testPoints[j]));
}, "extend() backwards with range " + i + " " + testRanges[i]
+ " and point " + j + " " + testPoints[j]);
}
}
}
function testExtend(endpoints, target) {
assert_equals(getSelection().rangeCount, endpoints.length/4,
"Sanity check: rangeCount must be correct");
var node = target[0];
var offset = target[1];
// "If the context object's range is null, throw an InvalidStateError
// exception and abort these steps."
if (getSelection().rangeCount == 0) {
assert_throws("INVALID_STATE_ERR", function() {
selection.extend(node, offset);
}, "extend() when rangeCount is 0 must throw InvalidStateError");
return;
}
assert_equals(getSelection().getRangeAt(0).startContainer, endpoints[0],
"Sanity check: startContainer must be correct");
assert_equals(getSelection().getRangeAt(0).startOffset, endpoints[1],
"Sanity check: startOffset must be correct");
assert_equals(getSelection().getRangeAt(0).endContainer, endpoints[2],
"Sanity check: endContainer must be correct");
assert_equals(getSelection().getRangeAt(0).endOffset, endpoints[3],
"Sanity check: endOffset must be correct");
// "Let anchor and focus be the context object's anchor and focus, and let
// new focus be the boundary point (node, offset)."
var anchorNode = getSelection().anchorNode;
var anchorOffset = getSelection().anchorOffset;
var focusNode = getSelection().focusNode;
var focusOffset = getSelection().focusOffset;
// "Let new range be a new range."
//
// We'll always be setting either new range's start or its end to new
// focus, so we'll always throw at some point. Test that now.
//
// From DOM4's "set the start or end of a range": "If node is a doctype,
// throw an "InvalidNodeTypeError" exception and terminate these steps."
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.extend(node, offset);
}, "extend() to a doctype must throw InvalidNodeTypeError");
return;
}
// From DOM4's "set the start or end of a range": "If offset is greater
// than node's length, throw an "IndexSizeError" exception and terminate
// these steps."
//
// FIXME: We should be casting offset to an unsigned int per WebIDL. Until
// we do, we need the offset < 0 check too.
if (offset < 0 || offset > getNodeLength(node)) {
assert_throws("INDEX_SIZE_ERR", function() {
selection.extend(node, offset);
}, "extend() to an offset that's greater than node length (" + getNodeLength(node) + ") must throw IndexSizeError");
return;
}
// Now back to the editing spec.
var originalRange = getSelection().getRangeAt(0);
// "If node's root is not the same as the context object's range's root,
// set new range's start and end to (node, offset)."
//
// "Otherwise, if anchor is before or equal to new focus, set new range's
// start to anchor, then set its end to new focus."
//
// "Otherwise, set new range's start to new focus, then set its end to
// anchor."
//
// "Set the context object's range to new range."
//
// "If new focus is before anchor, set the context object's direction to
// backwards. Otherwise, set it to forwards."
//
// The upshot of all these is summed up by just testing the anchor and
// offset.
getSelection().extend(node, offset);
if (furthestAncestor(anchorNode) == furthestAncestor(node)) {
assert_equals(getSelection().anchorNode, anchorNode,
"anchorNode must not change if the node passed to extend() has the same root as the original range");
assert_equals(getSelection().anchorOffset, anchorOffset,
"anchorOffset must not change if the node passed to extend() has the same root as the original range");
} else {
assert_equals(getSelection().anchorNode, node,
"anchorNode must be the node passed to extend() if it has a different root from the original range");
assert_equals(getSelection().anchorOffset, offset,
"anchorOffset must be the offset passed to extend() if the node has a different root from the original range");
}
assert_equals(getSelection().focusNode, node,
"focusNode must be the node passed to extend()");
assert_equals(getSelection().focusOffset, offset,
"focusOffset must be the offset passed to extend()");
assert_not_equals(getSelection().getRangeAt(0), originalRange,
"extend() must replace any existing range with a new one, not mutate the existing one");
}
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<title>The getRangeAt method</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
test(function() {
var sel = getSelection();
var range = document.createRange();
sel.addRange(range);
assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(-1); })
assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(1); })
});
</script>

View File

@ -0,0 +1,160 @@
<!doctype html>
<title>getSelection() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";
// TODO: Figure out more places where defaultView is or is not guaranteed to be
// null, and test whether getSelection() is null.
//
// TODO: Figure out a good way to test display: none iframes.
test(function() {
// Sanity checks like this are to flag known browser bugs with clearer
// error messages, instead of throwing inscrutable exceptions.
assert_true("Selection" in window,
"Sanity check: window must have Selection property");
assert_true(window.getSelection() instanceof Selection);
}, "window.getSelection() instanceof Selection");
test(function() {
assert_equals(window.getSelection(), window.getSelection());
}, "window.getSelection() === window.getSelection()");
test(function() {
assert_true("Selection" in window,
"Sanity check: window must have Selection property");
// This sanity check (which occurs a number of times below, too) is because
// document.getSelection() is supposed to return null if defaultView is
// null, so we need to figure out whether defaultView is null or not before
// we can make correct assertions about getSelection().
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(typeof document.getSelection(), "object",
"document.getSelection() must be an object");
assert_true(document.getSelection() instanceof Selection);
}, "document.getSelection() instanceof Selection");
test(function() {
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(document.getSelection(), document.getSelection());
}, "document.getSelection() === document.getSelection()");
test(function() {
assert_not_equals(document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(window.getSelection(), document.getSelection());
}, "window.getSelection() === document.getSelection()");
// "Each selection is associated with a single range, which may be null and is
// initially null."
//
// "The rangeCount attribute must return 0 if the context object's range is
// null, otherwise 1."
test(function() {
assert_equals(window.getSelection().rangeCount, 0,
"window.getSelection().rangeCount must initially be 0");
assert_equals(typeof document.getSelection(), "object",
"Sanity check: document.getSelection() must be an object");
assert_equals(document.getSelection().rangeCount, 0,
"document.getSelection().rangeCount must initially be 0");
}, "Selection's range must initially be null");
test(function() {
var doc = document.implementation.createHTMLDocument("");
assert_equals(doc.defaultView, null,
"Sanity check: defaultView of created HTML document must be null");
assert_equals(doc.getSelection(), null);
}, "getSelection() on HTML document with null defaultView must be null");
test(function() {
var xmlDoc = document.implementation.createDocument(null, "", null);
assert_true("getSelection" in xmlDoc, "XML document must have getSelection()");
assert_equals(xmlDoc.defaultView, null,
"Sanity check: defaultView of created XML document must be null");
assert_equals(xmlDoc.getSelection(), null);
}, "getSelection() on XML document with null defaultView must be null");
// Run a bunch of iframe tests, once immediately after the iframe is appended
// to the document and once onload. This makes a difference, because browsers
// differ (at the time of this writing) in whether they load about:blank in
// iframes synchronously or not. Per the HTML spec, there must be a browsing
// context associated with the iframe as soon as it's appended to the document,
// so there should be a selection too.
var iframe = document.createElement("iframe");
add_completion_callback(function() {
document.body.removeChild(iframe);
});
var testDescs = [];
var testFuncs = [];
testDescs.push("window.getSelection() instanceof Selection in an iframe");
testFuncs.push(function() {
assert_true("Selection" in iframe.contentWindow,
"Sanity check: window must have Selection property");
assert_not_equals(iframe.contentWindow.document.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_not_equals(iframe.contentWindow.getSelection(), null,
"window.getSelection() must not be null");
assert_true(iframe.contentWindow.getSelection() instanceof iframe.contentWindow.Selection);
});
testDescs.push("document.getSelection() instanceof Selection in an iframe");
testFuncs.push(function() {
assert_true("Selection" in iframe.contentWindow,
"Sanity check: window must have Selection property");
assert_not_equals(iframe.contentDocument.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_not_equals(iframe.contentDocument.getSelection(), null,
"document.getSelection() must not be null");
assert_equals(typeof iframe.contentDocument.getSelection(), "object",
"document.getSelection() must be an object");
assert_true(iframe.contentDocument.getSelection() instanceof iframe.contentWindow.Selection);
});
testDescs.push("window.getSelection() === document.getSelection() in an iframe");
testFuncs.push(function() {
assert_not_equals(iframe.contentDocument.defaultView, null,
"Sanity check: document.defaultView must not be null");
assert_equals(iframe.contentWindow.getSelection(), iframe.contentDocument.getSelection());
});
testDescs.push("getSelection() inside and outside iframe must return different objects");
testFuncs.push(function() {
assert_not_equals(iframe.contentWindow.getSelection(), getSelection());
});
testDescs.push("getSelection() on HTML document with null defaultView must be null inside an iframe");
testFuncs.push(function() {
var doc = iframe.contentDocument.implementation.createHTMLDocument("");
assert_equals(doc.defaultView, null,
"Sanity check: defaultView of created HTML document must be null");
assert_equals(doc.getSelection(), null);
});
var asyncTests = [];
testDescs.forEach(function(desc) {
asyncTests.push(async_test(desc + " onload"));
});
iframe.onload = function() {
asyncTests.forEach(function(t, i) {
t.step(testFuncs[i]);
t.done();
});
};
document.body.appendChild(iframe);
testDescs.forEach(function(desc, i) {
test(testFuncs[i], desc + " immediately after appendChild");
});
</script>

View File

@ -0,0 +1,41 @@
<!doctype html>
<title>Selection interface tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<script type=text/plain>
interface Selection {
readonly attribute Node? anchorNode;
readonly attribute unsigned long anchorOffset;
readonly attribute Node? focusNode;
readonly attribute unsigned long focusOffset;
readonly attribute boolean isCollapsed;
void collapse(Node node, unsigned long offset);
void collapseToStart();
void collapseToEnd();
void extend(Node node, unsigned long offset);
void selectAllChildren(Node node);
void deleteFromDocument();
readonly attribute unsigned long rangeCount;
Range getRangeAt(unsigned long index);
void addRange(Range range);
void removeRange(Range range);
void removeAllRanges();
stringifier;
};
</script>
<script>
"use strict";
var idlArray = new IdlArray();
idlArray.add_idls(document.querySelector("script[type=text\\/plain]").textContent);
idlArray.add_objects({Selection: ['getSelection()']});
idlArray.test();
</script>

View File

@ -0,0 +1,31 @@
<!doctype html>
<title>Selection.isCollapsed tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
test(function() {
selection.removeAllRanges();
assert_true(selection.isCollapsed, "isCollapsed must be true if both anchor and focus are null");
}, "Empty selection");
for (var i = 0; i < testRanges.length; i++) {
test(function() {
selection.removeAllRanges();
var endpoints = eval(testRanges[i]);
var range = ownerDocument(endpoints[0]).createRange();
range.setStart(endpoints[0], endpoints[1]);
range.setEnd(endpoints[2], endpoints[3]);
selection.addRange(range);
assert_equals(selection.isCollapsed,
endpoints[0] === endpoints[2] && endpoints[1] === endpoints[3],
"Value of isCollapsed");
}, "Range " + i + " " + testRanges[i]);
}
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,45 @@
<!doctype html>
<title>Selection.removeAllRanges() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
// Also test a selection with no ranges
testRanges.unshift("[]");
var range = rangeFromEndpoints([paras[0].firstChild, 0, paras[0].firstChild, 1]);
for (var i = 0; i < testRanges.length; i++) {
test(function() {
setSelectionForwards(eval(testRanges[i]));
selection.removeAllRanges();
assert_equals(selection.rangeCount, 0,
"After removeAllRanges(), rangeCount must be 0");
// Test that it's forwards
selection.addRange(range);
assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset,
"After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset");
assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset,
"After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset");
}, "Range " + i + " " + testRanges[i] + " forwards");
// Copy-pasted from above
test(function() {
setSelectionBackwards(eval(testRanges[i]));
selection.removeAllRanges();
assert_equals(selection.rangeCount, 0,
"After removeAllRanges(), rangeCount must be 0");
// Test that it's forwards
selection.addRange(range);
assert_equals(selection.anchorOffset, selection.getRangeAt(0).startOffset,
"After removeAllRanges(), addRange() must be forwards, so anchorOffset must equal startOffset rather than endOffset");
assert_equals(selection.focusOffset, selection.getRangeAt(0).endOffset,
"After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset");
}, "Range " + i + " " + testRanges[i] + " backwards");
}
testDiv.style.display = "none";
</script>

View File

@ -0,0 +1,53 @@
<!doctype html>
<title>Selection.selectAllChildren tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=common.js></script>
<script>
"use strict";
testRanges.unshift("[]");
for (var i = 0; i < testRanges.length; i++) {
var endpoints = eval(testRanges[i]);
for (var j = 0; j < testNodes.length; j++) {
var node = eval(testNodes[j]);
test(function() {
setSelectionForwards(endpoints);
var originalRange = getSelection().rangeCount
? getSelection().getRangeAt(0)
: null;
if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
assert_throws("INVALID_NODE_TYPE_ERR", function() {
selection.selectAllChildren(node);
}, "selectAllChildren() on a DocumentType must throw InvalidNodeTypeError");
return;
}
selection.selectAllChildren(node);
// This implicitly tests that the selection is forwards, by using
// anchorOffset/focusOffset instead of getRangeAt.
assert_equals(selection.rangeCount, 1,
"After selectAllChildren, rangeCount must be 1");
assert_equals(selection.anchorNode, node,
"After selectAllChildren, anchorNode must be the given node");
assert_equals(selection.anchorOffset, 0,
"After selectAllChildren, anchorOffset must be 0");
assert_equals(selection.focusNode, node,
"After selectAllChildren, focusNode must be the given node");
assert_equals(selection.focusOffset, node.childNodes.length,
"After selectAllChildren, focusOffset must be the given node's number of children");
if (originalRange) {
assert_not_equals(getSelection().getRangeAt(0), originalRange,
"selectAllChildren must replace any existing range, not mutate it");
}
}, "Range " + i + " " + testRanges[i] + ", node " + j + " " + testNodes[j]);
}
}
testDiv.style.display = "none";
</script>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/editing/conformancetest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_event.html.json \
test_runtest.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,310 @@
{
"Simple editable div: beforeinput event, canceled":true,
"Simple editable div: input event, canceled":true,
"Simple editable div: beforeinput event, uncanceled":true,
"Simple editable div: input event, uncanceled":true,
"Editable b: execCommand() must not throw, canceled":true,
"Editable b: beforeinput event, canceled":true,
"Editable b: input event, canceled":true,
"Editable b: execCommand() must not throw, uncanceled":true,
"Editable b: beforeinput event, uncanceled":true,
"Editable b: input event, uncanceled":true,
"No editable content: execCommand() must not throw, canceled":true,
"No editable content: execCommand() must not throw, uncanceled":true,
"Changing selection from handler: beforeinput event, canceled":true,
"Changing selection from handler: input event, canceled":true,
"Changing selection from handler: beforeinput event, uncanceled":true,
"Changing selection from handler: input event, uncanceled":true,
"Command backColor, value \"\": beforeinput event, canceled":true,
"Command backColor, value \"\": beforeinput event, uncanceled":true,
"Command backColor, value \"\": input event, uncanceled":true,
"Command backColor, value \"quasit\": beforeinput event, canceled":true,
"Command backColor, value \"quasit\": input event, canceled":true,
"Command backColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command backColor, value \"quasit\": input event, uncanceled":true,
"Command backColor, value \"green\": beforeinput event, canceled":true,
"Command backColor, value \"green\": input event, canceled":true,
"Command backColor, value \"green\": beforeinput event, uncanceled":true,
"Command backColor, value \"green\": input event, uncanceled":true,
"Command createLink, value \"\": execCommand() must not throw, canceled":true,
"Command createLink, value \"\": beforeinput event, canceled":true,
"Command createLink, value \"\": execCommand() must not throw, uncanceled":true,
"Command createLink, value \"\": beforeinput event, uncanceled":true,
"Command createLink, value \"\": input event, uncanceled":true,
"Command createLink, value \"quasit\": beforeinput event, canceled":true,
"Command createLink, value \"quasit\": input event, canceled":true,
"Command createLink, value \"quasit\": beforeinput event, uncanceled":true,
"Command createLink, value \"quasit\": input event, uncanceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": beforeinput event, canceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": input event, canceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": beforeinput event, uncanceled":true,
"Command createLink, value \"http://www.w3.org/community/editing/\": input event, uncanceled":true,
"Command fontName, value \"\": beforeinput event, canceled":true,
"Command fontName, value \"\": beforeinput event, uncanceled":true,
"Command fontName, value \"\": input event, uncanceled":true,
"Command fontName, value \"quasit\": beforeinput event, canceled":true,
"Command fontName, value \"quasit\": input event, canceled":true,
"Command fontName, value \"quasit\": beforeinput event, uncanceled":true,
"Command fontName, value \"quasit\": input event, uncanceled":true,
"Command fontName, value \"serif\": beforeinput event, canceled":true,
"Command fontName, value \"serif\": input event, canceled":true,
"Command fontName, value \"serif\": beforeinput event, uncanceled":true,
"Command fontName, value \"serif\": input event, uncanceled":true,
"Command fontName, value \"Helvetica\": beforeinput event, canceled":true,
"Command fontName, value \"Helvetica\": input event, canceled":true,
"Command fontName, value \"Helvetica\": beforeinput event, uncanceled":true,
"Command fontName, value \"Helvetica\": input event, uncanceled":true,
"Command fontSize, value \"\": beforeinput event, canceled":true,
"Command fontSize, value \"\": beforeinput event, uncanceled":true,
"Command fontSize, value \"\": input event, uncanceled":true,
"Command fontSize, value \"quasit\": beforeinput event, canceled":true,
"Command fontSize, value \"quasit\": beforeinput event, uncanceled":true,
"Command fontSize, value \"quasit\": input event, uncanceled":true,
"Command fontSize, value \"6\": beforeinput event, canceled":true,
"Command fontSize, value \"6\": input event, canceled":true,
"Command fontSize, value \"6\": beforeinput event, uncanceled":true,
"Command fontSize, value \"6\": input event, uncanceled":true,
"Command fontSize, value \"15px\": beforeinput event, canceled":true,
"Command fontSize, value \"15px\": input event, canceled":true,
"Command fontSize, value \"15px\": beforeinput event, uncanceled":true,
"Command fontSize, value \"15px\": input event, uncanceled":true,
"Command foreColor, value \"\": beforeinput event, canceled":true,
"Command foreColor, value \"\": beforeinput event, uncanceled":true,
"Command foreColor, value \"\": input event, uncanceled":true,
"Command foreColor, value \"quasit\": beforeinput event, canceled":true,
"Command foreColor, value \"quasit\": input event, canceled":true,
"Command foreColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command foreColor, value \"quasit\": input event, uncanceled":true,
"Command foreColor, value \"green\": beforeinput event, canceled":true,
"Command foreColor, value \"green\": input event, canceled":true,
"Command foreColor, value \"green\": beforeinput event, uncanceled":true,
"Command foreColor, value \"green\": input event, uncanceled":true,
"Command hiliteColor, value \"\": beforeinput event, canceled":true,
"Command hiliteColor, value \"\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"\": input event, uncanceled":true,
"Command hiliteColor, value \"quasit\": beforeinput event, canceled":true,
"Command hiliteColor, value \"quasit\": input event, canceled":true,
"Command hiliteColor, value \"quasit\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"quasit\": input event, uncanceled":true,
"Command hiliteColor, value \"green\": beforeinput event, canceled":true,
"Command hiliteColor, value \"green\": input event, canceled":true,
"Command hiliteColor, value \"green\": beforeinput event, uncanceled":true,
"Command hiliteColor, value \"green\": input event, uncanceled":true,
"Command italic, value \"\": beforeinput event, canceled":true,
"Command italic, value \"\": input event, canceled":true,
"Command italic, value \"\": beforeinput event, uncanceled":true,
"Command italic, value \"\": input event, uncanceled":true,
"Command italic, value \"quasit\": beforeinput event, canceled":true,
"Command italic, value \"quasit\": input event, canceled":true,
"Command italic, value \"quasit\": beforeinput event, uncanceled":true,
"Command italic, value \"quasit\": input event, uncanceled":true,
"Command removeFormat, value \"\": beforeinput event, canceled":true,
"Command removeFormat, value \"\": input event, canceled":true,
"Command removeFormat, value \"\": beforeinput event, uncanceled":true,
"Command removeFormat, value \"\": input event, uncanceled":true,
"Command removeFormat, value \"quasit\": beforeinput event, canceled":true,
"Command removeFormat, value \"quasit\": input event, canceled":true,
"Command removeFormat, value \"quasit\": beforeinput event, uncanceled":true,
"Command removeFormat, value \"quasit\": input event, uncanceled":true,
"Command strikeThrough, value \"\": beforeinput event, canceled":true,
"Command strikeThrough, value \"\": input event, canceled":true,
"Command strikeThrough, value \"\": beforeinput event, uncanceled":true,
"Command strikeThrough, value \"\": input event, uncanceled":true,
"Command strikeThrough, value \"quasit\": beforeinput event, canceled":true,
"Command strikeThrough, value \"quasit\": input event, canceled":true,
"Command strikeThrough, value \"quasit\": beforeinput event, uncanceled":true,
"Command strikeThrough, value \"quasit\": input event, uncanceled":true,
"Command subscript, value \"\": beforeinput event, canceled":true,
"Command subscript, value \"\": input event, canceled":true,
"Command subscript, value \"\": beforeinput event, uncanceled":true,
"Command subscript, value \"\": input event, uncanceled":true,
"Command subscript, value \"quasit\": beforeinput event, canceled":true,
"Command subscript, value \"quasit\": input event, canceled":true,
"Command subscript, value \"quasit\": beforeinput event, uncanceled":true,
"Command subscript, value \"quasit\": input event, uncanceled":true,
"Command superscript, value \"\": beforeinput event, canceled":true,
"Command superscript, value \"\": input event, canceled":true,
"Command superscript, value \"\": beforeinput event, uncanceled":true,
"Command superscript, value \"\": input event, uncanceled":true,
"Command superscript, value \"quasit\": beforeinput event, canceled":true,
"Command superscript, value \"quasit\": input event, canceled":true,
"Command superscript, value \"quasit\": beforeinput event, uncanceled":true,
"Command superscript, value \"quasit\": input event, uncanceled":true,
"Command underline, value \"\": beforeinput event, canceled":true,
"Command underline, value \"\": input event, canceled":true,
"Command underline, value \"\": beforeinput event, uncanceled":true,
"Command underline, value \"\": input event, uncanceled":true,
"Command underline, value \"quasit\": beforeinput event, canceled":true,
"Command underline, value \"quasit\": input event, canceled":true,
"Command underline, value \"quasit\": beforeinput event, uncanceled":true,
"Command underline, value \"quasit\": input event, uncanceled":true,
"Command unlink, value \"\": beforeinput event, canceled":true,
"Command unlink, value \"\": beforeinput event, uncanceled":true,
"Command unlink, value \"\": input event, uncanceled":true,
"Command unlink, value \"quasit\": beforeinput event, canceled":true,
"Command unlink, value \"quasit\": beforeinput event, uncanceled":true,
"Command unlink, value \"quasit\": input event, uncanceled":true,
"Command delete, value \"\": beforeinput event, canceled":true,
"Command delete, value \"\": input event, canceled":true,
"Command delete, value \"\": beforeinput event, uncanceled":true,
"Command delete, value \"\": input event, uncanceled":true,
"Command delete, value \"quasit\": beforeinput event, canceled":true,
"Command delete, value \"quasit\": input event, canceled":true,
"Command delete, value \"quasit\": beforeinput event, uncanceled":true,
"Command delete, value \"quasit\": input event, uncanceled":true,
"Command formatBlock, value \"\": beforeinput event, canceled":true,
"Command formatBlock, value \"\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"\": input event, uncanceled":true,
"Command formatBlock, value \"quasit\": beforeinput event, canceled":true,
"Command formatBlock, value \"quasit\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"quasit\": input event, uncanceled":true,
"Command formatBlock, value \"p\": beforeinput event, canceled":true,
"Command formatBlock, value \"p\": input event, canceled":true,
"Command formatBlock, value \"p\": beforeinput event, uncanceled":true,
"Command formatBlock, value \"p\": input event, uncanceled":true,
"Command forwardDelete, value \"\": beforeinput event, canceled":true,
"Command forwardDelete, value \"\": beforeinput event, uncanceled":true,
"Command forwardDelete, value \"\": input event, uncanceled":true,
"Command forwardDelete, value \"quasit\": beforeinput event, canceled":true,
"Command forwardDelete, value \"quasit\": beforeinput event, uncanceled":true,
"Command forwardDelete, value \"quasit\": input event, uncanceled":true,
"Command indent, value \"\": beforeinput event, canceled":true,
"Command indent, value \"\": input event, canceled":true,
"Command indent, value \"\": beforeinput event, uncanceled":true,
"Command indent, value \"\": input event, uncanceled":true,
"Command indent, value \"quasit\": beforeinput event, canceled":true,
"Command indent, value \"quasit\": input event, canceled":true,
"Command indent, value \"quasit\": beforeinput event, uncanceled":true,
"Command indent, value \"quasit\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"\": input event, canceled":true,
"Command insertHorizontalRule, value \"\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"quasit\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"quasit\": input event, canceled":true,
"Command insertHorizontalRule, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"quasit\": input event, uncanceled":true,
"Command insertHorizontalRule, value \"id\": beforeinput event, canceled":true,
"Command insertHorizontalRule, value \"id\": input event, canceled":true,
"Command insertHorizontalRule, value \"id\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"id\": input event, uncanceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, canceled":true,
"Command insertHTML, value \"\": beforeinput event, canceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, uncanceled":true,
"Command insertHTML, value \"\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"\": input event, uncanceled":true,
"Command insertHTML, value \"quasit\": beforeinput event, canceled":true,
"Command insertHTML, value \"quasit\": input event, canceled":true,
"Command insertHTML, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"quasit\": input event, uncanceled":true,
"Command insertHTML, value \"<b>hi</b>\": beforeinput event, canceled":true,
"Command insertHTML, value \"<b>hi</b>\": input event, canceled":true,
"Command insertHTML, value \"<b>hi</b>\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"<b>hi</b>\": input event, uncanceled":true,
"Command insertImage, value \"\": execCommand() must not throw, canceled":true,
"Command insertImage, value \"\": beforeinput event, canceled":true,
"Command insertImage, value \"\": execCommand() must not throw, uncanceled":true,
"Command insertImage, value \"\": beforeinput event, uncanceled":true,
"Command insertImage, value \"\": input event, uncanceled":true,
"Command insertImage, value \"quasit\": beforeinput event, canceled":true,
"Command insertImage, value \"quasit\": input event, canceled":true,
"Command insertImage, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertImage, value \"quasit\": input event, uncanceled":true,
"Command insertImage, value \"http://example.com/some-image\": beforeinput event, canceled":true,
"Command insertImage, value \"http://example.com/some-image\": input event, canceled":true,
"Command insertImage, value \"http://example.com/some-image\": beforeinput event, uncanceled":true,
"Command insertImage, value \"http://example.com/some-image\": input event, uncanceled":true,
"Command insertLineBreak, value \"\": beforeinput event, canceled":true,
"Command insertLineBreak, value \"\": beforeinput event, uncanceled":true,
"Command insertLineBreak, value \"\": input event, uncanceled":true,
"Command insertLineBreak, value \"quasit\": beforeinput event, canceled":true,
"Command insertLineBreak, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertLineBreak, value \"quasit\": input event, uncanceled":true,
"Command insertOrderedList, value \"\": beforeinput event, canceled":true,
"Command insertOrderedList, value \"\": input event, canceled":true,
"Command insertOrderedList, value \"\": beforeinput event, uncanceled":true,
"Command insertOrderedList, value \"\": input event, uncanceled":true,
"Command insertOrderedList, value \"quasit\": beforeinput event, canceled":true,
"Command insertOrderedList, value \"quasit\": input event, canceled":true,
"Command insertOrderedList, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertOrderedList, value \"quasit\": input event, uncanceled":true,
"Command insertParagraph, value \"\": beforeinput event, canceled":true,
"Command insertParagraph, value \"\": input event, canceled":true,
"Command insertParagraph, value \"\": beforeinput event, uncanceled":true,
"Command insertParagraph, value \"\": input event, uncanceled":true,
"Command insertParagraph, value \"quasit\": beforeinput event, canceled":true,
"Command insertParagraph, value \"quasit\": input event, canceled":true,
"Command insertParagraph, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertParagraph, value \"quasit\": input event, uncanceled":true,
"Command insertText, value \"\": beforeinput event, canceled":true,
"Command insertText, value \"\": beforeinput event, uncanceled":true,
"Command insertText, value \"\": input event, uncanceled":true,
"Command insertText, value \"quasit\": beforeinput event, canceled":true,
"Command insertText, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertText, value \"quasit\": input event, uncanceled":true,
"Command insertText, value \"abc\": beforeinput event, canceled":true,
"Command insertText, value \"abc\": beforeinput event, uncanceled":true,
"Command insertText, value \"abc\": input event, uncanceled":true,
"Command insertUnorderedList, value \"\": beforeinput event, canceled":true,
"Command insertUnorderedList, value \"\": input event, canceled":true,
"Command insertUnorderedList, value \"\": beforeinput event, uncanceled":true,
"Command insertUnorderedList, value \"\": input event, uncanceled":true,
"Command insertUnorderedList, value \"quasit\": beforeinput event, canceled":true,
"Command insertUnorderedList, value \"quasit\": input event, canceled":true,
"Command insertUnorderedList, value \"quasit\": beforeinput event, uncanceled":true,
"Command insertUnorderedList, value \"quasit\": input event, uncanceled":true,
"Command justifyCenter, value \"\": beforeinput event, canceled":true,
"Command justifyCenter, value \"\": input event, canceled":true,
"Command justifyCenter, value \"\": beforeinput event, uncanceled":true,
"Command justifyCenter, value \"\": input event, uncanceled":true,
"Command justifyCenter, value \"quasit\": beforeinput event, canceled":true,
"Command justifyCenter, value \"quasit\": input event, canceled":true,
"Command justifyCenter, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyCenter, value \"quasit\": input event, uncanceled":true,
"Command justifyFull, value \"\": beforeinput event, canceled":true,
"Command justifyFull, value \"\": input event, canceled":true,
"Command justifyFull, value \"\": beforeinput event, uncanceled":true,
"Command justifyFull, value \"\": input event, uncanceled":true,
"Command justifyFull, value \"quasit\": beforeinput event, canceled":true,
"Command justifyFull, value \"quasit\": input event, canceled":true,
"Command justifyFull, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyFull, value \"quasit\": input event, uncanceled":true,
"Command justifyLeft, value \"\": beforeinput event, canceled":true,
"Command justifyLeft, value \"\": input event, canceled":true,
"Command justifyLeft, value \"\": beforeinput event, uncanceled":true,
"Command justifyLeft, value \"\": input event, uncanceled":true,
"Command justifyLeft, value \"quasit\": beforeinput event, canceled":true,
"Command justifyLeft, value \"quasit\": input event, canceled":true,
"Command justifyLeft, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyLeft, value \"quasit\": input event, uncanceled":true,
"Command justifyRight, value \"\": beforeinput event, canceled":true,
"Command justifyRight, value \"\": input event, canceled":true,
"Command justifyRight, value \"\": beforeinput event, uncanceled":true,
"Command justifyRight, value \"\": input event, uncanceled":true,
"Command justifyRight, value \"quasit\": beforeinput event, canceled":true,
"Command justifyRight, value \"quasit\": input event, canceled":true,
"Command justifyRight, value \"quasit\": beforeinput event, uncanceled":true,
"Command justifyRight, value \"quasit\": input event, uncanceled":true,
"Command outdent, value \"\": beforeinput event, canceled":true,
"Command outdent, value \"\": beforeinput event, uncanceled":true,
"Command outdent, value \"\": input event, uncanceled":true,
"Command outdent, value \"quasit\": beforeinput event, canceled":true,
"Command outdent, value \"quasit\": beforeinput event, uncanceled":true,
"Command outdent, value \"quasit\": input event, uncanceled":true,
"Command redo, value \"\": beforeinput event, canceled":true,
"Command redo, value \"\": input event, canceled":true,
"Command redo, value \"\": beforeinput event, uncanceled":true,
"Command redo, value \"\": input event, uncanceled":true,
"Command redo, value \"quasit\": beforeinput event, canceled":true,
"Command redo, value \"quasit\": input event, canceled":true,
"Command redo, value \"quasit\": beforeinput event, uncanceled":true,
"Command redo, value \"quasit\": input event, uncanceled":true,
"Command undo, value \"\": beforeinput event, canceled":true,
"Command undo, value \"\": input event, canceled":true,
"Command undo, value \"\": beforeinput event, uncanceled":true,
"Command undo, value \"\": input event, uncanceled":true,
"Command undo, value \"quasit\": beforeinput event, canceled":true,
"Command undo, value \"quasit\": input event, canceled":true,
"Command undo, value \"quasit\": beforeinput event, uncanceled":true,
"Command undo, value \"quasit\": input event, uncanceled":true
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/imptests/failures/editing/selecttest
DIRS = \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TESTS = \
test_addRange.html.json \
test_Document-open.html.json \
test_getSelection.html.json \
test_interfaces.html.json \
$(NULL)
libs:: $(_TESTS)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,3 @@
{
"Selection must be replaced with a new object after document.open()":true
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
{
"getSelection() on HTML document with null defaultView must be null":true,
"getSelection() on XML document with null defaultView must be null":true,
"window.getSelection() instanceof Selection in an iframe immediately after appendChild":true,
"document.getSelection() instanceof Selection in an iframe immediately after appendChild":true,
"getSelection() on HTML document with null defaultView must be null inside an iframe onload":true
}

View File

@ -0,0 +1,11 @@
{
"Selection interface: existence and properties of interface object":true,
"Selection interface: existence and properties of interface prototype object":true,
"Selection interface: existence and properties of interface prototype object's \"constructor\" property":true,
"Selection interface: calling collapse() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling extend() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling selectAllChildren() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling getRangeAt() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling addRange() on getSelection() with too few arguments must throw TypeError":true,
"Selection interface: calling removeRange() on getSelection() with too few arguments must throw TypeError":true
}