summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/mochitest/test_inspector-retain.html
blob: e8342cf67ce5088a397190ae4990eb793311e464 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<!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 gWalker = null;
var gClient = null;
var gInspectee = null;

function assertOwnership() {
  return assertOwnershipTrees(gWalker);
}

addTest(function setup() {
  let url = document.getElementById("inspectorContent").href;
  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 => {
      ok(walker, "getWalker() should return an actor.");
      gClient = client;
      gWalker = walker;
    }).then(runNextTest));
  });
});

// Retain a node, and a second-order child (in another document, for kicks)
// Release the parent of the top item, which should cause one retained orphan.

// Then unretain the top node, which should retain the orphan.

// Then change the source of the iframe, which should kill that orphan.

addTest(function testRetain() {
  let originalOwnershipSize = 0;
  let bodyFront = null;
  let frameFront = null;
  let childListFront = null;
  // Get the toplevel body element and retain it.
  promiseDone(gWalker.querySelector(gWalker.rootNode, "body").then(front => {
    bodyFront = front;
    return gWalker.retainNode(bodyFront);
  }).then(() => {
    // Get an element in the child frame and retain it.
    return gWalker.querySelector(gWalker.rootNode, "#childFrame");
  }).then(frame => {
    frameFront = frame;
    return gWalker.children(frame, { maxNodes: 1 }).then(children => {
      return children.nodes[0];
    });
  }).then(childDoc => {
    return gWalker.querySelector(childDoc, "#longlist");
  }).then(list => {
    childListFront = list;
    originalOwnershipSize = assertOwnership();
    // and rtain it.
    return gWalker.retainNode(childListFront);
  }).then(() => {
    // OK, try releasing the parent of the first retained.
    return gWalker.releaseNode(bodyFront.parentNode());
  }).then(() => {
    let size = assertOwnership();
    let clientTree = clientOwnershipTree(gWalker);

    // That request should have freed the parent of the first retained
    // but moved the rest into the retained orphaned tree.
    is(ownershipTreeSize(clientTree.root) + ownershipTreeSize(clientTree.retained[0]) + 1,
       originalOwnershipSize,
       "Should have only lost one item overall.");
    is(gWalker._retainedOrphans.size, 1, "Should have retained one orphan");
    ok(gWalker._retainedOrphans.has(bodyFront), "Should have retained the expected node.");
  }).then(() => {
    // Unretain the body, which should promote the childListFront to a retained orphan.
    return gWalker.unretainNode(bodyFront);
  }).then(() => {
    assertOwnership();
    let clientTree = clientOwnershipTree(gWalker);

    is(gWalker._retainedOrphans.size, 1, "Should still only have one retained orphan.");
    ok(!gWalker._retainedOrphans.has(bodyFront), "Should have dropped the body node.")
    ok(gWalker._retainedOrphans.has(childListFront), "Should have retained the child node.")
  }).then(() => {
    // Change the source of the iframe, which should kill the retained orphan.
    gInspectee.querySelector("#childFrame").src = "data:text/html,<html>new child</html>";
    return waitForMutation(gWalker, isUnretained);
  }).then(mutations => {
    assertOwnership();
    let clientTree = clientOwnershipTree(gWalker);
    is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans.");

  }).then(runNextTest));
});

// Get a hold of a node, remove it from the doc and retain it at the same time.
// We should always win that race (even though the mutation happens before the
// retain request), because we haven't issued `getMutations` yet.
addTest(function testWinRace() {
  let front = null;
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(node => {
    front = node;
    let contentNode = gInspectee.querySelector("#a");
    contentNode.parentNode.removeChild(contentNode);
    // Now wait for that mutation and retain response to come in.
    return promise.all([
      gWalker.retainNode(front),
      waitForMutation(gWalker, isChildList)
    ]);
  }).then(() => {
    assertOwnership();
    let clientTree = clientOwnershipTree(gWalker);
    is(gWalker._retainedOrphans.size, 1, "Should have a retained orphan.");
    ok(gWalker._retainedOrphans.has(front), "Should have retained our expected node.");
    return gWalker.unretainNode(front);
  }).then(() => {
    // Make sure we're clear for the next test.
    assertOwnership();
    let clientTree = clientOwnershipTree(gWalker);
    is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans.");
  }).then(runNextTest));
});

// Same as above, but issue the request right after the 'new-mutations' event, so that
// we *lose* the race.
addTest(function testLoseRace() {
  let front = null;
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#z").then(node => {
    front = node;
    gInspectee.querySelector("#z").parentNode = null;
    let contentNode = gInspectee.querySelector("#a");
    contentNode.parentNode.removeChild(contentNode);
    return promiseOnce(gWalker, "new-mutations");
  }).then(() => {
    // Verify that we have an outstanding request (no good way to tell that it's a
    // getMutations request, but there's nothing else it would be).
    is(gWalker._requests.length, 1, "Should have an outstanding request.");
    return gWalker.retainNode(front)
  }).then(() => { ok(false, "Request should not have succeeded!"); },
          (err) => {
    ok(err, "noSuchActor", "Should have lost the race.");
    let clientTree = clientOwnershipTree(gWalker);
    is(gWalker._retainedOrphans.size, 0, "Should have no more retained orphans.");
    // Don't re-throw the error.
  }).then(runNextTest));
});

addTest(function cleanup() {
  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>