diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/server/tests/browser/browser_inspector-traversal.js | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/devtools/server/tests/browser/browser_inspector-traversal.js b/devtools/server/tests/browser/browser_inspector-traversal.js new file mode 100644 index 0000000000..786521cc18 --- /dev/null +++ b/devtools/server/tests/browser/browser_inspector-traversal.js @@ -0,0 +1,350 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/devtools/server/tests/browser/inspector-helpers.js", + this +); + +const checkActorIDs = []; + +add_task(async function loadNewChild() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + + // Make sure that refetching the root document of the walker returns the same + // actor as the getWalker returned. + const root = await walker.document(); + Assert.strictEqual( + root, + walker.rootNode, + "Re-fetching the document node should match the root document node." + ); + checkActorIDs.push(root.actorID); + await assertOwnershipTrees(walker); +}); + +add_task(async function testInnerHTML() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + + const docElement = await walker.documentElement(); + const longstring = await walker.innerHTML(docElement); + const innerHTML = await longstring.string(); + const actualInnerHTML = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + function () { + return content.document.documentElement.innerHTML; + } + ); + Assert.strictEqual(innerHTML, actualInnerHTML, "innerHTML should match"); +}); + +add_task(async function testOuterHTML() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + + const docElement = await walker.documentElement(); + const longstring = await walker.outerHTML(docElement); + const outerHTML = await longstring.string(); + const actualOuterHTML = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + function () { + return content.document.documentElement.outerHTML; + } + ); + Assert.strictEqual(outerHTML, actualOuterHTML, "outerHTML should match"); +}); + +add_task(async function testSetOuterHTMLNode() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const newHTML = '<p id="edit-html-done">after edit</p>'; + let node = await walker.querySelector(walker.rootNode, "#edit-html"); + await walker.setOuterHTML(node, newHTML); + node = await walker.querySelector(walker.rootNode, "#edit-html-done"); + const longstring = await walker.outerHTML(node); + const outerHTML = await longstring.string(); + is(outerHTML, newHTML, "outerHTML has been updated"); + node = await walker.querySelector(walker.rootNode, "#edit-html"); + ok(!node, "The node with the old ID cannot be selected anymore"); +}); + +add_task(async function testQuerySelector() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + let node = await walker.querySelector(walker.rootNode, "#longlist"); + is( + node.getAttribute("data-test"), + "exists", + "should have found the right node" + ); + await assertOwnershipTrees(walker); + node = await walker.querySelector(walker.rootNode, "unknownqueryselector"); + ok(!node, "Should not find a node here."); + await assertOwnershipTrees(walker); +}); + +add_task(async function testQuerySelectors() { + const { target, walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const nodeList = await walker.querySelectorAll( + walker.rootNode, + "#longlist div" + ); + is(nodeList.length, 26, "Expect 26 div children."); + await assertOwnershipTrees(walker); + const firstNode = await nodeList.item(0); + checkActorIDs.push(firstNode.actorID); + is(firstNode.id, "a", "First child should be a"); + await assertOwnershipTrees(walker); + let nodes = await nodeList.items(); + 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." + ); + await assertOwnershipTrees(walker); + nodes = await nodeList.items(-1); + 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. + const nodeListID = nodeList.actorID; + await assertOwnershipTrees(walker); + await nodeList.release(); + ok(!nodeList.actorID, "Actor should have been destroyed."); + await assertOwnershipTrees(walker); + await checkMissing(target, nodeListID); +}); + +// Helper to check the response of requests that return hasFirst/hasLast/nodes +// node lists (like `children` and `siblings`) +async function checkArray(walker, children, first, last, ids) { + is( + children.hasFirst, + first, + "Should " + (first ? "" : "not ") + " have the first node." + ); + is( + children.hasLast, + last, + "Should " + (last ? "" : "not ") + " have the last node." + ); + is( + children.nodes.length, + ids.length, + "Should have " + ids.length + " children listed." + ); + let responseIds = ""; + for (const node of children.nodes) { + responseIds += node.id; + } + is(responseIds, ids, "Correct nodes were returned."); + await assertOwnershipTrees(walker); +} + +add_task(async function testNoChildren() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const empty = await walker.querySelector(walker.rootNode, "#empty"); + await assertOwnershipTrees(walker); + const children = await walker.children(empty); + await checkArray(walker, children, true, true, ""); +}); + +add_task(async function testLongListTraversal() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const longList = await walker.querySelector(walker.rootNode, "#longlist"); + // First call with no options, expect all children. + await assertOwnershipTrees(walker); + let children = await walker.children(longList); + await checkArray(walker, children, true, true, "abcdefghijklmnopqrstuvwxyz"); + const allChildren = children.nodes; + await assertOwnershipTrees(walker); + // maxNodes should limit us to the first 5 nodes. + await assertOwnershipTrees(walker); + children = await walker.children(longList, { maxNodes: 5 }); + await checkArray(walker, children, true, false, "abcde"); + await assertOwnershipTrees(walker); + // maxNodes with the second item centered should still give us the first 5 nodes. + children = await walker.children(longList, { + maxNodes: 5, + center: allChildren[1], + }); + await checkArray(walker, children, true, false, "abcde"); + // maxNodes with a center in the middle of the list should put that item in the middle + const center = allChildren[13]; + is(center.id, "n", "Make sure I know how to count letters."); + children = await walker.children(longList, { maxNodes: 5, center }); + await checkArray(walker, children, false, false, "lmnop"); + // maxNodes with the second-to-last item centered should give us the last 5 nodes. + children = await walker.children(longList, { + maxNodes: 5, + center: allChildren[24], + }); + await checkArray(walker, children, false, true, "vwxyz"); + // maxNodes with a start in the middle should start at that node and fetch 5 + const start = allChildren[13]; + is(start.id, "n", "Make sure I know how to count letters."); + children = await walker.children(longList, { maxNodes: 5, start }); + await checkArray(walker, children, false, false, "nopqr"); + // maxNodes near the end should only return what's left + children = await walker.children(longList, { + maxNodes: 5, + start: allChildren[24], + }); + await checkArray(walker, children, false, true, "yz"); +}); + +add_task(async function testObjectNodeChildren() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const object = await walker.querySelector(walker.rootNode, "object"); + const children = await walker.children(object); + await checkArray(walker, children, true, true, "1"); +}); + +add_task(async function testNextSibling() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const y = await walker.querySelector(walker.rootNode, "#y"); + is(y.id, "y", "Got the right node."); + const z = await walker.nextSibling(y); + is(z.id, "z", "nextSibling got the next node."); + const nothing = await walker.nextSibling(z); + is(nothing, null, "nextSibling on the last node returned null."); +}); + +add_task(async function testPreviousSibling() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const b = await walker.querySelector(walker.rootNode, "#b"); + is(b.id, "b", "Got the right node."); + const a = await walker.previousSibling(b); + is(a.id, "a", "nextSibling got the next node."); + const nothing = await walker.previousSibling(a); + is(nothing, null, "previousSibling on the first node returned null."); +}); + +add_task(async function testFrameTraversal() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const childFrame = await walker.querySelector(walker.rootNode, "#childFrame"); + const children = await walker.children(childFrame); + const 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" + ); + await walker.querySelector(nodes[0], "#z"); +}); + +add_task(async function testLongValue() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + + SimpleTest.registerCleanupFunction(async function () { + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { + const { require } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/Loader.sys.mjs" + ); + const WalkerActor = require("resource://devtools/server/actors/inspector/walker.js"); + WalkerActor.setValueSummaryLength( + WalkerActor.DEFAULT_VALUE_SUMMARY_LENGTH + ); + }); + }); + + const longstringText = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + function () { + const { require } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/Loader.sys.mjs" + ); + const testSummaryLength = 10; + const WalkerActor = require("resource://devtools/server/actors/inspector/walker.js"); + + WalkerActor.setValueSummaryLength(testSummaryLength); + return content.document.getElementById("longstring").firstChild.nodeValue; + } + ); + + const node = await walker.querySelector(walker.rootNode, "#longstring"); + ok(!node.inlineTextChild, "Text is too long to be inlined"); + // Now we need to get the text node child... + const children = await walker.children(node, { maxNodes: 1 }); + const textNode = children.nodes[0]; + is(textNode.nodeType, Node.TEXT_NODE, "Value should be a text node"); + const value = await textNode.getNodeValue(); + const valueStr = await value.string(); + is( + valueStr, + longstringText, + "Full node value should match the string from the document." + ); +}); + +add_task(async function testShortValue() { + const { walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + const shortstringText = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + function () { + return content.document.getElementById("shortstring").firstChild + .nodeValue; + } + ); + + const node = await walker.querySelector(walker.rootNode, "#shortstring"); + ok(!!node.inlineTextChild, "Text is short enough to be inlined"); + // Now we need to get the text node child... + const children = await walker.children(node, { maxNodes: 1 }); + const textNode = children.nodes[0]; + is(textNode.nodeType, Node.TEXT_NODE, "Value should be a text node"); + const value = await textNode.getNodeValue(); + const valueStr = await value.string(); + is( + valueStr, + shortstringText, + "Full node value should match the string from the document." + ); +}); + +add_task(async function testReleaseWalker() { + const { target, walker } = await initInspectorFront( + MAIN_DOMAIN + "inspector-traversal-data.html" + ); + checkActorIDs.push(walker.actorID); + + await walker.release(); + for (const id of checkActorIDs) { + await checkMissing(target, id); + } +}); |