summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/test/browser_treeWidget_basic.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/shared/test/browser_treeWidget_basic.js')
-rw-r--r--devtools/client/shared/test/browser_treeWidget_basic.js391
1 files changed, 391 insertions, 0 deletions
diff --git a/devtools/client/shared/test/browser_treeWidget_basic.js b/devtools/client/shared/test/browser_treeWidget_basic.js
new file mode 100644
index 0000000000..48702b9b8d
--- /dev/null
+++ b/devtools/client/shared/test/browser_treeWidget_basic.js
@@ -0,0 +1,391 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the tree widget api works fine
+"use strict";
+
+const TEST_URI =
+ "data:text/html;charset=utf-8,<head>" +
+ "<link rel='stylesheet' type='text/css' href='chrome://devtools/skin/widg" +
+ "ets.css'></head><body><div></div><span></span></body>";
+const {
+ TreeWidget,
+} = require("resource://devtools/client/shared/widgets/TreeWidget.js");
+
+add_task(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["security.allow_unsafe_parent_loads", true]],
+ });
+ await addTab("about:blank");
+ const { host, doc } = await createHost("bottom", TEST_URI);
+
+ const tree = new TreeWidget(doc.querySelector("div"), {
+ defaultType: "store",
+ });
+
+ populateTree(tree, doc);
+ testTreeItemInsertedCorrectly(tree, doc);
+ testAPI(tree, doc);
+ populateUnsortedTree(tree, doc);
+ testUnsortedTreeItemInsertedCorrectly(tree, doc);
+
+ tree.destroy();
+ host.destroy();
+ gBrowser.removeCurrentTab();
+});
+
+function populateTree(tree, doc) {
+ tree.add([
+ {
+ id: "level1",
+ label: "Level 1",
+ },
+ {
+ id: "level2-1",
+ label: "Level 2",
+ },
+ {
+ id: "level3-1",
+ label: "Level 3 - Child 1",
+ type: "dir",
+ },
+ ]);
+ tree.add([
+ "level1",
+ "level2-1",
+ {
+ id: "level3-2",
+ label: "Level 3 - Child 2",
+ },
+ ]);
+ tree.add([
+ "level1",
+ "level2-1",
+ {
+ id: "level3-3",
+ label: "Level 3 - Child 3",
+ },
+ ]);
+ tree.add([
+ "level1",
+ {
+ id: "level2-2",
+ label: "Level 2.1",
+ },
+ {
+ id: "level3-1",
+ label: "Level 3.1",
+ },
+ ]);
+ tree.add([
+ {
+ id: "level1",
+ label: "Level 1",
+ },
+ {
+ id: "level2",
+ label: "Level 2",
+ },
+ {
+ id: "level3",
+ label: "Level 3",
+ type: "js",
+ },
+ ]);
+ tree.add(["level1.1", "level2", { id: "level3", type: "url" }]);
+}
+
+/**
+ * Test if the nodes are inserted correctly in the tree.
+ */
+function testTreeItemInsertedCorrectly(tree, doc) {
+ is(
+ tree.root.children.children.length,
+ 2,
+ "Number of top level elements match"
+ );
+ is(
+ tree.root.children.firstChild.lastChild.children.length,
+ 3,
+ "Number of first second level elements match"
+ );
+ is(
+ tree.root.children.lastChild.lastChild.children.length,
+ 1,
+ "Number of second second level elements match"
+ );
+
+ ok(tree.root.items.has("level1"), "Level1 top level element exists");
+ is(
+ tree.root.children.firstChild.dataset.id,
+ JSON.stringify(["level1"]),
+ "Data id of first top level element matches"
+ );
+ is(
+ tree.root.children.firstChild.firstChild.textContent,
+ "Level 1",
+ "Text content of first top level element matches"
+ );
+
+ ok(tree.root.items.has("level1.1"), "Level1.1 top level element exists");
+ is(
+ tree.root.children.firstChild.nextSibling.dataset.id,
+ JSON.stringify(["level1.1"]),
+ "Data id of second top level element matches"
+ );
+ is(
+ tree.root.children.firstChild.nextSibling.firstChild.textContent,
+ "level1.1",
+ "Text content of second top level element matches"
+ );
+
+ // Adding a new non text item in the tree.
+ const node = doc.createElement("div");
+ node.textContent = "Foo Bar";
+ node.className = "foo bar";
+ tree.add([
+ {
+ id: "level1.2",
+ node,
+ attachment: {
+ foo: "bar",
+ },
+ },
+ ]);
+
+ is(
+ tree.root.children.children.length,
+ 3,
+ "Number of top level elements match after update"
+ );
+ ok(tree.root.items.has("level1.2"), "New level node got added");
+ ok(
+ tree.attachments.has(JSON.stringify(["level1.2"])),
+ "Attachment is present for newly added node"
+ );
+ // The item should be added before level1 and level 1.1 as lexical sorting
+ is(
+ tree.root.children.firstChild.dataset.id,
+ JSON.stringify(["level1.2"]),
+ "Data id of last top level element matches"
+ );
+ is(
+ tree.root.children.firstChild.firstChild.firstChild,
+ node,
+ "Newly added node is inserted at the right location"
+ );
+}
+
+/**
+ * Populate the unsorted tree.
+ */
+function populateUnsortedTree(tree, doc) {
+ tree.sorted = false;
+
+ tree.add([{ id: "g-1", label: "g-1" }]);
+ tree.add(["g-1", { id: "d-2", label: "d-2.1" }]);
+ tree.add(["g-1", { id: "b-2", label: "b-2.2" }]);
+ tree.add(["g-1", { id: "a-2", label: "a-2.3" }]);
+}
+
+/**
+ * Test if the nodes are inserted correctly in the unsorted tree.
+ */
+function testUnsortedTreeItemInsertedCorrectly(tree, doc) {
+ ok(tree.root.items.has("g-1"), "g-1 top level element exists");
+
+ is(
+ tree.root.children.firstChild.lastChild.children.length,
+ 3,
+ "Number of children for g-1 matches"
+ );
+ is(
+ tree.root.children.firstChild.dataset.id,
+ JSON.stringify(["g-1"]),
+ "Data id of g-1 matches"
+ );
+ is(
+ tree.root.children.firstChild.firstChild.textContent,
+ "g-1",
+ "Text content of g-1 matches"
+ );
+ is(
+ tree.root.children.firstChild.lastChild.firstChild.dataset.id,
+ JSON.stringify(["g-1", "d-2"]),
+ "Data id of d-2 matches"
+ );
+ is(
+ tree.root.children.firstChild.lastChild.firstChild.textContent,
+ "d-2.1",
+ "Text content of d-2 matches"
+ );
+ is(
+ tree.root.children.firstChild.lastChild.firstChild.nextSibling.textContent,
+ "b-2.2",
+ "Text content of b-2 matches"
+ );
+ is(
+ tree.root.children.firstChild.lastChild.lastChild.textContent,
+ "a-2.3",
+ "Text content of a-2 matches"
+ );
+}
+
+/**
+ * Tests if the API exposed by TreeWidget works properly
+ */
+function testAPI(tree, doc) {
+ info("Testing TreeWidget API");
+ // Check if selectItem and selectedItem setter works as expected
+ // Nothing should be selected beforehand
+ ok(!doc.querySelector(".theme-selected"), "Nothing is selected");
+ tree.selectItem(["level1"]);
+ const node = doc.querySelector(".theme-selected");
+ ok(!!node, "Something got selected");
+ is(
+ node.parentNode.dataset.id,
+ JSON.stringify(["level1"]),
+ "Correct node selected"
+ );
+
+ tree.selectItem(["level1", "level2"]);
+ const node2 = doc.querySelector(".theme-selected");
+ ok(!!node2, "Something is still selected");
+ isnot(node, node2, "Newly selected node is different from previous");
+ is(
+ node2.parentNode.dataset.id,
+ JSON.stringify(["level1", "level2"]),
+ "Correct node selected"
+ );
+
+ // test if selectedItem getter works
+ is(tree.selectedItem.length, 2, "Correct length of selected item");
+ is(tree.selectedItem[0], "level1", "Correct selected item");
+ is(tree.selectedItem[1], "level2", "Correct selected item");
+
+ // test if isSelected works
+ ok(tree.isSelected(["level1", "level2"]), "isSelected works");
+
+ tree.selectedItem = ["level1"];
+ const node3 = doc.querySelector(".theme-selected");
+ ok(!!node3, "Something is still selected");
+ isnot(node2, node3, "Newly selected node is different from previous");
+ is(node3, node, "First and third selected nodes should be same");
+ is(
+ node3.parentNode.dataset.id,
+ JSON.stringify(["level1"]),
+ "Correct node selected"
+ );
+
+ // test if selectedItem getter works
+ is(tree.selectedItem.length, 1, "Correct length of selected item");
+ is(tree.selectedItem[0], "level1", "Correct selected item");
+
+ // test if clear selection works
+ tree.clearSelection();
+ ok(
+ !doc.querySelector(".theme-selected"),
+ "Nothing selected after clear selection call"
+ );
+
+ // test if collapseAll/expandAll work
+ ok(!!doc.querySelectorAll("[expanded]").length, "Some nodes are expanded");
+ tree.collapseAll();
+ is(
+ doc.querySelectorAll("[expanded]").length,
+ 0,
+ "Nothing is expanded after collapseAll call"
+ );
+ tree.expandAll();
+ is(
+ doc.querySelectorAll("[expanded]").length,
+ 13,
+ "All tree items expanded after expandAll call"
+ );
+
+ // test if selectNextItem and selectPreviousItem work
+ tree.selectedItem = ["level1", "level2"];
+ ok(tree.isSelected(["level1", "level2"]), "Correct item selected");
+ tree.selectNextItem();
+ ok(
+ tree.isSelected(["level1", "level2", "level3"]),
+ "Correct item selected after selectNextItem call"
+ );
+
+ tree.selectNextItem();
+ ok(
+ tree.isSelected(["level1", "level2-1"]),
+ "Correct item selected after second selectNextItem call"
+ );
+
+ tree.selectNextItem();
+ ok(
+ tree.isSelected(["level1", "level2-1", "level3-1"]),
+ "Correct item selected after third selectNextItem call"
+ );
+
+ tree.selectPreviousItem();
+ ok(
+ tree.isSelected(["level1", "level2-1"]),
+ "Correct item selected after selectPreviousItem call"
+ );
+
+ tree.selectPreviousItem();
+ ok(
+ tree.isSelected(["level1", "level2", "level3"]),
+ "Correct item selected after second selectPreviousItem call"
+ );
+
+ // test if remove works
+ ok(
+ doc.querySelector(
+ "[data-id='" + JSON.stringify(["level1", "level2", "level3"]) + "']"
+ ),
+ "level1-level2-level3 item exists before removing"
+ );
+ tree.remove(["level1", "level2", "level3"]);
+ ok(
+ !doc.querySelector(
+ "[data-id='" + JSON.stringify(["level1", "level2", "level3"]) + "']"
+ ),
+ "level1-level2-level3 item does not exist after removing"
+ );
+ const level2item = doc.querySelector(
+ "[data-id='" +
+ JSON.stringify(["level1", "level2"]) +
+ "'] > .tree-widget-item"
+ );
+ ok(
+ level2item.hasAttribute("empty"),
+ "level1-level2 item is marked as empty after removing"
+ );
+
+ tree.add([
+ {
+ id: "level1",
+ label: "Level 1",
+ },
+ {
+ id: "level2",
+ label: "Level 2",
+ },
+ {
+ id: "level3",
+ label: "Level 3",
+ type: "js",
+ },
+ ]);
+
+ // test if clearing the tree works
+ is(
+ doc.querySelectorAll("[level='1']").length,
+ 3,
+ "Correct number of top level items before clearing"
+ );
+ tree.clear();
+ is(
+ doc.querySelectorAll("[level='1']").length,
+ 0,
+ "No top level item after clearing the tree"
+ );
+}