devtools/server/tests/mochitest/test_inspector-traversal.html
author Julian Descottes <jdescottes@mozilla.com>
Fri, 26 Jan 2018 11:49:48 +0100
changeset 401521 4c42b9b8bd98c6f378f94a6fc896d4a58964ec67
parent 348382 1f17eeabf363349bd01b0c6c4edfaf58ade60c6e
child 401522 8e3c63c83301f63943e08a4a4284ee28bb1b1ee9
permissions -rw-r--r--
Bug 1102240 - Move inspector actor to dedicated folder;r=pbro MozReview-Commit-ID: LNgHweYJXcB

<!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" src="inspector-helpers.js"></script>
  <script type="application/javascript">
"use strict";

window.onload = function () {
  SimpleTest.waitForExplicitFinish();
  runNextTest();
};

let gInspectee = null;
let gClient = null;
let gWalker = null;
let checkActorIDs = [];

function assertOwnership() {
  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));
  });
});

addTest(function testWalkerRoot() {
  // Make sure that refetching the root document of the walker returns the same
  // actor as the getWalker returned.
  promiseDone(gWalker.document().then(root => {
    ok(root === gWalker.rootNode,
       "Re-fetching the document node should match the root document node.");
    checkActorIDs.push(root.actorID);
    assertOwnership();
  }).then(runNextTest));
});

addTest(function testInnerHTML() {
  promiseDone(gWalker.documentElement().then(docElement => {
    return gWalker.innerHTML(docElement);
  }).then(longstring => {
    return longstring.string();
  }).then(innerHTML => {
    ok(innerHTML === gInspectee.documentElement.innerHTML, "innerHTML should match");
  }).then(runNextTest));
});

addTest(function testOuterHTML() {
  promiseDone(gWalker.documentElement().then(docElement => {
    return gWalker.outerHTML(docElement);
  }).then(longstring => {
    return longstring.string();
  }).then(outerHTML => {
    ok(outerHTML === gInspectee.documentElement.outerHTML, "outerHTML should match");
  }).then(runNextTest));
});

addTest(function testSetOuterHTMLNode() {
  let newHTML = "<p id=\"edit-html-done\">after edit</p>";
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#edit-html").then(node => {
    return gWalker.setOuterHTML(node, newHTML);
  }).then(() => {
    return gWalker.querySelector(gWalker.rootNode, "#edit-html-done");
  }).then(node => {
    return gWalker.outerHTML(node);
  }).then(longstring => {
    return longstring.string();
  }).then(outerHTML => {
    is(outerHTML, newHTML, "outerHTML has been updated");
  }).then(() => {
    return gWalker.querySelector(gWalker.rootNode, "#edit-html");
  }).then(node => {
    ok(!node, "The node with the old ID cannot be selected anymore");
  }).then(runNextTest));
});

addTest(function testQuerySelector() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#longlist").then(node => {
    is(node.getAttribute("data-test"), "exists", "should have found the right node");
    assertOwnership();
  }).then(() => {
    return gWalker.querySelector(gWalker.rootNode, "unknownqueryselector").then(node => {
      ok(!node, "Should not find a node here.");
      assertOwnership();
    });
  }).then(runNextTest));
});

addTest(function testQuerySelectors() {
  let nodeList = null;
  let firstNode = null;
  let nodeListID = null;
  promiseDone(gWalker.querySelectorAll(gWalker.rootNode, "#longlist div").then(list => {
    nodeList = list;
    is(nodeList.length, 26, "Expect 26 div children.");
    assertOwnership();
    return nodeList.item(0);
  }).then(node => {
    firstNode = node;
    checkActorIDs.push(node.actorID);
    is(node.id, "a", "First child should be a");
    assertOwnership();
    return nodeList.items();
  }).then(nodes => {
    is(nodes.length, 26, "Expect 26 nodes");
    is(nodes[0], firstNode, "First node should be reused.");
    ok(nodes[0]._parent, "Parent node should be set.");
    ok(nodes[0]._next || nodes[0]._prev, "Siblings should be set.");
    ok(nodes[25]._next || nodes[25]._prev,
       "Siblings of " + nodes[25] + " should be set.");
    assertOwnership();
    return nodeList.items(-1);
  }).then(nodes => {
    is(nodes.length, 1, "Expect 1 node");
    is(nodes[0].id, "z", "Expect it to be the last node.");
    checkActorIDs.push(nodes[0].actorID);
    // Save the node list ID so we can ensure it was destroyed.
    nodeListID = nodeList.actorID;
    assertOwnership();
    return nodeList.release();
  }).then(() => {
    ok(!nodeList.actorID, "Actor should have been destroyed.");
    assertOwnership();
    return checkMissing(gClient, nodeListID);
  }).then(runNextTest));
});

// Helper to check the response of requests that return hasFirst/hasLast/nodes
// node lists (like `children` and `siblings`)
function nodeArrayChecker(first, last, ids) {
  return function (response) {
    is(response.hasFirst, first,
       "Should " + (first ? "" : "not ") + " have the first node.");
    is(response.hasLast, last, "Should " + (last ? "" : "not ") + " have the last node.");
    is(response.nodes.length, ids.length,
       "Should have " + ids.length + " children listed.");
    let responseIds = "";
    for (let node of response.nodes) {
      responseIds += node.id;
    }
    is(responseIds, ids, "Correct nodes were returned.");
    assertOwnership();
  };
}

addTest(function testNoChildren() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#empty").then(empty => {
    assertOwnership();
    return gWalker.children(empty).then(nodeArrayChecker(true, true, ""));
  }).then(runNextTest));
});

addTest(function testLongListTraversal() {
  let longList;
  let allChildren;
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#longlist").then(node => {
    longList = node;
    // First call with no options, expect all children.
    assertOwnership();
    return gWalker.children(longList).then(response => {
      nodeArrayChecker(true, true, "abcdefghijklmnopqrstuvwxyz")(response);
      allChildren = response.nodes;
      assertOwnership();
    });
  }).then(() => {
    // maxNodes should limit us to the first 5 nodes.
    assertOwnership();
    return gWalker.children(longList, { maxNodes: 5 })
           .then(nodeArrayChecker(true, false, "abcde"));
  }).then(() => {
    assertOwnership();
    // maxNodes with the second item centered should still give us the first 5 nodes.
    return gWalker.children(longList, { maxNodes: 5, center: allChildren[1] }).then(
      nodeArrayChecker(true, false, "abcde")
    );
  }).then(() => {
    // maxNodes with a center in the middle of the list should put that item in the middle
    let center = allChildren[13];
    is(center.id, "n", "Make sure I know how to count letters.");
    return gWalker.children(longList, { maxNodes: 5, center: center }).then(
      nodeArrayChecker(false, false, "lmnop")
    );
  }).then(() => {
    // maxNodes with the second-to-last item centered should give us the last 5 nodes.
    return gWalker.children(longList, { maxNodes: 5, center: allChildren[24] }).then(
      nodeArrayChecker(false, true, "vwxyz")
    );
  }).then(() => {
    // maxNodes with a start in the middle should start at that node and fetch 5
    let start = allChildren[13];
    is(start.id, "n", "Make sure I know how to count letters.");
    return gWalker.children(longList, { maxNodes: 5, start: start }).then(
      nodeArrayChecker(false, false, "nopqr")
    );
  }).then(() => {
    // maxNodes near the end should only return what's left
    return gWalker.children(longList, { maxNodes: 5, start: allChildren[24] }).then(
      nodeArrayChecker(false, true, "yz")
    );
  }).then(runNextTest));
});

addTest(function testObjectNodeChildren() {
  promiseDone(
    gWalker.querySelector(gWalker.rootNode, "object")
    .then(object => gWalker.children(object))
    .then(nodeArrayChecker(true, true, "1"))
    .then(runNextTest));
});

addTest(function testSiblings() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(a => {
    return gWalker.siblings(a, { maxNodes: 5, center: a })
           .then(nodeArrayChecker(true, false, "abcde"));
  }).then(() => {
    return gWalker.siblings(gWalker.rootNode).then(response => {
      ok(response.hasFirst && response.hasLast, "Has first and last.");
      is(response.nodes.length, 1, "Has only the document element.");
      ok(response.nodes[0] === gWalker.rootNode, "Document element is its own sibling.");
    });
  }).then(runNextTest));
});

addTest(function testNextSibling() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#y").then(y => {
    is(y.id, "y", "Got the right node.");
    return gWalker.nextSibling(y);
  }).then(z => {
    is(z.id, "z", "nextSibling got the next node.");
    return gWalker.nextSibling(z);
  }).then(nothing => {
    is(nothing, null, "nextSibling on the last node returned null.");
  }).then(runNextTest));
});

addTest(function testPreviousSibling() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#b").then(b => {
    is(b.id, "b", "Got the right node.");
    return gWalker.previousSibling(b);
  }).then(a => {
    is(a.id, "a", "nextSibling got the next node.");
    return gWalker.previousSibling(a);
  }).then(nothing => {
    is(nothing, null, "previousSibling on the first node returned null.");
  }).then(runNextTest));
});

addTest(function testFrameTraversal() {
  promiseDone(gWalker.querySelector(gWalker.rootNode, "#childFrame").then(childFrame => {
    return gWalker.children(childFrame);
  }).then(children => {
    let nodes = children.nodes;
    is(nodes.length, 1, "There should be only one child of the iframe");
    is(nodes[0].nodeType, Node.DOCUMENT_NODE, "iframe child should be a document node");
    return gWalker.querySelector(nodes[0], "#z");
  }).then(childDocumentZ => {
    return gWalker.parents(childDocumentZ);
  }).then(parents => {
    // Expected set of parent tag names for this item:
    let expectedParents = ["DIV", "BODY", "HTML", "#document", "IFRAME", "BODY", "HTML",
                           "#document"];
    for (let parent of parents) {
      let expected = expectedParents.shift();
      is(parent.nodeName, expected, "Got expected parent");
    }
  }).then(runNextTest));
});

addTest(function testLongValue() {
  const testSummaryLength = 10;
  const inspector = require("devtools/server/actors/inspector/inspector");

  inspector.setValueSummaryLength(testSummaryLength);
  SimpleTest.registerCleanupFunction(function () {
    inspector.setValueSummaryLength(inspector.DEFAULT_VALUE_SUMMARY_LENGTH);
  });

  let longstringText = gInspectee.getElementById("longstring").firstChild.nodeValue;

  promiseDone(gWalker.querySelector(gWalker.rootNode, "#longstring").then(node => {
    ok(!node.inlineTextChild, "Text is too long to be inlined");
    // Now we need to get the text node child...
    return gWalker.children(node, { maxNodes: 1 });
  }).then(children => {
    let textNode = children.nodes[0];
    is(textNode.nodeType, Node.TEXT_NODE, "Value should be a text node");
    return textNode;
  }).then(textNode => {
    return textNode.getNodeValue();
  }).then(value => {
    return value.string();
  }).then(valueStr => {
    is(valueStr, longstringText,
       "Full node value should match the string from the document.");
  }).then(runNextTest));
});

addTest(function testShortValue() {
  let shortstringText = gInspectee.getElementById("shortstring").firstChild.nodeValue;

  promiseDone(gWalker.querySelector(gWalker.rootNode, "#shortstring").then(node => {
    ok(!!node.inlineTextChild, "Text is short enough to be inlined");
    // Now we need to get the text node child...
    return gWalker.children(node, { maxNodes: 1 });
  }).then(children => {
    let textNode = children.nodes[0];
    is(textNode.nodeType, Node.TEXT_NODE, "Value should be a text node");
    return textNode;
  }).then(textNode => {
    return textNode.getNodeValue();
  }).then(value => {
    return value.string();
  }).then(valueStr => {
    is(valueStr, shortstringText,
       "Full node value should match the string from the document.");
  }).then(runNextTest));
});

addTest(function testReleaseWalker() {
  checkActorIDs.push(gWalker.actorID);

  promiseDone(gWalker.release().then(() => {
    let promises = Array.from(checkActorIDs, (id) => checkMissing(gClient, id));
    return promise.all(promises);
  }).then(runNextTest));
});

addTest(function cleanup() {
  gWalker = null;
  gInspectee = null;
  gClient = null;
  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>