mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 776875 - GCLI: Move existing GCLI commands into JSMs; r=jwalker
--HG-- rename : browser/devtools/commandline/GcliCookieCommands.jsm => browser/devtools/commandline/CmdCookie.jsm rename : browser/devtools/commandline/GcliCommands.jsm => browser/devtools/commandline/Commands.jsm rename : browser/devtools/commandline/gcli.css => browser/devtools/commandline/commandline.css rename : browser/devtools/commandline/gclioutput.xhtml => browser/devtools/commandline/commandlineoutput.xhtml rename : browser/devtools/commandline/gclitooltip.xhtml => browser/devtools/commandline/commandlinetooltip.xhtml rename : browser/devtools/commandline/test/browser_gcli_addon.js => browser/devtools/commandline/test/browser_cmd_addon.js rename : browser/devtools/commandline/test/browser_gcli_calllog.js => browser/devtools/commandline/test/browser_cmd_calllog.js rename : browser/devtools/commandline/test/browser_gcli_commands.js => browser/devtools/commandline/test/browser_cmd_commands.js rename : browser/devtools/commandline/test/browser_gcli_cookie.js => browser/devtools/commandline/test/browser_cmd_cookie.js rename : browser/devtools/commandline/test/browser_gcli_integrate.js => browser/devtools/commandline/test/browser_cmd_integrate.js rename : browser/devtools/commandline/test/browser_gcli_jsb.js => browser/devtools/commandline/test/browser_cmd_jsb.js rename : browser/devtools/commandline/test/resources_jsb_script.js => browser/devtools/commandline/test/browser_cmd_jsb_script.jsi rename : browser/devtools/commandline/test/browser_gcli_inspect.html => browser/devtools/commandline/test/browser_cmd_pagemod_export.html rename : browser/devtools/commandline/test/browser_gcli_pagemod_export.js => browser/devtools/commandline/test/browser_cmd_pagemod_export.js rename : browser/devtools/commandline/test/browser_gcli_pref.js => browser/devtools/commandline/test/browser_cmd_pref.js rename : browser/devtools/commandline/test/browser_gcli_restart.js => browser/devtools/commandline/test/browser_cmd_restart.js rename : browser/devtools/commandline/test/browser_gcli_settings.js => browser/devtools/commandline/test/browser_cmd_settings.js rename : browser/devtools/commandline/test/resources_dbg.html => browser/devtools/commandline/test/browser_dbg_cmd.html rename : browser/devtools/commandline/test/browser_gcli_dbg.js => browser/devtools/commandline/test/browser_dbg_cmd.js rename : browser/devtools/commandline/test/browser_gcli_break.html => browser/devtools/commandline/test/browser_dbg_cmd_break.html rename : browser/devtools/commandline/test/browser_gcli_break.js => browser/devtools/commandline/test/browser_dbg_cmd_break.js rename : browser/devtools/commandline/test/browser_gcli_inspect.html => browser/devtools/highlighter/test/browser_inspector_cmd_inspect.html rename : browser/devtools/commandline/test/browser_gcli_inspect.js => browser/devtools/highlighter/test/browser_inspector_cmd_inspect.js rename : browser/devtools/commandline/test/browser_gcli_responsivemode.js => browser/devtools/responsivedesign/test/browser_responsive_cmd.js rename : browser/devtools/commandline/test/resources.html => browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.html rename : browser/devtools/commandline/test/browser_gcli_edit.js => browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js rename : browser/devtools/commandline/test/resources_inpage.js => browser/devtools/styleeditor/test/resources_inpage.jsi rename : browser/devtools/commandline/test/resources_inpage1.css => browser/devtools/styleeditor/test/resources_inpage1.css rename : browser/devtools/commandline/test/resources_inpage2.css => browser/devtools/styleeditor/test/resources_inpage2.css rename : browser/devtools/commandline/GcliTiltCommands.jsm => browser/devtools/tilt/CmdTilt.jsm rename : browser/themes/gnomestripe/devtools/gcli.css => browser/themes/gnomestripe/devtools/commandline.css rename : browser/themes/pinstripe/devtools/gcli.css => browser/themes/pinstripe/devtools/commandline.css rename : browser/themes/winstripe/devtools/gcli.css => browser/themes/winstripe/devtools/commandline.css
This commit is contained in:
parent
bc1bb4ec39
commit
b6fe076c28
290
browser/devtools/commandline/CmdAddon.jsm
Normal file
290
browser/devtools/commandline/CmdAddon.jsm
Normal file
@ -0,0 +1,290 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
/**
|
||||
* 'addon' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "addon",
|
||||
description: gcli.lookup("addonDesc")
|
||||
});
|
||||
|
||||
/**
|
||||
* 'addon list' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "addon list",
|
||||
description: gcli.lookup("addonListDesc"),
|
||||
params: [{
|
||||
name: 'type',
|
||||
type: {
|
||||
name: 'selection',
|
||||
data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
|
||||
},
|
||||
defaultValue: 'all',
|
||||
description: gcli.lookup("addonListTypeDesc"),
|
||||
}],
|
||||
exec: function(aArgs, context) {
|
||||
function representEnabledAddon(aAddon) {
|
||||
return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
|
||||
getAddonStatus(aAddon) + "]]></li>";
|
||||
}
|
||||
|
||||
function representDisabledAddon(aAddon) {
|
||||
return "<li class=\"gcli-addon-disabled\">" +
|
||||
"<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
|
||||
"]]></li>";
|
||||
}
|
||||
|
||||
function getAddonStatus(aAddon) {
|
||||
let operations = [];
|
||||
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
|
||||
operations.push("PENDING_ENABLE");
|
||||
}
|
||||
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
|
||||
operations.push("PENDING_DISABLE");
|
||||
}
|
||||
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
|
||||
operations.push("PENDING_UNINSTALL");
|
||||
}
|
||||
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
|
||||
operations.push("PENDING_INSTALL");
|
||||
}
|
||||
|
||||
if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
|
||||
operations.push("PENDING_UPGRADE");
|
||||
}
|
||||
|
||||
if (operations.length) {
|
||||
return " (" + operations.join(", ") + ")";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two addons by their name. Used in sorting.
|
||||
*/
|
||||
function compareAddonNames(aNameA, aNameB) {
|
||||
return String.localeCompare(aNameA.name, aNameB.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the promise which is the scope (this) of this function, filling
|
||||
* it with an HTML representation of the passed add-ons.
|
||||
*/
|
||||
function list(aType, aAddons) {
|
||||
if (!aAddons.length) {
|
||||
this.resolve(gcli.lookup("addonNoneOfType"));
|
||||
}
|
||||
|
||||
// Separate the enabled add-ons from the disabled ones.
|
||||
let enabledAddons = [];
|
||||
let disabledAddons = [];
|
||||
|
||||
aAddons.forEach(function(aAddon) {
|
||||
if (aAddon.isActive) {
|
||||
enabledAddons.push(aAddon);
|
||||
} else {
|
||||
disabledAddons.push(aAddon);
|
||||
}
|
||||
});
|
||||
|
||||
let header;
|
||||
switch(aType) {
|
||||
case "dictionary":
|
||||
header = gcli.lookup("addonListDictionaryHeading");
|
||||
break;
|
||||
case "extension":
|
||||
header = gcli.lookup("addonListExtensionHeading");
|
||||
break;
|
||||
case "locale":
|
||||
header = gcli.lookup("addonListLocaleHeading");
|
||||
break;
|
||||
case "plugin":
|
||||
header = gcli.lookup("addonListPluginHeading");
|
||||
break;
|
||||
case "theme":
|
||||
header = gcli.lookup("addonListThemeHeading");
|
||||
case "all":
|
||||
header = gcli.lookup("addonListAllHeading");
|
||||
break;
|
||||
default:
|
||||
header = gcli.lookup("addonListUnknownHeading");
|
||||
}
|
||||
|
||||
// Map and sort the add-ons, and create an HTML list.
|
||||
this.resolve(header +
|
||||
"<ol>" +
|
||||
enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
|
||||
disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
|
||||
"</ol>");
|
||||
}
|
||||
|
||||
// Create the promise that will be resolved when the add-on listing has
|
||||
// been finished.
|
||||
let promise = context.createPromise();
|
||||
let types = aArgs.type == "all" ? null : [aArgs.type];
|
||||
AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
// We need a list of addon names for the enable and disable commands. Because
|
||||
// getting the name list is async we do not add the commands until we have the
|
||||
// list.
|
||||
AddonManager.getAllAddons(function addonAsync(aAddons) {
|
||||
// We listen for installs to keep our addon list up to date. There is no need
|
||||
// to listen for uninstalls because uninstalled addons are simply disabled
|
||||
// until restart (to enable undo functionality).
|
||||
AddonManager.addAddonListener({
|
||||
onInstalled: function(aAddon) {
|
||||
addonNameCache.push({
|
||||
name: representAddon(aAddon).replace(/\s/g, "_"),
|
||||
value: aAddon.name
|
||||
});
|
||||
},
|
||||
onUninstalled: function(aAddon) {
|
||||
let name = representAddon(aAddon).replace(/\s/g, "_");
|
||||
|
||||
for (let i = 0; i < addonNameCache.length; i++) {
|
||||
if(addonNameCache[i].name == name) {
|
||||
addonNameCache.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a string that represents the passed add-on.
|
||||
*/
|
||||
function representAddon(aAddon) {
|
||||
let name = aAddon.name + " " + aAddon.version;
|
||||
return name.trim();
|
||||
}
|
||||
|
||||
let addonNameCache = [];
|
||||
|
||||
// The name parameter, used in "addon enable" and "addon disable."
|
||||
let nameParameter = {
|
||||
name: "name",
|
||||
type: {
|
||||
name: "selection",
|
||||
lookup: addonNameCache
|
||||
},
|
||||
description: gcli.lookup("addonNameDesc")
|
||||
};
|
||||
|
||||
for (let addon of aAddons) {
|
||||
addonNameCache.push({
|
||||
name: representAddon(addon).replace(/\s/g, "_"),
|
||||
value: addon.name
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 'addon enable' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "addon enable",
|
||||
description: gcli.lookup("addonEnableDesc"),
|
||||
params: [nameParameter],
|
||||
exec: function(aArgs, context) {
|
||||
/**
|
||||
* Enables the addon in the passed list which has a name that matches
|
||||
* according to the passed name comparer, and resolves the promise which
|
||||
* is the scope (this) of this function to display the result of this
|
||||
* enable attempt.
|
||||
*/
|
||||
function enable(aName, addons) {
|
||||
// Find the add-on.
|
||||
let addon = null;
|
||||
addons.some(function(candidate) {
|
||||
if (candidate.name == aName) {
|
||||
addon = candidate;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
let name = representAddon(addon);
|
||||
|
||||
if (!addon.userDisabled) {
|
||||
this.resolve("<![CDATA[" +
|
||||
gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
|
||||
} else {
|
||||
addon.userDisabled = false;
|
||||
// nl-nl: {$1} is ingeschakeld.
|
||||
this.resolve("<![CDATA[" +
|
||||
gcli.lookupFormat("addonEnabled", [name]) + "]]>");
|
||||
}
|
||||
}
|
||||
|
||||
let promise = context.createPromise();
|
||||
// List the installed add-ons, enable one when done listing.
|
||||
AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'addon disable' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "addon disable",
|
||||
description: gcli.lookup("addonDisableDesc"),
|
||||
params: [nameParameter],
|
||||
exec: function(aArgs, context) {
|
||||
/**
|
||||
* Like enable, but ... you know ... the exact opposite.
|
||||
*/
|
||||
function disable(aName, addons) {
|
||||
// Find the add-on.
|
||||
let addon = null;
|
||||
addons.some(function(candidate) {
|
||||
if (candidate.name == aName) {
|
||||
addon = candidate;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
let name = representAddon(addon);
|
||||
|
||||
if (addon.userDisabled) {
|
||||
this.resolve("<![CDATA[" +
|
||||
gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
|
||||
} else {
|
||||
addon.userDisabled = true;
|
||||
// nl-nl: {$1} is uitgeschakeld.
|
||||
this.resolve("<![CDATA[" +
|
||||
gcli.lookupFormat("addonDisabled", [name]) + "]]>");
|
||||
}
|
||||
}
|
||||
|
||||
let promise = context.createPromise();
|
||||
// List the installed add-ons, disable one when done listing.
|
||||
AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
|
||||
});
|
170
browser/devtools/commandline/CmdBreak.jsm
Normal file
170
browser/devtools/commandline/CmdBreak.jsm
Normal file
@ -0,0 +1,170 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
"resource:///modules/HUDService.jsm");
|
||||
|
||||
/**
|
||||
* 'break' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "break",
|
||||
description: gcli.lookup("breakDesc"),
|
||||
manual: gcli.lookup("breakManual")
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'break list' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "break list",
|
||||
description: gcli.lookup("breaklistDesc"),
|
||||
returnType: "html",
|
||||
exec: function(args, context) {
|
||||
let win = HUDService.currentContext();
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
if (!dbg) {
|
||||
return gcli.lookup("breakaddDebuggerStopped");
|
||||
}
|
||||
let breakpoints = dbg.breakpoints;
|
||||
|
||||
if (Object.keys(breakpoints).length === 0) {
|
||||
return gcli.lookup("breaklistNone");
|
||||
}
|
||||
|
||||
let reply = gcli.lookup("breaklistIntro");
|
||||
reply += "<ol>";
|
||||
for each (let breakpoint in breakpoints) {
|
||||
let text = gcli.lookupFormat("breaklistLineEntry",
|
||||
[breakpoint.location.url,
|
||||
breakpoint.location.line]);
|
||||
reply += "<li>" + text + "</li>";
|
||||
};
|
||||
reply += "</ol>";
|
||||
return reply;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'break add' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "break add",
|
||||
description: gcli.lookup("breakaddDesc"),
|
||||
manual: gcli.lookup("breakaddManual")
|
||||
});
|
||||
|
||||
/**
|
||||
* 'break add line' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "break add line",
|
||||
description: gcli.lookup("breakaddlineDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "file",
|
||||
type: {
|
||||
name: "selection",
|
||||
data: function() {
|
||||
let win = HUDService.currentContext();
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
let files = [];
|
||||
if (dbg) {
|
||||
let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
|
||||
for each (let script in scriptsView.scriptLocations) {
|
||||
files.push(script);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
},
|
||||
description: gcli.lookup("breakaddlineFileDesc")
|
||||
},
|
||||
{
|
||||
name: "line",
|
||||
type: { name: "number", min: 1, step: 10 },
|
||||
description: gcli.lookup("breakaddlineLineDesc")
|
||||
}
|
||||
],
|
||||
returnType: "html",
|
||||
exec: function(args, context) {
|
||||
args.type = "line";
|
||||
let win = HUDService.currentContext();
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
if (!dbg) {
|
||||
return gcli.lookup("breakaddDebuggerStopped");
|
||||
}
|
||||
var promise = context.createPromise();
|
||||
let position = { url: args.file, line: args.line };
|
||||
dbg.addBreakpoint(position, function(aBreakpoint, aError) {
|
||||
if (aError) {
|
||||
promise.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
|
||||
return;
|
||||
}
|
||||
promise.resolve(gcli.lookup("breakaddAdded"));
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'break del' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "break del",
|
||||
description: gcli.lookup("breakdelDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "breakid",
|
||||
type: {
|
||||
name: "number",
|
||||
min: 0,
|
||||
max: function() {
|
||||
let win = HUDService.currentContext();
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
if (!dbg) {
|
||||
return gcli.lookup("breakaddDebuggerStopped");
|
||||
}
|
||||
return Object.keys(dbg.breakpoints).length - 1;
|
||||
},
|
||||
},
|
||||
description: gcli.lookup("breakdelBreakidDesc")
|
||||
}
|
||||
],
|
||||
returnType: "html",
|
||||
exec: function(args, context) {
|
||||
let win = HUDService.currentContext();
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
if (!dbg) {
|
||||
return gcli.lookup("breakaddDebuggerStopped");
|
||||
}
|
||||
|
||||
let breakpoints = dbg.breakpoints;
|
||||
let id = Object.keys(dbg.breakpoints)[args.breakid];
|
||||
if (!id || !(id in breakpoints)) {
|
||||
return gcli.lookup("breakNotFound");
|
||||
}
|
||||
|
||||
let promise = context.createPromise();
|
||||
try {
|
||||
dbg.removeBreakpoint(breakpoints[id], function() {
|
||||
promise.resolve(gcli.lookup("breakdelRemoved"));
|
||||
});
|
||||
} catch (ex) {
|
||||
// If the debugger has been closed already, don't scare the user.
|
||||
promise.resolve(gcli.lookup("breakdelRemoved"));
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
});
|
103
browser/devtools/commandline/CmdCalllog.jsm
Normal file
103
browser/devtools/commandline/CmdCalllog.jsm
Normal file
@ -0,0 +1,103 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
"resource:///modules/HUDService.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
|
||||
let JsDebugger = {};
|
||||
Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
|
||||
|
||||
let global = Components.utils.getGlobalForObject({});
|
||||
JsDebugger.addDebuggerToGlobal(global);
|
||||
|
||||
return global.Debugger;
|
||||
});
|
||||
|
||||
let debuggers = [];
|
||||
|
||||
/**
|
||||
* 'calllog' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "calllog",
|
||||
description: gcli.lookup("calllogDesc")
|
||||
})
|
||||
|
||||
/**
|
||||
* 'calllog start' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "calllog start",
|
||||
description: gcli.lookup("calllogStartDesc"),
|
||||
|
||||
exec: function(args, context) {
|
||||
let contentWindow = context.environment.contentDocument.defaultView;
|
||||
|
||||
let dbg = new Debugger(contentWindow);
|
||||
dbg.onEnterFrame = function(frame) {
|
||||
// BUG 773652 - Make the output from the GCLI calllog command nicer
|
||||
contentWindow.console.log("Method call: " + this.callDescription(frame));
|
||||
}.bind(this);
|
||||
|
||||
debuggers.push(dbg);
|
||||
|
||||
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
|
||||
HUDService.activateHUDForContext(tab);
|
||||
|
||||
return gcli.lookup("calllogStartReply");
|
||||
},
|
||||
|
||||
callDescription: function(frame) {
|
||||
let name = "<anonymous>";
|
||||
if (frame.callee.name) {
|
||||
name = frame.callee.name;
|
||||
}
|
||||
else {
|
||||
let desc = frame.callee.getOwnPropertyDescriptor("displayName");
|
||||
if (desc && desc.value && typeof desc.value == "string") {
|
||||
name = desc.value;
|
||||
}
|
||||
}
|
||||
|
||||
let args = frame.arguments.map(this.valueToString).join(", ");
|
||||
return name + "(" + args + ")";
|
||||
},
|
||||
|
||||
valueToString: function(value) {
|
||||
if (typeof value !== "object" || value === null) {
|
||||
return uneval(value);
|
||||
}
|
||||
return "[object " + value.class + "]";
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'calllog stop' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "calllog stop",
|
||||
description: gcli.lookup("calllogStopDesc"),
|
||||
|
||||
exec: function(args, context) {
|
||||
let numDebuggers = debuggers.length;
|
||||
if (numDebuggers == 0) {
|
||||
return gcli.lookup("calllogStopNoLogging");
|
||||
}
|
||||
|
||||
for (let dbg of debuggers) {
|
||||
dbg.onEnterFrame = undefined;
|
||||
}
|
||||
debuggers = [];
|
||||
|
||||
return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
|
||||
}
|
||||
});
|
126
browser/devtools/commandline/CmdCmd.jsm
Normal file
126
browser/devtools/commandline/CmdCmd.jsm
Normal file
@ -0,0 +1,126 @@
|
||||
/* 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/. */
|
||||
|
||||
let EXPORTED_SYMBOLS = [ "CmdCommands" ];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let prefSvc = "@mozilla.org/preferences-service;1";
|
||||
XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
|
||||
let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
|
||||
return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource:///modules/devtools/Console.jsm");
|
||||
|
||||
/**
|
||||
* A place to store the names of the commands that we have added as a result of
|
||||
* calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
|
||||
* added commands.
|
||||
*/
|
||||
let commands = [];
|
||||
|
||||
/**
|
||||
* Exported API
|
||||
*/
|
||||
let CmdCommands = {
|
||||
/**
|
||||
* Called to look in a directory pointed at by the devtools.commands.dir pref
|
||||
* for *.mozcmd files which are then loaded.
|
||||
* @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
|
||||
* we eval the script from the .mozcmd file. This should be a chrome window.
|
||||
*/
|
||||
refreshAutoCommands: function GC_refreshAutoCommands(aSandboxPrincipal) {
|
||||
// First get rid of the last set of commands
|
||||
commands.forEach(function(name) {
|
||||
gcli.removeCommand(name);
|
||||
});
|
||||
|
||||
let dirName = prefBranch.getComplexValue("devtools.commands.dir",
|
||||
Ci.nsISupportsString).data;
|
||||
if (dirName == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
dir.initWithPath(dirName);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new Error('\'' + dirName + '\' is not a directory.');
|
||||
}
|
||||
|
||||
let en = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
|
||||
|
||||
while (true) {
|
||||
let file = en.nextFile;
|
||||
if (!file) {
|
||||
break;
|
||||
}
|
||||
if (file.leafName.match(/.*\.mozcmd$/) && file.isFile() && file.isReadable()) {
|
||||
loadCommandFile(file, aSandboxPrincipal);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the commands from a single file
|
||||
* @param nsIFile aFile The file containing the commands that we should read
|
||||
* @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
|
||||
* we eval the script from the .mozcmd file. This should be a chrome window.
|
||||
*/
|
||||
function loadCommandFile(aFile, aSandboxPrincipal) {
|
||||
NetUtil.asyncFetch(aFile, function refresh_fetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
console.error("NetUtil.asyncFetch(" + aFile.path + ",..) failed. Status=" + aStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
aStream.close();
|
||||
|
||||
let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
|
||||
sandboxPrototype: aSandboxPrincipal,
|
||||
wantXrays: false,
|
||||
sandboxName: aFile.path
|
||||
});
|
||||
let data = Cu.evalInSandbox(source, sandbox, "1.8", aFile.leafName, 1);
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
console.error("Command file '" + aFile.leafName + "' does not have top level array.");
|
||||
return;
|
||||
}
|
||||
|
||||
data.forEach(function(commandSpec) {
|
||||
gcli.addCommand(commandSpec);
|
||||
commands.push(commandSpec.name);
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* 'cmd' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cmd",
|
||||
description: gcli.lookup("cmdDesc"),
|
||||
hidden: true
|
||||
});
|
||||
|
||||
/**
|
||||
* 'cmd refresh' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "cmd refresh",
|
||||
description: gcli.lookup("cmdRefreshDesc"),
|
||||
hidden: true,
|
||||
exec: function Command_cmdRefresh(args, context) {
|
||||
GcliCmdCommands.refreshAutoCommands(context.environment.chromeDocument.defaultView);
|
||||
}
|
||||
});
|
62
browser/devtools/commandline/CmdConsole.jsm
Normal file
62
browser/devtools/commandline/CmdConsole.jsm
Normal file
@ -0,0 +1,62 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
"resource:///modules/HUDService.jsm");
|
||||
|
||||
/**
|
||||
* 'console' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "console",
|
||||
description: gcli.lookup("consoleDesc"),
|
||||
manual: gcli.lookup("consoleManual")
|
||||
});
|
||||
|
||||
/**
|
||||
* 'console clear' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "console clear",
|
||||
description: gcli.lookup("consoleclearDesc"),
|
||||
exec: function Command_consoleClear(args, context) {
|
||||
let window = context.environment.contentDocument.defaultView;
|
||||
let hud = HUDService.getHudByWindow(window);
|
||||
// hud will be null if the web console has not been opened for this window
|
||||
if (hud) {
|
||||
hud.jsterm.clearOutput();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'console close' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "console close",
|
||||
description: gcli.lookup("consolecloseDesc"),
|
||||
exec: function Command_consoleClose(args, context) {
|
||||
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
|
||||
HUDService.deactivateHUDForContext(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'console open' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "console open",
|
||||
description: gcli.lookup("consoleopenDesc"),
|
||||
exec: function Command_consoleOpen(args, context) {
|
||||
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
|
||||
HUDService.activateHUDForContext(tab);
|
||||
}
|
||||
});
|
@ -2,11 +2,15 @@
|
||||
* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Components.utils.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource:///modules/devtools/Console.jsm");
|
||||
|
||||
// We should really be using nsICookieManager so we can read more than just the
|
||||
// key/value of cookies. The difficulty is filtering the cookies that are
|
136
browser/devtools/commandline/CmdDbg.jsm
Normal file
136
browser/devtools/commandline/CmdDbg.jsm
Normal file
@ -0,0 +1,136 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/**
|
||||
* 'dbg' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "dbg",
|
||||
description: gcli.lookup("dbgDesc"),
|
||||
manual: gcli.lookup("dbgManual")
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'dbg interrupt' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "dbg interrupt",
|
||||
description: gcli.lookup("dbgInterrupt"),
|
||||
params: [],
|
||||
exec: function(args, context) {
|
||||
let win = context.environment.chromeDocument.defaultView;
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
|
||||
if (dbg) {
|
||||
let controller = dbg.contentWindow.DebuggerController;
|
||||
let thread = controller.activeThread;
|
||||
if (!thread.paused) {
|
||||
thread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'dbg continue' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "dbg continue",
|
||||
description: gcli.lookup("dbgContinue"),
|
||||
params: [],
|
||||
exec: function(args, context) {
|
||||
let win = context.environment.chromeDocument.defaultView;
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
|
||||
if (dbg) {
|
||||
let controller = dbg.contentWindow.DebuggerController;
|
||||
let thread = controller.activeThread;
|
||||
if (thread.paused) {
|
||||
thread.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'dbg step' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "dbg step",
|
||||
description: gcli.lookup("dbgStepDesc"),
|
||||
manual: gcli.lookup("dbgStepManual")
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 'dbg step over' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "dbg step over",
|
||||
description: gcli.lookup("dbgStepOverDesc"),
|
||||
params: [],
|
||||
exec: function(args, context) {
|
||||
let win = context.environment.chromeDocument.defaultView;
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
|
||||
if (dbg) {
|
||||
let controller = dbg.contentWindow.DebuggerController;
|
||||
let thread = controller.activeThread;
|
||||
if (thread.paused) {
|
||||
thread.stepOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'dbg step in' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: 'dbg step in',
|
||||
description: gcli.lookup("dbgStepInDesc"),
|
||||
params: [],
|
||||
exec: function(args, context) {
|
||||
let win = context.environment.chromeDocument.defaultView;
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
|
||||
if (dbg) {
|
||||
let controller = dbg.contentWindow.DebuggerController;
|
||||
let thread = controller.activeThread;
|
||||
if (thread.paused) {
|
||||
thread.stepIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'dbg step over' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: 'dbg step out',
|
||||
description: gcli.lookup("dbgStepOutDesc"),
|
||||
params: [],
|
||||
exec: function(args, context) {
|
||||
let win = context.environment.chromeDocument.defaultView;
|
||||
let dbg = win.DebuggerUI.getDebugger();
|
||||
|
||||
if (dbg) {
|
||||
let controller = dbg.contentWindow.DebuggerController;
|
||||
let thread = controller.activeThread;
|
||||
if (thread.paused) {
|
||||
thread.stepOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
29
browser/devtools/commandline/CmdEcho.jsm
Normal file
29
browser/devtools/commandline/CmdEcho.jsm
Normal file
@ -0,0 +1,29 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
/**
|
||||
* 'echo' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "echo",
|
||||
description: gcli.lookup("echoDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "message",
|
||||
type: "string",
|
||||
description: gcli.lookup("echoMessageDesc")
|
||||
}
|
||||
],
|
||||
returnType: "string",
|
||||
hidden: true,
|
||||
exec: function Command_echo(args, context) {
|
||||
return args.message;
|
||||
}
|
||||
});
|
31
browser/devtools/commandline/CmdExport.jsm
Normal file
31
browser/devtools/commandline/CmdExport.jsm
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
/**
|
||||
* 'export' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "export",
|
||||
description: gcli.lookup("exportDesc"),
|
||||
});
|
||||
|
||||
/**
|
||||
* The 'export html' command. This command allows the user to export the page to
|
||||
* HTML after they do DOM changes.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "export html",
|
||||
description: gcli.lookup("exportHtmlDesc"),
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let window = document.defaultView;
|
||||
let page = document.documentElement.outerHTML;
|
||||
window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
|
||||
}
|
||||
});
|
138
browser/devtools/commandline/CmdJsb.jsm
Normal file
138
browser/devtools/commandline/CmdJsb.jsm
Normal file
@ -0,0 +1,138 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const XMLHttpRequest =
|
||||
Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
|
||||
"resource:///modules/devtools/Jsbeautify.jsm");
|
||||
|
||||
/**
|
||||
* jsb command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: 'jsb',
|
||||
description: gcli.lookup('jsbDesc'),
|
||||
returnValue:'string',
|
||||
hidden: true,
|
||||
params: [
|
||||
{
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
description: gcli.lookup('jsbUrlDesc'),
|
||||
manual: 'The URL of the JS to prettify'
|
||||
},
|
||||
{
|
||||
name: 'indentSize',
|
||||
type: 'number',
|
||||
description: gcli.lookup('jsbIndentSizeDesc'),
|
||||
manual: gcli.lookup('jsbIndentSizeManual'),
|
||||
defaultValue: 2
|
||||
},
|
||||
{
|
||||
name: 'indentChar',
|
||||
type: {
|
||||
name: 'selection',
|
||||
lookup: [{name: "space", value: " "}, {name: "tab", value: "\t"}]
|
||||
},
|
||||
description: gcli.lookup('jsbIndentCharDesc'),
|
||||
manual: gcli.lookup('jsbIndentCharManual'),
|
||||
defaultValue: ' ',
|
||||
},
|
||||
{
|
||||
name: 'preserveNewlines',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbPreserveNewlinesDesc'),
|
||||
manual: gcli.lookup('jsbPreserveNewlinesManual'),
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: 'preserveMaxNewlines',
|
||||
type: 'number',
|
||||
description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
|
||||
manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
|
||||
defaultValue: -1
|
||||
},
|
||||
{
|
||||
name: 'jslintHappy',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbJslintHappyDesc'),
|
||||
manual: gcli.lookup('jsbJslintHappyManual'),
|
||||
defaultValue: false
|
||||
},
|
||||
{
|
||||
name: 'braceStyle',
|
||||
type: {
|
||||
name: 'selection',
|
||||
data: ['collapse', 'expand', 'end-expand', 'expand-strict']
|
||||
},
|
||||
description: gcli.lookup('jsbBraceStyleDesc'),
|
||||
manual: gcli.lookup('jsbBraceStyleManual'),
|
||||
defaultValue: "collapse"
|
||||
},
|
||||
{
|
||||
name: 'spaceBeforeConditional',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
|
||||
manual: gcli.lookup('jsbSpaceBeforeConditionalManual'),
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: 'unescapeStrings',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbUnescapeStringsDesc'),
|
||||
manual: gcli.lookup('jsbUnescapeStringsManual'),
|
||||
defaultValue: false
|
||||
}
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let opts = {
|
||||
indent_size: args.indentSize,
|
||||
indent_char: args.indentChar,
|
||||
preserve_newlines: args.preserveNewlines,
|
||||
max_preserve_newlines: args.preserveMaxNewlines == -1 ?
|
||||
undefined : args.preserveMaxNewlines,
|
||||
jslint_happy: args.jslintHappy,
|
||||
brace_style: args.braceStyle,
|
||||
space_before_conditional: args.spaceBeforeConditional,
|
||||
unescape_strings: args.unescapeStrings
|
||||
}
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
||||
try {
|
||||
xhr.open("GET", args.url, true);
|
||||
} catch(e) {
|
||||
return gcli.lookup('jsbInvalidURL');
|
||||
}
|
||||
|
||||
let promise = context.createPromise();
|
||||
|
||||
xhr.onreadystatechange = function(aEvt) {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200 || xhr.status == 0) {
|
||||
let browserDoc = context.environment.chromeDocument;
|
||||
let browserWindow = browserDoc.defaultView;
|
||||
let browser = browserWindow.gBrowser;
|
||||
|
||||
browser.selectedTab = browser.addTab("data:text/plain;base64," +
|
||||
browserWindow.btoa(js_beautify(xhr.responseText, opts)));
|
||||
promise.resolve();
|
||||
}
|
||||
else {
|
||||
promise.resolve("Unable to load page to beautify: " + args.url + " " +
|
||||
xhr.status + " " + xhr.statusText);
|
||||
}
|
||||
};
|
||||
}
|
||||
xhr.send(null);
|
||||
return promise;
|
||||
}
|
||||
});
|
264
browser/devtools/commandline/CmdPagemod.jsm
Normal file
264
browser/devtools/commandline/CmdPagemod.jsm
Normal file
@ -0,0 +1,264 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
/**
|
||||
* 'pagemod' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "pagemod",
|
||||
description: gcli.lookup("pagemodDesc"),
|
||||
});
|
||||
|
||||
/**
|
||||
* The 'pagemod replace' command. This command allows the user to search and
|
||||
* replace within text nodes and attributes.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "pagemod replace",
|
||||
description: gcli.lookup("pagemodReplaceDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "search",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodReplaceSearchDesc"),
|
||||
},
|
||||
{
|
||||
name: "replace",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodReplaceReplaceDesc"),
|
||||
},
|
||||
{
|
||||
name: "ignoreCase",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
|
||||
},
|
||||
{
|
||||
name: "selector",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodReplaceSelectorDesc"),
|
||||
defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
|
||||
},
|
||||
{
|
||||
name: "root",
|
||||
type: "node",
|
||||
description: gcli.lookup("pagemodReplaceRootDesc"),
|
||||
defaultValue: null,
|
||||
},
|
||||
{
|
||||
name: "attrOnly",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
|
||||
},
|
||||
{
|
||||
name: "contentOnly",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
|
||||
},
|
||||
{
|
||||
name: "attributes",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodReplaceAttributesDesc"),
|
||||
defaultValue: null,
|
||||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let searchTextNodes = !args.attrOnly;
|
||||
let searchAttributes = !args.contentOnly;
|
||||
let regexOptions = args.ignoreCase ? 'ig' : 'g';
|
||||
let search = new RegExp(escapeRegex(args.search), regexOptions);
|
||||
let attributeRegex = null;
|
||||
if (args.attributes) {
|
||||
attributeRegex = new RegExp(args.attributes, regexOptions);
|
||||
}
|
||||
|
||||
let root = args.root || document;
|
||||
let elements = root.querySelectorAll(args.selector);
|
||||
elements = Array.prototype.slice.call(elements);
|
||||
|
||||
let replacedTextNodes = 0;
|
||||
let replacedAttributes = 0;
|
||||
|
||||
function replaceAttribute() {
|
||||
replacedAttributes++;
|
||||
return args.replace;
|
||||
}
|
||||
function replaceTextNode() {
|
||||
replacedTextNodes++;
|
||||
return args.replace;
|
||||
}
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let element = elements[i];
|
||||
if (searchTextNodes) {
|
||||
for (let y = 0; y < element.childNodes.length; y++) {
|
||||
let node = element.childNodes[y];
|
||||
if (node.nodeType == node.TEXT_NODE) {
|
||||
node.textContent = node.textContent.replace(search, replaceTextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (searchAttributes) {
|
||||
if (!element.attributes) {
|
||||
continue;
|
||||
}
|
||||
for (let y = 0; y < element.attributes.length; y++) {
|
||||
let attr = element.attributes[y];
|
||||
if (!attributeRegex || attributeRegex.test(attr.name)) {
|
||||
attr.value = attr.value.replace(search, replaceAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gcli.lookupFormat("pagemodReplaceResult",
|
||||
[elements.length, replacedTextNodes,
|
||||
replacedAttributes]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'pagemod remove' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "pagemod remove",
|
||||
description: gcli.lookup("pagemodRemoveDesc"),
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* The 'pagemod remove element' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "pagemod remove element",
|
||||
description: gcli.lookup("pagemodRemoveElementDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "search",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodRemoveElementSearchDesc"),
|
||||
},
|
||||
{
|
||||
name: "root",
|
||||
type: "node",
|
||||
description: gcli.lookup("pagemodRemoveElementRootDesc"),
|
||||
defaultValue: null,
|
||||
},
|
||||
{
|
||||
name: 'stripOnly',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
|
||||
},
|
||||
{
|
||||
name: 'ifEmptyOnly',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
|
||||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
let root = args.root || document;
|
||||
let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
|
||||
|
||||
let removed = 0;
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let element = elements[i];
|
||||
let parentNode = element.parentNode;
|
||||
if (!parentNode || !element.removeChild) {
|
||||
continue;
|
||||
}
|
||||
if (args.stripOnly) {
|
||||
while (element.hasChildNodes()) {
|
||||
parentNode.insertBefore(element.childNodes[0], element);
|
||||
}
|
||||
}
|
||||
if (!args.ifEmptyOnly || !element.hasChildNodes()) {
|
||||
element.parentNode.removeChild(element);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
|
||||
[elements.length, removed]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The 'pagemod remove attribute' command.
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "pagemod remove attribute",
|
||||
description: gcli.lookup("pagemodRemoveAttributeDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "searchAttributes",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
|
||||
},
|
||||
{
|
||||
name: "searchElements",
|
||||
type: "string",
|
||||
description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
|
||||
},
|
||||
{
|
||||
name: "root",
|
||||
type: "node",
|
||||
description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
|
||||
defaultValue: null,
|
||||
},
|
||||
{
|
||||
name: "ignoreCase",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
|
||||
},
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let document = context.environment.contentDocument;
|
||||
|
||||
let root = args.root || document;
|
||||
let regexOptions = args.ignoreCase ? 'ig' : 'g';
|
||||
let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
|
||||
let elements = root.querySelectorAll(args.searchElements);
|
||||
elements = Array.prototype.slice.call(elements);
|
||||
|
||||
let removed = 0;
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let element = elements[i];
|
||||
if (!element.attributes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrs = Array.prototype.slice.call(element.attributes);
|
||||
for (let y = 0; y < attrs.length; y++) {
|
||||
let attr = attrs[y];
|
||||
if (attributeRegex.test(attr.name)) {
|
||||
element.removeAttribute(attr.name);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gcli.lookupFormat("pagemodRemoveAttributeResult",
|
||||
[elements.length, removed]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Make a given string safe to use in a regular expression.
|
||||
*
|
||||
* @param string aString
|
||||
* The string you want to use in a regex.
|
||||
* @return string
|
||||
* The equivalent of |aString| but safe to use in a regex.
|
||||
*/
|
||||
function escapeRegex(aString) {
|
||||
return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
}
|
55
browser/devtools/commandline/CmdRestart.jsm
Normal file
55
browser/devtools/commandline/CmdRestart.jsm
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Restart command
|
||||
*
|
||||
* @param boolean nocache
|
||||
* Disables loading content from cache upon restart.
|
||||
*
|
||||
* Examples :
|
||||
* >> restart
|
||||
* - restarts browser immediately
|
||||
* >> restart --nocache
|
||||
* - restarts immediately and starts Firefox without using cache
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "restart",
|
||||
description: gcli.lookup("restartFirefoxDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "nocache",
|
||||
type: "boolean",
|
||||
defaultValue: false,
|
||||
description: gcli.lookup("restartFirefoxNocacheDesc")
|
||||
}
|
||||
],
|
||||
returnType: "string",
|
||||
exec: function Restart(args, context) {
|
||||
let canceled = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
|
||||
if (canceled.data) {
|
||||
return gcli.lookup("restartFirefoxRequestCancelled");
|
||||
}
|
||||
|
||||
// disable loading content from cache.
|
||||
if (args.nocache) {
|
||||
Services.appinfo.invalidateCachesOnRestart();
|
||||
}
|
||||
|
||||
// restart
|
||||
Cc['@mozilla.org/toolkit/app-startup;1']
|
||||
.getService(Ci.nsIAppStartup)
|
||||
.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
return gcli.lookup("restartFirefoxRestarting");
|
||||
}
|
||||
});
|
135
browser/devtools/commandline/CmdScreenshot.jsm
Normal file
135
browser/devtools/commandline/CmdScreenshot.jsm
Normal file
@ -0,0 +1,135 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
|
||||
"resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
|
||||
/**
|
||||
* 'screenshot' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "screenshot",
|
||||
description: gcli.lookup("screenshotDesc"),
|
||||
manual: gcli.lookup("screenshotManual"),
|
||||
returnType: "string",
|
||||
params: [
|
||||
{
|
||||
name: "filename",
|
||||
type: "string",
|
||||
description: gcli.lookup("screenshotFilenameDesc"),
|
||||
manual: gcli.lookup("screenshotFilenameManual")
|
||||
},
|
||||
{
|
||||
name: "delay",
|
||||
type: { name: "number", min: 0 },
|
||||
defaultValue: 0,
|
||||
description: gcli.lookup("screenshotDelayDesc"),
|
||||
manual: gcli.lookup("screenshotDelayManual")
|
||||
},
|
||||
{
|
||||
name: "fullpage",
|
||||
type: "boolean",
|
||||
defaultValue: false,
|
||||
description: gcli.lookup("screenshotFullPageDesc"),
|
||||
manual: gcli.lookup("screenshotFullPageManual")
|
||||
},
|
||||
{
|
||||
name: "node",
|
||||
type: "node",
|
||||
defaultValue: null,
|
||||
description: gcli.lookup("inspectNodeDesc"),
|
||||
manual: gcli.lookup("inspectNodeManual")
|
||||
}
|
||||
],
|
||||
exec: function Command_screenshot(args, context) {
|
||||
var document = context.environment.contentDocument;
|
||||
if (args.delay > 0) {
|
||||
var promise = context.createPromise();
|
||||
document.defaultView.setTimeout(function Command_screenshotDelay() {
|
||||
let reply = this.grabScreen(document, args.filename);
|
||||
promise.resolve(reply);
|
||||
}.bind(this), args.delay * 1000);
|
||||
return promise;
|
||||
}
|
||||
else {
|
||||
return this.grabScreen(document, args.filename, args.fullpage, args.node);
|
||||
}
|
||||
},
|
||||
grabScreen:
|
||||
function Command_screenshotGrabScreen(document, filename, fullpage, node) {
|
||||
let window = document.defaultView;
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
let left = 0;
|
||||
let top = 0;
|
||||
let width;
|
||||
let height;
|
||||
|
||||
if (!fullpage) {
|
||||
if (!node) {
|
||||
left = window.scrollX;
|
||||
top = window.scrollY;
|
||||
width = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
} else {
|
||||
let rect = LayoutHelpers.getRect(node, window);
|
||||
top = rect.top;
|
||||
left = rect.left;
|
||||
width = rect.width;
|
||||
height = rect.height;
|
||||
}
|
||||
} else {
|
||||
width = window.innerWidth + window.scrollMaxX;
|
||||
height = window.innerHeight + window.scrollMaxY;
|
||||
}
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawWindow(window, left, top, width, height, "#fff");
|
||||
|
||||
let data = canvas.toDataURL("image/png", "");
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
|
||||
// Check there is a .png extension to filename
|
||||
if (!filename.match(/.png$/i)) {
|
||||
filename += ".png";
|
||||
}
|
||||
|
||||
// If the filename is relative, tack it onto the download directory
|
||||
if (!filename.match(/[\\\/]/)) {
|
||||
let downloadMgr = Cc["@mozilla.org/download-manager;1"]
|
||||
.getService(Ci.nsIDownloadManager);
|
||||
let tempfile = downloadMgr.userDownloadsDirectory;
|
||||
tempfile.append(filename);
|
||||
filename = tempfile.path;
|
||||
}
|
||||
|
||||
try {
|
||||
file.initWithPath(filename);
|
||||
} catch (ex) {
|
||||
return "Error saving to " + filename;
|
||||
}
|
||||
|
||||
let ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
let Persist = Ci.nsIWebBrowserPersist;
|
||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(Persist);
|
||||
persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
|
||||
Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
|
||||
let source = ioService.newURI(data, "UTF8", null);
|
||||
persist.saveURI(source, null, null, null, null, file);
|
||||
|
||||
return "Saved to " + filename;
|
||||
}
|
||||
});
|
25
browser/devtools/commandline/Commands.jsm
Normal file
25
browser/devtools/commandline/Commands.jsm
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource:///modules/devtools/CmdAddon.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdBreak.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdCalllog.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdConsole.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdCookie.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdDbg.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdEcho.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdEdit.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdExport.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdInspect.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdJsb.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdPagemod.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdResize.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdRestart.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdScreenshot.jsm");
|
||||
Cu.import("resource:///modules/devtools/CmdTilt.jsm");
|
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,8 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/>
|
||||
</head>
|
||||
<body class="gcli-body">
|
||||
<div id="gcli-output-root"></div>
|
@ -9,8 +9,8 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/>
|
||||
</head>
|
||||
<body class="gcli-body">
|
||||
<div id="gcli-tooltip-root"></div>
|
@ -12,35 +12,28 @@ relativesrcdir = @relativesrcdir@
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
browser_gcli_addon.js \
|
||||
browser_gcli_break.js \
|
||||
browser_gcli_calllog.js \
|
||||
browser_gcli_commands.js \
|
||||
browser_gcli_cookie.js \
|
||||
browser_gcli_dbg.js \
|
||||
browser_gcli_edit.js \
|
||||
browser_gcli_inspect.js \
|
||||
browser_gcli_integrate.js \
|
||||
browser_gcli_jsb.js \
|
||||
browser_gcli_pagemod_export.js \
|
||||
browser_gcli_pref.js \
|
||||
browser_gcli_responsivemode.js \
|
||||
browser_gcli_restart.js \
|
||||
browser_gcli_settings.js \
|
||||
browser_dbg_cmd_break.js \
|
||||
browser_dbg_cmd.js \
|
||||
browser_cmd_addon.js \
|
||||
browser_cmd_calllog.js \
|
||||
browser_cmd_commands.js \
|
||||
browser_cmd_cookie.js \
|
||||
browser_cmd_integrate.js \
|
||||
browser_cmd_jsb.js \
|
||||
browser_cmd_pagemod_export.js \
|
||||
browser_cmd_pref.js \
|
||||
browser_cmd_restart.js \
|
||||
browser_cmd_settings.js \
|
||||
browser_gcli_web.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_gcli_break.html \
|
||||
browser_gcli_inspect.html \
|
||||
resources_dbg.html \
|
||||
resources_inpage.js \
|
||||
resources_inpage1.css \
|
||||
resources_inpage2.css \
|
||||
resources_jsb_script.js \
|
||||
resources.html \
|
||||
browser_dbg_cmd_break.html \
|
||||
browser_dbg_cmd.html \
|
||||
browser_cmd_pagemod_export.html \
|
||||
browser_cmd_jsb_script.jsi \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
50
browser/devtools/commandline/test/browser_cmd_addon.js
Normal file
50
browser/devtools/commandline/test/browser_cmd_addon.js
Normal file
@ -0,0 +1,50 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the addon commands works as they should
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
|
||||
}
|
||||
|
||||
function GAT_test() {
|
||||
Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
}
|
||||
|
||||
var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
|
||||
Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list dictionary",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list extension",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list locale",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list plugin",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list theme",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list all",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon disable Test_Plug-in_1.0.0.0",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon enable Test_Plug-in_1.0.0.0",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
});
|
@ -9,11 +9,7 @@ Components.utils.import("resource:///modules/HUDService.jsm", imported);
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testCallLogStatus();
|
||||
testCallLogExec();
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testCallLogStatus, testCallLogExec ]);
|
||||
}
|
||||
|
||||
function testCallLogStatus() {
|
@ -9,13 +9,7 @@ Components.utils.import("resource:///modules/HUDService.jsm", imported);
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testEcho();
|
||||
testConsole(tab);
|
||||
|
||||
imported = undefined;
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testEcho, testConsole ]);
|
||||
}
|
||||
|
||||
function testEcho() {
|
||||
@ -28,7 +22,7 @@ function testEcho() {
|
||||
*/
|
||||
}
|
||||
|
||||
function testConsole(tab) {
|
||||
function testConsole(browser, tab) {
|
||||
let hud = null;
|
||||
function onWebConsoleOpen(aSubject) {
|
||||
Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
|
||||
@ -70,6 +64,5 @@ function testConsole(tab) {
|
||||
ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
|
||||
|
||||
imported = undefined;
|
||||
finish();
|
||||
}
|
||||
}
|
@ -6,10 +6,7 @@
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testCookieCommands();
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testCookieCommands ]);
|
||||
}
|
||||
|
||||
function testCookieCommands() {
|
51
browser/devtools/commandline/test/browser_cmd_jsb.js
Normal file
51
browser/devtools/commandline/test/browser_cmd_jsb.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the jsb command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/browser_cmd_jsb_script.jsi";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", [ /*GJT_test*/ ]);
|
||||
}
|
||||
|
||||
function GJT_test() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "jsb AAA",
|
||||
outputMatch: /valid/
|
||||
});
|
||||
|
||||
gBrowser.addTabsProgressListener({
|
||||
onProgressChange: DeveloperToolbarTest.checkCalled(function GJT_onProgressChange(aBrowser) {
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
|
||||
let win = aBrowser._contentWindow;
|
||||
let uri = win.document.location.href;
|
||||
let result = win.atob(uri.replace(/.*,/, ""));
|
||||
|
||||
result = result.replace(/[\r\n]]/g, "\n");
|
||||
|
||||
checkResult(result);
|
||||
})
|
||||
});
|
||||
|
||||
info("Checking beautification");
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "jsb " + TEST_URI + " 4 space true -1 false collapse true false",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
|
||||
function checkResult(aResult) {
|
||||
let correct = "function somefunc() {\n" +
|
||||
" for (let n = 0; n < 500; n++) {\n" +
|
||||
" if (n % 2 == 1) {\n" +
|
||||
" console.log(n);\n" +
|
||||
" console.log(n + 1);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
is(aResult, correct, "JS has been correctly prettified");
|
||||
}
|
||||
}
|
@ -3,20 +3,23 @@
|
||||
|
||||
// Tests that the inspect command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
|
||||
"test/browser_cmd_pagemod_export.html";
|
||||
|
||||
function test() {
|
||||
let initialHtml = "";
|
||||
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
initialHtml = content.document.documentElement.innerHTML;
|
||||
DeveloperToolbarTest.test(TEST_URI, [
|
||||
init,
|
||||
testExportHtml,
|
||||
testPageModReplace,
|
||||
testPageModRemoveElement,
|
||||
testPageModRemoveAttribute
|
||||
]);
|
||||
|
||||
testExportHtml();
|
||||
testPageModReplace();
|
||||
testPageModRemoveElement();
|
||||
testPageModRemoveAttribute();
|
||||
finish();
|
||||
});
|
||||
function init() {
|
||||
initialHtml = content.document.documentElement.innerHTML;
|
||||
}
|
||||
|
||||
function testExportHtml() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
@ -22,19 +22,16 @@ imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-pref";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
setup();
|
||||
|
||||
testPrefSetEnable();
|
||||
testPrefStatus();
|
||||
testPrefBoolExec();
|
||||
testPrefNumberExec();
|
||||
testPrefStringExec();
|
||||
testPrefSetDisable();
|
||||
|
||||
shutdown();
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [
|
||||
setup,
|
||||
testPrefSetEnable,
|
||||
testPrefStatus,
|
||||
testPrefBoolExec,
|
||||
testPrefNumberExec,
|
||||
testPrefStringExec,
|
||||
testPrefSetDisable,
|
||||
shutdown
|
||||
]);
|
||||
}
|
||||
|
||||
let tiltEnabledOrig = undefined;
|
@ -6,10 +6,7 @@
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testRestart();
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testRestart ]);
|
||||
}
|
||||
|
||||
function testRestart() {
|
@ -22,14 +22,7 @@ imports.XPCOMUtils.defineLazyGetter(imports, "supportsString", function() {
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-settings";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
setup();
|
||||
|
||||
testSettings();
|
||||
|
||||
shutdown();
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ setup, testSettings, shutdown ]);
|
||||
}
|
||||
|
||||
let tiltEnabled = undefined;
|
72
browser/devtools/commandline/test/browser_dbg_cmd.js
Normal file
72
browser/devtools/commandline/test/browser_dbg_cmd.js
Normal file
@ -0,0 +1,72 @@
|
||||
function test() {
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/browser_dbg_cmd.html";
|
||||
|
||||
DeveloperToolbarTest.test(TEST_URI, function() {
|
||||
testDbgCmd();
|
||||
});
|
||||
}
|
||||
|
||||
function testDbgCmd() {
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
ok(pane, "toggleDebugger() should return a pane.");
|
||||
let frame = pane._frame;
|
||||
|
||||
frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
|
||||
frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
|
||||
// Wait for the initial resume...
|
||||
aEvent.target.ownerDocument.defaultView.gClient
|
||||
.addOneTimeListener("resumed", function() {
|
||||
|
||||
info("Starting tests.");
|
||||
|
||||
let contentDoc = content.window.document;
|
||||
let output = contentDoc.querySelector("input[type=text]");
|
||||
let btnDoit = contentDoc.querySelector("input[type=button]");
|
||||
|
||||
cmd("dbg interrupt", function() {
|
||||
ok(true, "debugger is paused");
|
||||
pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
|
||||
ok(true, "debugger continued");
|
||||
pane.contentWindow.gClient.addOneTimeListener("paused", function() {
|
||||
cmd("dbg step in", function() {
|
||||
cmd("dbg step in", function() {
|
||||
cmd("dbg step in", function() {
|
||||
is(output.value, "step in", "debugger stepped in");
|
||||
cmd("dbg step over", function() {
|
||||
is(output.value, "step over", "debugger stepped over");
|
||||
cmd("dbg step out", function() {
|
||||
is(output.value, "step out", "debugger stepped out");
|
||||
cmd("dbg continue", function() {
|
||||
cmd("dbg continue", function() {
|
||||
is(output.value, "dbg continue", "debugger continued");
|
||||
pane.contentWindow.gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
EventUtils.sendMouseEvent({type:"click"}, btnDoit);
|
||||
});
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "dbg continue",
|
||||
blankOutput: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function cmd(aTyped, aCallback) {
|
||||
pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: aTyped,
|
||||
blankOutput: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
@ -3,15 +3,23 @@
|
||||
|
||||
// Tests that the break command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_break.html";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/browser_dbg_cmd_break.html";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testBreakCommands();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testBreakCommands ]);
|
||||
}
|
||||
|
||||
function testBreakCommands() {
|
||||
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info(content.document.documentElement.innerHTML + '\n');
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "brea",
|
||||
directTabText: "k",
|
||||
@ -35,13 +43,16 @@ function testBreakCommands() {
|
||||
});
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
|
||||
|
||||
var dbgConnected = DeveloperToolbarTest.checkCalled(function() {
|
||||
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
|
||||
// Wait for the initial resume.
|
||||
let client = pane.contentWindow.gClient;
|
||||
client.addOneTimeListener("resumed", function() {
|
||||
client.activeThread.addOneTimeListener("framesadded", function() {
|
||||
|
||||
var resumed = DeveloperToolbarTest.checkCalled(function() {
|
||||
|
||||
var framesAdded = DeveloperToolbarTest.checkCalled(function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0,
|
||||
status: "VALID"
|
||||
@ -61,7 +72,7 @@ function testBreakCommands() {
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
|
||||
client.activeThread.resume(function() {
|
||||
var cleanup = DeveloperToolbarTest.checkCalled(function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break del 0",
|
||||
status: "VALID"
|
||||
@ -70,13 +81,19 @@ function testBreakCommands() {
|
||||
args: { breakid: 0 },
|
||||
completed: false
|
||||
});
|
||||
|
||||
finish();
|
||||
});
|
||||
|
||||
client.activeThread.resume(cleanup);
|
||||
});
|
||||
|
||||
client.activeThread.addOneTimeListener("framesadded", framesAdded);
|
||||
|
||||
// Trigger newScript notifications using eval.
|
||||
content.wrappedJSObject.firstCall();
|
||||
});
|
||||
}, true);
|
||||
|
||||
client.addOneTimeListener("resumed", resumed);
|
||||
});
|
||||
|
||||
pane._frame.addEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", function GAT_test() {
|
||||
function GAT_ready() {
|
||||
Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list dictionary",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list extension",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list locale",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list plugin",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list theme",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon list all",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon disable Test_Plug-in_1.0.0.0",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "addon enable Test_Plug-in_1.0.0.0",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
finish();
|
||||
}
|
||||
Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
});
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
function test() {
|
||||
const TEST_URI = TEST_BASE_HTTP + "resources_dbg.html";
|
||||
|
||||
DeveloperToolbarTest.test(TEST_URI, function GAT_test() {
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
ok(pane, "toggleDebugger() should return a pane.");
|
||||
let frame = pane._frame;
|
||||
|
||||
frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
|
||||
frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
|
||||
// Wait for the initial resume...
|
||||
aEvent.target.ownerDocument.defaultView.gClient
|
||||
.addOneTimeListener("resumed", function() {
|
||||
|
||||
info("Starting tests.");
|
||||
|
||||
let contentDoc = content.window.document;
|
||||
let output = contentDoc.querySelector("input[type=text]");
|
||||
let btnDoit = contentDoc.querySelector("input[type=button]");
|
||||
|
||||
cmd("dbg interrupt", function() {
|
||||
ok(true, "debugger is paused");
|
||||
pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
|
||||
ok(true, "debugger continued");
|
||||
pane.contentWindow.gClient.addOneTimeListener("paused", function() {
|
||||
cmd("dbg step in", function() {
|
||||
cmd("dbg step in", function() {
|
||||
cmd("dbg step in", function() {
|
||||
is(output.value, "step in", "debugger stepped in");
|
||||
cmd("dbg step over", function() {
|
||||
is(output.value, "step over", "debugger stepped over");
|
||||
cmd("dbg step out", function() {
|
||||
is(output.value, "step out", "debugger stepped out");
|
||||
cmd("dbg continue", function() {
|
||||
cmd("dbg continue", function() {
|
||||
is(output.value, "dbg continue", "debugger continued");
|
||||
pane.contentWindow.gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
EventUtils.sendMouseEvent({type:"click"}, btnDoit);
|
||||
});
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "dbg continue",
|
||||
blankOutput: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function cmd(aTyped, aCallback) {
|
||||
pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: aTyped,
|
||||
blankOutput: true
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
function test() {
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/resources_jsb_script.js";
|
||||
|
||||
DeveloperToolbarTest.test("about:blank", function GJT_test() {
|
||||
/* Commented out by bug 774057, re-enable with un-hidden jsb command
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "jsb AAA",
|
||||
outputMatch: /valid/
|
||||
});
|
||||
|
||||
gBrowser.addTabsProgressListener({
|
||||
onProgressChange: function GJT_onProgressChange(aBrowser) {
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
|
||||
let win = aBrowser._contentWindow;
|
||||
let uri = win.document.location.href;
|
||||
let result = win.atob(uri.replace(/.*,/, ""));
|
||||
|
||||
result = result.replace(/[\r\n]]/g, "\n");
|
||||
|
||||
checkResult(result);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
info("Checking beautification");
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "jsb " + TEST_URI + " 4 space true -1 false collapse true false",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
|
||||
function checkResult(aResult) {
|
||||
let correct = "function somefunc() {\n" +
|
||||
" for (let n = 0; n < 500; n++) {\n" +
|
||||
" if (n % 2 == 1) {\n" +
|
||||
" console.log(n);\n" +
|
||||
" console.log(n + 1);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
is(aResult, correct, "JS has been correctly prettified");
|
||||
}
|
||||
*/
|
||||
finish();
|
||||
});
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", function GAT_test() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize on",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize to 400 400",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
executeSoon(finish);
|
||||
});
|
||||
|
||||
function isOpen() {
|
||||
return !!gBrowser.selectedTab.__responsiveUI;
|
||||
}
|
||||
|
||||
function isClosed() {
|
||||
return !isOpen();
|
||||
}
|
||||
}
|
@ -11,6 +11,10 @@ let console = (function() {
|
||||
return tempScope.console;
|
||||
})();
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
*/
|
||||
@ -39,518 +43,3 @@ registerCleanupFunction(function tearDown() {
|
||||
|
||||
console = undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
function doTest(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param testFunc A function containing the tests to run. This should
|
||||
* arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, testFunc) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
addTab(uri, function(browser, tab) {
|
||||
DeveloperToolbarTest.show(function() {
|
||||
|
||||
try {
|
||||
testFunc(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
console.error(ex);
|
||||
finish();
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Memory leak hunter. Walks a tree of objects looking for DOM nodes.
|
||||
* Usage:
|
||||
* leakHunt({
|
||||
* thing: thing,
|
||||
* otherthing: otherthing
|
||||
* });
|
||||
*/
|
||||
|
||||
var noRecurse = [
|
||||
/^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/,
|
||||
/^Window$/, /^Document$/,
|
||||
/^XULDocument$/, /^XULElement$/,
|
||||
/^DOMWindow$/, /^HTMLDocument$/, /^HTML.*Element$/
|
||||
];
|
||||
|
||||
var hide = [ /^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/ ];
|
||||
|
||||
function leakHunt(root, path, seen) {
|
||||
path = path || [];
|
||||
seen = seen || [];
|
||||
|
||||
try {
|
||||
var output = leakHuntInner(root, path, seen);
|
||||
output.forEach(function(line) {
|
||||
dump(line + '\n');
|
||||
});
|
||||
}
|
||||
catch (ex) {
|
||||
dump(ex + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function leakHuntInner(root, path, seen) {
|
||||
var prefix = new Array(path.length).join(' ');
|
||||
|
||||
var reply = [];
|
||||
function log(msg) {
|
||||
reply.push(msg);
|
||||
}
|
||||
|
||||
var direct
|
||||
try {
|
||||
direct = Object.keys(root);
|
||||
}
|
||||
catch (ex) {
|
||||
log(prefix + ' Error enumerating: ' + ex);
|
||||
return reply;
|
||||
}
|
||||
|
||||
for (var prop in root) {
|
||||
var newPath = path.slice();
|
||||
newPath.push(prop);
|
||||
prefix = new Array(newPath.length).join(' ');
|
||||
|
||||
var data;
|
||||
try {
|
||||
data = root[prop];
|
||||
}
|
||||
catch (ex) {
|
||||
log(prefix + prop + ' Error reading: ' + ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
var recurse = true;
|
||||
var message = getType(data);
|
||||
|
||||
if (matchesAnyPattern(message, hide)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message === 'function' && direct.indexOf(prop) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message === 'string') {
|
||||
var extra = data.length > 10 ? data.substring(0, 9) + '_' : data;
|
||||
message += ' "' + extra.replace(/\n/g, "|") + '"';
|
||||
recurse = false;
|
||||
}
|
||||
else if (matchesAnyPattern(message, noRecurse)) {
|
||||
message += ' (no recurse)'
|
||||
recurse = false;
|
||||
}
|
||||
else if (seen.indexOf(data) !== -1) {
|
||||
message += ' (already seen)';
|
||||
recurse = false;
|
||||
}
|
||||
|
||||
if (recurse) {
|
||||
seen.push(data);
|
||||
var lines = leakHuntInner(data, newPath, seen);
|
||||
if (lines.length == 0) {
|
||||
if (message !== 'function') {
|
||||
log(prefix + prop + ' = ' + message + ' { }');
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(prefix + prop + ' = ' + message + ' {');
|
||||
lines.forEach(function(line) {
|
||||
reply.push(line);
|
||||
});
|
||||
log(prefix + '}');
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(prefix + prop + ' = ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
function matchesAnyPattern(str, patterns) {
|
||||
var match = false;
|
||||
patterns.forEach(function(pattern) {
|
||||
if (str.match(pattern)) {
|
||||
match = true;
|
||||
}
|
||||
});
|
||||
return match;
|
||||
}
|
||||
|
||||
function getType(data) {
|
||||
if (data === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (data === undefined) {
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
var type = typeof data;
|
||||
if (type === 'object' || type === 'Object') {
|
||||
type = getCtorName(data);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
function getCtorName(aObj) {
|
||||
try {
|
||||
if (aObj.constructor && aObj.constructor.name) {
|
||||
return aObj.constructor.name;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
return 'UnknownObject';
|
||||
}
|
||||
|
||||
// If that fails, use Objects toString which sometimes gives something
|
||||
// better than 'Object', and at least defaults to Object if nothing better
|
||||
return Object.prototype.toString.call(aObj).slice(8, -1);
|
||||
}
|
||||
|
459
browser/devtools/commandline/test/helper.js
Normal file
459
browser/devtools/commandline/test/helper.js
Normal file
@ -0,0 +1,459 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
|
||||
* OF THIS FILE.
|
||||
*
|
||||
* UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
|
||||
* THE NAUGHTY STEP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* FOR A LONG TIME.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
info('Starting tests for ' + checks.typed);
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param target Either a function or array of functions containing the tests
|
||||
* to run. If an array of test function is passed then we will clear up after
|
||||
* the tests have completed. If a single test function is passed then this
|
||||
* function should arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, target) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = uri;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
var onTabLoad = function() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
|
||||
DeveloperToolbarTest.show(function() {
|
||||
if (Array.isArray(target)) {
|
||||
try {
|
||||
target.forEach(function(func) {
|
||||
func(browser, tab);
|
||||
})
|
||||
}
|
||||
finally {
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
target(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
DeveloperToolbarTest._finish();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
};
|
||||
|
||||
DeveloperToolbarTest._outstanding = [];
|
||||
|
||||
DeveloperToolbarTest._checkFinish = function() {
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
DeveloperToolbarTest.closeAllTabs();
|
||||
finish();
|
||||
}
|
||||
|
||||
DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
|
||||
var todo = function() {
|
||||
var reply = aFunc.apply(aScope, arguments);
|
||||
DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
|
||||
return aJob != todo;
|
||||
});
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
return reply;
|
||||
}
|
||||
DeveloperToolbarTest._outstanding.push(todo);
|
||||
return todo;
|
||||
};
|
||||
|
||||
DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
|
||||
return function() {
|
||||
ok(false, aMsg);
|
||||
return aFunc.apply(aScope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DeveloperToolbarTest.closeAllTabs = function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
};
|
29
browser/devtools/highlighter/CmdInspect.jsm
Normal file
29
browser/devtools/highlighter/CmdInspect.jsm
Normal file
@ -0,0 +1,29 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
/**
|
||||
* 'inspect' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "inspect",
|
||||
description: gcli.lookup("inspectDesc"),
|
||||
manual: gcli.lookup("inspectManual"),
|
||||
params: [
|
||||
{
|
||||
name: "node",
|
||||
type: "node",
|
||||
description: gcli.lookup("inspectNodeDesc"),
|
||||
manual: gcli.lookup("inspectNodeManual")
|
||||
}
|
||||
],
|
||||
exec: function Command_inspect(args, context) {
|
||||
let document = context.environment.chromeDocument;
|
||||
document.defaultView.InspectorUI.openInspectorUI(args.node);
|
||||
}
|
||||
});
|
@ -24,3 +24,6 @@ EXTRA_PP_JS_MODULES = \
|
||||
TEST_DIRS += test
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs::
|
||||
$(NSINSTALL) $(srcdir)/CmdInspect.jsm $(FINAL_TARGET)/modules/devtools
|
||||
|
@ -37,7 +37,10 @@ _BROWSER_FILES = \
|
||||
browser_inspector_pseudoClass_menu.js \
|
||||
browser_inspector_destroyselection.html \
|
||||
browser_inspector_destroyselection.js \
|
||||
browser_inspector_cmd_inspect.js \
|
||||
browser_inspector_cmd_inspect.html \
|
||||
head.js \
|
||||
helper.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
|
@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GCLI inspect command test</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- This is a list of 0 h1 elements -->
|
||||
|
||||
<!-- This is a list of 1 div elements -->
|
||||
<div>Hello, I'm a div</div>
|
||||
|
||||
<!-- This is a list of 2 span elements -->
|
||||
<span>Hello, I'm a span</span>
|
||||
<span>And me</span>
|
||||
|
||||
<!-- This is a collection of various things that match only once -->
|
||||
<p class="someclass">.someclass</p>
|
||||
<p id="someid">#someid</p>
|
||||
<button disabled>button[disabled]</button>
|
||||
<p><strong>p>strong</strong></p>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -3,14 +3,11 @@
|
||||
|
||||
// Tests that the inspect command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/highlighter/" +
|
||||
"test/browser_inspector_cmd_inspect.html";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testInspect();
|
||||
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testInspect ]);
|
||||
}
|
||||
|
||||
function testInspect() {
|
@ -7,6 +7,10 @@ let tempScope = {};
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tempScope);
|
||||
let LayoutHelpers = tempScope.LayoutHelpers;
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
|
||||
// Clear preferences that may be set during the course of tests.
|
||||
function clearUserPrefs()
|
||||
{
|
||||
|
459
browser/devtools/highlighter/test/helper.js
Normal file
459
browser/devtools/highlighter/test/helper.js
Normal file
@ -0,0 +1,459 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
|
||||
* OF THIS FILE.
|
||||
*
|
||||
* UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
|
||||
* THE NAUGHTY STEP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* FOR A LONG TIME.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
info('Starting tests for ' + checks.typed);
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param target Either a function or array of functions containing the tests
|
||||
* to run. If an array of test function is passed then we will clear up after
|
||||
* the tests have completed. If a single test function is passed then this
|
||||
* function should arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, target) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = uri;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
var onTabLoad = function() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
|
||||
DeveloperToolbarTest.show(function() {
|
||||
if (Array.isArray(target)) {
|
||||
try {
|
||||
target.forEach(function(func) {
|
||||
func(browser, tab);
|
||||
})
|
||||
}
|
||||
finally {
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
target(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
DeveloperToolbarTest._finish();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
};
|
||||
|
||||
DeveloperToolbarTest._outstanding = [];
|
||||
|
||||
DeveloperToolbarTest._checkFinish = function() {
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
DeveloperToolbarTest.closeAllTabs();
|
||||
finish();
|
||||
}
|
||||
|
||||
DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
|
||||
var todo = function() {
|
||||
var reply = aFunc.apply(aScope, arguments);
|
||||
DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
|
||||
return aJob != todo;
|
||||
});
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
return reply;
|
||||
}
|
||||
DeveloperToolbarTest._outstanding.push(todo);
|
||||
return todo;
|
||||
};
|
||||
|
||||
DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
|
||||
return function() {
|
||||
ok(false, aMsg);
|
||||
return aFunc.apply(aScope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DeveloperToolbarTest.closeAllTabs = function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
};
|
@ -26,6 +26,6 @@ browser.jar:
|
||||
content/browser/debugger.css (debugger/debugger.css)
|
||||
content/browser/debugger-controller.js (debugger/debugger-controller.js)
|
||||
content/browser/debugger-view.js (debugger/debugger-view.js)
|
||||
content/browser/devtools/gcli.css (commandline/gcli.css)
|
||||
content/browser/devtools/gclioutput.xhtml (commandline/gclioutput.xhtml)
|
||||
content/browser/devtools/gclitooltip.xhtml (commandline/gclitooltip.xhtml)
|
||||
content/browser/devtools/commandline.css (commandline/commandline.css)
|
||||
content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
|
||||
content/browser/devtools/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)
|
||||
|
64
browser/devtools/responsivedesign/CmdResize.jsm
Normal file
64
browser/devtools/responsivedesign/CmdResize.jsm
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
/* Responsive Mode commands */
|
||||
gcli.addCommand({
|
||||
name: 'resize',
|
||||
description: gcli.lookup('resizeModeDesc')
|
||||
});
|
||||
|
||||
gcli.addCommand({
|
||||
name: 'resize on',
|
||||
description: gcli.lookup('resizeModeOnDesc'),
|
||||
manual: gcli.lookup('resizeModeManual'),
|
||||
exec: gcli_cmd_resize
|
||||
});
|
||||
|
||||
gcli.addCommand({
|
||||
name: 'resize off',
|
||||
description: gcli.lookup('resizeModeOffDesc'),
|
||||
manual: gcli.lookup('resizeModeManual'),
|
||||
exec: gcli_cmd_resize
|
||||
});
|
||||
|
||||
gcli.addCommand({
|
||||
name: 'resize toggle',
|
||||
description: gcli.lookup('resizeModeToggleDesc'),
|
||||
manual: gcli.lookup('resizeModeManual'),
|
||||
exec: gcli_cmd_resize
|
||||
});
|
||||
|
||||
gcli.addCommand({
|
||||
name: 'resize to',
|
||||
description: gcli.lookup('resizeModeToDesc'),
|
||||
params: [
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
description: gcli.lookup("resizePageArgWidthDesc"),
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
description: gcli.lookup("resizePageArgHeightDesc"),
|
||||
},
|
||||
],
|
||||
exec: gcli_cmd_resize
|
||||
});
|
||||
|
||||
function gcli_cmd_resize(args, context) {
|
||||
let browserDoc = context.environment.chromeDocument;
|
||||
let browserWindow = browserDoc.defaultView;
|
||||
let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
|
||||
mgr.handleGcliCommand(browserWindow,
|
||||
browserWindow.gBrowser.selectedTab,
|
||||
this.name,
|
||||
args);
|
||||
}
|
@ -47,7 +47,10 @@ include $(topsrcdir)/config/rules.mk
|
||||
_BROWSER_FILES = \
|
||||
browser_responsiveui.js \
|
||||
browser_responsiveruleview.js \
|
||||
browser_responsive_cmd.js \
|
||||
browser_responsivecomputedview.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
|
||||
}
|
||||
|
||||
function isOpen() {
|
||||
return !!gBrowser.selectedTab.__responsiveUI;
|
||||
}
|
||||
|
||||
function isClosed() {
|
||||
return !isOpen();
|
||||
}
|
||||
|
||||
function GAT_test() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize on",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize to 400 400",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
// executeSoon(finish);
|
||||
}
|
8
browser/devtools/responsivedesign/test/head.js
Normal file
8
browser/devtools/responsivedesign/test/head.js
Normal file
@ -0,0 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
459
browser/devtools/responsivedesign/test/helper.js
Normal file
459
browser/devtools/responsivedesign/test/helper.js
Normal file
@ -0,0 +1,459 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
|
||||
* OF THIS FILE.
|
||||
*
|
||||
* UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
|
||||
* THE NAUGHTY STEP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* FOR A LONG TIME.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
info('Starting tests for ' + checks.typed);
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param target Either a function or array of functions containing the tests
|
||||
* to run. If an array of test function is passed then we will clear up after
|
||||
* the tests have completed. If a single test function is passed then this
|
||||
* function should arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, target) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = uri;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
var onTabLoad = function() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
|
||||
DeveloperToolbarTest.show(function() {
|
||||
if (Array.isArray(target)) {
|
||||
try {
|
||||
target.forEach(function(func) {
|
||||
func(browser, tab);
|
||||
})
|
||||
}
|
||||
finally {
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
target(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
DeveloperToolbarTest._finish();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
};
|
||||
|
||||
DeveloperToolbarTest._outstanding = [];
|
||||
|
||||
DeveloperToolbarTest._checkFinish = function() {
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
DeveloperToolbarTest.closeAllTabs();
|
||||
finish();
|
||||
}
|
||||
|
||||
DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
|
||||
var todo = function() {
|
||||
var reply = aFunc.apply(aScope, arguments);
|
||||
DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
|
||||
return aJob != todo;
|
||||
});
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
return reply;
|
||||
}
|
||||
DeveloperToolbarTest._outstanding.push(todo);
|
||||
return todo;
|
||||
};
|
||||
|
||||
DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
|
||||
return function() {
|
||||
ok(false, aMsg);
|
||||
return aFunc.apply(aScope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DeveloperToolbarTest.closeAllTabs = function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
};
|
@ -13,6 +13,7 @@ const WEBCONSOLE_CONTENT_SCRIPT_URL =
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource:///modules/devtools/Commands.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
@ -20,8 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gcli",
|
||||
"resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "GcliCommands",
|
||||
"resource:///modules/devtools/GcliCommands.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
|
||||
"resource:///modules/devtools/CmdCmd.jsm");
|
||||
|
||||
/**
|
||||
* A component to manage the global developer toolbar, which contains a GCLI
|
||||
@ -45,7 +46,7 @@ function DeveloperToolbar(aChromeWindow, aToolbarElement)
|
||||
.getElementById("developer-toolbar-webconsole");
|
||||
|
||||
try {
|
||||
GcliCommands.refreshAutoCommands(aChromeWindow);
|
||||
CmdCommands.refreshAutoCommands(aChromeWindow);
|
||||
}
|
||||
catch (ex) {
|
||||
console.error(ex);
|
||||
@ -556,7 +557,7 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
class="gcli-panel">
|
||||
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="gcli-output-frame"
|
||||
src="chrome://browser/content/devtools/gclioutput.xhtml"
|
||||
src="chrome://browser/content/devtools/commandlineoutput.xhtml"
|
||||
flex="1"/>
|
||||
</tooltip>
|
||||
*/
|
||||
@ -571,7 +572,7 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
|
||||
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
|
||||
this._frame.id = "gcli-output-frame";
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/gclioutput.xhtml");
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlineoutput.xhtml");
|
||||
this._frame.setAttribute("flex", "1");
|
||||
this._panel.appendChild(this._frame);
|
||||
|
||||
@ -767,7 +768,7 @@ function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
class="gcli-panel">
|
||||
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="gcli-tooltip-frame"
|
||||
src="chrome://browser/content/devtools/gclitooltip.xhtml"
|
||||
src="chrome://browser/content/devtools/commandlinetooltip.xhtml"
|
||||
flex="1"/>
|
||||
</tooltip>
|
||||
*/
|
||||
@ -782,7 +783,7 @@ function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
|
||||
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
|
||||
this._frame.id = "gcli-tooltip-frame";
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/gclitooltip.xhtml");
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlinetooltip.xhtml");
|
||||
this._frame.setAttribute("flex", "1");
|
||||
this._panel.appendChild(this._frame);
|
||||
|
||||
|
@ -21,6 +21,8 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_toolbar_webconsole_errors_count.js \
|
||||
browser_layoutHelpers.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
leakhunt.js \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
|
@ -8,6 +8,10 @@ let console = (function() {
|
||||
return tempScope.console;
|
||||
})();
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
*/
|
||||
@ -37,87 +41,6 @@ registerCleanupFunction(function tearDown() {
|
||||
console = undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = {
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
show: function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
hide: function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param testFunc A function containing the tests to run. This should
|
||||
* arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
test: function DTT_test(uri, testFunc) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) menuItem.hidden = true;
|
||||
if (command) command.setAttribute("disabled", "true");
|
||||
if (appMenuItem) appMenuItem.hidden = true;
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) menuItem.hidden = false;
|
||||
if (command) command.removeAttribute("disabled");
|
||||
if (appMenuItem) appMenuItem.hidden = false;
|
||||
|
||||
addTab(uri, function(browser, tab) {
|
||||
DeveloperToolbarTest.show(function() {
|
||||
|
||||
try {
|
||||
testFunc(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
console.error(ex);
|
||||
finish();
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
function catchFail(func) {
|
||||
return function() {
|
||||
try {
|
||||
|
459
browser/devtools/shared/test/helper.js
Normal file
459
browser/devtools/shared/test/helper.js
Normal file
@ -0,0 +1,459 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
|
||||
* OF THIS FILE.
|
||||
*
|
||||
* UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
|
||||
* THE NAUGHTY STEP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* FOR A LONG TIME.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
info('Starting tests for ' + checks.typed);
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param target Either a function or array of functions containing the tests
|
||||
* to run. If an array of test function is passed then we will clear up after
|
||||
* the tests have completed. If a single test function is passed then this
|
||||
* function should arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, target) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = uri;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
var onTabLoad = function() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
|
||||
DeveloperToolbarTest.show(function() {
|
||||
if (Array.isArray(target)) {
|
||||
try {
|
||||
target.forEach(function(func) {
|
||||
func(browser, tab);
|
||||
})
|
||||
}
|
||||
finally {
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
target(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
DeveloperToolbarTest._finish();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
};
|
||||
|
||||
DeveloperToolbarTest._outstanding = [];
|
||||
|
||||
DeveloperToolbarTest._checkFinish = function() {
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
DeveloperToolbarTest.closeAllTabs();
|
||||
finish();
|
||||
}
|
||||
|
||||
DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
|
||||
var todo = function() {
|
||||
var reply = aFunc.apply(aScope, arguments);
|
||||
DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
|
||||
return aJob != todo;
|
||||
});
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
return reply;
|
||||
}
|
||||
DeveloperToolbarTest._outstanding.push(todo);
|
||||
return todo;
|
||||
};
|
||||
|
||||
DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
|
||||
return function() {
|
||||
ok(false, aMsg);
|
||||
return aFunc.apply(aScope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DeveloperToolbarTest.closeAllTabs = function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
};
|
157
browser/devtools/shared/test/leakhunt.js
Normal file
157
browser/devtools/shared/test/leakhunt.js
Normal file
@ -0,0 +1,157 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Memory leak hunter. Walks a tree of objects looking for DOM nodes.
|
||||
* Usage:
|
||||
* leakHunt({
|
||||
* thing: thing,
|
||||
* otherthing: otherthing
|
||||
* });
|
||||
*/
|
||||
|
||||
var noRecurse = [
|
||||
/^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/,
|
||||
/^Window$/, /^Document$/,
|
||||
/^XULDocument$/, /^XULElement$/,
|
||||
/^DOMWindow$/, /^HTMLDocument$/, /^HTML.*Element$/
|
||||
];
|
||||
|
||||
var hide = [ /^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/ ];
|
||||
|
||||
function leakHunt(root, path, seen) {
|
||||
path = path || [];
|
||||
seen = seen || [];
|
||||
|
||||
try {
|
||||
var output = leakHuntInner(root, path, seen);
|
||||
output.forEach(function(line) {
|
||||
dump(line + '\n');
|
||||
});
|
||||
}
|
||||
catch (ex) {
|
||||
dump(ex + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function leakHuntInner(root, path, seen) {
|
||||
var prefix = new Array(path.length).join(' ');
|
||||
|
||||
var reply = [];
|
||||
function log(msg) {
|
||||
reply.push(msg);
|
||||
}
|
||||
|
||||
var direct
|
||||
try {
|
||||
direct = Object.keys(root);
|
||||
}
|
||||
catch (ex) {
|
||||
log(prefix + ' Error enumerating: ' + ex);
|
||||
return reply;
|
||||
}
|
||||
|
||||
for (var prop in root) {
|
||||
var newPath = path.slice();
|
||||
newPath.push(prop);
|
||||
prefix = new Array(newPath.length).join(' ');
|
||||
|
||||
var data;
|
||||
try {
|
||||
data = root[prop];
|
||||
}
|
||||
catch (ex) {
|
||||
log(prefix + prop + ' Error reading: ' + ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
var recurse = true;
|
||||
var message = getType(data);
|
||||
|
||||
if (matchesAnyPattern(message, hide)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message === 'function' && direct.indexOf(prop) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message === 'string') {
|
||||
var extra = data.length > 10 ? data.substring(0, 9) + '_' : data;
|
||||
message += ' "' + extra.replace(/\n/g, "|") + '"';
|
||||
recurse = false;
|
||||
}
|
||||
else if (matchesAnyPattern(message, noRecurse)) {
|
||||
message += ' (no recurse)'
|
||||
recurse = false;
|
||||
}
|
||||
else if (seen.indexOf(data) !== -1) {
|
||||
message += ' (already seen)';
|
||||
recurse = false;
|
||||
}
|
||||
|
||||
if (recurse) {
|
||||
seen.push(data);
|
||||
var lines = leakHuntInner(data, newPath, seen);
|
||||
if (lines.length == 0) {
|
||||
if (message !== 'function') {
|
||||
log(prefix + prop + ' = ' + message + ' { }');
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(prefix + prop + ' = ' + message + ' {');
|
||||
lines.forEach(function(line) {
|
||||
reply.push(line);
|
||||
});
|
||||
log(prefix + '}');
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(prefix + prop + ' = ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
function matchesAnyPattern(str, patterns) {
|
||||
var match = false;
|
||||
patterns.forEach(function(pattern) {
|
||||
if (str.match(pattern)) {
|
||||
match = true;
|
||||
}
|
||||
});
|
||||
return match;
|
||||
}
|
||||
|
||||
function getType(data) {
|
||||
if (data === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (data === undefined) {
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
var type = typeof data;
|
||||
if (type === 'object' || type === 'Object') {
|
||||
type = getCtorName(data);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
function getCtorName(aObj) {
|
||||
try {
|
||||
if (aObj.constructor && aObj.constructor.name) {
|
||||
return aObj.constructor.name;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
return 'UnknownObject';
|
||||
}
|
||||
|
||||
// If that fails, use Objects toString which sometimes gives something
|
||||
// better than 'Object', and at least defaults to Object if nothing better
|
||||
return Object.prototype.toString.call(aObj).slice(8, -1);
|
||||
}
|
46
browser/devtools/styleeditor/CmdEdit.jsm
Normal file
46
browser/devtools/styleeditor/CmdEdit.jsm
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
|
||||
"resource:///modules/HUDService.jsm");
|
||||
|
||||
/**
|
||||
* 'edit' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "edit",
|
||||
description: gcli.lookup("editDesc"),
|
||||
manual: gcli.lookup("editManual2"),
|
||||
params: [
|
||||
{
|
||||
name: 'resource',
|
||||
type: {
|
||||
name: 'resource',
|
||||
include: 'text/css'
|
||||
},
|
||||
description: gcli.lookup("editResourceDesc")
|
||||
},
|
||||
{
|
||||
name: "line",
|
||||
defaultValue: 1,
|
||||
type: {
|
||||
name: "number",
|
||||
min: 1,
|
||||
step: 10
|
||||
},
|
||||
description: gcli.lookup("editLineToJumpToDesc")
|
||||
}
|
||||
],
|
||||
exec: function(args, context) {
|
||||
let win = HUDService.currentContext();
|
||||
win.StyleEditor.openChrome(args.resource.element, args.line);
|
||||
}
|
||||
});
|
@ -14,6 +14,8 @@ include $(topsrcdir)/config/rules.mk
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_styleeditor_enabled.js \
|
||||
browser_styleeditor_filesave.js \
|
||||
browser_styleeditor_cmd_edit.js \
|
||||
browser_styleeditor_cmd_edit.html \
|
||||
browser_styleeditor_import.js \
|
||||
browser_styleeditor_init.js \
|
||||
browser_styleeditor_loading.js \
|
||||
@ -26,9 +28,13 @@ _BROWSER_TEST_FILES = \
|
||||
browser_styleeditor_sv_resize.js \
|
||||
four.html \
|
||||
head.js \
|
||||
helper.js \
|
||||
media.html \
|
||||
media-small.css \
|
||||
minified.html \
|
||||
resources_inpage.jsi \
|
||||
resources_inpage1.css \
|
||||
resources_inpage2.css \
|
||||
simple.css \
|
||||
simple.css.gz \
|
||||
simple.css.gz^headers^ \
|
||||
|
@ -16,7 +16,7 @@
|
||||
pid.parentNode.appendChild(div);
|
||||
});
|
||||
</script>
|
||||
<script src="resources_inpage.js"></script>
|
||||
<script src="resources_inpage.jsi"></script>
|
||||
<link rel="stylesheet" type="text/css" href="resources_inpage1.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="resources_inpage2.css"/>
|
||||
<style type="text/css">
|
@ -3,15 +3,13 @@
|
||||
|
||||
// Tests that the edit command works
|
||||
|
||||
const TEST_URI = TEST_BASE_HTTP + "resources.html";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/styleeditor/" +
|
||||
"test/browser_styleeditor_cmd_edit.html";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testEditStatus(browser, tab);
|
||||
// Bug 759853
|
||||
// testEditExec(browser, tab); // calls finish()
|
||||
finish();
|
||||
});
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testEditStatus ]);
|
||||
// Bug 759853
|
||||
// testEditExec
|
||||
}
|
||||
|
||||
function testEditStatus(browser, tab) {
|
||||
@ -42,7 +40,7 @@ function testEditStatus(browser, tab) {
|
||||
typed: "edit http",
|
||||
markup: "VVVVVIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
|
||||
directTabText: "://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
|
||||
arrowTabText: "",
|
||||
emptyParameters: [ " [line]" ],
|
||||
});
|
||||
@ -52,7 +50,7 @@ function testEditStatus(browser, tab) {
|
||||
markup: "VVVVVIIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
|
||||
emptyParameters: [ " [line]" ],
|
||||
});
|
||||
|
||||
@ -61,7 +59,7 @@ function testEditStatus(browser, tab) {
|
||||
markup: "VVVVVIIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage2.css",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage2.css",
|
||||
emptyParameters: [ " [line]" ],
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
@ -8,6 +7,10 @@ const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleedito
|
||||
|
||||
let gChromeWindow; //StyleEditorChrome window
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
if (gChromeWindow) {
|
||||
|
459
browser/devtools/styleeditor/test/helper.js
Normal file
459
browser/devtools/styleeditor/test/helper.js
Normal file
@ -0,0 +1,459 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* DO NOT ALTER THIS FILE WITHOUT KEEPING IT IN SYNC WITH THE OTHER COPIES
|
||||
* OF THIS FILE.
|
||||
*
|
||||
* UNAUTHORIZED ALTERATION WILL RESULT IN THE ALTEREE BEING SENT TO SIT ON
|
||||
* THE NAUGHTY STEP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* FOR A LONG TIME.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar.
|
||||
* Parts of this code exist in:
|
||||
* - browser/devtools/commandline/test/head.js
|
||||
* - browser/devtools/shared/test/head.js
|
||||
*/
|
||||
let DeveloperToolbarTest = { };
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
DeveloperToolbarTest.show = function DTT_show(aCallback) {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show(true, aCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
DeveloperToolbarTest.hide = function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check() is the new status. Similar API except that it doesn't attempt to
|
||||
* alter the display/requisition at all, and it makes extra checks.
|
||||
* Test inputs
|
||||
* typed: The text to type at the input
|
||||
* Available checks:
|
||||
* input: The text displayed in the input field
|
||||
* cursor: The position of the start of the cursor
|
||||
* status: One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
|
||||
* directTabText: Simple completion text
|
||||
* arrowTabText: When the completion is not an extension (without arrow)
|
||||
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
|
||||
* args: Maps of checks to make against the arguments:
|
||||
* value: i.e. assignment.value (which ignores defaultValue)
|
||||
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
|
||||
* Care should be taken with this since it's something of an
|
||||
* implementation detail
|
||||
* arg: The toString value of the argument
|
||||
* status: i.e. assignment.getStatus
|
||||
* message: i.e. assignment.getMessage
|
||||
* name: For commands - checks assignment.value.name
|
||||
*/
|
||||
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
|
||||
if (!checks.emptyParameters) {
|
||||
checks.emptyParameters = [];
|
||||
}
|
||||
if (!checks.directTabText) {
|
||||
checks.directTabText = '';
|
||||
}
|
||||
if (!checks.arrowTabText) {
|
||||
checks.arrowTabText = '';
|
||||
}
|
||||
|
||||
var display = DeveloperToolbar.display;
|
||||
|
||||
if (checks.typed) {
|
||||
info('Starting tests for ' + checks.typed);
|
||||
display.inputter.setInput(checks.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(checks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
display.inputter.setCursor(checks.cursor)
|
||||
}
|
||||
|
||||
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
|
||||
|
||||
var requisition = display.requisition;
|
||||
var completer = display.completer;
|
||||
var actual = completer._getCompleterTemplateData();
|
||||
|
||||
/*
|
||||
if (checks.input) {
|
||||
is(display.inputter.element.value,
|
||||
checks.input,
|
||||
'input');
|
||||
}
|
||||
|
||||
if (checks.cursor) {
|
||||
is(display.inputter.element.selectionStart,
|
||||
checks.cursor,
|
||||
'cursor');
|
||||
}
|
||||
*/
|
||||
|
||||
if (checks.status) {
|
||||
is(requisition.getStatus().toString(),
|
||||
checks.status,
|
||||
'status');
|
||||
}
|
||||
|
||||
if (checks.markup) {
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
is(checks.markup,
|
||||
actualMarkup,
|
||||
'markup');
|
||||
}
|
||||
|
||||
if (checks.emptyParameters) {
|
||||
var actualParams = actual.emptyParameters;
|
||||
is(actualParams.length,
|
||||
checks.emptyParameters.length,
|
||||
'emptyParameters.length');
|
||||
|
||||
if (actualParams.length === checks.emptyParameters.length) {
|
||||
for (var i = 0; i < actualParams.length; i++) {
|
||||
is(actualParams[i].replace(/\u00a0/g, ' '),
|
||||
checks.emptyParameters[i],
|
||||
'emptyParameters[' + i + ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.directTabText) {
|
||||
is(actual.directTabText,
|
||||
checks.directTabText,
|
||||
'directTabText');
|
||||
}
|
||||
|
||||
if (checks.arrowTabText) {
|
||||
is(actual.arrowTabText,
|
||||
' \u00a0\u21E5 ' + checks.arrowTabText,
|
||||
'arrowTabText');
|
||||
}
|
||||
|
||||
if (checks.args) {
|
||||
Object.keys(checks.args).forEach(function(paramName) {
|
||||
var check = checks.args[paramName];
|
||||
|
||||
var assignment;
|
||||
if (paramName === 'command') {
|
||||
assignment = requisition.commandAssignment;
|
||||
}
|
||||
else {
|
||||
assignment = requisition.getAssignment(paramName);
|
||||
}
|
||||
|
||||
if (assignment == null) {
|
||||
ok(false, 'Unknown parameter: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (check.value) {
|
||||
is(assignment.value,
|
||||
check.value,
|
||||
'checkStatus value for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.name) {
|
||||
is(assignment.value.name,
|
||||
check.name,
|
||||
'checkStatus name for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.type) {
|
||||
is(assignment.arg.type,
|
||||
check.type,
|
||||
'checkStatus type for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.arg) {
|
||||
is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'checkStatus arg for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.status) {
|
||||
is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'checkStatus status for ' + paramName);
|
||||
}
|
||||
|
||||
if (check.message) {
|
||||
is(assignment.getMessage(),
|
||||
check.message,
|
||||
'checkStatus message for ' + paramName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // RegExp to test against textContent of output
|
||||
* // (can also be array of RegExps)
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
DeveloperToolbarTest.exec = function DTT_exec(tests) {
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = tests.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (typeof expectedArg === 'function') {
|
||||
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
ok(false, "html output for " + typed + " against " + match.source +
|
||||
" (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param target Either a function or array of functions containing the tests
|
||||
* to run. If an array of test function is passed then we will clear up after
|
||||
* the tests have completed. If a single test function is passed then this
|
||||
* function should arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
DeveloperToolbarTest.test = function DTT_test(uri, target) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
|
||||
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = uri;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
var onTabLoad = function() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
|
||||
DeveloperToolbarTest.show(function() {
|
||||
if (Array.isArray(target)) {
|
||||
try {
|
||||
target.forEach(function(func) {
|
||||
func(browser, tab);
|
||||
})
|
||||
}
|
||||
finally {
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
target(browser, tab);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "" + ex);
|
||||
DeveloperToolbarTest._finish();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
};
|
||||
|
||||
DeveloperToolbarTest._outstanding = [];
|
||||
|
||||
DeveloperToolbarTest._checkFinish = function() {
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
DeveloperToolbarTest.closeAllTabs();
|
||||
finish();
|
||||
}
|
||||
|
||||
DeveloperToolbarTest.checkCalled = function(aFunc, aScope) {
|
||||
var todo = function() {
|
||||
var reply = aFunc.apply(aScope, arguments);
|
||||
DeveloperToolbarTest._outstanding = DeveloperToolbarTest._outstanding.filter(function(aJob) {
|
||||
return aJob != todo;
|
||||
});
|
||||
DeveloperToolbarTest._checkFinish();
|
||||
return reply;
|
||||
}
|
||||
DeveloperToolbarTest._outstanding.push(todo);
|
||||
return todo;
|
||||
};
|
||||
|
||||
DeveloperToolbarTest.checkNotCalled = function(aMsg, aFunc, aScope) {
|
||||
return function() {
|
||||
ok(false, aMsg);
|
||||
return aFunc.apply(aScope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DeveloperToolbarTest.closeAllTabs = function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
|
||||
// This script is used from within browser_gcli_edit.html
|
||||
// This script is used from within browser_styleeditor_cmd_edit.html
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
var pid = document.getElementById('pid');
|
@ -107,7 +107,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
|
||||
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
|
@ -143,7 +143,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
|
||||
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
|
@ -131,7 +131,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
|
||||
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
@ -334,7 +334,7 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
|
||||
skin/classic/aero/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/aero/browser/devtools/commandline.css (devtools/commandline.css)
|
||||
skin/classic/aero/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
|
||||
skin/classic/aero/browser/devtools/markup-view.css (devtools/markup-view.css)
|
||||
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
|
||||
|
Loading…
Reference in New Issue
Block a user