| OLD | NEW |
| (Empty) | |
| 1 <!doctype html> |
| 2 <title>Range.extractContents() tests</title> |
| 3 <link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> |
| 4 <meta name=timeout content=long> |
| 5 <p>To debug test failures, add a query parameter "subtest" with the test id (lik
e |
| 6 "?subtest=5"). Only that test will be run. Then you can look at the resulting |
| 7 iframe in the DOM. |
| 8 <div id=log></div> |
| 9 <script src=/resources/testharness.js></script> |
| 10 <script src=/resources/testharnessreport.js></script> |
| 11 <script src=../common.js></script> |
| 12 <script> |
| 13 "use strict"; |
| 14 |
| 15 testDiv.parentNode.removeChild(testDiv); |
| 16 |
| 17 var actualIframe = document.createElement("iframe"); |
| 18 actualIframe.style.display = "none"; |
| 19 document.body.appendChild(actualIframe); |
| 20 |
| 21 var expectedIframe = document.createElement("iframe"); |
| 22 expectedIframe.style.display = "none"; |
| 23 document.body.appendChild(expectedIframe); |
| 24 |
| 25 function restoreIframe(iframe, i) { |
| 26 // Most of this function is designed to work around the fact that Opera |
| 27 // doesn't let you add a doctype to a document that no longer has one, in |
| 28 // any way I can figure out. I eventually compromised on something that |
| 29 // will still let Opera pass most tests that don't actually involve |
| 30 // doctypes. |
| 31 while (iframe.contentDocument.firstChild |
| 32 && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { |
| 33 iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); |
| 34 } |
| 35 |
| 36 while (iframe.contentDocument.lastChild |
| 37 && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { |
| 38 iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); |
| 39 } |
| 40 |
| 41 if (!iframe.contentDocument.firstChild) { |
| 42 // This will throw an exception in Opera if we reach here, which is why |
| 43 // I try to avoid it. It will never happen in a browser that obeys the |
| 44 // spec, so it's really just insurance. I don't think it actually gets |
| 45 // hit by anything. |
| 46 iframe.contentDocument.appendChild(iframe.contentDocument.implementation.cre
ateDocumentType("html", "", "")); |
| 47 } |
| 48 iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true
)); |
| 49 iframe.contentWindow.setupRangeTests(); |
| 50 iframe.contentWindow.testRangeInput = testRanges[i]; |
| 51 iframe.contentWindow.run(); |
| 52 } |
| 53 |
| 54 function testExtractContents(i) { |
| 55 restoreIframe(actualIframe, i); |
| 56 restoreIframe(expectedIframe, i); |
| 57 |
| 58 var actualRange = actualIframe.contentWindow.testRange; |
| 59 var expectedRange = expectedIframe.contentWindow.testRange; |
| 60 var actualFrag, expectedFrag; |
| 61 var actualRoots, expectedRoots; |
| 62 |
| 63 domTests[i].step(function() { |
| 64 assert_equals(actualIframe.contentWindow.unexpectedException, null, |
| 65 "Unexpected exception thrown when setting up Range for actual extractConte
nts()"); |
| 66 assert_equals(expectedIframe.contentWindow.unexpectedException, null, |
| 67 "Unexpected exception thrown when setting up Range for simulated extractCo
ntents()"); |
| 68 assert_equals(typeof actualRange, "object", |
| 69 "typeof Range produced in actual iframe"); |
| 70 assert_equals(typeof expectedRange, "object", |
| 71 "typeof Range produced in expected iframe"); |
| 72 |
| 73 // Just to be pedantic, we'll test not only that the tree we're |
| 74 // modifying is the same in expected vs. actual, but also that all the |
| 75 // nodes originally in it were the same. Typically some nodes will |
| 76 // become detached when the algorithm is run, but they still exist and |
| 77 // references can still be kept to them, so they should also remain the |
| 78 // same. |
| 79 // |
| 80 // We initialize the list to all nodes, and later on remove all the |
| 81 // ones which still have parents, since the parents will presumably be |
| 82 // tested for isEqualNode() and checking the children would be |
| 83 // redundant. |
| 84 var actualAllNodes = []; |
| 85 var node = furthestAncestor(actualRange.startContainer); |
| 86 do { |
| 87 actualAllNodes.push(node); |
| 88 } while (node = nextNode(node)); |
| 89 |
| 90 var expectedAllNodes = []; |
| 91 var node = furthestAncestor(expectedRange.startContainer); |
| 92 do { |
| 93 expectedAllNodes.push(node); |
| 94 } while (node = nextNode(node)); |
| 95 |
| 96 expectedFrag = myExtractContents(expectedRange); |
| 97 if (typeof expectedFrag == "string") { |
| 98 assert_throws(expectedFrag, function() { |
| 99 actualRange.extractContents(); |
| 100 }); |
| 101 } else { |
| 102 actualFrag = actualRange.extractContents(); |
| 103 } |
| 104 |
| 105 actualRoots = []; |
| 106 for (var j = 0; j < actualAllNodes.length; j++) { |
| 107 if (!actualAllNodes[j].parentNode) { |
| 108 actualRoots.push(actualAllNodes[j]); |
| 109 } |
| 110 } |
| 111 |
| 112 expectedRoots = []; |
| 113 for (var j = 0; j < expectedAllNodes.length; j++) { |
| 114 if (!expectedAllNodes[j].parentNode) { |
| 115 expectedRoots.push(expectedAllNodes[j]); |
| 116 } |
| 117 } |
| 118 |
| 119 for (var j = 0; j < actualRoots.length; j++) { |
| 120 assertNodesEqual(actualRoots[j], expectedRoots[j], j ? "detached node #" +
j : "tree root"); |
| 121 |
| 122 if (j == 0) { |
| 123 // Clearly something is wrong if the node lists are different |
| 124 // lengths. We want to report this only after we've already |
| 125 // checked the main tree for equality, though, so it doesn't |
| 126 // mask more interesting errors. |
| 127 assert_equals(actualRoots.length, expectedRoots.length, |
| 128 "Actual and expected DOMs were broken up into a different number of pi
eces by extractContents() (this probably means you created or detached nodes whe
n you weren't supposed to)"); |
| 129 } |
| 130 } |
| 131 }); |
| 132 domTests[i].done(); |
| 133 |
| 134 positionTests[i].step(function() { |
| 135 assert_equals(actualIframe.contentWindow.unexpectedException, null, |
| 136 "Unexpected exception thrown when setting up Range for actual extractConte
nts()"); |
| 137 assert_equals(expectedIframe.contentWindow.unexpectedException, null, |
| 138 "Unexpected exception thrown when setting up Range for simulated extractCo
ntents()"); |
| 139 assert_equals(typeof actualRange, "object", |
| 140 "typeof Range produced in actual iframe"); |
| 141 assert_equals(typeof expectedRange, "object", |
| 142 "typeof Range produced in expected iframe"); |
| 143 |
| 144 assert_true(actualRoots[0].isEqualNode(expectedRoots[0]), |
| 145 "The resulting DOMs were not equal, so comparing positions makes no sense"
); |
| 146 |
| 147 if (typeof expectedFrag == "string") { |
| 148 // It's no longer true that, e.g., startContainer and endContainer |
| 149 // must always be the same |
| 150 return; |
| 151 } |
| 152 assert_equals(actualRange.startContainer, actualRange.endContainer, |
| 153 "startContainer and endContainer must always be the same after extractCont
ents()"); |
| 154 assert_equals(actualRange.startOffset, actualRange.endOffset, |
| 155 "startOffset and endOffset must always be the same after extractContents()
"); |
| 156 assert_equals(expectedRange.startContainer, expectedRange.endContainer, |
| 157 "Test bug! Expected startContainer and endContainer must always be the sa
me after extractContents()"); |
| 158 assert_equals(expectedRange.startOffset, expectedRange.endOffset, |
| 159 "Test bug! Expected startOffset and endOffset must always be the same aft
er extractContents()"); |
| 160 |
| 161 assert_equals(actualRange.startOffset, expectedRange.startOffset, |
| 162 "Unexpected startOffset after extractContents()"); |
| 163 // How do we decide that the two nodes are equal, since they're in |
| 164 // different trees? Since the DOMs are the same, it's enough to check |
| 165 // that the index in the parent is the same all the way up the tree. |
| 166 // But we can first cheat by just checking they're actually equal. |
| 167 assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContai
ner), |
| 168 "Unexpected startContainer after extractContents(), expected " + |
| 169 expectedRange.startContainer.nodeName.toLowerCase() + " but got " + |
| 170 actualRange.startContainer.nodeName.toLowerCase()); |
| 171 var currentActual = actualRange.startContainer; |
| 172 var currentExpected = expectedRange.startContainer; |
| 173 var actual = ""; |
| 174 var expected = ""; |
| 175 while (currentActual && currentExpected) { |
| 176 actual = indexOf(currentActual) + "-" + actual; |
| 177 expected = indexOf(currentExpected) + "-" + expected; |
| 178 |
| 179 currentActual = currentActual.parentNode; |
| 180 currentExpected = currentExpected.parentNode; |
| 181 } |
| 182 actual = actual.substr(0, actual.length - 1); |
| 183 expected = expected.substr(0, expected.length - 1); |
| 184 assert_equals(actual, expected, |
| 185 "startContainer superficially looks right but is actually the wrong node i
f you trace back its index in all its ancestors (I'm surprised this actually hap
pened"); |
| 186 }); |
| 187 positionTests[i].done(); |
| 188 |
| 189 fragTests[i].step(function() { |
| 190 assert_equals(actualIframe.contentWindow.unexpectedException, null, |
| 191 "Unexpected exception thrown when setting up Range for actual extractConte
nts()"); |
| 192 assert_equals(expectedIframe.contentWindow.unexpectedException, null, |
| 193 "Unexpected exception thrown when setting up Range for simulated extractCo
ntents()"); |
| 194 assert_equals(typeof actualRange, "object", |
| 195 "typeof Range produced in actual iframe"); |
| 196 assert_equals(typeof expectedRange, "object", |
| 197 "typeof Range produced in expected iframe"); |
| 198 |
| 199 if (typeof expectedFrag == "string") { |
| 200 // Comparing makes no sense |
| 201 return; |
| 202 } |
| 203 assertNodesEqual(actualFrag, expectedFrag, |
| 204 "returned fragment"); |
| 205 }); |
| 206 fragTests[i].done(); |
| 207 } |
| 208 |
| 209 // First test a detached Range, synchronously |
| 210 test(function() { |
| 211 var range = document.createRange(); |
| 212 range.detach(); |
| 213 assert_array_equals(range.extractContents().childNodes, []); |
| 214 }, "Detached Range"); |
| 215 |
| 216 var iStart = 0; |
| 217 var iStop = testRanges.length; |
| 218 |
| 219 if (/subtest=[0-9]+/.test(location.search)) { |
| 220 var matches = /subtest=([0-9]+)/.exec(location.search); |
| 221 iStart = Number(matches[1]); |
| 222 iStop = Number(matches[1]) + 1; |
| 223 } |
| 224 |
| 225 var domTests = []; |
| 226 var positionTests = []; |
| 227 var fragTests = []; |
| 228 |
| 229 for (var i = iStart; i < iStop; i++) { |
| 230 domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i])
; |
| 231 positionTests[i] = async_test("Resulting cursor position for range " + i + " "
+ testRanges[i]); |
| 232 fragTests[i] = async_test("Returned fragment for range " + i + " " + testRange
s[i]); |
| 233 } |
| 234 |
| 235 var referenceDoc = document.implementation.createHTMLDocument(""); |
| 236 referenceDoc.removeChild(referenceDoc.documentElement); |
| 237 |
| 238 actualIframe.onload = function() { |
| 239 expectedIframe.onload = function() { |
| 240 for (var i = iStart; i < iStop; i++) { |
| 241 testExtractContents(i); |
| 242 } |
| 243 } |
| 244 expectedIframe.src = "Range-test-iframe.html"; |
| 245 referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNod
e(true)); |
| 246 } |
| 247 actualIframe.src = "Range-test-iframe.html"; |
| 248 </script> |
| OLD | NEW |