summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/test/browser/browser_memory_dominator_trees_01.js
blob: 3380d6e211dea3b8ab2f84c2141be725f726709f (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
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

// Sanity test for dominator trees, their focused nodes, and keyboard navigating
// through nodes across incrementally fetching subtrees.

"use strict";

const {
  dominatorTreeState,
  viewState,
} = require("devtools/client/memory/constants");
const {
  expandDominatorTreeNode,
} = require("devtools/client/memory/actions/snapshot");
const { changeView } = require("devtools/client/memory/actions/view");

const TEST_URL = "http://example.com/browser/devtools/client/memory/test/browser/doc_big_tree.html";

this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
  // Taking snapshots and computing dominator trees is slow :-/
  requestLongerTimeout(4);

  const store = panel.panelWin.gStore;
  const { getState, dispatch } = store;
  const doc = panel.panelWin.document;

  dispatch(changeView(viewState.DOMINATOR_TREE));

  // Take a snapshot.

  const takeSnapshotButton = doc.getElementById("take-snapshot");
  EventUtils.synthesizeMouseAtCenter(takeSnapshotButton, {}, panel.panelWin);

  // Wait for the dominator tree to be computed and fetched.

  yield waitUntilDominatorTreeState(store, [dominatorTreeState.LOADED]);
  ok(true, "Computed and fetched the dominator tree.");

  // Expand all the dominator tree nodes that are eagerly fetched, except for
  // the leaves which will trigger fetching their lazily loaded subtrees.

  const id = getState().snapshots[0].id;
  const root = getState().snapshots[0].dominatorTree.root;
  (function expandAllEagerlyFetched(node = root) {
    if (!node.moreChildrenAvailable || node.children) {
      dispatch(expandDominatorTreeNode(id, node));
    }

    if (node.children) {
      for (let child of node.children) {
        expandAllEagerlyFetched(child);
      }
    }
  }());

  // Find the deepest eagerly loaded node: one which has more children but none
  // of them are loaded.

  const deepest = (function findDeepest(node = root) {
    if (node.moreChildrenAvailable && !node.children) {
      return node;
    }

    if (node.children) {
      for (let child of node.children) {
        const found = findDeepest(child);
        if (found) {
          return found;
        }
      }
    }

    return null;
  }());

  ok(deepest, "Found the deepest node");
  ok(!getState().snapshots[0].dominatorTree.expanded.has(deepest.nodeId),
     "The deepest node should not be expanded");

  // Select the deepest node.

  EventUtils.synthesizeMouseAtCenter(doc.querySelector(`.node-${deepest.nodeId}`),
                                     {},
                                     panel.panelWin);
  yield waitUntilState(store, state =>
    state.snapshots[0].dominatorTree.focused.nodeId === deepest.nodeId);
  ok(doc.querySelector(`.node-${deepest.nodeId}`).classList.contains("focused"),
     "The deepest node should be focused now");

  // Expand the deepest node, which triggers an incremental fetch of its lazily
  // loaded subtree.

  EventUtils.synthesizeKey("VK_RIGHT", {}, panel.panelWin);
  yield waitUntilState(store, state =>
    state.snapshots[0].dominatorTree.expanded.has(deepest.nodeId));
  is(getState().snapshots[0].dominatorTree.state,
     dominatorTreeState.INCREMENTAL_FETCHING,
     "Expanding the deepest node should start an incremental fetch of its subtree");
  ok(doc.querySelector(`.node-${deepest.nodeId}`).classList.contains("focused"),
     "The deepest node should still be focused after expansion");

  // Wait for the incremental fetch to complete.

  yield waitUntilState(store, state =>
    state.snapshots[0].dominatorTree.state === dominatorTreeState.LOADED);
  ok(true, "And the incremental fetch completes.");
  ok(doc.querySelector(`.node-${deepest.nodeId}`).classList.contains("focused"),
     "The deepest node should still be focused after we have loaded its children");

  // Find the most up-to-date version of the node whose children we just
  // incrementally fetched.

  const newDeepest = (function findNewDeepest(node = getState().snapshots[0].dominatorTree.root) {
    if (node.nodeId === deepest.nodeId) {
      return node;
    }

    if (node.children) {
      for (let child of node.children) {
        const found = findNewDeepest(child);
        if (found) {
          return found;
        }
      }
    }

    return null;
  }());

  ok(newDeepest, "We found the up-to-date version of deepest");
  ok(newDeepest.children, "And its children are loaded");
  ok(newDeepest.children.length, "And there are more than 0 children");

  const firstChild = newDeepest.children[0];
  ok(firstChild, "deepest should have a first child");
  ok(doc.querySelector(`.node-${firstChild.nodeId}`),
     "and the first child should exist in the dom");

  // Select the newly loaded first child by pressing the right arrow once more.

  EventUtils.synthesizeKey("VK_RIGHT", {}, panel.panelWin);
  yield waitUntilState(store, state =>
    state.snapshots[0].dominatorTree.focused === firstChild);
  ok(doc.querySelector(`.node-${firstChild.nodeId}`).classList.contains("focused"),
     "The first child should now be focused");
});