1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/devtools/server/tests/mochitest/test_inspector-retain.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<!-- 1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id= 1.8 +--> 1.9 +<head> 1.10 + <meta charset="utf-8"> 1.11 + <title>Test for Bug </title> 1.12 + 1.13 + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 1.14 + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> 1.15 + <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script> 1.16 + <script type="application/javascript;version=1.8"> 1.17 +Components.utils.import("resource://gre/modules/devtools/Loader.jsm"); 1.18 +const {Promise: promise} = Components.utils.import("resource://gre/modules/Promise.jsm", {}); 1.19 + 1.20 +const inspector = devtools.require("devtools/server/actors/inspector"); 1.21 + 1.22 +window.onload = function() { 1.23 + SimpleTest.waitForExplicitFinish(); 1.24 + runNextTest(); 1.25 +} 1.26 + 1.27 +var gWalker = null; 1.28 +var gClient = null; 1.29 +var gInspectee = null; 1.30 + 1.31 +function assertOwnership() { 1.32 + return assertOwnershipTrees(gWalker); 1.33 +} 1.34 + 1.35 +addTest(function setup() { 1.36 + let url = document.getElementById("inspectorContent").href; 1.37 + attachURL(url, function(err, client, tab, doc) { 1.38 + gInspectee = doc; 1.39 + let {InspectorFront} = devtools.require("devtools/server/actors/inspector"); 1.40 + let inspector = InspectorFront(client, tab); 1.41 + promiseDone(inspector.getWalker().then(walker => { 1.42 + ok(walker, "getWalker() should return an actor."); 1.43 + gClient = client; 1.44 + gWalker = walker; 1.45 + }).then(runNextTest)); 1.46 + }); 1.47 +}); 1.48 + 1.49 +// Retain a node, and a second-order child (in another document, for kicks) 1.50 +// Release the parent of the top item, which should cause one retained orphan. 1.51 + 1.52 +// Then unretain the top node, which should retain the orphan. 1.53 + 1.54 +// Then change the source of the iframe, which should kill that orphan. 1.55 + 1.56 +addTest(function testRetain() { 1.57 + let originalOwnershipSize = 0; 1.58 + let bodyFront = null; 1.59 + let frameFront = null; 1.60 + let childListFront = null; 1.61 + // Get the toplevel body element and retain it. 1.62 + promiseDone(gWalker.querySelector(gWalker.rootNode, "body").then(front => { 1.63 + bodyFront = front; 1.64 + return gWalker.retainNode(bodyFront); 1.65 + }).then(() => { 1.66 + // Get an element in the child frame and retain it. 1.67 + return gWalker.querySelector(gWalker.rootNode, "#childFrame"); 1.68 + }).then(frame => { 1.69 + frameFront = frame; 1.70 + return gWalker.children(frame, { maxNodes: 1 }).then(children => { 1.71 + return children.nodes[0]; 1.72 + }); 1.73 + }).then(childDoc => { 1.74 + return gWalker.querySelector(childDoc, "#longlist"); 1.75 + }).then(list => { 1.76 + childListFront = list; 1.77 + originalOwnershipSize = assertOwnership(); 1.78 + // and rtain it. 1.79 + return gWalker.retainNode(childListFront); 1.80 + }).then(() => { 1.81 + // OK, try releasing the parent of the first retained. 1.82 + return gWalker.releaseNode(bodyFront.parentNode()); 1.83 + }).then(() => { 1.84 + let size = assertOwnership(); 1.85 + let clientTree = clientOwnershipTree(gWalker); 1.86 + 1.87 + // That request should have freed the parent of the first retained 1.88 + // but moved the rest into the retained orphaned tree. 1.89 + is(ownershipTreeSize(clientTree.root) + ownershipTreeSize(clientTree.retained[0]) + 1, 1.90 + originalOwnershipSize, 1.91 + "Should have only lost one item overall."); 1.92 + is(gWalker._retainedOrphans.size, 1, "Should have retained one orphan"); 1.93 + ok(gWalker._retainedOrphans.has(bodyFront), "Should have retained the expected node."); 1.94 + }).then(() => { 1.95 + // Unretain the body, which should promote the childListFront to a retained orphan. 1.96 + return gWalker.unretainNode(bodyFront); 1.97 + }).then(() => { 1.98 + assertOwnership(); 1.99 + let clientTree = clientOwnershipTree(gWalker); 1.100 + 1.101 + is(gWalker._retainedOrphans.size, 1, "Should still only have one retained orphan."); 1.102 + ok(!gWalker._retainedOrphans.has(bodyFront), "Should have dropped the body node.") 1.103 + ok(gWalker._retainedOrphans.has(childListFront), "Should have retained the child node.") 1.104 + }).then(() => { 1.105 + // Change the source of the iframe, which should kill the retained orphan. 1.106 + gInspectee.querySelector("#childFrame").src = "data:text/html,<html>new child</html>"; 1.107 + return waitForMutation(gWalker, isUnretained); 1.108 + }).then(mutations => { 1.109 + assertOwnership(); 1.110 + let clientTree = clientOwnershipTree(gWalker); 1.111 + is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans."); 1.112 + 1.113 + }).then(runNextTest)); 1.114 +}); 1.115 + 1.116 +// Get a hold of a node, remove it from the doc and retain it at the same time. 1.117 +// We should always win that race (even though the mutation happens before the 1.118 +// retain request), because we haven't issued `getMutations` yet. 1.119 +addTest(function testWinRace() { 1.120 + let front = null; 1.121 + promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(node => { 1.122 + front = node; 1.123 + let contentNode = gInspectee.querySelector("#a"); 1.124 + contentNode.parentNode.removeChild(contentNode); 1.125 + // Now wait for that mutation and retain response to come in. 1.126 + return promise.all([ 1.127 + gWalker.retainNode(front), 1.128 + waitForMutation(gWalker, isChildList) 1.129 + ]); 1.130 + }).then(() => { 1.131 + assertOwnership(); 1.132 + let clientTree = clientOwnershipTree(gWalker); 1.133 + is(gWalker._retainedOrphans.size, 1, "Should have a retained orphan."); 1.134 + ok(gWalker._retainedOrphans.has(front), "Should have retained our expected node."); 1.135 + return gWalker.unretainNode(front); 1.136 + }).then(() => { 1.137 + // Make sure we're clear for the next test. 1.138 + assertOwnership(); 1.139 + let clientTree = clientOwnershipTree(gWalker); 1.140 + is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans."); 1.141 + }).then(runNextTest)); 1.142 +}); 1.143 + 1.144 +// Same as above, but issue the request right after the 'new-mutations' event, so that 1.145 +// we *lose* the race. 1.146 +addTest(function testLoseRace() { 1.147 + let front = null; 1.148 + promiseDone(gWalker.querySelector(gWalker.rootNode, "#z").then(node => { 1.149 + front = node; 1.150 + gInspectee.querySelector("#z").parentNode = null; 1.151 + let contentNode = gInspectee.querySelector("#a"); 1.152 + contentNode.parentNode.removeChild(contentNode); 1.153 + return promiseOnce(gWalker, "new-mutations"); 1.154 + }).then(() => { 1.155 + // Verify that we have an outstanding request (no good way to tell that it's a 1.156 + // getMutations request, but there's nothing else it would be). 1.157 + is(gWalker._requests.length, 1, "Should have an outstanding request."); 1.158 + return gWalker.retainNode(front) 1.159 + }).then(() => { ok(false, "Request should not have succeeded!"); }, 1.160 + (err) => { 1.161 + ok(err, "noSuchActor", "Should have lost the race."); 1.162 + let clientTree = clientOwnershipTree(gWalker); 1.163 + is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans."); 1.164 + // Don't re-throw the error. 1.165 + }).then(runNextTest)); 1.166 +}); 1.167 + 1.168 +addTest(function cleanup() { 1.169 + delete gWalker; 1.170 + delete gClient; 1.171 + runNextTest(); 1.172 +}); 1.173 + 1.174 + </script> 1.175 +</head> 1.176 +<body> 1.177 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a> 1.178 +<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a> 1.179 +<p id="display"></p> 1.180 +<div id="content" style="display: none"> 1.181 + 1.182 +</div> 1.183 +<pre id="test"> 1.184 +</pre> 1.185 +</body> 1.186 +</html>