Bug 1181837 - 6 - Include inspector's head.js in rule and computed view tests to remove duplication; r=bgrins

This commit is contained in:
Patrick Brosset 2016-01-20 09:17:11 +01:00
parent f0bc872ead
commit 9b6ebd4e60
38 changed files with 233 additions and 920 deletions

View File

@ -28,7 +28,10 @@ let promise = require("promise");
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
const CHROME_URL_ROOT = TEST_DIR + "/";
const URL_ROOT = CHROME_URL_ROOT.replace("chrome://mochitests/content/", "http://example.com/");
const URL_ROOT = CHROME_URL_ROOT.replace("chrome://mochitests/content/",
"http://example.com/");
const URL_ROOT_SSL = CHROME_URL_ROOT.replace("chrome://mochitests/content/",
"https://example.com/");
// All test are asynchronous
waitForExplicitFinish();

View File

@ -8,7 +8,7 @@
const {PropertyView} =
require("devtools/client/inspector/computed/computed");
const TEST_URI = TEST_URL_ROOT + "doc_matched_selectors.html";
const TEST_URI = URL_ROOT + "doc_matched_selectors.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Tests that we correctly display appropriate media query titles in the
// property view.
const TEST_URI = TEST_URL_ROOT + "doc_media_queries.html";
const TEST_URI = URL_ROOT + "doc_media_queries.html";
var {PropertyView} = require("devtools/client/inspector/computed/computed");
var {CssLogic} = require("devtools/shared/inspector/css-logic");

View File

@ -7,7 +7,7 @@
// Tests that the computed view shows the original source link when source maps
// are enabled.
const TESTCASE_URI = TEST_URL_ROOT_SSL + "doc_sourcemaps.html";
const TESTCASE_URI = URL_ROOT_SSL + "doc_sourcemaps.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const SCSS_LOC = "doc_sourcemaps.scss:4";
const CSS_LOC = "doc_sourcemaps.css:1";

View File

@ -6,7 +6,7 @@
// Tests that pseudoelements are displayed correctly in the rule view.
const TEST_URI = TEST_URL_ROOT + "doc_pseudoelement.html";
const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -19,7 +19,9 @@ add_task(function*() {
info("Changing the node's style and waiting for the update");
let onUpdated = inspector.once("computed-view-refreshed");
getNode("#testdiv").style.cssText = "font-size: 15px; color: red;";
// FIXME: use the testActor to set style on the node.
content.document.querySelector("#testdiv")
.style.cssText = "font-size: 15px; color: red;";
yield onUpdated;
fontSize = getComputedViewPropertyValue(view, "font-size");

View File

@ -44,7 +44,7 @@ add_task(function*() {
yield checkSelectAll(view);
});
function checkCopySelection(view) {
function* checkCopySelection(view) {
info("Testing selection copy");
let contentDocument = view.styleDocument;
@ -63,16 +63,15 @@ function checkCopySelection(view) {
"font-size: 16px;[\\r\\n]+" +
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(props[0]);
}, () => {
return checkClipboardData(expectedPattern);
}).then(() => {}, () => {
try {
yield waitForClipboard(() => fireCopyEvent(props[0]),
() => checkClipboardData(expectedPattern));
} catch (e) {
failedClipboard(expectedPattern);
});
}
}
function checkSelectAll(view) {
function* checkSelectAll(view) {
info("Testing select-all copy");
let contentDoc = view.styleDocument;
@ -86,13 +85,12 @@ function checkSelectAll(view) {
"font-size: 16px;[\\r\\n]+" +
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(prop);
}, () => {
return checkClipboardData(expectedPattern);
}).then(() => {}, () => {
try {
yield waitForClipboard(() => fireCopyEvent(prop),
() => checkClipboardData(expectedPattern));
} catch (e) {
failedClipboard(expectedPattern);
});
}
}
function checkClipboardData(expectedPattern) {

View File

@ -1,137 +1,31 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let Cu = Components.utils;
let {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let {TargetFactory} = require("devtools/client/framework/target");
let {CssComputedView} =
require("devtools/client/inspector/computed/computed");
let DevToolsUtils = require("devtools/shared/DevToolsUtils");
let promise = require("promise");
let {console} =
Components.utils.import("resource://gre/modules/Console.jsm", {});
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
// All tests are asynchronous
waitForExplicitFinish();
const TEST_URL_ROOT =
"http://example.com/browser/devtools/client/inspector/computed/test/";
const TEST_URL_ROOT_SSL =
"https://example.com/browser/devtools/client/inspector/computed/test/";
const ROOT_TEST_DIR = getRootDirectory(gTestPath);
const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
// Auto clean-up when a test ends
registerCleanupFunction(function*() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
DevToolsUtils.testing = true;
registerCleanupFunction(() => DevToolsUtils.testing = false);
// Clean-up all prefs that might have been changed during a test run
// (safer here because if the test fails, then the pref is never reverted)
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
Services.prefs.clearUserPref("devtools.dump.emit");
Services.prefs.clearUserPref("devtools.defaultColorUnit");
});
/**
* The functions found below are here to ease test development and maintenance.
* Most of these functions are stateless and will require some form of context
* (the instance of the current toolbox, or inspector panel for instance).
*
* Most of these functions are async too and return promises.
*
* All tests should follow the following pattern:
*
* add_task(function*() {
* yield addTab(TEST_URI);
* let {toolbox, inspector, view} = yield openComputedView();
*
* yield selectNode("#test", inspector);
* yield someAsyncTestFunction(view);
* });
*
* add_task is the way to define the testcase in the test file. It accepts
* a single generator-function argument.
* The generator function should yield any async call.
*
* There is no need to clean tabs up at the end of a test as this is done
* automatically.
*
* It is advised not to store any references on the global scope. There
* shouldn't be a need to anyway. Thanks to add_task, test steps, even
* though asynchronous, can be described in a nice flat way, and
* if/for/while/... control flow can be used as in sync code, making it
* possible to write the outline of the test case all in add_task, and delegate
* actual processing and assertions to other functions.
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
/* *********************************************
* UTILS
* *********************************************
* General test utilities.
* Add new tabs, open the toolbox and switch to the various panels, select
* nodes, get node references, ...
*/
/**
* 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 addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let browser = tab.linkedBrowser;
info("Loading the helper frame script " + FRAME_SCRIPT_URL);
browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
def.resolve(tab);
}, true);
return def.promise;
}
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
*
* @param {String|DOMNode} nodeOrSelector
* @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
* doesn't implement *all* of the DOMNode's properties
*/
function getNode(nodeOrSelector) {
info("Getting the node for '" + nodeOrSelector + "'");
return typeof nodeOrSelector === "string" ?
content.document.querySelector(nodeOrSelector) :
nodeOrSelector;
function openComputedView() {
return openInspectorSidebarTab("computedview").then(objects => {
return {
toolbox: objects.toolbox,
inspector: objects.inspector,
view: objects.view.view
};
});
}
/**
@ -146,187 +40,6 @@ function getNodeFront(selector, {walker}) {
return walker.querySelector(walker.rootNode, selector);
}
/*
* Set the inspector's current selection to a node or to the first match of the
* given css selector.
*
* @param {String|NodeFront} data
* The node to select
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @return {Promise} Resolves when the inspector is updated with the new node
*/
var selectNode = Task.async(function*(data, inspector, reason="test") {
info("Selecting the node for '" + data + "'");
let nodeFront = data;
if (!data._form) {
nodeFront = yield getNodeFront(data, inspector);
}
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(nodeFront, reason);
yield updated;
});
/**
* Open the toolbox, with the inspector tool visible.
*
* @return a promise that resolves when the inspector is ready
*/
var openInspector = Task.async(function*() {
info("Opening the inspector");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let inspector, toolbox;
// Checking if the toolbox and the inspector are already loaded
// The inspector-updated event should only be waited for if the inspector
// isn't loaded yet
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
inspector = toolbox.getPanel("inspector");
if (inspector) {
info("Toolbox and inspector already open");
return {
toolbox: toolbox,
inspector: inspector
};
}
}
info("Opening the toolbox");
toolbox = yield gDevTools.showToolbox(target, "inspector");
yield waitForToolboxFrameFocus(toolbox);
inspector = toolbox.getPanel("inspector");
info("Waiting for the inspector to update");
yield inspector.once("inspector-updated");
return {
toolbox: toolbox,
inspector: inspector
};
});
/**
* Wait for the toolbox frame to receive focus after it loads
*
* @param {Toolbox} toolbox
* @return a promise that resolves when focus has been received
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
let def = promise.defer();
let win = toolbox.frame.contentWindow;
waitForFocus(def.resolve, win);
return def.promise;
}
/**
* Open the toolbox, with the inspector tool visible, and the sidebar that
* corresponds to the given id selected
*
* @return a promise that resolves when the inspector is ready and the sidebar
* view is visible and ready
*/
var openInspectorSideBar = Task.async(function*(id) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id].view
};
});
/**
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
function openComputedView() {
return openInspectorSideBar("computedview");
}
/**
* Wait for eventName on target to be delivered a number of times.
*
* @param {Object} target
* An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Number} numTimes
* Number of deliveries to wait for.
* @param {Boolean} useCapture
* Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function waitForNEvents(target, eventName, numTimes, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
let count = 0;
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
if (++count == numTimes) {
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}
}, useCapture);
break;
}
}
return deferred.promise;
}
/**
* Wait for eventName on target.
*
* @param {Object} target
* An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture
* Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
return waitForNEvents(target, eventName, 1, useCapture);
}
/**
* This shouldn't be used in the tests, but is useful when writing new tests or
* debugging existing tests in order to introduce delays in the test steps
*
* @param {Number} ms
* The time to wait
* @return A promise that resolves when the time is passed
*/
function wait(ms) {
let def = promise.defer();
content.setTimeout(def.resolve, ms);
return def.promise;
}
/**
* Listen for a new tab to open and return a promise that resolves when one
* does and completes the load event.
@ -343,23 +56,6 @@ var waitForTab = Task.async(function*() {
return tab;
});
/**
* @see SimpleTest.waitForClipboard
*
* @param {Function} setup
* Function to execute before checking for the
* clipboard content
* @param {String|Boolean} expected
* An expected string or validator function
* @return a promise that resolves when the expected string has been found or
* the validator function has returned true, rejects otherwise.
*/
function waitForClipboard(setup, expected) {
let def = promise.defer();
SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
return def.promise;
}
/**
* Dispatch the copy event on the given element
*/
@ -369,18 +65,6 @@ function fireCopyEvent(element) {
element.dispatchEvent(evt);
}
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
*
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Simulate the key input for the given input in the window.
*
@ -395,13 +79,6 @@ function synthesizeKeys(input, win) {
}
}
/* *********************************************
* COMPUTED-VIEW
* *********************************************
* Computed-view related utility functions.
* Allows to get properties, links, expand properties, ...
*/
/**
* Get references to the name and value span nodes corresponding to a given
* property name in the computed-view
@ -534,77 +211,3 @@ function getComputedViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".rule-link .link");
return links[index];
}
/* *********************************************
* STYLE-EDITOR
* *********************************************
* Style-editor related utility functions.
*/
/**
* Wait for the toolbox to emit the styleeditor-selected event and when done
* wait for the stylesheet identified by href to be loaded in the stylesheet
* editor
*
* @param {Toolbox} toolbox
* @param {String} href
* Optional, if not provided, wait for the first editor to be ready
* @return a promise that resolves to the editor when the stylesheet editor is
* ready
*/
function waitForStyleEditor(toolbox, href) {
let def = promise.defer();
info("Waiting for the toolbox to switch to the styleeditor");
toolbox.once("styleeditor-selected").then(() => {
let panel = toolbox.getCurrentPanel();
ok(panel && panel.UI, "Styleeditor panel switched to front");
// A helper that resolves the promise once it receives an editor that
// matches the expected href. Returns false if the editor was not correct.
let gotEditor = (event, editor) => {
let currentHref = editor.styleSheet.href;
if (!href || (href && currentHref.endsWith(href))) {
info("Stylesheet editor selected");
panel.UI.off("editor-selected", gotEditor);
editor.getSourceEditor().then(sourceEditor => {
info("Stylesheet editor fully loaded");
def.resolve(sourceEditor);
});
return true;
}
info("The editor was incorrect. Waiting for editor-selected event.");
return false;
};
// The expected editor may already be selected. Check the if the currently
// selected editor is the expected one and if not wait for an
// editor-selected event.
if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
// The expected editor is not selected (yet). Wait for it.
panel.UI.on("editor-selected", gotEditor);
}
});
return def.promise;
}
/**
* Reload the current page and wait for the inspector to be initialized after
* the navigation
*
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves after page reload and inspector
* initialization
*/
function reloadPage(inspector) {
let onNewRoot = inspector.once("new-root");
content.location.reload();
return onNewRoot.then(() => {
inspector.markup._waitForChildren();
});
}

View File

@ -45,52 +45,29 @@ function selectAndHighlightNode(nodeOrSelector, inspector) {
return updated;
}
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Open the toolbox, with the inspector tool visible, and the layout-view
* sidebar tab selected.
* @return a promise that resolves when the inspector is ready and the layout
* view is visible and ready
*/
var openLayoutView = Task.async(function*() {
let {toolbox, inspector} = yield openInspector();
function openLayoutView() {
return openInspectorSidebarTab("layoutview").then(objects => {
// The actual highligher show/hide methods are mocked in layoutview tests.
// The highlighter is tested in devtools/inspector/test.
function mockHighlighter({highlighter}) {
highlighter.showBoxModel = function(nodeFront, options) {
return promise.resolve();
};
highlighter.hideBoxModel = function() {
return promise.resolve();
};
}
mockHighlighter(objects.toolbox);
// The actual highligher show/hide methods are mocked in layoutview tests.
// The highlighter is tested in devtools/inspector/test.
function mockHighlighter({highlighter}) {
highlighter.showBoxModel = function(nodeFront, options) {
return promise.resolve();
};
highlighter.hideBoxModel = function() {
return promise.resolve();
};
}
mockHighlighter(toolbox);
if (!hasSideBarTab(inspector, "layoutview")) {
info("Waiting for the layoutview sidebar to be ready");
yield inspector.sidebar.once("layoutview-ready");
}
info("Selecting the layoutview sidebar");
inspector.sidebar.select("layoutview");
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab("layoutview")["layoutview"]
};
});
return objects;
});
}
/**
* Wait for the layoutview-updated event.

View File

@ -7,7 +7,7 @@
// Tests that adding properties to rules work and reselecting the element still
// show them.
const TEST_URI = TEST_URL_ROOT + "doc_content_stylesheet.html";
const TEST_URI = URL_ROOT + "doc_content_stylesheet.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -39,7 +39,7 @@ add_task(function* () {
});
function* testShowMdnTooltip(view) {
setBaseCssDocsUrl(TEST_URL_ROOT);
setBaseCssDocsUrl(URL_ROOT);
info("Setting the popupNode for the MDN docs tooltip");

View File

@ -13,7 +13,7 @@ XPCOMUtils.defineLazyGetter(this, "osString", function() {
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
});
const TEST_URI = TEST_URL_ROOT + "doc_copystyles.html";
const TEST_URI = URL_ROOT + "doc_copystyles.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Test to ensure that CSSOM doesn't make the rule view blow up.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1224121
const TEST_URI = TEST_URL_ROOT + "doc_cssom.html";
const TEST_URI = URL_ROOT + "doc_cssom.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -4,7 +4,7 @@
"use strict";
const TEST_URI = TEST_URL_ROOT + "doc_custom.html";
const TEST_URI = URL_ROOT + "doc_custom.html";
// Tests the display of custom declarations in the rule-view.

View File

@ -23,7 +23,7 @@ const TEST_URI = `
<div id="testid2">Styled Node</div>
`;
var BACKGROUND_IMAGE_URL = 'url("' + TEST_URL_ROOT + 'doc_test_image.png")';
var BACKGROUND_IMAGE_URL = 'url("' + URL_ROOT + 'doc_test_image.png")';
var TEST_DATA = [
{ name: "border-color", value: "red", isValid: true },

View File

@ -5,7 +5,7 @@
// Tests the that Filter Editor Tooltip opens by clicking on filter swatches
const TEST_URL = TEST_URL_ROOT + "doc_filter.html";
const TEST_URL = URL_ROOT + "doc_filter.html";
add_task(function*() {
yield addTab(TEST_URL);

View File

@ -5,7 +5,7 @@
// Tests the Filter Editor Tooltip committing changes on ENTER
const TEST_URL = TEST_URL_ROOT + "doc_filter.html";
const TEST_URL = URL_ROOT + "doc_filter.html";
add_task(function*() {
yield addTab(TEST_URL);

View File

@ -6,7 +6,7 @@
// Tests that changes made to the Filter Editor Tooltip are reverted when
// ESC is pressed
const TEST_URL = TEST_URL_ROOT + "doc_filter.html";
const TEST_URL = URL_ROOT + "doc_filter.html";
add_task(function*() {
yield addTab(TEST_URL);

View File

@ -7,9 +7,6 @@
// Tests that we can guess indentation from a style sheet, not just a
// rule.
// Needed for openStyleEditor.
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/styleeditor/test/head.js", this);
// Use a weird indentation depth to avoid accidental success.
const TEST_URI = `
<style type='text/css'>
@ -35,12 +32,12 @@ div {
add_task(function*() {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
let {toolbox, inspector, view} = yield openRuleView();
yield selectNode("#testid", inspector);
yield testIndentation(inspector, view);
yield testIndentation(toolbox, inspector, view);
});
function* testIndentation(inspector, view) {
function* testIndentation(toolbox, inspector, view) {
let ruleEditor = getRuleViewRuleEditor(view, 2);
info("Focusing a new property name in the rule-view");
@ -68,9 +65,9 @@ function* testIndentation(inspector, view) {
yield onBlur;
yield onModifications;
let { ui } = yield openStyleEditor();
let { UI } = yield toolbox.selectTool("styleeditor");
let styleEditor = yield ui.editors[0].getSourceEditor();
let styleEditor = yield UI.editors[0].getSourceEditor();
let text = styleEditor.sourceEditor.getText();
is(text, expectedText, "style inspector changes are synced");
}

View File

@ -7,7 +7,7 @@
// Test that editing a rule will update the line numbers of subsequent
// rules in the rule view.
const TESTCASE_URI = TEST_URL_ROOT + "doc_keyframeLineNumbers.html";
const TESTCASE_URI = URL_ROOT + "doc_keyframeLineNumbers.html";
add_task(function*() {
yield addTab(TESTCASE_URI);

View File

@ -7,7 +7,7 @@
// Test that keyframe rules and gutters are displayed correctly in the
// rule view.
const TEST_URI = TEST_URL_ROOT + "doc_keyframeanimation.html";
const TEST_URI = URL_ROOT + "doc_keyframeanimation.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Test that verifies the content of the keyframes rule and property changes
// to keyframe rules.
const TEST_URI = TEST_URL_ROOT + "doc_keyframeanimation.html";
const TEST_URI = URL_ROOT + "doc_keyframeanimation.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Test that editing a rule will update the line numbers of subsequent
// rules in the rule view.
const TESTCASE_URI = TEST_URL_ROOT + "doc_ruleLineNumbers.html";
const TESTCASE_URI = URL_ROOT + "doc_ruleLineNumbers.html";
add_task(function*() {
yield addTab(TESTCASE_URI);

View File

@ -7,7 +7,7 @@
// Tests that we correctly display appropriate media query titles in the
// rule view.
const TEST_URI = TEST_URL_ROOT + "doc_media_queries.html";
const TEST_URI = URL_ROOT + "doc_media_queries.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Test that the stylesheet links in the rule view are correct when source maps
// are involved.
const TESTCASE_URI = TEST_URL_ROOT + "doc_sourcemaps.html";
const TESTCASE_URI = URL_ROOT + "doc_sourcemaps.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const SCSS_LOC = "doc_sourcemaps.scss:4";
const CSS_LOC = "doc_sourcemaps.css:1";

View File

@ -6,7 +6,7 @@
// Test that pseudoelements are displayed correctly in the rule view
const TEST_URI = TEST_URL_ROOT + "doc_pseudoelement.html";
const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
const PSEUDO_PREF = "devtools.inspector.show_pseudo_elements";
add_task(function*() {

View File

@ -6,7 +6,7 @@
// Test that pseudoelements are displayed correctly in the rule view
const TEST_URI = TEST_URL_ROOT + "doc_pseudoelement.html";
const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -8,7 +8,7 @@
// selectors.
const SEARCH = "20%";
const TEST_URI = TEST_URL_ROOT + "doc_keyframeanimation.html";
const TEST_URI = URL_ROOT + "doc_keyframeanimation.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -7,7 +7,7 @@
// Tests that the rule view search filter works properly for stylesheet source.
const SEARCH = "doc_urls_clickable.css";
const TEST_URI = TEST_URL_ROOT + "doc_urls_clickable.html";
const TEST_URI = URL_ROOT + "doc_urls_clickable.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -8,7 +8,7 @@
// input that could be parsed as a property line.
const SEARCH = "doc_urls_clickable.css: url";
const TEST_URI = TEST_URL_ROOT + "doc_urls_clickable.html";
const TEST_URI = URL_ROOT + "doc_urls_clickable.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -8,7 +8,7 @@
// source.
const SEARCH = "`doc_urls_clickable.css:1`";
const TEST_URI = TEST_URL_ROOT + "doc_urls_clickable.html";
const TEST_URI = URL_ROOT + "doc_urls_clickable.html";
add_task(function*() {
yield addTab(TEST_URI);

View File

@ -19,7 +19,7 @@ const STYLESHEET_URL = "data:text/css,"+encodeURIComponent(
"}"].join("\n"));
const EXTERNAL_STYLESHEET_FILE_NAME = "doc_style_editor_link.css";
const EXTERNAL_STYLESHEET_URL = TEST_URL_ROOT + EXTERNAL_STYLESHEET_FILE_NAME;
const EXTERNAL_STYLESHEET_URL = URL_ROOT + EXTERNAL_STYLESHEET_FILE_NAME;
const DOCUMENT_URL = "data:text/html;charset=utf-8,"+encodeURIComponent(
['<html>' +

View File

@ -6,8 +6,8 @@
// Tests to make sure that URLs are clickable in the rule view
const TEST_URI = TEST_URL_ROOT + "doc_urls_clickable.html";
const TEST_IMAGE = TEST_URL_ROOT + "doc_test_image.png";
const TEST_URI = URL_ROOT + "doc_urls_clickable.html";
const TEST_IMAGE = URL_ROOT + "doc_test_image.png";
const BASE_64_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAA" +
"FCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAA" +
"BJRU5ErkJggg==";

View File

@ -10,7 +10,7 @@
var PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles";
const { PrefObserver } = require("devtools/client/styleeditor/utils");
const TEST_URI = TEST_URL_ROOT + "doc_author-sheet.html";
const TEST_URI = URL_ROOT + "doc_author-sheet.html";
const TEST_DATA = [
{

View File

@ -1,125 +1,60 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var Cu = Components.utils;
var {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
var {TargetFactory} = require("devtools/client/framework/target");
var {CssRuleView, _ElementStyle} =
require("devtools/client/inspector/rules/rules");
var {CssLogic, CssSelector} = require("devtools/shared/inspector/css-logic");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var promise = require("promise");
var {editableField, getInplaceEditorForSpan: inplaceEditor} =
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.defaultColorUnit");
});
var {CssLogic} = require("devtools/shared/inspector/css-logic");
var {getInplaceEditorForSpan: inplaceEditor} =
require("devtools/client/shared/inplace-editor");
var {console} =
Components.utils.import("resource://gre/modules/Console.jsm", {});
// All tests are asynchronous
waitForExplicitFinish();
const TEST_URL_ROOT =
"http://example.com/browser/devtools/client/inspector/rules/test/";
const TEST_URL_ROOT_SSL =
"https://example.com/browser/devtools/client/inspector/rules/test/";
const ROOT_TEST_DIR = getRootDirectory(gTestPath);
const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
// Auto clean-up when a test ends
registerCleanupFunction(function*() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
DevToolsUtils.testing = true;
registerCleanupFunction(() => DevToolsUtils.testing = false);
// Clean-up all prefs that might have been changed during a test run
// (safer here because if the test fails, then the pref is never reverted)
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
Services.prefs.clearUserPref("devtools.dump.emit");
Services.prefs.clearUserPref("devtools.defaultColorUnit");
});
/**
* The functions found below are here to ease test development and maintenance.
* Most of these functions are stateless and will require some form of context
* (the instance of the current toolbox, or inspector panel for instance).
*
* Most of these functions are async too and return promises.
*
* All tests should follow the following pattern:
*
* add_task(function*() {
* yield addTab(TEST_URI);
* let {toolbox, inspector, view} = yield openComputedView();
*
* yield selectNode("#test", inspector);
* yield someAsyncTestFunction(view);
* });
*
* add_task is the way to define the testcase in the test file. It accepts
* a single generator-function argument.
* The generator function should yield any async call.
*
* There is no need to clean tabs up at the end of a test as this is done
* automatically.
*
* It is advised not to store any references on the global scope. There
* shouldn't be a need to anyway. Thanks to add_task, test steps, even
* though asynchronous, can be described in a nice flat way, and
* if/for/while/... control flow can be used as in sync code, making it
* possible to write the outline of the test case all in add_task, and delegate
* actual processing and assertions to other functions.
*/
/* *********************************************
* UTILS
* *********************************************
* General test utilities.
* Add new tabs, open the toolbox and switch to the various panels, select
* nodes, get node references, ...
* The rule-view tests rely on a frame-script to be injected in the content test
* page. So override the shared-head's addTab to load the frame script after the
* tab was added.
* FIXME: Refactor the rule-view tests to use the testActor instead of a frame
* script, so they can run on remote targets too.
*/
var _addTab = addTab;
addTab = function(url) {
return _addTab(url).then(tab => {
info("Loading the helper frame script " + FRAME_SCRIPT_URL);
let browser = tab.linkedBrowser;
browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
return tab;
});
}
/**
* Add a new test tab in the browser and load the given url.
* Open the toolbox, with the inspector tool visible, and the rule-view
* sidebar tab selected.
*
* @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
* @return a promise that resolves when the inspector is ready and the rule
* view is visible and ready
*/
function addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let browser = tab.linkedBrowser;
info("Loading the helper frame script " + FRAME_SCRIPT_URL);
browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
def.resolve(tab);
}, true);
return def.promise;
function openRuleView() {
return openInspectorSidebarTab("ruleview").then(objects => {
return {
toolbox: objects.toolbox,
inspector: objects.inspector,
view: objects.view.view
};
});
}
/**
@ -137,42 +72,6 @@ function getNode(nodeOrSelector) {
nodeOrSelector;
}
/**
* Get the NodeFront for a given css selector, via the protocol
*
* @param {String} selector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return {Promise} Resolves to the NodeFront instance
*/
function getNodeFront(selector, {walker}) {
return walker.querySelector(walker.rootNode, selector);
}
/*
* Set the inspector's current selection to a node or to the first match of the
* given css selector.
*
* @param {String|NodeFront} data
* The node to select
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @return {Promise} Resolves when the inspector is updated with the new node
*/
var selectNode = Task.async(function*(data, inspector, reason="test") {
info("Selecting the node for '" + data + "'");
let nodeFront = data;
if (!data._form) {
nodeFront = yield getNodeFront(data, inspector);
}
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(nodeFront, reason);
yield updated;
});
/**
* Set the inspector's current selection to null so that no node is selected
*
@ -187,107 +86,6 @@ function clearCurrentNodeSelection(inspector) {
return updated;
}
/**
* Open the toolbox, with the inspector tool visible.
*
* @return a promise that resolves when the inspector is ready
*/
var openInspector = Task.async(function*() {
info("Opening the inspector");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let inspector, toolbox;
// Checking if the toolbox and the inspector are already loaded
// The inspector-updated event should only be waited for if the inspector
// isn't loaded yet
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
inspector = toolbox.getPanel("inspector");
if (inspector) {
info("Toolbox and inspector already open");
return {
toolbox: toolbox,
inspector: inspector
};
}
}
info("Opening the toolbox");
toolbox = yield gDevTools.showToolbox(target, "inspector");
yield waitForToolboxFrameFocus(toolbox);
inspector = toolbox.getPanel("inspector");
info("Waiting for the inspector to update");
yield inspector.once("inspector-updated");
return {
toolbox: toolbox,
inspector: inspector
};
});
/**
* Wait for the toolbox frame to receive focus after it loads
*
* @param {Toolbox} toolbox
* @return a promise that resolves when focus has been received
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
let def = promise.defer();
let win = toolbox.frame.contentWindow;
waitForFocus(def.resolve, win);
return def.promise;
}
/**
* Open the toolbox, with the inspector tool visible, and the sidebar that
* corresponds to the given id selected
*
* @return a promise that resolves when the inspector is ready and the sidebar
* view is visible and ready
*/
var openInspectorSideBar = Task.async(function*(id) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id].view
};
});
/**
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
function openComputedView() {
return openInspectorSideBar("computedview");
}
/**
* Open the toolbox, with the inspector tool visible, and the rule-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the rule
* view is visible and ready
*/
function openRuleView() {
return openInspectorSideBar("ruleview");
}
/**
* Wait for eventName on target to be delivered a number of times.
*
@ -326,21 +124,6 @@ function waitForNEvents(target, eventName, numTimes, useCapture = false) {
return deferred.promise;
}
/**
* Wait for eventName on target.
*
* @param {Object} target
* An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture
* Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
return waitForNEvents(target, eventName, 1, useCapture);
}
/**
* This shouldn't be used in the tests, but is useful when writing new tests or
* debugging existing tests in order to introduce delays in the test steps
@ -513,23 +296,6 @@ var waitForTab = Task.async(function*() {
return tab;
});
/**
* @see SimpleTest.waitForClipboard
*
* @param {Function} setup
* Function to execute before checking for the
* clipboard content
* @param {String|Boolean} expected
* An expected string or validator function
* @return a promise that resolves when the expected string has been found or
* the validator function has returned true, rejects otherwise.
*/
function waitForClipboard(setup, expected) {
let def = promise.defer();
SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
return def.promise;
}
/**
* Polls a given function waiting for it to return true.
*
@ -577,18 +343,6 @@ function addStyle(doc, style) {
return node;
}
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
*
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Get the dataURL for the font family tooltip.
*
@ -621,13 +375,6 @@ function synthesizeKeys(input, win) {
}
}
/* *********************************************
* RULE-VIEW
* *********************************************
* Rule-view related test utility functions
* This object contains functions to get rules, get properties, ...
*/
/**
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
* selector
@ -881,109 +628,6 @@ var setSearchFilter = Task.async(function*(view, searchValue) {
yield view.inspector.once("ruleview-filtered");
});
/* *********************************************
* COMPUTED-VIEW
* *********************************************
* Computed-view related utility functions.
* Allows to get properties, links, expand properties, ...
*/
/**
* Get references to the name and value span nodes corresponding to a given
* property name in the computed-view
*
* @param {CssComputedView} view
* The instance of the computed view panel
* @param {String} name
* The name of the property to retrieve
* @return an object {nameSpan, valueSpan}
*/
function getComputedViewProperty(view, name) {
let prop;
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
let nameSpan = property.querySelector(".property-name");
let valueSpan = property.querySelector(".property-value");
if (nameSpan.textContent === name) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
break;
}
}
return prop;
}
/**
* Get the text value of the property corresponding to a given name in the
* computed-view
*
* @param {CssComputedView} view
* The instance of the computed view panel
* @param {String} name
* The name of the property to retrieve
* @return {String} The property value
*/
function getComputedViewPropertyValue(view, name, propertyName) {
return getComputedViewProperty(view, name, propertyName)
.valueSpan.textContent;
}
/* *********************************************
* STYLE-EDITOR
* *********************************************
* Style-editor related utility functions.
*/
/**
* Wait for the toolbox to emit the styleeditor-selected event and when done
* wait for the stylesheet identified by href to be loaded in the stylesheet
* editor
*
* @param {Toolbox} toolbox
* @param {String} href
* Optional, if not provided, wait for the first editor to be ready
* @return a promise that resolves to the editor when the stylesheet editor is
* ready
*/
function waitForStyleEditor(toolbox, href) {
let def = promise.defer();
info("Waiting for the toolbox to switch to the styleeditor");
toolbox.once("styleeditor-selected").then(() => {
let panel = toolbox.getCurrentPanel();
ok(panel && panel.UI, "Styleeditor panel switched to front");
// A helper that resolves the promise once it receives an editor that
// matches the expected href. Returns false if the editor was not correct.
let gotEditor = (event, editor) => {
let currentHref = editor.styleSheet.href;
if (!href || (href && currentHref.endsWith(href))) {
info("Stylesheet editor selected");
panel.UI.off("editor-selected", gotEditor);
editor.getSourceEditor().then(sourceEditor => {
info("Stylesheet editor fully loaded");
def.resolve(sourceEditor);
});
return true;
}
info("The editor was incorrect. Waiting for editor-selected event.");
return false;
};
// The expected editor may already be selected. Check the if the currently
// selected editor is the expected one and if not wait for an
// editor-selected event.
if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
// The expected editor is not selected (yet). Wait for it.
panel.UI.on("editor-selected", gotEditor);
}
});
return def.promise;
}
/**
* Reload the current page and wait for the inspector to be initialized after
* the navigation

View File

@ -7,7 +7,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URL = URL_ROOT + "doc_inspector_outerhtml.html";
add_task(function *() {
add_task(function*() {
let { inspector } = yield openInspectorForURL(TEST_URL);
let root = inspector.markup._elt;
@ -33,19 +33,12 @@ function* setSelectionNodeFront(node, inspector) {
}
function* checkClipboard(expectedText, node) {
let deferred = promise.defer();
waitForClipboard(
expectedText,
() => fireCopyEvent(node),
deferred.resolve,
deferred.reject
);
try {
yield deferred.promise;
yield waitForClipboard(() => fireCopyEvent(node), expectedText);
ok(true, "Clipboard successfully filled with : " + expectedText);
} catch (e) {
ok(false, "Clipboard could not be filled with the expected text : " + expectedText);
ok(false, "Clipboard could not be filled with the expected text : " +
expectedText);
}
}

View File

@ -34,7 +34,7 @@ const COPY_ITEMS_TEST_DATA = [
},
];
add_task(function *() {
add_task(function*() {
let { inspector } = yield openInspectorForURL(TEST_URL);
for (let {desc, id, selector, text} of COPY_ITEMS_TEST_DATA) {
info("Testing " + desc);
@ -43,9 +43,6 @@ add_task(function *() {
let item = inspector.panelDoc.getElementById(id);
ok(item, "The popup has a " + desc + " menu item.");
let deferred = promise.defer();
waitForClipboard(text, () => item.doCommand(),
deferred.resolve, deferred.reject);
yield deferred.promise;
yield waitForClipboard(() => item.doCommand(), text);
}
});

View File

@ -14,11 +14,6 @@ Services.scriptloader.loadSubScript(
// Services.prefs.clearUserPref("devtools.debugger.log");
// });
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
var ROOT_TEST_DIR = getRootDirectory(gTestPath);
// Import the GCLI test helper
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/commandline/test/helpers.js",
@ -35,7 +30,6 @@ registerCleanupFunction(() => {
});
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.dump.emit");
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
});
@ -165,6 +159,43 @@ function getActiveInspector() {
return gDevTools.getToolbox(target).getPanel("inspector");
}
/**
* Open the toolbox, with the inspector tool visible, and the one of the sidebar
* tabs selected.
* @param {String} id The ID of the sidebar tab to be opened
* @param {String} hostType Optional hostType, as defined in Toolbox.HostType
* @return a promise that resolves when the inspector is ready and the tab is
* visible and ready
*/
var openInspectorSidebarTab = Task.async(function*(id, hostType) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id]
};
});
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Get the NodeFront for a node that matches a given css selector, via the
* protocol.
@ -477,3 +508,71 @@ function waitForChildrenUpdated({markup}) {
});
return def.promise;
}
/**
* Wait for the toolbox to emit the styleeditor-selected event and when done
* wait for the stylesheet identified by href to be loaded in the stylesheet
* editor
*
* @param {Toolbox} toolbox
* @param {String} href
* Optional, if not provided, wait for the first editor to be ready
* @return a promise that resolves to the editor when the stylesheet editor is
* ready
*/
function waitForStyleEditor(toolbox, href) {
let def = promise.defer();
info("Waiting for the toolbox to switch to the styleeditor");
toolbox.once("styleeditor-selected").then(() => {
let panel = toolbox.getCurrentPanel();
ok(panel && panel.UI, "Styleeditor panel switched to front");
// A helper that resolves the promise once it receives an editor that
// matches the expected href. Returns false if the editor was not correct.
let gotEditor = (event, editor) => {
let currentHref = editor.styleSheet.href;
if (!href || (href && currentHref.endsWith(href))) {
info("Stylesheet editor selected");
panel.UI.off("editor-selected", gotEditor);
editor.getSourceEditor().then(sourceEditor => {
info("Stylesheet editor fully loaded");
def.resolve(sourceEditor);
});
return true;
}
info("The editor was incorrect. Waiting for editor-selected event.");
return false;
};
// The expected editor may already be selected. Check the if the currently
// selected editor is the expected one and if not wait for an
// editor-selected event.
if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
// The expected editor is not selected (yet). Wait for it.
panel.UI.on("editor-selected", gotEditor);
}
});
return def.promise;
}
/**
* @see SimpleTest.waitForClipboard
*
* @param {Function} setup
* Function to execute before checking for the
* clipboard content
* @param {String|Function} expected
* An expected string or validator function
* @return a promise that resolves when the expected string has been found or
* the validator function has returned true, rejects otherwise.
*/
function waitForClipboard(setup, expected) {
let def = promise.defer();
SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
return def.promise;
}