mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 773565 - GCLI Autocomplete goes wild when boolean params are used in a group; r=dcamp
--HG-- rename : browser/devtools/highlighter/test/helper.js => browser/devtools/highlighter/test/helpers.js rename : browser/devtools/responsivedesign/test/helper.js => browser/devtools/responsivedesign/test/helpers.js rename : browser/devtools/shared/test/helper.js => browser/devtools/shared/test/helpers.js rename : browser/devtools/styleeditor/test/helper.js => browser/devtools/styleeditor/test/helpers.js
This commit is contained in:
parent
67f8af60a8
commit
af1fd14c62
@ -21,7 +21,6 @@ gcli.addCommand({
|
||||
name: 'jsb',
|
||||
description: gcli.lookup('jsbDesc'),
|
||||
returnValue:'string',
|
||||
hidden: true,
|
||||
params: [
|
||||
{
|
||||
name: 'url',
|
||||
@ -40,7 +39,10 @@ gcli.addCommand({
|
||||
name: 'indentChar',
|
||||
type: {
|
||||
name: 'selection',
|
||||
lookup: [{name: "space", value: " "}, {name: "tab", value: "\t"}]
|
||||
lookup: [
|
||||
{ name: "space", value: " " },
|
||||
{ name: "tab", value: "\t" }
|
||||
]
|
||||
},
|
||||
description: gcli.lookup('jsbIndentCharDesc'),
|
||||
manual: gcli.lookup('jsbIndentCharManual'),
|
||||
@ -50,8 +52,7 @@ gcli.addCommand({
|
||||
name: 'preserveNewlines',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbPreserveNewlinesDesc'),
|
||||
manual: gcli.lookup('jsbPreserveNewlinesManual'),
|
||||
defaultValue: true
|
||||
manual: gcli.lookup('jsbPreserveNewlinesManual')
|
||||
},
|
||||
{
|
||||
name: 'preserveMaxNewlines',
|
||||
@ -64,8 +65,7 @@ gcli.addCommand({
|
||||
name: 'jslintHappy',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbJslintHappyDesc'),
|
||||
manual: gcli.lookup('jsbJslintHappyManual'),
|
||||
defaultValue: false
|
||||
manual: gcli.lookup('jsbJslintHappyManual')
|
||||
},
|
||||
{
|
||||
name: 'braceStyle',
|
||||
@ -81,58 +81,56 @@ gcli.addCommand({
|
||||
name: 'spaceBeforeConditional',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
|
||||
manual: gcli.lookup('jsbSpaceBeforeConditionalManual'),
|
||||
defaultValue: true
|
||||
manual: gcli.lookup('jsbSpaceBeforeConditionalManual')
|
||||
},
|
||||
{
|
||||
name: 'unescapeStrings',
|
||||
type: 'boolean',
|
||||
description: gcli.lookup('jsbUnescapeStringsDesc'),
|
||||
manual: gcli.lookup('jsbUnescapeStringsManual'),
|
||||
defaultValue: false
|
||||
manual: gcli.lookup('jsbUnescapeStringsManual')
|
||||
}
|
||||
],
|
||||
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 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();
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
||||
try {
|
||||
xhr.open("GET", args.url, true);
|
||||
} catch(e) {
|
||||
return gcli.lookup('jsbInvalidURL');
|
||||
}
|
||||
try {
|
||||
xhr.open("GET", args.url, true);
|
||||
} catch(e) {
|
||||
return gcli.lookup('jsbInvalidURL');
|
||||
}
|
||||
|
||||
let promise = context.createPromise();
|
||||
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;
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
@ -28,7 +28,6 @@ gcli.addCommand({
|
||||
{
|
||||
name: "nocache",
|
||||
type: "boolean",
|
||||
defaultValue: false,
|
||||
description: gcli.lookup("restartFirefoxNocacheDesc")
|
||||
}
|
||||
],
|
||||
|
@ -37,7 +37,6 @@ gcli.addCommand({
|
||||
{
|
||||
name: "fullpage",
|
||||
type: "boolean",
|
||||
defaultValue: false,
|
||||
description: gcli.lookup("screenshotFullPageDesc"),
|
||||
manual: gcli.lookup("screenshotFullPageManual")
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_cmd_settings.js \
|
||||
browser_gcli_web.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
helpers.js \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
|
@ -8,43 +8,87 @@ function test() {
|
||||
}
|
||||
|
||||
function GAT_test() {
|
||||
var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
|
||||
Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
|
||||
helpers.setInput('addon list dictionary');
|
||||
helpers.check({
|
||||
input: 'addon list dictionary',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon list extension');
|
||||
helpers.check({
|
||||
input: 'addon list extension',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon list locale');
|
||||
helpers.check({
|
||||
input: 'addon list locale',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon list plugin');
|
||||
helpers.check({
|
||||
input: 'addon list plugin',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon list theme');
|
||||
helpers.check({
|
||||
input: 'addon list theme',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon list all');
|
||||
helpers.check({
|
||||
input: 'addon list all',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon disable Test_Plug-in_1.0.0.0');
|
||||
helpers.check({
|
||||
input: 'addon disable Test_Plug-in_1.0.0.0',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
helpers.setInput('addon disable WRONG');
|
||||
helpers.check({
|
||||
input: 'addon disable WRONG',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVEEEEE',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
helpers.setInput('addon enable Test_Plug-in_1.0.0.0');
|
||||
helpers.check({
|
||||
input: 'addon enable Test_Plug-in_1.0.0.0',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
command: { name: 'addon enable' },
|
||||
name: { value: 'Test Plug-in', status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
});
|
||||
|
||||
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 });
|
||||
});
|
||||
|
@ -13,21 +13,28 @@ function test() {
|
||||
}
|
||||
|
||||
function testCallLogStatus() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "calllog",
|
||||
status: "ERROR"
|
||||
helpers.setInput('calllog');
|
||||
helpers.check({
|
||||
input: 'calllog',
|
||||
hints: '',
|
||||
markup: 'IIIIIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "calllog start",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('calllog start');
|
||||
helpers.check({
|
||||
input: 'calllog start',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "calllog start",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('calllog stop');
|
||||
helpers.check({
|
||||
input: 'calllog stop',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
}
|
||||
|
||||
@ -39,7 +46,7 @@ function testCallLogExec() {
|
||||
});
|
||||
|
||||
let hud = null;
|
||||
function onWebConsoleOpen(aSubject) {
|
||||
var onWebConsoleOpen = DeveloperToolbarTest.checkCalled(function(aSubject) {
|
||||
Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
|
||||
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
@ -66,7 +73,7 @@ function testCallLogExec() {
|
||||
args: {},
|
||||
blankOutput: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
|
||||
|
||||
|
@ -6,40 +6,73 @@
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testCookieCommands ]);
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testCookieCheck, testCookieExec ]);
|
||||
}
|
||||
|
||||
function testCookieCommands() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "cook",
|
||||
directTabText: "ie",
|
||||
status: "ERROR"
|
||||
function testCookieCheck() {
|
||||
helpers.setInput('cookie');
|
||||
helpers.check({
|
||||
input: 'cookie',
|
||||
hints: '',
|
||||
markup: 'IIIIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "cookie l",
|
||||
directTabText: "ist",
|
||||
status: "ERROR"
|
||||
helpers.setInput('cookie lis');
|
||||
helpers.check({
|
||||
input: 'cookie lis',
|
||||
hints: 't',
|
||||
markup: 'IIIIIIVIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "cookie list",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('cookie list');
|
||||
helpers.check({
|
||||
input: 'cookie list',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "cookie remove",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ " <key>" ]
|
||||
helpers.setInput('cookie remove');
|
||||
helpers.check({
|
||||
input: 'cookie remove',
|
||||
hints: ' <key>',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "cookie set",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ " <key>", " <value>", " [options]" ],
|
||||
helpers.setInput('cookie set');
|
||||
helpers.check({
|
||||
input: 'cookie set',
|
||||
hints: ' <key> <value> [options]',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
helpers.setInput('cookie set fruit');
|
||||
helpers.check({
|
||||
input: 'cookie set fruit',
|
||||
hints: ' <value> [options]',
|
||||
markup: 'VVVVVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
helpers.setInput('cookie set fruit ban');
|
||||
helpers.check({
|
||||
input: 'cookie set fruit ban',
|
||||
hints: ' [options]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
key: { value: 'fruit' },
|
||||
value: { value: 'ban' },
|
||||
secure: { value: false },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testCookieExec() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "cookie set fruit banana",
|
||||
args: {
|
||||
|
@ -7,13 +7,16 @@ const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/browser_cmd_jsb_script.jsi";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", [ GJT_test ]);
|
||||
DeveloperToolbarTest.test("about:blank", [ /*GJT_test*/ ]);
|
||||
}
|
||||
|
||||
function GJT_test() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "jsb AAA",
|
||||
outputMatch: /valid/
|
||||
helpers.setInput('jsb');
|
||||
helpers.check({
|
||||
input: 'jsb',
|
||||
hints: ' <url> [indentSize] [indentChar] [preserveNewlines] [preserveMaxNewlines] [jslintHappy] [braceStyle] [spaceBeforeConditional] [unescapeStrings]',
|
||||
markup: 'VVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
gBrowser.addTabsProgressListener({
|
||||
@ -26,26 +29,29 @@ function GJT_test() {
|
||||
|
||||
result = result.replace(/[\r\n]]/g, "\n");
|
||||
|
||||
checkResult(result);
|
||||
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(result, correct, "JS has been correctly prettified");
|
||||
})
|
||||
});
|
||||
|
||||
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");
|
||||
}
|
||||
helpers.setInput('jsb ' + TEST_URI);
|
||||
/*
|
||||
helpers.check({
|
||||
input: 'jsb',
|
||||
hints: ' [options]',
|
||||
markup: 'VVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
*/
|
||||
|
||||
DeveloperToolbarTest.exec({ completed: false });
|
||||
}
|
||||
|
@ -22,9 +22,12 @@ function test() {
|
||||
}
|
||||
|
||||
function testExportHtml() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "export html",
|
||||
status: "VALID"
|
||||
helpers.setInput('export html');
|
||||
helpers.check({
|
||||
input: 'export html',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
let oldOpen = content.open;
|
||||
@ -53,33 +56,36 @@ function test() {
|
||||
}
|
||||
|
||||
function testPageModReplace() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod replace",
|
||||
emptyParameters: [" <search>", " <replace>", " [ignoreCase]",
|
||||
" [selector]", " [root]", " [attrOnly]",
|
||||
" [contentOnly]", " [attributes]"],
|
||||
status: "ERROR"
|
||||
helpers.setInput('pagemod replace');
|
||||
helpers.check({
|
||||
input: 'pagemod replace',
|
||||
hints: ' <search> <replace> [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
|
||||
markup: 'VVVVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod replace some foo",
|
||||
emptyParameters: [" [ignoreCase]", " [selector]", " [root]",
|
||||
" [attrOnly]", " [contentOnly]", " [attributes]"],
|
||||
status: "VALID"
|
||||
helpers.setInput('pagemod replace some foo');
|
||||
helpers.check({
|
||||
input: 'pagemod replace some foo',
|
||||
hints: ' [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod replace some foo true",
|
||||
emptyParameters: [" [selector]", " [root]", " [attrOnly]",
|
||||
" [contentOnly]", " [attributes]"],
|
||||
status: "VALID"
|
||||
helpers.setInput('pagemod replace some foo true');
|
||||
helpers.check({
|
||||
input: 'pagemod replace some foo true',
|
||||
hints: ' [selector] [root] [attrOnly] [contentOnly] [attributes]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod replace some foo true --attrOnly",
|
||||
emptyParameters: [" [selector]", " [root]", " [contentOnly]",
|
||||
" [attributes]"],
|
||||
status: "VALID"
|
||||
helpers.setInput('pagemod replace some foo true --attrOnly');
|
||||
helpers.check({
|
||||
input: 'pagemod replace some foo true --attrOnly',
|
||||
hints: ' [selector] [root] [contentOnly] [attributes]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
@ -146,21 +152,28 @@ function test() {
|
||||
}
|
||||
|
||||
function testPageModRemoveElement() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod remove",
|
||||
status: "ERROR"
|
||||
helpers.setInput('pagemod remove');
|
||||
helpers.check({
|
||||
input: 'pagemod remove',
|
||||
hints: '',
|
||||
markup: 'IIIIIIIVIIIIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod remove element",
|
||||
emptyParameters: [" <search>", " [root]", " [stripOnly]", " [ifEmptyOnly]"],
|
||||
status: "ERROR"
|
||||
helpers.setInput('pagemod remove element');
|
||||
helpers.check({
|
||||
input: 'pagemod remove element',
|
||||
hints: ' <search> [root] [stripOnly] [ifEmptyOnly]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod remove element foo",
|
||||
emptyParameters: [" [root]", " [stripOnly]", " [ifEmptyOnly]"],
|
||||
status: "VALID"
|
||||
helpers.setInput('pagemod remove element foo');
|
||||
helpers.check({
|
||||
input: 'pagemod remove element foo',
|
||||
hints: ' [root] [stripOnly] [ifEmptyOnly]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
@ -215,16 +228,32 @@ function test() {
|
||||
}
|
||||
|
||||
function testPageModRemoveAttribute() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod remove attribute",
|
||||
emptyParameters: [" <searchAttributes>", " <searchElements>", " [root]", " [ignoreCase]"],
|
||||
status: "ERROR"
|
||||
helpers.setInput('pagemod remove attribute ');
|
||||
helpers.check({
|
||||
input: 'pagemod remove attribute ',
|
||||
hints: '<searchAttributes> <searchElements> [root] [ignoreCase]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
searchAttributes: { value: undefined, status: 'INCOMPLETE' },
|
||||
searchElements: { value: undefined, status: 'INCOMPLETE' },
|
||||
root: { value: undefined },
|
||||
ignoreCase: { value: false },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pagemod remove attribute foo bar",
|
||||
emptyParameters: [" [root]", " [ignoreCase]"],
|
||||
status: "VALID"
|
||||
helpers.setInput('pagemod remove attribute foo bar');
|
||||
helpers.check({
|
||||
input: 'pagemod remove attribute foo bar',
|
||||
hints: ' [root] [ignoreCase]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
searchAttributes: { value: 'foo' },
|
||||
searchElements: { value: 'bar' },
|
||||
root: { value: undefined },
|
||||
ignoreCase: { value: false },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
|
@ -69,92 +69,103 @@ function shutdown() {
|
||||
}
|
||||
|
||||
function testPrefStatus() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref s",
|
||||
markup: "IIIIVI",
|
||||
status: "ERROR",
|
||||
directTabText: "et"
|
||||
helpers.setInput('pref');
|
||||
helpers.check({
|
||||
input: 'pref',
|
||||
hints: '',
|
||||
markup: 'IIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show",
|
||||
markup: "VVVVVVVVV",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ " <setting>" ]
|
||||
helpers.setInput('pref s');
|
||||
helpers.check({
|
||||
input: 'pref s',
|
||||
hints: 'et',
|
||||
markup: 'IIIIVI',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show tempTBo",
|
||||
markup: "VVVVVVVVVVEEEEEEE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref sh');
|
||||
helpers.check({
|
||||
input: 'pref sh',
|
||||
hints: 'ow',
|
||||
markup: 'IIIIVII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.toolbar.ena",
|
||||
markup: "VVVVVVVVVVIIIIIIIIIIIIIIIIIIII",
|
||||
directTabText: "bled",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref show ');
|
||||
helpers.check({
|
||||
input: 'pref show ',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show hideIntro",
|
||||
markup: "VVVVVVVVVVIIIIIIIII",
|
||||
directTabText: "",
|
||||
arrowTabText: "devtools.gcli.hideIntro",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref show usetexttospeech');
|
||||
helpers.check({
|
||||
input: 'pref show usetexttospeech',
|
||||
hints: ' -> accessibility.usetexttospeech',
|
||||
markup: 'VVVVVVVVVVIIIIIIIIIIIIIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.toolbar.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref show devtools.til');
|
||||
helpers.check({
|
||||
input: 'pref show devtools.til',
|
||||
hints: 't.enabled',
|
||||
markup: 'VVVVVVVVVVIIIIIIIIIIII',
|
||||
status: 'ERROR',
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
setting: { value: undefined, status: 'INCOMPLETE' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.tilt.enabled 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
|
||||
directTabText: "",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref reset devtools.tilt.enabled');
|
||||
helpers.check({
|
||||
input: 'pref reset devtools.tilt.enabled',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref show devtools.tilt.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref show devtools.tilt.enabled 4');
|
||||
helpers.check({
|
||||
input: 'pref show devtools.tilt.enabled 4',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref reset devtools.tilt.enabled",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref set devtools.tilt.enabled 4');
|
||||
helpers.check({
|
||||
input: 'pref set devtools.tilt.enabled 4',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
setting: { arg: ' devtools.tilt.enabled' },
|
||||
value: { status: 'ERROR', message: 'Can\'t use \'4\'.' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref set devtools.tilt.enabled 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref set devtools.editor.tabsize 4');
|
||||
helpers.check({
|
||||
input: 'pref set devtools.editor.tabsize 4',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
setting: { arg: ' devtools.editor.tabsize' },
|
||||
value: { value: 4 },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref set devtools.editor.tabsize 4",
|
||||
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ ]
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "pref list",
|
||||
markup: "EEEEVEEEE",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ ]
|
||||
helpers.setInput('pref list');
|
||||
helpers.check({
|
||||
input: 'pref list',
|
||||
hints: '',
|
||||
markup: 'EEEEVEEEE',
|
||||
status: 'ERROR'
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -10,36 +10,23 @@ function test() {
|
||||
}
|
||||
|
||||
function testRestart() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "restart",
|
||||
markup: "VVVVVVV",
|
||||
status: "VALID",
|
||||
emptyParameters: [ " [nocache]" ],
|
||||
helpers.setInput('restart');
|
||||
helpers.check({
|
||||
input: 'restart',
|
||||
markup: 'VVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
nocache: { value: false },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "restart ",
|
||||
markup: "VVVVVVVV",
|
||||
status: "VALID",
|
||||
directTabText: "false"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "restart t",
|
||||
markup: "VVVVVVVVI",
|
||||
status: "ERROR",
|
||||
directTabText: "rue"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "restart --nocache",
|
||||
markup: "VVVVVVVVVVVVVVVVV",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "restart --noca",
|
||||
markup: "VVVVVVVVEEEEEE",
|
||||
status: "ERROR",
|
||||
helpers.setInput('restart --nocache');
|
||||
helpers.check({
|
||||
input: 'restart --nocache',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
nocache: { value: true },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -11,35 +11,28 @@ function test() {
|
||||
}
|
||||
|
||||
function testBreakCommands() {
|
||||
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info('###################################################');
|
||||
info(content.document.documentElement.innerHTML + '\n');
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "brea",
|
||||
directTabText: "k",
|
||||
status: "ERROR"
|
||||
helpers.setInput('break');
|
||||
helpers.check({
|
||||
input: 'break',
|
||||
hints: '',
|
||||
markup: 'IIIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break",
|
||||
status: "ERROR"
|
||||
helpers.setInput('break add');
|
||||
helpers.check({
|
||||
input: 'break add',
|
||||
hints: '',
|
||||
markup: 'IIIIIVIII',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add line",
|
||||
emptyParameters: [ " <file>", " <line>" ],
|
||||
status: "ERROR"
|
||||
helpers.setInput('break add line');
|
||||
helpers.check({
|
||||
input: 'break add line',
|
||||
hints: ' <file> <line>',
|
||||
markup: 'VVVVVVVVVVVVVV',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
@ -53,10 +46,16 @@ function testBreakCommands() {
|
||||
var resumed = DeveloperToolbarTest.checkCalled(function() {
|
||||
|
||||
var framesAdded = DeveloperToolbarTest.checkCalled(function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0,
|
||||
status: "VALID"
|
||||
helpers.setInput('break add line ' + TEST_URI + ' ' + content.wrappedJSObject.line0);
|
||||
helpers.check({
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
file: { value: TEST_URI },
|
||||
line: { value: content.wrappedJSObject.line0 },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
args: {
|
||||
type: 'line',
|
||||
@ -66,17 +65,39 @@ function testBreakCommands() {
|
||||
completed: false
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break list",
|
||||
status: "VALID"
|
||||
helpers.setInput('break list');
|
||||
helpers.check({
|
||||
input: 'break list',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
|
||||
var cleanup = DeveloperToolbarTest.checkCalled(function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break del 0",
|
||||
status: "VALID"
|
||||
helpers.setInput('break del 9');
|
||||
helpers.check({
|
||||
input: 'break del 9',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
breakid: { status: 'ERROR', message: '9 is greater than maximum allowed: 0.' },
|
||||
}
|
||||
});
|
||||
|
||||
helpers.setInput('break del 0');
|
||||
helpers.check({
|
||||
input: 'break del 0',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
breakid: { value: 0 },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
args: { breakid: 0 },
|
||||
completed: false
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ let console = (function() {
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
|
@ -1,459 +0,0 @@
|
||||
/* 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();
|
||||
}
|
||||
};
|
881
browser/devtools/commandline/test/helpers.js
Normal file
881
browser/devtools/commandline/test/helpers.js
Normal file
@ -0,0 +1,881 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Use as a JSM
|
||||
* ------------
|
||||
* helpers._createDebugCheck() and maybe other functions in this file can be
|
||||
* useful at runtime, so it is possible to use helpers.js as a JSM.
|
||||
* Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
|
||||
* DeveloperToolbar.jsm the following:
|
||||
*
|
||||
* XPCOMUtils.defineLazyModuleGetter(this, "helpers",
|
||||
* "resource:///modules/devtools/helpers.jsm");
|
||||
*
|
||||
* At the bottom of DeveloperToolbar.prototype._onload add this:
|
||||
*
|
||||
* var options = { display: this.display };
|
||||
* this._input.onkeypress = function(ev) {
|
||||
* helpers.setup(options);
|
||||
* dump(helpers._createDebugCheck() + '\n\n');
|
||||
* };
|
||||
*
|
||||
* Now GCLI will emit output on every keypress that both explains the state
|
||||
* of GCLI and can be run as a test case.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = [ 'helpers' ];
|
||||
|
||||
var test = { };
|
||||
|
||||
/**
|
||||
* 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 + ']');
|
||||
}
|
||||
}
|
||||
else {
|
||||
info('Expected: [ \"' + actualParams.join('", "') + '" ]');
|
||||
}
|
||||
}
|
||||
|
||||
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 (helpers) {
|
||||
helpers.setup({ display: DeveloperToolbar.display });
|
||||
}
|
||||
|
||||
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() {
|
||||
info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
info('Finish');
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers._display = undefined;
|
||||
|
||||
helpers.setup = function(options) {
|
||||
helpers._display = options.display;
|
||||
if (typeof ok !== 'undefined') {
|
||||
test.ok = ok;
|
||||
test.is = is;
|
||||
test.log = info;
|
||||
}
|
||||
};
|
||||
|
||||
helpers.shutdown = function(options) {
|
||||
helpers._display = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Various functions to return the actual state of the command line
|
||||
*/
|
||||
helpers._actual = {
|
||||
input: function() {
|
||||
return helpers._display.inputter.element.value;
|
||||
},
|
||||
|
||||
hints: function() {
|
||||
var templateData = helpers._display.completer._getCompleterTemplateData();
|
||||
var actualHints = templateData.directTabText +
|
||||
templateData.emptyParameters.join('') +
|
||||
templateData.arrowTabText;
|
||||
return actualHints.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u21E5/, '->')
|
||||
.replace(/ $/, '');
|
||||
},
|
||||
|
||||
markup: function() {
|
||||
var cursor = helpers._display.inputter.element.selectionStart;
|
||||
var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
|
||||
return statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
},
|
||||
|
||||
cursor: function() {
|
||||
return helpers._display.inputter.element.selectionStart;
|
||||
},
|
||||
|
||||
current: function() {
|
||||
return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
|
||||
},
|
||||
|
||||
status: function() {
|
||||
return helpers._display.requisition.getStatus().toString();
|
||||
},
|
||||
|
||||
outputState: function() {
|
||||
var outputData = helpers._display.focusManager._shouldShowOutput();
|
||||
return outputData.visible + ':' + outputData.reason;
|
||||
},
|
||||
|
||||
tooltipState: function() {
|
||||
var tooltipData = helpers._display.focusManager._shouldShowTooltip();
|
||||
return tooltipData.visible + ':' + tooltipData.reason;
|
||||
}
|
||||
};
|
||||
|
||||
helpers._directToString = [ 'boolean', 'undefined', 'number' ];
|
||||
|
||||
helpers._createDebugCheck = function() {
|
||||
var requisition = helpers._display.requisition;
|
||||
var command = requisition.commandAssignment.value;
|
||||
var input = helpers._actual.input();
|
||||
var padding = Array(input.length + 1).join(' ');
|
||||
|
||||
var output = '';
|
||||
output += 'helpers.setInput(\'' + input + '\');\n';
|
||||
output += 'helpers.check({\n';
|
||||
output += ' input: \'' + input + '\',\n';
|
||||
output += ' hints: ' + padding + '\'' + helpers._actual.hints() + '\',\n';
|
||||
output += ' markup: \'' + helpers._actual.markup() + '\',\n';
|
||||
output += ' cursor: ' + helpers._actual.cursor() + ',\n';
|
||||
output += ' current: \'' + helpers._actual.current() + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status() + '\',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState() + '\',\n';
|
||||
|
||||
if (command) {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
|
||||
output += ' args: {\n';
|
||||
output += ' command: { name: \'' + command.name + '\' },\n';
|
||||
|
||||
requisition.getAssignments().forEach(function(assignment) {
|
||||
output += ' ' + assignment.param.name + ': { ';
|
||||
|
||||
if (typeof assignment.value === 'string') {
|
||||
output += 'value: \'' + assignment.value + '\', ';
|
||||
}
|
||||
else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else if (assignment.value === null) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else {
|
||||
output += '/*value:' + assignment.value + ',*/ ';
|
||||
}
|
||||
|
||||
output += 'arg: \'' + assignment.arg + '\', ';
|
||||
output += 'status: \'' + assignment.getStatus().toString() + '\', ';
|
||||
output += 'message: \'' + assignment.getMessage() + '\'';
|
||||
output += ' },\n';
|
||||
});
|
||||
|
||||
output += ' }\n';
|
||||
}
|
||||
else {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
|
||||
}
|
||||
output += '});';
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* We're splitting status into setup() which alters the state of the system
|
||||
* and check() which ensures that things are in the right place afterwards.
|
||||
*/
|
||||
helpers.setInput = function(typed, cursor) {
|
||||
helpers._display.inputter.setInput(typed);
|
||||
|
||||
if (cursor) {
|
||||
helpers._display.inputter.setCursor({ start: cursor, end: cursor });
|
||||
}
|
||||
|
||||
helpers._display.focusManager.onInputChange();
|
||||
|
||||
test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate focusing the input field
|
||||
*/
|
||||
helpers.focusInput = function() {
|
||||
helpers._display.inputter.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing TAB in the input field
|
||||
*/
|
||||
helpers.pressTab = function() {
|
||||
helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing RETURN in the input field
|
||||
*/
|
||||
helpers.pressReturn = function() {
|
||||
helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing a key by keyCode in the input field
|
||||
*/
|
||||
helpers.pressKey = function(keyCode) {
|
||||
var fakeEvent = {
|
||||
keyCode: keyCode,
|
||||
preventDefault: function() { },
|
||||
timeStamp: new Date().getTime()
|
||||
};
|
||||
helpers._display.inputter.onKeyDown(fakeEvent);
|
||||
helpers._display.inputter.onKeyUp(fakeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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"
|
||||
* hints: The hint text, i.e. a concatenation of the directTabText, the
|
||||
* emptyParameters and the arrowTabText. The text as inserted into the UI
|
||||
* will include NBSP and Unicode RARR characters, these should be
|
||||
* represented using normal space and '->' for the 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
|
||||
*/
|
||||
helpers.check = function(checks) {
|
||||
if ('input' in checks) {
|
||||
test.is(helpers._actual.input(), checks.input, 'input');
|
||||
}
|
||||
|
||||
if ('cursor' in checks) {
|
||||
test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
|
||||
}
|
||||
|
||||
if ('current' in checks) {
|
||||
test.is(helpers._actual.current(), checks.current, 'current');
|
||||
}
|
||||
|
||||
if ('status' in checks) {
|
||||
test.is(helpers._actual.status(), checks.status, 'status');
|
||||
}
|
||||
|
||||
if ('markup' in checks) {
|
||||
test.is(helpers._actual.markup(), checks.markup, 'markup');
|
||||
}
|
||||
|
||||
if ('hints' in checks) {
|
||||
test.is(helpers._actual.hints(), checks.hints, 'hints');
|
||||
}
|
||||
|
||||
if ('tooltipState' in checks) {
|
||||
test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
|
||||
}
|
||||
|
||||
if ('outputState' in checks) {
|
||||
test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
|
||||
}
|
||||
|
||||
if (checks.args != null) {
|
||||
var requisition = helpers._display.requisition;
|
||||
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) {
|
||||
test.ok(false, 'Unknown arg: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('value' in check) {
|
||||
test.is(assignment.value,
|
||||
check.value,
|
||||
'arg.' + paramName + '.value');
|
||||
}
|
||||
|
||||
if ('name' in check) {
|
||||
test.is(assignment.value.name,
|
||||
check.name,
|
||||
'arg.' + paramName + '.name');
|
||||
}
|
||||
|
||||
if ('type' in check) {
|
||||
test.is(assignment.arg.type,
|
||||
check.type,
|
||||
'arg.' + paramName + '.type');
|
||||
}
|
||||
|
||||
if ('arg' in check) {
|
||||
test.is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'arg.' + paramName + '.arg');
|
||||
}
|
||||
|
||||
if ('status' in check) {
|
||||
test.is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'arg.' + paramName + '.status');
|
||||
}
|
||||
|
||||
if ('message' in check) {
|
||||
test.is(assignment.getMessage(),
|
||||
check.message,
|
||||
'arg.' + paramName + '.message');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.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$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
helpers.exec = function(tests) {
|
||||
var requisition = helpers._display.requisition;
|
||||
var inputter = helpers._display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.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'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(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)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
@ -40,7 +40,7 @@ _BROWSER_FILES = \
|
||||
browser_inspector_cmd_inspect.js \
|
||||
browser_inspector_cmd_inspect.html \
|
||||
head.js \
|
||||
helper.js \
|
||||
helpers.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
|
@ -11,55 +11,110 @@ function test() {
|
||||
}
|
||||
|
||||
function testInspect() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspec",
|
||||
directTabText: "t",
|
||||
status: "ERROR"
|
||||
helpers.setInput('inspect');
|
||||
helpers.check({
|
||||
input: 'inspect',
|
||||
hints: ' <node>',
|
||||
markup: 'VVVVVVV',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect",
|
||||
emptyParameters: [ " <node>" ],
|
||||
status: "ERROR"
|
||||
helpers.setInput('inspect h1');
|
||||
helpers.check({
|
||||
input: 'inspect h1',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
node: { message: 'No matches' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect h1",
|
||||
status: "ERROR"
|
||||
helpers.setInput('inspect span');
|
||||
helpers.check({
|
||||
input: 'inspect span',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVEEEE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
node: { message: 'Too many matches (2)' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect span",
|
||||
status: "ERROR"
|
||||
helpers.setInput('inspect div');
|
||||
helpers.check({
|
||||
input: 'inspect div',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect div",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect .someclas');
|
||||
helpers.check({
|
||||
input: 'inspect .someclas',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVIIIIIIIII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
node: { message: 'No matches' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect .someclass",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect .someclass');
|
||||
helpers.check({
|
||||
input: 'inspect .someclass',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect #someid",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect #someid');
|
||||
helpers.check({
|
||||
input: 'inspect #someid',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect button[disabled]",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect button[disabled]');
|
||||
helpers.check({
|
||||
input: 'inspect button[disabled]',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect p>strong",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect p>strong');
|
||||
helpers.check({
|
||||
input: 'inspect p>strong',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
node: { message: '' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect :root",
|
||||
status: "VALID"
|
||||
helpers.setInput('inspect :root');
|
||||
helpers.check({
|
||||
input: 'inspect :root',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ let LayoutHelpers = tempScope.LayoutHelpers;
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
|
||||
// Clear preferences that may be set during the course of tests.
|
||||
function clearUserPrefs()
|
||||
|
@ -1,459 +0,0 @@
|
||||
/* 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();
|
||||
}
|
||||
};
|
881
browser/devtools/highlighter/test/helpers.js
Normal file
881
browser/devtools/highlighter/test/helpers.js
Normal file
@ -0,0 +1,881 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Use as a JSM
|
||||
* ------------
|
||||
* helpers._createDebugCheck() and maybe other functions in this file can be
|
||||
* useful at runtime, so it is possible to use helpers.js as a JSM.
|
||||
* Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
|
||||
* DeveloperToolbar.jsm the following:
|
||||
*
|
||||
* XPCOMUtils.defineLazyModuleGetter(this, "helpers",
|
||||
* "resource:///modules/devtools/helpers.jsm");
|
||||
*
|
||||
* At the bottom of DeveloperToolbar.prototype._onload add this:
|
||||
*
|
||||
* var options = { display: this.display };
|
||||
* this._input.onkeypress = function(ev) {
|
||||
* helpers.setup(options);
|
||||
* dump(helpers._createDebugCheck() + '\n\n');
|
||||
* };
|
||||
*
|
||||
* Now GCLI will emit output on every keypress that both explains the state
|
||||
* of GCLI and can be run as a test case.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = [ 'helpers' ];
|
||||
|
||||
var test = { };
|
||||
|
||||
/**
|
||||
* 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 + ']');
|
||||
}
|
||||
}
|
||||
else {
|
||||
info('Expected: [ \"' + actualParams.join('", "') + '" ]');
|
||||
}
|
||||
}
|
||||
|
||||
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 (helpers) {
|
||||
helpers.setup({ display: DeveloperToolbar.display });
|
||||
}
|
||||
|
||||
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() {
|
||||
info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
info('Finish');
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers._display = undefined;
|
||||
|
||||
helpers.setup = function(options) {
|
||||
helpers._display = options.display;
|
||||
if (typeof ok !== 'undefined') {
|
||||
test.ok = ok;
|
||||
test.is = is;
|
||||
test.log = info;
|
||||
}
|
||||
};
|
||||
|
||||
helpers.shutdown = function(options) {
|
||||
helpers._display = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Various functions to return the actual state of the command line
|
||||
*/
|
||||
helpers._actual = {
|
||||
input: function() {
|
||||
return helpers._display.inputter.element.value;
|
||||
},
|
||||
|
||||
hints: function() {
|
||||
var templateData = helpers._display.completer._getCompleterTemplateData();
|
||||
var actualHints = templateData.directTabText +
|
||||
templateData.emptyParameters.join('') +
|
||||
templateData.arrowTabText;
|
||||
return actualHints.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u21E5/, '->')
|
||||
.replace(/ $/, '');
|
||||
},
|
||||
|
||||
markup: function() {
|
||||
var cursor = helpers._display.inputter.element.selectionStart;
|
||||
var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
|
||||
return statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
},
|
||||
|
||||
cursor: function() {
|
||||
return helpers._display.inputter.element.selectionStart;
|
||||
},
|
||||
|
||||
current: function() {
|
||||
return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
|
||||
},
|
||||
|
||||
status: function() {
|
||||
return helpers._display.requisition.getStatus().toString();
|
||||
},
|
||||
|
||||
outputState: function() {
|
||||
var outputData = helpers._display.focusManager._shouldShowOutput();
|
||||
return outputData.visible + ':' + outputData.reason;
|
||||
},
|
||||
|
||||
tooltipState: function() {
|
||||
var tooltipData = helpers._display.focusManager._shouldShowTooltip();
|
||||
return tooltipData.visible + ':' + tooltipData.reason;
|
||||
}
|
||||
};
|
||||
|
||||
helpers._directToString = [ 'boolean', 'undefined', 'number' ];
|
||||
|
||||
helpers._createDebugCheck = function() {
|
||||
var requisition = helpers._display.requisition;
|
||||
var command = requisition.commandAssignment.value;
|
||||
var input = helpers._actual.input();
|
||||
var padding = Array(input.length + 1).join(' ');
|
||||
|
||||
var output = '';
|
||||
output += 'helpers.setInput(\'' + input + '\');\n';
|
||||
output += 'helpers.check({\n';
|
||||
output += ' input: \'' + input + '\',\n';
|
||||
output += ' hints: ' + padding + '\'' + helpers._actual.hints() + '\',\n';
|
||||
output += ' markup: \'' + helpers._actual.markup() + '\',\n';
|
||||
output += ' cursor: ' + helpers._actual.cursor() + ',\n';
|
||||
output += ' current: \'' + helpers._actual.current() + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status() + '\',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState() + '\',\n';
|
||||
|
||||
if (command) {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
|
||||
output += ' args: {\n';
|
||||
output += ' command: { name: \'' + command.name + '\' },\n';
|
||||
|
||||
requisition.getAssignments().forEach(function(assignment) {
|
||||
output += ' ' + assignment.param.name + ': { ';
|
||||
|
||||
if (typeof assignment.value === 'string') {
|
||||
output += 'value: \'' + assignment.value + '\', ';
|
||||
}
|
||||
else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else if (assignment.value === null) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else {
|
||||
output += '/*value:' + assignment.value + ',*/ ';
|
||||
}
|
||||
|
||||
output += 'arg: \'' + assignment.arg + '\', ';
|
||||
output += 'status: \'' + assignment.getStatus().toString() + '\', ';
|
||||
output += 'message: \'' + assignment.getMessage() + '\'';
|
||||
output += ' },\n';
|
||||
});
|
||||
|
||||
output += ' }\n';
|
||||
}
|
||||
else {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
|
||||
}
|
||||
output += '});';
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* We're splitting status into setup() which alters the state of the system
|
||||
* and check() which ensures that things are in the right place afterwards.
|
||||
*/
|
||||
helpers.setInput = function(typed, cursor) {
|
||||
helpers._display.inputter.setInput(typed);
|
||||
|
||||
if (cursor) {
|
||||
helpers._display.inputter.setCursor({ start: cursor, end: cursor });
|
||||
}
|
||||
|
||||
helpers._display.focusManager.onInputChange();
|
||||
|
||||
test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate focusing the input field
|
||||
*/
|
||||
helpers.focusInput = function() {
|
||||
helpers._display.inputter.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing TAB in the input field
|
||||
*/
|
||||
helpers.pressTab = function() {
|
||||
helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing RETURN in the input field
|
||||
*/
|
||||
helpers.pressReturn = function() {
|
||||
helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing a key by keyCode in the input field
|
||||
*/
|
||||
helpers.pressKey = function(keyCode) {
|
||||
var fakeEvent = {
|
||||
keyCode: keyCode,
|
||||
preventDefault: function() { },
|
||||
timeStamp: new Date().getTime()
|
||||
};
|
||||
helpers._display.inputter.onKeyDown(fakeEvent);
|
||||
helpers._display.inputter.onKeyUp(fakeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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"
|
||||
* hints: The hint text, i.e. a concatenation of the directTabText, the
|
||||
* emptyParameters and the arrowTabText. The text as inserted into the UI
|
||||
* will include NBSP and Unicode RARR characters, these should be
|
||||
* represented using normal space and '->' for the 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
|
||||
*/
|
||||
helpers.check = function(checks) {
|
||||
if ('input' in checks) {
|
||||
test.is(helpers._actual.input(), checks.input, 'input');
|
||||
}
|
||||
|
||||
if ('cursor' in checks) {
|
||||
test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
|
||||
}
|
||||
|
||||
if ('current' in checks) {
|
||||
test.is(helpers._actual.current(), checks.current, 'current');
|
||||
}
|
||||
|
||||
if ('status' in checks) {
|
||||
test.is(helpers._actual.status(), checks.status, 'status');
|
||||
}
|
||||
|
||||
if ('markup' in checks) {
|
||||
test.is(helpers._actual.markup(), checks.markup, 'markup');
|
||||
}
|
||||
|
||||
if ('hints' in checks) {
|
||||
test.is(helpers._actual.hints(), checks.hints, 'hints');
|
||||
}
|
||||
|
||||
if ('tooltipState' in checks) {
|
||||
test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
|
||||
}
|
||||
|
||||
if ('outputState' in checks) {
|
||||
test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
|
||||
}
|
||||
|
||||
if (checks.args != null) {
|
||||
var requisition = helpers._display.requisition;
|
||||
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) {
|
||||
test.ok(false, 'Unknown arg: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('value' in check) {
|
||||
test.is(assignment.value,
|
||||
check.value,
|
||||
'arg.' + paramName + '.value');
|
||||
}
|
||||
|
||||
if ('name' in check) {
|
||||
test.is(assignment.value.name,
|
||||
check.name,
|
||||
'arg.' + paramName + '.name');
|
||||
}
|
||||
|
||||
if ('type' in check) {
|
||||
test.is(assignment.arg.type,
|
||||
check.type,
|
||||
'arg.' + paramName + '.type');
|
||||
}
|
||||
|
||||
if ('arg' in check) {
|
||||
test.is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'arg.' + paramName + '.arg');
|
||||
}
|
||||
|
||||
if ('status' in check) {
|
||||
test.is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'arg.' + paramName + '.status');
|
||||
}
|
||||
|
||||
if ('message' in check) {
|
||||
test.is(assignment.getMessage(),
|
||||
check.message,
|
||||
'arg.' + paramName + '.message');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.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$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
helpers.exec = function(tests) {
|
||||
var requisition = helpers._display.requisition;
|
||||
var inputter = helpers._display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.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'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(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)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
@ -50,7 +50,7 @@ _BROWSER_FILES = \
|
||||
browser_responsive_cmd.js \
|
||||
browser_responsivecomputedview.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
helpers.js \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
@ -14,47 +14,73 @@ function isClosed() {
|
||||
}
|
||||
|
||||
function GAT_test() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize toggle');
|
||||
helpers.check({
|
||||
input: 'resize toggle',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize toggle",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize toggle');
|
||||
helpers.check({
|
||||
input: 'resize toggle',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize on",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize on');
|
||||
helpers.check({
|
||||
input: 'resize on',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize off');
|
||||
helpers.check({
|
||||
input: 'resize off',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize to 400 400",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize to 400 400');
|
||||
helpers.check({
|
||||
input: 'resize to 400 400',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
width: { value: 400 },
|
||||
height: { value: 400 },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isOpen(), "responsive mode is open");
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "resize off",
|
||||
status: "VALID"
|
||||
helpers.setInput('resize off');
|
||||
helpers.check({
|
||||
input: 'resize off',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'VALID'
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.exec();
|
||||
ok(isClosed(), "responsive mode is closed");
|
||||
|
||||
// executeSoon(finish);
|
||||
}
|
||||
|
@ -5,4 +5,4 @@
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
|
@ -1,459 +0,0 @@
|
||||
/* 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();
|
||||
}
|
||||
};
|
881
browser/devtools/responsivedesign/test/helpers.js
Normal file
881
browser/devtools/responsivedesign/test/helpers.js
Normal file
@ -0,0 +1,881 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Use as a JSM
|
||||
* ------------
|
||||
* helpers._createDebugCheck() and maybe other functions in this file can be
|
||||
* useful at runtime, so it is possible to use helpers.js as a JSM.
|
||||
* Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
|
||||
* DeveloperToolbar.jsm the following:
|
||||
*
|
||||
* XPCOMUtils.defineLazyModuleGetter(this, "helpers",
|
||||
* "resource:///modules/devtools/helpers.jsm");
|
||||
*
|
||||
* At the bottom of DeveloperToolbar.prototype._onload add this:
|
||||
*
|
||||
* var options = { display: this.display };
|
||||
* this._input.onkeypress = function(ev) {
|
||||
* helpers.setup(options);
|
||||
* dump(helpers._createDebugCheck() + '\n\n');
|
||||
* };
|
||||
*
|
||||
* Now GCLI will emit output on every keypress that both explains the state
|
||||
* of GCLI and can be run as a test case.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = [ 'helpers' ];
|
||||
|
||||
var test = { };
|
||||
|
||||
/**
|
||||
* 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 + ']');
|
||||
}
|
||||
}
|
||||
else {
|
||||
info('Expected: [ \"' + actualParams.join('", "') + '" ]');
|
||||
}
|
||||
}
|
||||
|
||||
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 (helpers) {
|
||||
helpers.setup({ display: DeveloperToolbar.display });
|
||||
}
|
||||
|
||||
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() {
|
||||
info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
info('Finish');
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers._display = undefined;
|
||||
|
||||
helpers.setup = function(options) {
|
||||
helpers._display = options.display;
|
||||
if (typeof ok !== 'undefined') {
|
||||
test.ok = ok;
|
||||
test.is = is;
|
||||
test.log = info;
|
||||
}
|
||||
};
|
||||
|
||||
helpers.shutdown = function(options) {
|
||||
helpers._display = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Various functions to return the actual state of the command line
|
||||
*/
|
||||
helpers._actual = {
|
||||
input: function() {
|
||||
return helpers._display.inputter.element.value;
|
||||
},
|
||||
|
||||
hints: function() {
|
||||
var templateData = helpers._display.completer._getCompleterTemplateData();
|
||||
var actualHints = templateData.directTabText +
|
||||
templateData.emptyParameters.join('') +
|
||||
templateData.arrowTabText;
|
||||
return actualHints.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u21E5/, '->')
|
||||
.replace(/ $/, '');
|
||||
},
|
||||
|
||||
markup: function() {
|
||||
var cursor = helpers._display.inputter.element.selectionStart;
|
||||
var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
|
||||
return statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
},
|
||||
|
||||
cursor: function() {
|
||||
return helpers._display.inputter.element.selectionStart;
|
||||
},
|
||||
|
||||
current: function() {
|
||||
return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
|
||||
},
|
||||
|
||||
status: function() {
|
||||
return helpers._display.requisition.getStatus().toString();
|
||||
},
|
||||
|
||||
outputState: function() {
|
||||
var outputData = helpers._display.focusManager._shouldShowOutput();
|
||||
return outputData.visible + ':' + outputData.reason;
|
||||
},
|
||||
|
||||
tooltipState: function() {
|
||||
var tooltipData = helpers._display.focusManager._shouldShowTooltip();
|
||||
return tooltipData.visible + ':' + tooltipData.reason;
|
||||
}
|
||||
};
|
||||
|
||||
helpers._directToString = [ 'boolean', 'undefined', 'number' ];
|
||||
|
||||
helpers._createDebugCheck = function() {
|
||||
var requisition = helpers._display.requisition;
|
||||
var command = requisition.commandAssignment.value;
|
||||
var input = helpers._actual.input();
|
||||
var padding = Array(input.length + 1).join(' ');
|
||||
|
||||
var output = '';
|
||||
output += 'helpers.setInput(\'' + input + '\');\n';
|
||||
output += 'helpers.check({\n';
|
||||
output += ' input: \'' + input + '\',\n';
|
||||
output += ' hints: ' + padding + '\'' + helpers._actual.hints() + '\',\n';
|
||||
output += ' markup: \'' + helpers._actual.markup() + '\',\n';
|
||||
output += ' cursor: ' + helpers._actual.cursor() + ',\n';
|
||||
output += ' current: \'' + helpers._actual.current() + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status() + '\',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState() + '\',\n';
|
||||
|
||||
if (command) {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
|
||||
output += ' args: {\n';
|
||||
output += ' command: { name: \'' + command.name + '\' },\n';
|
||||
|
||||
requisition.getAssignments().forEach(function(assignment) {
|
||||
output += ' ' + assignment.param.name + ': { ';
|
||||
|
||||
if (typeof assignment.value === 'string') {
|
||||
output += 'value: \'' + assignment.value + '\', ';
|
||||
}
|
||||
else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else if (assignment.value === null) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else {
|
||||
output += '/*value:' + assignment.value + ',*/ ';
|
||||
}
|
||||
|
||||
output += 'arg: \'' + assignment.arg + '\', ';
|
||||
output += 'status: \'' + assignment.getStatus().toString() + '\', ';
|
||||
output += 'message: \'' + assignment.getMessage() + '\'';
|
||||
output += ' },\n';
|
||||
});
|
||||
|
||||
output += ' }\n';
|
||||
}
|
||||
else {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
|
||||
}
|
||||
output += '});';
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* We're splitting status into setup() which alters the state of the system
|
||||
* and check() which ensures that things are in the right place afterwards.
|
||||
*/
|
||||
helpers.setInput = function(typed, cursor) {
|
||||
helpers._display.inputter.setInput(typed);
|
||||
|
||||
if (cursor) {
|
||||
helpers._display.inputter.setCursor({ start: cursor, end: cursor });
|
||||
}
|
||||
|
||||
helpers._display.focusManager.onInputChange();
|
||||
|
||||
test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate focusing the input field
|
||||
*/
|
||||
helpers.focusInput = function() {
|
||||
helpers._display.inputter.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing TAB in the input field
|
||||
*/
|
||||
helpers.pressTab = function() {
|
||||
helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing RETURN in the input field
|
||||
*/
|
||||
helpers.pressReturn = function() {
|
||||
helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing a key by keyCode in the input field
|
||||
*/
|
||||
helpers.pressKey = function(keyCode) {
|
||||
var fakeEvent = {
|
||||
keyCode: keyCode,
|
||||
preventDefault: function() { },
|
||||
timeStamp: new Date().getTime()
|
||||
};
|
||||
helpers._display.inputter.onKeyDown(fakeEvent);
|
||||
helpers._display.inputter.onKeyUp(fakeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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"
|
||||
* hints: The hint text, i.e. a concatenation of the directTabText, the
|
||||
* emptyParameters and the arrowTabText. The text as inserted into the UI
|
||||
* will include NBSP and Unicode RARR characters, these should be
|
||||
* represented using normal space and '->' for the 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
|
||||
*/
|
||||
helpers.check = function(checks) {
|
||||
if ('input' in checks) {
|
||||
test.is(helpers._actual.input(), checks.input, 'input');
|
||||
}
|
||||
|
||||
if ('cursor' in checks) {
|
||||
test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
|
||||
}
|
||||
|
||||
if ('current' in checks) {
|
||||
test.is(helpers._actual.current(), checks.current, 'current');
|
||||
}
|
||||
|
||||
if ('status' in checks) {
|
||||
test.is(helpers._actual.status(), checks.status, 'status');
|
||||
}
|
||||
|
||||
if ('markup' in checks) {
|
||||
test.is(helpers._actual.markup(), checks.markup, 'markup');
|
||||
}
|
||||
|
||||
if ('hints' in checks) {
|
||||
test.is(helpers._actual.hints(), checks.hints, 'hints');
|
||||
}
|
||||
|
||||
if ('tooltipState' in checks) {
|
||||
test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
|
||||
}
|
||||
|
||||
if ('outputState' in checks) {
|
||||
test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
|
||||
}
|
||||
|
||||
if (checks.args != null) {
|
||||
var requisition = helpers._display.requisition;
|
||||
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) {
|
||||
test.ok(false, 'Unknown arg: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('value' in check) {
|
||||
test.is(assignment.value,
|
||||
check.value,
|
||||
'arg.' + paramName + '.value');
|
||||
}
|
||||
|
||||
if ('name' in check) {
|
||||
test.is(assignment.value.name,
|
||||
check.name,
|
||||
'arg.' + paramName + '.name');
|
||||
}
|
||||
|
||||
if ('type' in check) {
|
||||
test.is(assignment.arg.type,
|
||||
check.type,
|
||||
'arg.' + paramName + '.type');
|
||||
}
|
||||
|
||||
if ('arg' in check) {
|
||||
test.is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'arg.' + paramName + '.arg');
|
||||
}
|
||||
|
||||
if ('status' in check) {
|
||||
test.is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'arg.' + paramName + '.status');
|
||||
}
|
||||
|
||||
if ('message' in check) {
|
||||
test.is(assignment.getMessage(),
|
||||
check.message,
|
||||
'arg.' + paramName + '.message');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.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$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
helpers.exec = function(tests) {
|
||||
var requisition = helpers._display.requisition;
|
||||
var inputter = helpers._display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.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'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(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)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
@ -21,7 +21,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_toolbar_webconsole_errors_count.js \
|
||||
browser_layoutHelpers.js \
|
||||
head.js \
|
||||
helper.js \
|
||||
helpers.js \
|
||||
leakhunt.js \
|
||||
$(NULL)
|
||||
|
||||
|
@ -10,7 +10,7 @@ let console = (function() {
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
|
@ -1,459 +0,0 @@
|
||||
/* 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();
|
||||
}
|
||||
};
|
881
browser/devtools/shared/test/helpers.js
Normal file
881
browser/devtools/shared/test/helpers.js
Normal file
@ -0,0 +1,881 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Use as a JSM
|
||||
* ------------
|
||||
* helpers._createDebugCheck() and maybe other functions in this file can be
|
||||
* useful at runtime, so it is possible to use helpers.js as a JSM.
|
||||
* Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
|
||||
* DeveloperToolbar.jsm the following:
|
||||
*
|
||||
* XPCOMUtils.defineLazyModuleGetter(this, "helpers",
|
||||
* "resource:///modules/devtools/helpers.jsm");
|
||||
*
|
||||
* At the bottom of DeveloperToolbar.prototype._onload add this:
|
||||
*
|
||||
* var options = { display: this.display };
|
||||
* this._input.onkeypress = function(ev) {
|
||||
* helpers.setup(options);
|
||||
* dump(helpers._createDebugCheck() + '\n\n');
|
||||
* };
|
||||
*
|
||||
* Now GCLI will emit output on every keypress that both explains the state
|
||||
* of GCLI and can be run as a test case.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = [ 'helpers' ];
|
||||
|
||||
var test = { };
|
||||
|
||||
/**
|
||||
* 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 + ']');
|
||||
}
|
||||
}
|
||||
else {
|
||||
info('Expected: [ \"' + actualParams.join('", "') + '" ]');
|
||||
}
|
||||
}
|
||||
|
||||
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 (helpers) {
|
||||
helpers.setup({ display: DeveloperToolbar.display });
|
||||
}
|
||||
|
||||
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() {
|
||||
info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
info('Finish');
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers._display = undefined;
|
||||
|
||||
helpers.setup = function(options) {
|
||||
helpers._display = options.display;
|
||||
if (typeof ok !== 'undefined') {
|
||||
test.ok = ok;
|
||||
test.is = is;
|
||||
test.log = info;
|
||||
}
|
||||
};
|
||||
|
||||
helpers.shutdown = function(options) {
|
||||
helpers._display = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Various functions to return the actual state of the command line
|
||||
*/
|
||||
helpers._actual = {
|
||||
input: function() {
|
||||
return helpers._display.inputter.element.value;
|
||||
},
|
||||
|
||||
hints: function() {
|
||||
var templateData = helpers._display.completer._getCompleterTemplateData();
|
||||
var actualHints = templateData.directTabText +
|
||||
templateData.emptyParameters.join('') +
|
||||
templateData.arrowTabText;
|
||||
return actualHints.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u21E5/, '->')
|
||||
.replace(/ $/, '');
|
||||
},
|
||||
|
||||
markup: function() {
|
||||
var cursor = helpers._display.inputter.element.selectionStart;
|
||||
var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
|
||||
return statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
},
|
||||
|
||||
cursor: function() {
|
||||
return helpers._display.inputter.element.selectionStart;
|
||||
},
|
||||
|
||||
current: function() {
|
||||
return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
|
||||
},
|
||||
|
||||
status: function() {
|
||||
return helpers._display.requisition.getStatus().toString();
|
||||
},
|
||||
|
||||
outputState: function() {
|
||||
var outputData = helpers._display.focusManager._shouldShowOutput();
|
||||
return outputData.visible + ':' + outputData.reason;
|
||||
},
|
||||
|
||||
tooltipState: function() {
|
||||
var tooltipData = helpers._display.focusManager._shouldShowTooltip();
|
||||
return tooltipData.visible + ':' + tooltipData.reason;
|
||||
}
|
||||
};
|
||||
|
||||
helpers._directToString = [ 'boolean', 'undefined', 'number' ];
|
||||
|
||||
helpers._createDebugCheck = function() {
|
||||
var requisition = helpers._display.requisition;
|
||||
var command = requisition.commandAssignment.value;
|
||||
var input = helpers._actual.input();
|
||||
var padding = Array(input.length + 1).join(' ');
|
||||
|
||||
var output = '';
|
||||
output += 'helpers.setInput(\'' + input + '\');\n';
|
||||
output += 'helpers.check({\n';
|
||||
output += ' input: \'' + input + '\',\n';
|
||||
output += ' hints: ' + padding + '\'' + helpers._actual.hints() + '\',\n';
|
||||
output += ' markup: \'' + helpers._actual.markup() + '\',\n';
|
||||
output += ' cursor: ' + helpers._actual.cursor() + ',\n';
|
||||
output += ' current: \'' + helpers._actual.current() + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status() + '\',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState() + '\',\n';
|
||||
|
||||
if (command) {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
|
||||
output += ' args: {\n';
|
||||
output += ' command: { name: \'' + command.name + '\' },\n';
|
||||
|
||||
requisition.getAssignments().forEach(function(assignment) {
|
||||
output += ' ' + assignment.param.name + ': { ';
|
||||
|
||||
if (typeof assignment.value === 'string') {
|
||||
output += 'value: \'' + assignment.value + '\', ';
|
||||
}
|
||||
else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else if (assignment.value === null) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else {
|
||||
output += '/*value:' + assignment.value + ',*/ ';
|
||||
}
|
||||
|
||||
output += 'arg: \'' + assignment.arg + '\', ';
|
||||
output += 'status: \'' + assignment.getStatus().toString() + '\', ';
|
||||
output += 'message: \'' + assignment.getMessage() + '\'';
|
||||
output += ' },\n';
|
||||
});
|
||||
|
||||
output += ' }\n';
|
||||
}
|
||||
else {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
|
||||
}
|
||||
output += '});';
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* We're splitting status into setup() which alters the state of the system
|
||||
* and check() which ensures that things are in the right place afterwards.
|
||||
*/
|
||||
helpers.setInput = function(typed, cursor) {
|
||||
helpers._display.inputter.setInput(typed);
|
||||
|
||||
if (cursor) {
|
||||
helpers._display.inputter.setCursor({ start: cursor, end: cursor });
|
||||
}
|
||||
|
||||
helpers._display.focusManager.onInputChange();
|
||||
|
||||
test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate focusing the input field
|
||||
*/
|
||||
helpers.focusInput = function() {
|
||||
helpers._display.inputter.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing TAB in the input field
|
||||
*/
|
||||
helpers.pressTab = function() {
|
||||
helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing RETURN in the input field
|
||||
*/
|
||||
helpers.pressReturn = function() {
|
||||
helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing a key by keyCode in the input field
|
||||
*/
|
||||
helpers.pressKey = function(keyCode) {
|
||||
var fakeEvent = {
|
||||
keyCode: keyCode,
|
||||
preventDefault: function() { },
|
||||
timeStamp: new Date().getTime()
|
||||
};
|
||||
helpers._display.inputter.onKeyDown(fakeEvent);
|
||||
helpers._display.inputter.onKeyUp(fakeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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"
|
||||
* hints: The hint text, i.e. a concatenation of the directTabText, the
|
||||
* emptyParameters and the arrowTabText. The text as inserted into the UI
|
||||
* will include NBSP and Unicode RARR characters, these should be
|
||||
* represented using normal space and '->' for the 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
|
||||
*/
|
||||
helpers.check = function(checks) {
|
||||
if ('input' in checks) {
|
||||
test.is(helpers._actual.input(), checks.input, 'input');
|
||||
}
|
||||
|
||||
if ('cursor' in checks) {
|
||||
test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
|
||||
}
|
||||
|
||||
if ('current' in checks) {
|
||||
test.is(helpers._actual.current(), checks.current, 'current');
|
||||
}
|
||||
|
||||
if ('status' in checks) {
|
||||
test.is(helpers._actual.status(), checks.status, 'status');
|
||||
}
|
||||
|
||||
if ('markup' in checks) {
|
||||
test.is(helpers._actual.markup(), checks.markup, 'markup');
|
||||
}
|
||||
|
||||
if ('hints' in checks) {
|
||||
test.is(helpers._actual.hints(), checks.hints, 'hints');
|
||||
}
|
||||
|
||||
if ('tooltipState' in checks) {
|
||||
test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
|
||||
}
|
||||
|
||||
if ('outputState' in checks) {
|
||||
test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
|
||||
}
|
||||
|
||||
if (checks.args != null) {
|
||||
var requisition = helpers._display.requisition;
|
||||
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) {
|
||||
test.ok(false, 'Unknown arg: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('value' in check) {
|
||||
test.is(assignment.value,
|
||||
check.value,
|
||||
'arg.' + paramName + '.value');
|
||||
}
|
||||
|
||||
if ('name' in check) {
|
||||
test.is(assignment.value.name,
|
||||
check.name,
|
||||
'arg.' + paramName + '.name');
|
||||
}
|
||||
|
||||
if ('type' in check) {
|
||||
test.is(assignment.arg.type,
|
||||
check.type,
|
||||
'arg.' + paramName + '.type');
|
||||
}
|
||||
|
||||
if ('arg' in check) {
|
||||
test.is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'arg.' + paramName + '.arg');
|
||||
}
|
||||
|
||||
if ('status' in check) {
|
||||
test.is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'arg.' + paramName + '.status');
|
||||
}
|
||||
|
||||
if ('message' in check) {
|
||||
test.is(assignment.getMessage(),
|
||||
check.message,
|
||||
'arg.' + paramName + '.message');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.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$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
helpers.exec = function(tests) {
|
||||
var requisition = helpers._display.requisition;
|
||||
var inputter = helpers._display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.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'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(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)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
@ -28,7 +28,7 @@ _BROWSER_TEST_FILES = \
|
||||
browser_styleeditor_sv_resize.js \
|
||||
four.html \
|
||||
head.js \
|
||||
helper.js \
|
||||
helpers.js \
|
||||
media.html \
|
||||
media-small.css \
|
||||
minified.html \
|
||||
|
@ -13,95 +13,136 @@ function test() {
|
||||
}
|
||||
|
||||
function testEditStatus(browser, tab) {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit",
|
||||
markup: "VVVV",
|
||||
status: "ERROR",
|
||||
emptyParameters: [ " <resource>", " [line]" ],
|
||||
helpers.setInput('edit');
|
||||
helpers.check({
|
||||
input: 'edit',
|
||||
hints: ' <resource> [line]',
|
||||
markup: 'VVVV',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { status: 'INCOMPLETE' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit i",
|
||||
markup: "VVVVVI",
|
||||
status: "ERROR",
|
||||
directTabText: "nline-css",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit i');
|
||||
helpers.check({
|
||||
input: 'edit i',
|
||||
hints: 'nline-css [line]',
|
||||
markup: 'VVVVVI',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' i', status: 'INCOMPLETE' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit c",
|
||||
markup: "VVVVVI",
|
||||
status: "ERROR",
|
||||
directTabText: "ss#style2",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit c');
|
||||
helpers.check({
|
||||
input: 'edit c',
|
||||
hints: 'ss#style2 [line]',
|
||||
markup: 'VVVVVI',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' c', status: 'INCOMPLETE' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit http",
|
||||
markup: "VVVVVIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
|
||||
arrowTabText: "",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit http');
|
||||
helpers.check({
|
||||
input: 'edit http',
|
||||
hints: '://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css [line]',
|
||||
markup: 'VVVVVIIII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' http', status: 'INCOMPLETE', message: '' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit page1",
|
||||
markup: "VVVVVIIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit page1');
|
||||
helpers.check({
|
||||
input: 'edit page1',
|
||||
hints: ' [line] -> http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage1.css',
|
||||
markup: 'VVVVVIIIII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' page1', status: 'INCOMPLETE', message: '' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit page2",
|
||||
markup: "VVVVVIIIII",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
arrowTabText: "http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage2.css",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit page2');
|
||||
helpers.check({
|
||||
input: 'edit page2',
|
||||
hints: ' [line] -> http://example.com/browser/browser/devtools/styleeditor/test/resources_inpage2.css',
|
||||
markup: 'VVVVVIIIII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' page2', status: 'INCOMPLETE', message: '' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit stylez",
|
||||
markup: "VVVVVEEEEEE",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
arrowTabText: "",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit stylez');
|
||||
helpers.check({
|
||||
input: 'edit stylez',
|
||||
hints: ' [line]',
|
||||
markup: 'VVVVVEEEEEE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' stylez', status: 'ERROR', message: 'Can\'t use \'stylez\'.' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit css#style2",
|
||||
markup: "VVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
directTabText: "",
|
||||
emptyParameters: [ " [line]" ],
|
||||
helpers.setInput('edit css#style2');
|
||||
helpers.check({
|
||||
input: 'edit css#style2',
|
||||
hints: ' [line]',
|
||||
markup: 'VVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
resource: { arg: ' css#style2', status: 'VALID', message: '' },
|
||||
line: { status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit css#style2 5",
|
||||
markup: "VVVVVVVVVVVVVVVVV",
|
||||
status: "VALID",
|
||||
directTabText: "",
|
||||
emptyParameters: [ ],
|
||||
helpers.setInput('edit css#style2 5');
|
||||
helpers.check({
|
||||
input: 'edit css#style2 5',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
resource: { arg: ' css#style2', status: 'VALID', message: '' },
|
||||
line: { value: 5, arg: ' 5', status: 'VALID' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit css#style2 0",
|
||||
markup: "VVVVVVVVVVVVVVVVE",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
emptyParameters: [ ],
|
||||
helpers.setInput('edit css#style2 0');
|
||||
helpers.check({
|
||||
input: 'edit css#style2 0',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' css#style2', status: 'VALID', message: '' },
|
||||
line: { arg: ' 0', status: 'ERROR', message: '0 is smaller than minimum allowed: 1.' },
|
||||
}
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "edit css#style2 -1",
|
||||
markup: "VVVVVVVVVVVVVVVVEE",
|
||||
status: "ERROR",
|
||||
directTabText: "",
|
||||
emptyParameters: [ ],
|
||||
helpers.setInput('edit css#style2 -1');
|
||||
helpers.check({
|
||||
input: 'edit css#style2 -1',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVEE',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
resource: { arg: ' css#style2', status: 'VALID', message: '' },
|
||||
line: { arg: ' -1', status: 'ERROR', message: '-1 is smaller than minimum allowed: 1.' },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ let gChromeWindow; //StyleEditorChrome window
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
|
@ -1,459 +0,0 @@
|
||||
/* 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();
|
||||
}
|
||||
};
|
881
browser/devtools/styleeditor/test/helpers.js
Normal file
881
browser/devtools/styleeditor/test/helpers.js
Normal file
@ -0,0 +1,881 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Use as a JSM
|
||||
* ------------
|
||||
* helpers._createDebugCheck() and maybe other functions in this file can be
|
||||
* useful at runtime, so it is possible to use helpers.js as a JSM.
|
||||
* Copy commandline/test/helpers.js to shared/helpers.jsm, and then add to
|
||||
* DeveloperToolbar.jsm the following:
|
||||
*
|
||||
* XPCOMUtils.defineLazyModuleGetter(this, "helpers",
|
||||
* "resource:///modules/devtools/helpers.jsm");
|
||||
*
|
||||
* At the bottom of DeveloperToolbar.prototype._onload add this:
|
||||
*
|
||||
* var options = { display: this.display };
|
||||
* this._input.onkeypress = function(ev) {
|
||||
* helpers.setup(options);
|
||||
* dump(helpers._createDebugCheck() + '\n\n');
|
||||
* };
|
||||
*
|
||||
* Now GCLI will emit output on every keypress that both explains the state
|
||||
* of GCLI and can be run as a test case.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = [ 'helpers' ];
|
||||
|
||||
var test = { };
|
||||
|
||||
/**
|
||||
* 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 + ']');
|
||||
}
|
||||
}
|
||||
else {
|
||||
info('Expected: [ \"' + actualParams.join('", "') + '" ]');
|
||||
}
|
||||
}
|
||||
|
||||
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 (helpers) {
|
||||
helpers.setup({ display: DeveloperToolbar.display });
|
||||
}
|
||||
|
||||
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() {
|
||||
info('_checkFinish. ' + DeveloperToolbarTest._outstanding.length + ' outstanding');
|
||||
if (DeveloperToolbarTest._outstanding.length == 0) {
|
||||
DeveloperToolbarTest._finish();
|
||||
}
|
||||
}
|
||||
|
||||
DeveloperToolbarTest._finish = function() {
|
||||
info('Finish');
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers._display = undefined;
|
||||
|
||||
helpers.setup = function(options) {
|
||||
helpers._display = options.display;
|
||||
if (typeof ok !== 'undefined') {
|
||||
test.ok = ok;
|
||||
test.is = is;
|
||||
test.log = info;
|
||||
}
|
||||
};
|
||||
|
||||
helpers.shutdown = function(options) {
|
||||
helpers._display = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Various functions to return the actual state of the command line
|
||||
*/
|
||||
helpers._actual = {
|
||||
input: function() {
|
||||
return helpers._display.inputter.element.value;
|
||||
},
|
||||
|
||||
hints: function() {
|
||||
var templateData = helpers._display.completer._getCompleterTemplateData();
|
||||
var actualHints = templateData.directTabText +
|
||||
templateData.emptyParameters.join('') +
|
||||
templateData.arrowTabText;
|
||||
return actualHints.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u21E5/, '->')
|
||||
.replace(/ $/, '');
|
||||
},
|
||||
|
||||
markup: function() {
|
||||
var cursor = helpers._display.inputter.element.selectionStart;
|
||||
var statusMarkup = helpers._display.requisition.getInputStatusMarkup(cursor);
|
||||
return statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
},
|
||||
|
||||
cursor: function() {
|
||||
return helpers._display.inputter.element.selectionStart;
|
||||
},
|
||||
|
||||
current: function() {
|
||||
return helpers._display.requisition.getAssignmentAt(helpers._actual.cursor()).param.name;
|
||||
},
|
||||
|
||||
status: function() {
|
||||
return helpers._display.requisition.getStatus().toString();
|
||||
},
|
||||
|
||||
outputState: function() {
|
||||
var outputData = helpers._display.focusManager._shouldShowOutput();
|
||||
return outputData.visible + ':' + outputData.reason;
|
||||
},
|
||||
|
||||
tooltipState: function() {
|
||||
var tooltipData = helpers._display.focusManager._shouldShowTooltip();
|
||||
return tooltipData.visible + ':' + tooltipData.reason;
|
||||
}
|
||||
};
|
||||
|
||||
helpers._directToString = [ 'boolean', 'undefined', 'number' ];
|
||||
|
||||
helpers._createDebugCheck = function() {
|
||||
var requisition = helpers._display.requisition;
|
||||
var command = requisition.commandAssignment.value;
|
||||
var input = helpers._actual.input();
|
||||
var padding = Array(input.length + 1).join(' ');
|
||||
|
||||
var output = '';
|
||||
output += 'helpers.setInput(\'' + input + '\');\n';
|
||||
output += 'helpers.check({\n';
|
||||
output += ' input: \'' + input + '\',\n';
|
||||
output += ' hints: ' + padding + '\'' + helpers._actual.hints() + '\',\n';
|
||||
output += ' markup: \'' + helpers._actual.markup() + '\',\n';
|
||||
output += ' cursor: ' + helpers._actual.cursor() + ',\n';
|
||||
output += ' current: \'' + helpers._actual.current() + '\',\n';
|
||||
output += ' status: \'' + helpers._actual.status() + '\',\n';
|
||||
output += ' outputState: \'' + helpers._actual.outputState() + '\',\n';
|
||||
|
||||
if (command) {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\',\n';
|
||||
output += ' args: {\n';
|
||||
output += ' command: { name: \'' + command.name + '\' },\n';
|
||||
|
||||
requisition.getAssignments().forEach(function(assignment) {
|
||||
output += ' ' + assignment.param.name + ': { ';
|
||||
|
||||
if (typeof assignment.value === 'string') {
|
||||
output += 'value: \'' + assignment.value + '\', ';
|
||||
}
|
||||
else if (helpers._directToString.indexOf(typeof assignment.value) !== -1) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else if (assignment.value === null) {
|
||||
output += 'value: ' + assignment.value + ', ';
|
||||
}
|
||||
else {
|
||||
output += '/*value:' + assignment.value + ',*/ ';
|
||||
}
|
||||
|
||||
output += 'arg: \'' + assignment.arg + '\', ';
|
||||
output += 'status: \'' + assignment.getStatus().toString() + '\', ';
|
||||
output += 'message: \'' + assignment.getMessage() + '\'';
|
||||
output += ' },\n';
|
||||
});
|
||||
|
||||
output += ' }\n';
|
||||
}
|
||||
else {
|
||||
output += ' tooltipState: \'' + helpers._actual.tooltipState() + '\'\n';
|
||||
}
|
||||
output += '});';
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* We're splitting status into setup() which alters the state of the system
|
||||
* and check() which ensures that things are in the right place afterwards.
|
||||
*/
|
||||
helpers.setInput = function(typed, cursor) {
|
||||
helpers._display.inputter.setInput(typed);
|
||||
|
||||
if (cursor) {
|
||||
helpers._display.inputter.setCursor({ start: cursor, end: cursor });
|
||||
}
|
||||
|
||||
helpers._display.focusManager.onInputChange();
|
||||
|
||||
test.log('setInput("' + typed + '"' + (cursor == null ? '' : ', ' + cursor) + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate focusing the input field
|
||||
*/
|
||||
helpers.focusInput = function() {
|
||||
helpers._display.inputter.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing TAB in the input field
|
||||
*/
|
||||
helpers.pressTab = function() {
|
||||
helpers.pressKey(9 /*KeyEvent.DOM_VK_TAB*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing RETURN in the input field
|
||||
*/
|
||||
helpers.pressReturn = function() {
|
||||
helpers.pressKey(13 /*KeyEvent.DOM_VK_RETURN*/);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate pressing a key by keyCode in the input field
|
||||
*/
|
||||
helpers.pressKey = function(keyCode) {
|
||||
var fakeEvent = {
|
||||
keyCode: keyCode,
|
||||
preventDefault: function() { },
|
||||
timeStamp: new Date().getTime()
|
||||
};
|
||||
helpers._display.inputter.onKeyDown(fakeEvent);
|
||||
helpers._display.inputter.onKeyUp(fakeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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"
|
||||
* hints: The hint text, i.e. a concatenation of the directTabText, the
|
||||
* emptyParameters and the arrowTabText. The text as inserted into the UI
|
||||
* will include NBSP and Unicode RARR characters, these should be
|
||||
* represented using normal space and '->' for the 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
|
||||
*/
|
||||
helpers.check = function(checks) {
|
||||
if ('input' in checks) {
|
||||
test.is(helpers._actual.input(), checks.input, 'input');
|
||||
}
|
||||
|
||||
if ('cursor' in checks) {
|
||||
test.is(helpers._actual.cursor(), checks.cursor, 'cursor');
|
||||
}
|
||||
|
||||
if ('current' in checks) {
|
||||
test.is(helpers._actual.current(), checks.current, 'current');
|
||||
}
|
||||
|
||||
if ('status' in checks) {
|
||||
test.is(helpers._actual.status(), checks.status, 'status');
|
||||
}
|
||||
|
||||
if ('markup' in checks) {
|
||||
test.is(helpers._actual.markup(), checks.markup, 'markup');
|
||||
}
|
||||
|
||||
if ('hints' in checks) {
|
||||
test.is(helpers._actual.hints(), checks.hints, 'hints');
|
||||
}
|
||||
|
||||
if ('tooltipState' in checks) {
|
||||
test.is(helpers._actual.tooltipState(), checks.tooltipState, 'tooltipState');
|
||||
}
|
||||
|
||||
if ('outputState' in checks) {
|
||||
test.is(helpers._actual.outputState(), checks.outputState, 'outputState');
|
||||
}
|
||||
|
||||
if (checks.args != null) {
|
||||
var requisition = helpers._display.requisition;
|
||||
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) {
|
||||
test.ok(false, 'Unknown arg: ' + paramName);
|
||||
return;
|
||||
}
|
||||
|
||||
if ('value' in check) {
|
||||
test.is(assignment.value,
|
||||
check.value,
|
||||
'arg.' + paramName + '.value');
|
||||
}
|
||||
|
||||
if ('name' in check) {
|
||||
test.is(assignment.value.name,
|
||||
check.name,
|
||||
'arg.' + paramName + '.name');
|
||||
}
|
||||
|
||||
if ('type' in check) {
|
||||
test.is(assignment.arg.type,
|
||||
check.type,
|
||||
'arg.' + paramName + '.type');
|
||||
}
|
||||
|
||||
if ('arg' in check) {
|
||||
test.is(assignment.arg.toString(),
|
||||
check.arg,
|
||||
'arg.' + paramName + '.arg');
|
||||
}
|
||||
|
||||
if ('status' in check) {
|
||||
test.is(assignment.getStatus().toString(),
|
||||
check.status,
|
||||
'arg.' + paramName + '.status');
|
||||
}
|
||||
|
||||
if ('message' in check) {
|
||||
test.is(assignment.getMessage(),
|
||||
check.message,
|
||||
'arg.' + paramName + '.message');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.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$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
helpers.exec = function(tests) {
|
||||
var requisition = helpers._display.requisition;
|
||||
var inputter = helpers._display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.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'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
var doTest = function(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(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)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user