summaryrefslogtreecommitdiffstats
path: root/devtools/client/dom/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/dom/test')
-rw-r--r--devtools/client/dom/test/.eslintrc.js6
-rw-r--r--devtools/client/dom/test/browser.ini12
-rw-r--r--devtools/client/dom/test/browser_dom_array.js40
-rw-r--r--devtools/client/dom/test/browser_dom_basic.js24
-rw-r--r--devtools/client/dom/test/browser_dom_refresh.js25
-rw-r--r--devtools/client/dom/test/head.js239
-rw-r--r--devtools/client/dom/test/page_array.html19
-rw-r--r--devtools/client/dom/test/page_basic.html15
8 files changed, 380 insertions, 0 deletions
diff --git a/devtools/client/dom/test/.eslintrc.js b/devtools/client/dom/test/.eslintrc.js
new file mode 100644
index 000000000..140985533
--- /dev/null
+++ b/devtools/client/dom/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../.eslintrc.mochitests.js",
+};
diff --git a/devtools/client/dom/test/browser.ini b/devtools/client/dom/test/browser.ini
new file mode 100644
index 000000000..e8e35b32b
--- /dev/null
+++ b/devtools/client/dom/test/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ head.js
+ page_array.html
+ page_basic.html
+ !/devtools/client/framework/test/shared-head.js
+
+[browser_dom_array.js]
+[browser_dom_basic.js]
+[browser_dom_refresh.js]
diff --git a/devtools/client/dom/test/browser_dom_array.js b/devtools/client/dom/test/browser_dom_array.js
new file mode 100644
index 000000000..2813af320
--- /dev/null
+++ b/devtools/client/dom/test/browser_dom_array.js
@@ -0,0 +1,40 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_PAGE_URL = URL_ROOT + "page_array.html";
+const TEST_ARRAY = [
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
+];
+
+/**
+ * Basic test that checks content of the DOM panel.
+ */
+add_task(function* () {
+ info("Test DOM Panel Array Expansion started");
+
+ let { panel } = yield addTestTab(TEST_PAGE_URL);
+
+ // Expand specified row and wait till children are displayed.
+ yield expandRow(panel, "_a");
+
+ // Verify that children is displayed now.
+ let childRows = getAllRowsForLabel(panel, "_a");
+
+ let item = childRows.pop();
+ is(item.name, "length", "length property is correct");
+ is(item.value, 26, "length property value is 26");
+
+ let i = 0;
+ for (let name in childRows) {
+ let row = childRows[name];
+
+ is(name, i++, `index ${name} is correct and sorted into the correct position`);
+ ok(typeof row.name === "number", "array index is displayed as a number");
+ is(TEST_ARRAY[name], row.value, `value for array[${name}] is ${row.value}`);
+ }
+});
diff --git a/devtools/client/dom/test/browser_dom_basic.js b/devtools/client/dom/test/browser_dom_basic.js
new file mode 100644
index 000000000..2b76fe0fe
--- /dev/null
+++ b/devtools/client/dom/test/browser_dom_basic.js
@@ -0,0 +1,24 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_PAGE_URL = URL_ROOT + "page_basic.html";
+
+/**
+ * Basic test that checks content of the DOM panel.
+ */
+add_task(function* () {
+ info("Test DOM panel basic started");
+
+ let { panel } = yield addTestTab(TEST_PAGE_URL);
+
+ // Expand specified row and wait till children are displayed.
+ yield expandRow(panel, "_a");
+
+ // Verify that child is displayed now.
+ let childRow = getRowByLabel(panel, "_data");
+ ok(childRow, "Child row must exist");
+});
diff --git a/devtools/client/dom/test/browser_dom_refresh.js b/devtools/client/dom/test/browser_dom_refresh.js
new file mode 100644
index 000000000..9fdc6aa7f
--- /dev/null
+++ b/devtools/client/dom/test/browser_dom_refresh.js
@@ -0,0 +1,25 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_PAGE_URL = URL_ROOT + "page_basic.html";
+
+/**
+ * Basic test that checks the Refresh action in DOM panel.
+ */
+add_task(function* () {
+ info("Test DOM panel basic started");
+
+ let { panel } = yield addTestTab(TEST_PAGE_URL);
+
+ // Create a new variable in the page scope and refresh the panel.
+ yield evaluateJSAsync(panel, "var _b = 10");
+ yield refreshPanel(panel);
+
+ // Verify that the variable is displayed now.
+ let row = getRowByLabel(panel, "_b");
+ ok(row, "New variable must be displayed");
+});
diff --git a/devtools/client/dom/test/head.js b/devtools/client/dom/test/head.js
new file mode 100644
index 000000000..f9382786b
--- /dev/null
+++ b/devtools/client/dom/test/head.js
@@ -0,0 +1,239 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */
+/* import-globals-from ../../framework/test/shared-head.js */
+
+"use strict";
+
+const FRAME_SCRIPT_UTILS_URL =
+ "chrome://devtools/content/shared/frame-script-utils.js";
+
+// shared-head.js handles imports, constants, and utility functions
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
+
+// DOM panel actions.
+const constants = require("devtools/client/dom/content/constants");
+
+// Uncomment this pref to dump all devtools emitted events to the console.
+// Services.prefs.setBoolPref("devtools.dom.enabled", true);
+
+// Enable the DOM panel
+Services.prefs.setBoolPref("devtools.dom.enabled", true);
+
+registerCleanupFunction(() => {
+ info("finish() was called, cleaning up...");
+ Services.prefs.clearUserPref("devtools.dump.emit");
+ Services.prefs.clearUserPref("devtools.dom.enabled");
+});
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ * @param {String} url
+ * The url to be loaded in the new tab
+ * @return a promise that resolves to the tab object when
+ * the url is loaded
+ */
+function addTestTab(url) {
+ info("Adding a new test tab with URL: '" + url + "'");
+
+ return new Promise(resolve => {
+ addTab(url).then(tab => {
+ // Load devtools/shared/frame-script-utils.js
+ getFrameScript();
+
+ // Select the DOM panel and wait till it's initialized.
+ initDOMPanel(tab).then(panel => {
+ waitForDispatch(panel, "FETCH_PROPERTIES").then(() => {
+ resolve({
+ tab: tab,
+ browser: tab.linkedBrowser,
+ panel: panel
+ });
+ });
+ });
+ });
+ });
+}
+
+/**
+ * Open the DOM panel for the given tab.
+ *
+ * @param {nsIDOMElement} tab
+ * Optional tab element for which you want open the DOM panel.
+ * The default tab is taken from the global variable |tab|.
+ * @return a promise that is resolved once the web console is open.
+ */
+function initDOMPanel(tab) {
+ return new Promise(resolve => {
+ let target = TargetFactory.forTab(tab || gBrowser.selectedTab);
+ gDevTools.showToolbox(target, "dom").then(toolbox => {
+ let panel = toolbox.getCurrentPanel();
+ resolve(panel);
+ });
+ });
+}
+
+/**
+ * Synthesize asynchronous click event (with clean stack trace).
+ */
+function synthesizeMouseClickSoon(panel, element) {
+ return new Promise(resolve => {
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(element, 2, 2, {}, panel.panelWin);
+ resolve();
+ });
+ });
+}
+
+/**
+ * Returns tree row with specified label.
+ */
+function getRowByLabel(panel, text) {
+ let doc = panel.panelWin.document;
+ let labels = [...doc.querySelectorAll(".treeLabel")];
+ let label = labels.find(node => node.textContent == text);
+ return label ? label.closest(".treeRow") : null;
+}
+
+/**
+ * Returns the children (tree row text) of the specified object name as an
+ * array.
+ */
+function getAllRowsForLabel(panel, text) {
+ let rootObjectLevel;
+ let node;
+ let result = [];
+ let doc = panel.panelWin.document;
+ let nodes = [...doc.querySelectorAll(".treeLabel")];
+
+ // Find the label (object name) for which we want the children. We remove
+ // nodes from the start of the array until we reach the property. The children
+ // are then at the start of the array.
+ while (true) {
+ node = nodes.shift();
+
+ if (!node || node.textContent === text) {
+ rootObjectLevel = node.getAttribute("data-level");
+ break;
+ }
+ }
+
+ // Return an empty array if the node is not found.
+ if (!node) {
+ return result;
+ }
+
+ // Now get the children.
+ for (node of nodes) {
+ let level = node.getAttribute("data-level");
+
+ if (level > rootObjectLevel) {
+ result.push({
+ name: normalizeTreeValue(node.textContent),
+ value: normalizeTreeValue(node.parentNode.nextElementSibling.textContent)
+ });
+ } else {
+ break;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Strings in the tree are in the form ""a"" and numbers in the form "1". We
+ * normalize these values by converting ""a"" to "a" and "1" to 1.
+ *
+ * @param {String} value
+ * The value to normalize.
+ * @return {String|Number}
+ * The normalized value.
+ */
+function normalizeTreeValue(value) {
+ if (value === `""`) {
+ return "";
+ }
+ if (value.startsWith(`"`) && value.endsWith(`"`)) {
+ return value.substr(1, value.length - 2);
+ }
+ if (isFinite(value) && parseInt(value, 10) == value) {
+ return parseInt(value, 10);
+ }
+
+ return value;
+}
+
+/**
+ * Expands elements with given label and waits till
+ * children are received from the backend.
+ */
+function expandRow(panel, labelText) {
+ let row = getRowByLabel(panel, labelText);
+ return synthesizeMouseClickSoon(panel, row).then(() => {
+ // Wait till children (properties) are fetched
+ // from the backend.
+ return waitForDispatch(panel, "FETCH_PROPERTIES");
+ });
+}
+
+function evaluateJSAsync(panel, expression) {
+ return new Promise(resolve => {
+ panel.target.activeConsole.evaluateJSAsync(expression, res => {
+ resolve(res);
+ });
+ });
+}
+
+function refreshPanel(panel) {
+ let doc = panel.panelWin.document;
+ let button = doc.querySelector(".btn.refresh");
+ return synthesizeMouseClickSoon(panel, button).then(() => {
+ // Wait till children (properties) are fetched
+ // from the backend.
+ return waitForDispatch(panel, "FETCH_PROPERTIES");
+ });
+}
+
+// Redux related API, use from shared location
+// as soon as bug 1261076 is fixed.
+
+// Wait until an action of `type` is dispatched. If it's part of an
+// async operation, wait until the `status` field is "done" or "error"
+function _afterDispatchDone(store, type) {
+ return new Promise(resolve => {
+ store.dispatch({
+ // Normally we would use `services.WAIT_UNTIL`, but use the
+ // internal name here so tests aren't forced to always pass it
+ // in
+ type: "@@service/waitUntil",
+ predicate: action => {
+ if (action.type === type) {
+ return action.status ?
+ (action.status === "end" || action.status === "error") :
+ true;
+ }
+ return false;
+ },
+ run: (dispatch, getState, action) => {
+ resolve(action);
+ }
+ });
+ });
+}
+
+function waitForDispatch(panel, type, eventRepeat = 1) {
+ const store = panel.panelWin.view.mainFrame.store;
+ const actionType = constants[type];
+ let count = 0;
+
+ return Task.spawn(function* () {
+ info("Waiting for " + type + " to dispatch " + eventRepeat + " time(s)");
+ while (count < eventRepeat) {
+ yield _afterDispatchDone(store, actionType);
+ count++;
+ info(type + " dispatched " + count + " time(s)");
+ }
+ });
+}
diff --git a/devtools/client/dom/test/page_array.html b/devtools/client/dom/test/page_array.html
new file mode 100644
index 000000000..703b93a85
--- /dev/null
+++ b/devtools/client/dom/test/page_array.html
@@ -0,0 +1,19 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>DOM Panel Array Expansion Test Page</title>
+ </head>
+ <body>
+ <h2>DOM Panel Array Expansion Test Page</h2>
+ <script type="text/javascript">
+ "use strict";
+ window._a = [
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
+ ];
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/dom/test/page_basic.html b/devtools/client/dom/test/page_basic.html
new file mode 100644
index 000000000..170b3112a
--- /dev/null
+++ b/devtools/client/dom/test/page_basic.html
@@ -0,0 +1,15 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>DOM test page</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ "use strict";
+ window._a = {_data: "test"};
+ </script>
+ </body>
+</html>