<html> <head> <title>Fragment Mutation Tests</title> <script> if (window.layoutTestController) layoutTestController.dumpAsText(); var log = []; function logResult(description, outcome) { log.push({ description: description, outcome: outcome}); } function printLog(methodName) { var entries = log.map(function(entry) { return "<li>" + entry.description + ": " + entry.outcome; }); document.body.appendChild(document.createElement("p")).innerHTML = "This test creates a fragment containing three elements: \"B\", \"U\", and \"P\", " + " attempts to " + methodName + " this fragment and studies effects of mutation events on the fragment."; document.body.appendChild(document.createElement("ul")).innerHTML = entries.join("\n"); document.body.appendChild(document.createElement("br")); log = []; } function produceNodeNameString(nodes) { var node = nodes.firstChild; var result = ""; while(node) { result += node.nodeName; node = node.nextSibling; } return result; } function expectException(code) { return function(stash, exception) { if (!exception) return "FAIL, expected exception with code " + code + ". The resulting fragment was: \"" + produceNodeNameString(stash) + "\"."; if (code == exception.code) return "PASS"; return "FAIL, expected exception code: " + code + ", was: " + exception + "."; } } function expectNodes(nodes) { return function(stash, exception) { if (exception) return "FAIL, unexpected exception thrown: " + exception; var result = produceNodeNameString(stash); if (nodes == result) return "PASS"; return "FAIL, expected \"" + nodes + "\", was \"" + result + "\"."; }; } function testFragment(method, description, mutationHandler, expectation, nonStop) { var once = 0; var logged = 0; var frag = document.createDocumentFragment(); var stash = document.body.appendChild(document.createElement("div")); frag.appendChild(document.createElement("b")); frag.appendChild(document.createElement("u")); frag.appendChild(document.createElement("p")); frag.addEventListener("DOMSubtreeModified", function(evt) { if (!nonStop && once++) return; try { mutationHandler(evt, frag, stash); } catch(e) { logResult(description, expectation(stash, e)); logged++; } }, false); try { method(stash, frag); } catch(e) { logResult(description, expectation(stash, e)); logged++; } if (!logged) logResult(description, expectation(stash)); document.body.removeChild(stash); } function appendChildMethod(object, subject) { object.appendChild(subject); } function insertBeforeMethod(object, subject) { object.insertBefore(subject, object.firstChild); } function runTest(methodName, method) { var missing = document.body.appendChild(document.createElement("em")); testFragment(method, "Inserting an element in front of the next item in fragment should not affect the result", function(evt, frag) { frag.insertBefore(missing, frag.firstChild); }, expectNodes("BUP")); testFragment(method, "Removing next item should not abort iteration", function(evt, frag) { frag.removeChild(frag.firstChild); }, expectNodes("BUP")); var extra = document.body.appendChild(document.createElement("em")); testFragment(method, "Appending an element at the end of the fragment should not affect the result", function(evt, frag) { frag.appendChild(extra); }, expectNodes("BUP")); testFragment(method, "Continually re-appending removed element to the fragment should eventually throw NOT_FOUND_ERR", function(evt, frag, stash) { stash.insertBefore(frag.lastChild, stash.firstChild); }, expectException(8), true); testFragment(method, "Moving next item to become previous sibling of the re-parentee should not result in stack exhaustion", function(evt, frag, stash) { document.body.insertBefore(frag.firstChild, stash); }, expectNodes("BUP")); printLog(methodName); } function runTests() { runTest("appendChild", appendChildMethod); runTest("insertBefore", insertBeforeMethod); } </script> </head> <body onload="runTests()"> </body> </html>