diff options
Diffstat (limited to 'devtools/server/tests/mochitest/test_inspector-mutations-childlist.html')
-rw-r--r-- | devtools/server/tests/mochitest/test_inspector-mutations-childlist.html | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html b/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html new file mode 100644 index 000000000..d845b987e --- /dev/null +++ b/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html @@ -0,0 +1,310 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id= +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug </title> + + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script> + <script type="application/javascript;version=1.8"> +const inspector = require("devtools/shared/fronts/inspector"); + +window.onload = function() { + SimpleTest.waitForExplicitFinish(); + runNextTest(); +} + +var gInspectee = null; +var gWalker = null; +var gClient = null; +var gCleanupConnection = null; + +function setup(callback) { + let url = document.getElementById("inspectorContent").href; + gCleanupConnection = attachURL(url, function(err, client, tab, doc) { + gInspectee = doc; + let {InspectorFront} = require("devtools/shared/fronts/inspector"); + let inspector = InspectorFront(client, tab); + promiseDone(inspector.getWalker().then(walker => { + gClient = client; + gWalker = walker; + }).then(callback)); + }); +} + +function teardown() { + gWalker = null; + gClient = null; + gInspectee = null; + if (gCleanupConnection) { + gCleanupConnection(); + gCleanupConnection = null; + } +} + +function assertOwnership() { + let num = assertOwnershipTrees(gWalker); +} + +function setParent(nodeSelector, newParentSelector) { + let node = gInspectee.querySelector(nodeSelector); + if (newParentSelector) { + let newParent = gInspectee.querySelector(newParentSelector); + newParent.appendChild(node); + } else { + node.parentNode.removeChild(node); + } +} + +function loadSelector(selector) { + return gWalker.querySelectorAll(gWalker.rootNode, selector).then(nodeList => { + return nodeList.items(); + }); +} + +function loadSelectors(selectors) { + return promise.all(Array.from(selectors, (sel) => loadSelector(sel))); +} + +function doMoves(moves) { + for (let move of moves) { + setParent(move[0], move[1]); + } +} + +/** + * Test a set of tree rearrangements and make sure they cause the expected changes. + */ + +var gDummySerial = 0; + +function mutationTest(testSpec) { + return function() { + setup(() => { + promiseDone(loadSelectors(testSpec.load || ["html"]).then(() => { + gWalker.autoCleanup = !!testSpec.autoCleanup; + if (testSpec.preCheck) { + testSpec.preCheck(); + } + doMoves(testSpec.moves || []); + + // Some of these moves will trigger no mutation events, + // so do a dummy change to the root node to trigger + // a mutation event anyway. + gInspectee.documentElement.setAttribute("data-dummy", gDummySerial++); + + gWalker.once("mutations", (mutations) => { + // Filter out our dummy mutation. + mutations = mutations.filter(change => { + if (change.type == "attributes" && + change.attributeName == "data-dummy") { + return false; + } + return true; + }); + assertOwnership(); + if (testSpec.postCheck) { + testSpec.postCheck(mutations); + } + teardown(); + runNextTest(); + }); + })); + }) + } +} + +// Verify that our dummy mutation works. +addTest(mutationTest({ + autoCleanup: false, + postCheck: function(mutations) { + is(mutations.length, 0, "Dummy mutation is filtered out."); + } +})); + +// Test a simple move to a different location in the sibling list for the same +// parent. +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist div"], + moves: [ + ["#a", "#longlist"] + ], + postCheck: function(mutations) { + let remove = mutations[0]; + is(remove.type, "childList", "First mutation should be a childList.") + ok(remove.removed.length > 0, "First mutation should be a removal.") + let add = mutations[1]; + is(add.type, "childList", "Second mutation should be a childList removal.") + ok(add.added.length > 0, "Second mutation should be an addition.") + let a = add.added[0]; + is(a.id, "a", "Added node should be #a"); + is(a.parentNode(), remove.target, "Should still be a child of longlist."); + is(remove.target, add.target, "First and second mutations should be against the same node."); + } +})); + +// Test a move to another location that is within our ownership tree. +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist div", "#longlist-sibling"], + moves: [ + ["#a", "#longlist-sibling"] + ], + postCheck: function(mutations) { + let remove = mutations[0]; + is(remove.type, "childList", "First mutation should be a childList.") + ok(remove.removed.length > 0, "First mutation should be a removal.") + let add = mutations[1]; + is(add.type, "childList", "Second mutation should be a childList removal.") + ok(add.added.length > 0, "Second mutation should be an addition.") + let a = add.added[0]; + is(a.id, "a", "Added node should be #a"); + is(a.parentNode(), add.target, "Should still be a child of longlist."); + is(add.target.id, "longlist-sibling", "long-sibling should be the target."); + } +})); + +// Move an unseen node with a seen parent into our ownership tree - should generate a +// childList pair with no adds or removes. +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist"], + moves: [ + ["#longlist-sibling", "#longlist"] + ], + postCheck: function(mutations) { + is(mutations.length, 2, "Should generate two mutations"); + is(mutations[0].type, "childList", "Should be childList mutations."); + is(mutations[0].added.length, 0, "Should have no adds."); + is(mutations[0].removed.length, 0, "Should have no removes."); + is(mutations[1].type, "childList", "Should be childList mutations."); + is(mutations[1].added.length, 0, "Should have no adds."); + is(mutations[1].removed.length, 0, "Should have no removes."); + } +})); + +// Move an unseen node with an unseen parent into our ownership tree. Should only +// generate one childList mutation with no adds or removes. +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist div"], + moves: [ + ["#longlist-sibling-firstchild", "#longlist"] + ], + postCheck: function(mutations) { + is(mutations.length, 1, "Should generate two mutations"); + is(mutations[0].type, "childList", "Should be childList mutations."); + is(mutations[0].added.length, 0, "Should have no adds."); + is(mutations[0].removed.length, 0, "Should have no removes."); + } +})); + +// Move a node between unseen nodes, should generate no mutations. +addTest(mutationTest({ + autoCleanup: false, + load: ["html"], + moves: [ + ["#longlist-sibling", "#longlist"] + ], + postCheck: function(mutations) { + is(mutations.length, 0, "Should generate no mutations."); + } +})); + +// Orphan a node and don't clean it up +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist div"], + moves: [ + ["#longlist", null] + ], + postCheck: function(mutations) { + is(mutations.length, 1, "Should generate one mutation."); + let change = mutations[0]; + is(change.type, "childList", "Should be a childList."); + is(change.removed.length, 1, "Should have removed a child."); + let ownership = clientOwnershipTree(gWalker); + is(ownership.orphaned.length, 1, "Should have one orphaned subtree."); + is(ownershipTreeSize(ownership.orphaned[0]), 1 + 26 + 26, "Should have orphaned longlist, and 26 children, and 26 singleTextChilds"); + } +})); + +// Orphan a node, and do clean it up. +addTest(mutationTest({ + autoCleanup: true, + load: ["#longlist div"], + moves: [ + ["#longlist", null] + ], + postCheck: function(mutations) { + is(mutations.length, 1, "Should generate one mutation."); + let change = mutations[0]; + is(change.type, "childList", "Should be a childList."); + is(change.removed.length, 1, "Should have removed a child."); + let ownership = clientOwnershipTree(gWalker); + is(ownership.orphaned.length, 0, "Should have no orphaned subtrees."); + } +})); + +// Orphan a node by moving it into the tree but out of our visible subtree. +addTest(mutationTest({ + autoCleanup: false, + load: ["#longlist div"], + moves: [ + ["#longlist", "#longlist-sibling"] + ], + postCheck: function(mutations) { + is(mutations.length, 1, "Should generate one mutation."); + let change = mutations[0]; + is(change.type, "childList", "Should be a childList."); + is(change.removed.length, 1, "Should have removed a child."); + let ownership = clientOwnershipTree(gWalker); + is(ownership.orphaned.length, 1, "Should have one orphaned subtree."); + is(ownershipTreeSize(ownership.orphaned[0]), 1 + 26 + 26, "Should have orphaned longlist, 26 children, and 26 singleTextChilds."); + } +})); + +// Orphan a node by moving it into the tree but out of our visible subtree, and clean it up. +addTest(mutationTest({ + autoCleanup: true, + load: ["#longlist div"], + moves: [ + ["#longlist", "#longlist-sibling"] + ], + postCheck: function(mutations) { + is(mutations.length, 1, "Should generate one mutation."); + let change = mutations[0]; + is(change.type, "childList", "Should be a childList."); + is(change.removed.length, 1, "Should have removed a child."); + let ownership = clientOwnershipTree(gWalker); + is(ownership.orphaned.length, 0, "Should have no orphaned subtrees."); + } +})); + + +addTest(function cleanup() { + delete gInspectee; + delete gWalker; + delete gClient; + runNextTest(); +}); + + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a> +<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> |