diff options
Diffstat (limited to 'devtools/client/dom/test')
-rw-r--r-- | devtools/client/dom/test/.eslintrc.js | 6 | ||||
-rw-r--r-- | devtools/client/dom/test/browser.ini | 12 | ||||
-rw-r--r-- | devtools/client/dom/test/browser_dom_array.js | 40 | ||||
-rw-r--r-- | devtools/client/dom/test/browser_dom_basic.js | 24 | ||||
-rw-r--r-- | devtools/client/dom/test/browser_dom_refresh.js | 25 | ||||
-rw-r--r-- | devtools/client/dom/test/head.js | 239 | ||||
-rw-r--r-- | devtools/client/dom/test/page_array.html | 19 | ||||
-rw-r--r-- | devtools/client/dom/test/page_basic.html | 15 |
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> |