mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
320 lines
9.1 KiB
JavaScript
320 lines
9.1 KiB
JavaScript
/* vim:set ts=2 sw=2 sts=2 et: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleinspector/test/";
|
|
const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleinspector/test/";
|
|
|
|
//Services.prefs.setBoolPref("devtools.dump.emit", true);
|
|
Services.prefs.setBoolPref("devtools.debugger.log", true);
|
|
|
|
let tempScope = {};
|
|
|
|
Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
|
|
let ConsoleUtils = tempScope.ConsoleUtils;
|
|
let gDevTools = tempScope.gDevTools;
|
|
|
|
Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
|
|
let devtools = tempScope.devtools;
|
|
|
|
let TargetFactory = devtools.TargetFactory;
|
|
let {CssHtmlTree} = devtools.require("devtools/styleinspector/computed-view");
|
|
let {CssRuleView, _ElementStyle} = devtools.require("devtools/styleinspector/rule-view");
|
|
let {CssLogic, CssSelector} = devtools.require("devtools/styleinspector/css-logic");
|
|
|
|
let promise = devtools.require("sdk/core/promise");
|
|
|
|
gDevTools.testing = true;
|
|
SimpleTest.registerCleanupFunction(() => {
|
|
gDevTools.testing = false;
|
|
});
|
|
|
|
SimpleTest.registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("devtools.debugger.log");
|
|
Services.prefs.clearUserPref("devtools.dump.emit");
|
|
});
|
|
|
|
let {
|
|
editableField,
|
|
getInplaceEditorForSpan: inplaceEditor
|
|
} = devtools.require("devtools/shared/inplace-editor");
|
|
Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
|
|
let console = tempScope.console;
|
|
|
|
let browser, hudId, hud, hudBox, filterBox, outputNode, cs;
|
|
|
|
function addTab(aURL)
|
|
{
|
|
gBrowser.selectedTab = gBrowser.addTab();
|
|
content.location = aURL;
|
|
browser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
|
}
|
|
|
|
function openInspector(callback)
|
|
{
|
|
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
|
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
|
callback(toolbox.getCurrentPanel());
|
|
});
|
|
}
|
|
|
|
function getActiveInspector()
|
|
{
|
|
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
|
return gDevTools.getToolbox(target).getPanel("inspector");
|
|
}
|
|
|
|
function openView(name, callback)
|
|
{
|
|
openInspector(inspector => {
|
|
function onReady() {
|
|
inspector.sidebar.select(name);
|
|
let { view } = inspector.sidebar.getWindowForTab(name)[name];
|
|
callback(inspector, view);
|
|
}
|
|
|
|
if (inspector.sidebar.getTab(name)) {
|
|
onReady();
|
|
} else {
|
|
inspector.sidebar.once(name + "-ready", onReady);
|
|
}
|
|
});
|
|
}
|
|
|
|
function openRuleView(callback)
|
|
{
|
|
openView("ruleview", callback);
|
|
}
|
|
|
|
function openComputedView(callback)
|
|
{
|
|
openView("computedview", callback);
|
|
}
|
|
|
|
/**
|
|
* 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}
|
|
*/
|
|
function getNode(nodeOrSelector)
|
|
{
|
|
let node = nodeOrSelector;
|
|
|
|
if (typeof nodeOrSelector === "string") {
|
|
node = content.document.querySelector(nodeOrSelector);
|
|
ok(node, "A node was found for selector " + nodeOrSelector);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Set the inspector's current selection to a node or to the first match of the
|
|
* given css selector
|
|
* @param {String|DOMNode} nodeOrSelector
|
|
* @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 a promise that resolves when the inspector is updated with the new
|
|
* node
|
|
*/
|
|
function selectNode(nodeOrSelector, inspector, reason="test")
|
|
{
|
|
info("Selecting the node " + nodeOrSelector);
|
|
let node = getNode(nodeOrSelector);
|
|
let updated = inspector.once("inspector-updated");
|
|
inspector.selection.setNode(node, reason);
|
|
return updated;
|
|
}
|
|
|
|
function addStyle(aDocument, aString)
|
|
{
|
|
let node = aDocument.createElement('style');
|
|
node.setAttribute("type", "text/css");
|
|
node.textContent = aString;
|
|
aDocument.getElementsByTagName("head")[0].appendChild(node);
|
|
return node;
|
|
}
|
|
|
|
function finishTest()
|
|
{
|
|
finish();
|
|
}
|
|
|
|
function tearDown()
|
|
{
|
|
try {
|
|
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
|
gDevTools.closeToolbox(target);
|
|
}
|
|
catch (ex) {
|
|
dump(ex);
|
|
}
|
|
while (gBrowser.tabs.length > 1) {
|
|
gBrowser.removeCurrentTab();
|
|
}
|
|
browser = hudId = hud = filterBox = outputNode = cs = null;
|
|
}
|
|
|
|
function getComputedView() {
|
|
let inspector = getActiveInspector();
|
|
return inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
|
}
|
|
|
|
function ruleView()
|
|
{
|
|
let inspector = getActiveInspector();
|
|
return inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
|
}
|
|
|
|
function waitForEditorFocus(aParent, aCallback)
|
|
{
|
|
aParent.addEventListener("focus", function onFocus(evt) {
|
|
if (inplaceEditor(evt.target) && evt.target.tagName == "input") {
|
|
aParent.removeEventListener("focus", onFocus, true);
|
|
let editor = inplaceEditor(evt.target);
|
|
executeSoon(function() {
|
|
aCallback(editor);
|
|
});
|
|
}
|
|
}, true);
|
|
}
|
|
|
|
function waitForEditorBlur(aEditor, aCallback)
|
|
{
|
|
let input = aEditor.input;
|
|
input.addEventListener("blur", function onBlur() {
|
|
input.removeEventListener("blur", onBlur, false);
|
|
executeSoon(function() {
|
|
aCallback();
|
|
});
|
|
}, false);
|
|
}
|
|
|
|
function fireCopyEvent(element) {
|
|
let evt = element.ownerDocument.createEvent("Event");
|
|
evt.initEvent("copy", true, true);
|
|
element.dispatchEvent(evt);
|
|
}
|
|
|
|
function contextMenuClick(element) {
|
|
var evt = element.ownerDocument.createEvent('MouseEvents');
|
|
|
|
var button = 2; // right click
|
|
|
|
evt.initMouseEvent('contextmenu', true, true,
|
|
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
|
|
false, false, false, button, null);
|
|
|
|
element.dispatchEvent(evt);
|
|
}
|
|
|
|
function expectRuleChange(rule) {
|
|
return rule._applyingModifications;
|
|
}
|
|
|
|
function promiseDone(promise) {
|
|
promise.then(null, err => {
|
|
ok(false, "Promise failed: " + err);
|
|
if (err.stack) {
|
|
dump(err.stack);
|
|
}
|
|
SimpleTest.finish();
|
|
});
|
|
}
|
|
|
|
function getComputedPropertyValue(aName)
|
|
{
|
|
let computedview = getComputedView();
|
|
let props = computedview.styleDocument.querySelectorAll(".property-view");
|
|
|
|
for (let prop of props) {
|
|
let name = prop.querySelector(".property-name");
|
|
|
|
if (name.textContent === aName) {
|
|
let value = prop.querySelector(".property-value");
|
|
return value.textContent;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Polls a given function waiting for it to become true.
|
|
*
|
|
* @param object aOptions
|
|
* Options object with the following properties:
|
|
* - validatorFn
|
|
* A validator function that returns a boolean. This is called every few
|
|
* milliseconds to check if the result is true. When it is true, succesFn
|
|
* is called and polling stops. If validatorFn never returns true, then
|
|
* polling timeouts after several tries and a failure is recorded.
|
|
* - successFn
|
|
* A function called when the validator function returns true.
|
|
* - failureFn
|
|
* A function called if the validator function timeouts - fails to return
|
|
* true in the given time.
|
|
* - name
|
|
* Name of test. This is used to generate the success and failure
|
|
* messages.
|
|
* - timeout
|
|
* Timeout for validator function, in milliseconds. Default is 5000.
|
|
*/
|
|
function waitForSuccess(aOptions)
|
|
{
|
|
let start = Date.now();
|
|
let timeout = aOptions.timeout || 5000;
|
|
|
|
function wait(validatorFn, successFn, failureFn)
|
|
{
|
|
if ((Date.now() - start) > timeout) {
|
|
// Log the failure.
|
|
ok(false, "Timed out while waiting for: " + aOptions.name);
|
|
failureFn(aOptions);
|
|
return;
|
|
}
|
|
|
|
if (validatorFn(aOptions)) {
|
|
ok(true, aOptions.name);
|
|
successFn();
|
|
}
|
|
else {
|
|
setTimeout(function() wait(validatorFn, successFn, failureFn), 100);
|
|
}
|
|
}
|
|
|
|
wait(aOptions.validatorFn, aOptions.successFn, aOptions.failureFn);
|
|
}
|
|
|
|
registerCleanupFunction(tearDown);
|
|
|
|
waitForExplicitFinish();
|
|
|
|
/**
|
|
* @return a promise that resolves when the tooltip is shown
|
|
*/
|
|
function assertTooltipShownOn(tooltip, element) {
|
|
return Task.spawn(function*() {
|
|
let isTarget = yield isHoverTooltipTarget(tooltip, element);
|
|
ok(isTarget, "The element is a tooltip target");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Given a tooltip object instance (see Tooltip.js), checks if it is set to
|
|
* toggle and hover and if so, checks if the given target is a valid hover target.
|
|
* This won't actually show the tooltip (the less we interact with XUL panels
|
|
* during test runs, the better).
|
|
* @return a promise that resolves when the answer is known. Also, this will
|
|
* delegate to a function in the rule-view which will insert content into the
|
|
* tooltip
|
|
*/
|
|
function isHoverTooltipTarget(tooltip, target) {
|
|
if (!tooltip._basedNode || !tooltip.panel) {
|
|
return promise.reject(new Error("The tooltip passed isn't set to toggle on hover or is not a tooltip"));
|
|
}
|
|
// The tooltip delegates to a user defined cb that inserts content in the tooltip
|
|
// when calling isValidHoverTarget
|
|
return tooltip.isValidHoverTarget(target);
|
|
}
|